一如何實現智慧合約的遷移
雖然相比其他網際網路技術,智慧合約等區塊鏈技術相對安全,但是並非絕對安全,即使是零漏洞的合約也有可能被竊取的私鑰劫持。先前的Bancor 和 KICKICO黑客事件表明:攻擊者可以損害智慧合約錢包。在這些攻擊中,即使合約具備可升級性機制,也可能無法修復已部署的智慧合約。唯一的解決辦法是重新部署並正確初始化新的合約例項,以便為使用者恢復功能。
因此,所有智慧合約開發者必須在合約設計階段整合一個遷移程式。此外,企業必須做好在合約損害事件發生時實施遷移的準備。
遷移過程有兩個步驟:
1、恢復要遷移的資料
2、
具體操作如下:
第一步:資料恢復
你需要從區塊鏈的某個特定區塊中讀取資料。要想從損害事件(黑客攻擊或故障)中恢復資料,你需要在事件發生之前使用這個區塊,或者過濾攻擊者的操作。
如果可以的話,請暫停合約。這對於使用者來說更加透明公平,並能阻止攻擊者盯上那些對遷移不知情的使用者。
資料恢復的具體操作取決於你的資料結構。
對於簡單型別的公共變數(public variables,例如 uint 或 address)來說,通過它們的getter來檢索特定值就可以了。而對於私有變數(private variables),你可以依賴事件,也可以計算變數的記憶體偏移量,然後使用
由於元素的數量是已知的,因此陣列也很容易恢復。
至於對映(mappings)的話,情況有點複雜。由於鍵(Keys)在對映過程中不會被儲存,所以你需要將它們進行恢復才能訪問對應的值(Values)。為了簡化鏈下追蹤的過程,我們建議在值被儲存在對映中時觸發事件(emit events)。
在 ERC20 代幣合約中,你可以通過追蹤代幣的Transfer事件的地址來獲取代幣持有者列表。這個過程很難。
對此,我們準備了兩個幫助方案:第一,你可以掃描區塊鏈並自行檢索持有者;第二,你可以依靠以太坊區塊鏈的公開Goog BigTable 存檔。
如果你不熟悉web3 API,無法從區塊鏈中提取資訊。那麼你可以使用ethereum-etl ,其提供了一系列指令碼來簡化資料提取的過程。
如果你沒有已經完成同步的區塊鏈,那麼你可以使用Google BigQuery API。圖1展示瞭如何通過BigQuery來收集某個特定代幣的所有地址:
圖1:利用Google BigQuery來恢復那些與在0x41424344這個地址中的代幣相關聯的Transfer事件的所有地址
BigQuery提供對區塊號的訪問,因此你可以將查詢結果調整為返回特定區塊的交易。
一旦你恢復了所有代幣持有者的地址,你就可以離線查詢 balanceOf 函式 以恢復與每個持有者相關的餘額,同時過濾餘額為零的帳戶。
現在我們知道如何檢索將要遷移的資料,接下來我們要將資料寫入新合約。
第二步:資料寫入
完成資料收集後,你需要開啟新合約。
對於簡單變數,你可以通過合約的建構函式來設定相應的值。
如果你的資料無法儲存在單筆交易中,那麼情況會有點複雜,成本也會略高。每筆交易都包含在某個區塊中,該區塊限制了其交易可以使用的 gas 總量(即所謂的 GasLimit)。如果某筆交易的 gas 成本接近或超過此限制,那麼礦工將不會將其打包進該區塊內。因此,如果想要遷移大量資料,那麼你必須將資料遷移拆分成多筆交易。
這類情況的解決方案是:在合約中新增初始化狀態,只有合約擁有者才能更改狀態變數,並且使用者無法執行任何操作。
對於 ERC20 代幣,上述過程將需要以下步驟:
1、在初始化狀態下部署合約,
2、遷移餘額,
3、將合約的狀態移至生產狀態。
初始化狀態可以通過使用 OpenZeppelin 提供的 Pausable 功能和指示初始化狀態的布林值(boolean)來實現。
為了降低成本,我們可以使用batchTransfer(批量傳輸)函式(該函式允許你在單筆交易中設定多個帳戶)來實現餘額的遷移:
圖2:batchTransfer 函式示例
建議
在合約部署之前做好遷移程式的功課。
使用事件(events)來提高資料追蹤的效率。
如果你想要部署可升級合約,那麼你必須準備好遷移程式,因為你的金鑰可能會受到損害,或者你的合約可能會受到錯誤且不可逆轉的操縱。
智慧合約帶來了新的開發正規化——其不可變性要求使用者重新思考搭建應用的方式,並且需要更透徹全面的設計和開發過程。
作者:Trail of Bits Blog
翻譯:喏唄爾
來源:Unitimes