一如何實(shí)現(xiàn)智能合約的遷移

雖然相比其他互聯(lián)網(wǎng)技術(shù),智能合約等區(qū)塊鏈技術(shù)相對安全,但是并非絕對安全,即使是零漏洞的合約也有可能被竊取的私鑰劫持。先前的Bancor 和KICKICO黑客事件表明:攻擊者可以損害智能合約錢包。在這些攻擊中,即使合約具備可升級性機(jī)制,也可能無法修復(fù)已部署的智能合約。唯一的解決辦法是重新部署并正確初始化新的合約實(shí)例,以便為用戶恢復(fù)功能。

  因此,所有智能合約開發(fā)者必須在合約設(shè)計(jì)階段整合一個(gè)遷移程序。此外,企業(yè)必須做好在合約損害事件發(fā)生時(shí)實(shí)施遷移的準(zhǔn)備。

  遷移過程有兩個(gè)步驟:

  1、恢復(fù)要遷移的數(shù)據(jù)

  2、將數(shù)據(jù)寫入新合約

  具體操作如下:

第一步:數(shù)據(jù)恢復(fù)

你需要從區(qū)塊鏈的某個(gè)特定區(qū)塊中讀取數(shù)據(jù)。要想從損害事件(黑客攻擊或故障)中恢復(fù)數(shù)據(jù),你需要在事件發(fā)生之前使用這個(gè)區(qū)塊,或者過濾攻擊者的操作。

  如果可以的話,請暫停合約。這對于用戶來說更加透明公平,并能阻止攻擊者盯上那些對遷移不知情的用戶。

  數(shù)據(jù)恢復(fù)的具體操作取決于你的數(shù)據(jù)結(jié)構(gòu)。

對于簡單類型的公共變量(public variables,例如 uint 或 address)來說,通過它們的getter來檢索特定值就可以了。而對于私有變量(private variables),你可以依賴事件,也可以計(jì)算變量的內(nèi)存偏移量,然后使用 getStorageAt[4]函數(shù)檢索它的值。

  由于元素的數(shù)量是已知的,因此數(shù)組也很容易恢復(fù)。

至于映射(mappings)的話,情況有點(diǎn)復(fù)雜。由于鍵(Keys)在映射過程中不會(huì)被存儲(chǔ),所以你需要將它們進(jìn)行恢復(fù)才能訪問對應(yīng)的值(Values)。為了簡化鏈下追蹤的過程,我們建議在值被存儲(chǔ)在映射中時(shí)觸發(fā)事件(emit

  events)。

  在ERC20代幣合約中,你可以通過追蹤代幣的Transfer事件的地址來獲取代幣持有者列表。這個(gè)過程很難。

對此,我們準(zhǔn)備了兩個(gè)幫助方案:第一,你可以掃描區(qū)塊鏈并自行檢索持有者;第二,你可以依靠以太坊區(qū)塊鏈的公開Goog

  BigTable存檔。

  如果你不熟悉web3 API,無法從區(qū)塊鏈中提取信息。那么你可以使用ethereum-etl ,其提供了一系列腳本來簡化數(shù)據(jù)提取的過程。

  如果你沒有已經(jīng)完成同步的區(qū)塊鏈,那么你可以使用Google BigQuery

  API。圖1展示了如何通過BigQuery來收集某個(gè)特定代幣的所有地址:


  圖1:利用Google BigQuery來恢復(fù)那些與在0x41424344這個(gè)地址中的代幣相關(guān)聯(lián)的Transfer事件的所有地址

  BigQuery提供對區(qū)塊號(hào)的訪問,因此你可以將查詢結(jié)果調(diào)整為返回特定區(qū)塊的交易。

  一旦你恢復(fù)了所有代幣持有者的地址,你就可以離線查詢balanceOf函數(shù) 以恢復(fù)與每個(gè)持有者相關(guān)的余額,同時(shí)過濾余額為零的帳戶。

  現(xiàn)在我們知道如何檢索將要遷移的數(shù)據(jù),接下來我們要將數(shù)據(jù)寫入新合約。

第二步:數(shù)據(jù)寫入

  完成數(shù)據(jù)收集后,你需要開啟新合約。

  對于簡單變量,你可以通過合約的構(gòu)造函數(shù)來設(shè)置相應(yīng)的值。

  如果你的數(shù)據(jù)無法保存在單筆交易中,那么情況會(huì)有點(diǎn)復(fù)雜,成本也會(huì)略高。每筆交易都包含在某個(gè)區(qū)塊中,該區(qū)塊限制了其交易可以使用的gas總量(即所謂的

  GasLimit)。如果某筆交易的 gas

  成本接近或超過此限制,那么礦工將不會(huì)將其打包進(jìn)該區(qū)塊內(nèi)。因此,如果想要遷移大量數(shù)據(jù),那么你必須將數(shù)據(jù)遷移拆分成多筆交易。

這類情況的解決方案是:在合約中添加初始化狀態(tài),只有合約擁有者才能更改狀態(tài)變量,并且用戶無法執(zhí)行任何操作。

  對于ERC20代幣,上述過程將需要以下步驟:

  1、在初始化狀態(tài)下部署合約,

  2、遷移余額,

  3、將合約的狀態(tài)移至生產(chǎn)狀態(tài)。

  初始化狀態(tài)可以通過使用OpenZeppelin提供的 Pausable 功能和指示初始化狀態(tài)的布爾值(boolean)來實(shí)現(xiàn)。

  為了降低成本,我們可以使用batchTransfer(批量傳輸)函數(shù)(該函數(shù)允許你在單筆交易中設(shè)置多個(gè)帳戶)來實(shí)現(xiàn)余額的遷移:


  圖2:batchTransfer 函數(shù)示例

建議

  在合約部署之前做好遷移程序的功課。

  使用事件(events)來提高數(shù)據(jù)追蹤的效率。

  如果你想要部署可升級合約,那么你必須準(zhǔn)備好遷移程序,因?yàn)槟愕拿荑€可能會(huì)受到損害,或者你的合約可能會(huì)受到錯(cuò)誤且不可逆轉(zhuǎn)的操縱。

  智能合約帶來了新的開發(fā)范式——其不可變性要求用戶重新思考搭建應(yīng)用的方式,并且需要更透徹全面的設(shè)計(jì)和開發(fā)過程。

  作者:Trail of Bits Blog

  翻譯:喏唄爾

  來源:Unitimes

  原文鏈接:https://www.kg.com/article/510392457444331520

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容