• <option id="cacee"><noscript id="cacee"></noscript></option>
  • <table id="cacee"><noscript id="cacee"></noscript></table>
  • <td id="cacee"></td>
  • <option id="cacee"></option>
  • <table id="cacee"></table>
  • <option id="cacee"><option id="cacee"></option></option>
  • <table id="cacee"><source id="cacee"></source></table><td id="cacee"><rt id="cacee"></rt></td>
    <option id="cacee"><option id="cacee"></option></option>
     找回密碼
     立即注冊

    掃一掃,登錄網站

    首頁 自媒體 查看內容
    • 1203
    • 0
    • 分享到

    一文讀懂如何實現智能合約遷移

    2018-11-13 13:57

    來源: Uni-times

    智能合約也會遭受損害:比如存在漏洞、合約擁有者的錢包被盜,或者由于某種錯誤設置導致死鎖。如果你為自己的企業開發了智能合約,那么你必須做好應對類似事件的預案。在很多情況下,唯一的解決方案是部署一個新的合約實例,并將數據遷移到該實例中。


    如果你打算開發一個可升級的合約,遷移程序(migration procedure)將有助于免除可升級性機制(upgradability mechanism)的潛在危險[1]


    本文旨在為你詳細講解如何實現合約遷移。


    你需要嵌入合約遷移功能


    即使是零漏洞的合約也可能被竊取的私鑰劫持。先前的Bancor [2] 和 KICKICO [3]黑客事件表明:攻擊者可以損害智能合約錢包。在這些攻擊中,即使合約具備可升級性機制,也可能無法修復已部署的智能合約。唯一的解決辦法是重新部署并正確初始化新的合約實例,以便為用戶恢復功能。


    因此,所有智能合約開發者必須在合約設計階段整合一個遷移程序。此外,企業必須做好在合約損害事件發生時實施遷移的準備。


    遷移過程有兩個步驟:


    1. 恢復要遷移的數據

    2. 將數據寫入新合約


    我們來深入探討其中的細節、成本和操作后果。


    第一步:數據恢復


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


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


    數據恢復的具體操作取決于你的數據結構。


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


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


    上述技術你都可以使用。


    至于映射(mappings)的話,情況有點復雜。由于鍵(Keys)在映射過程中不會被存儲,所以你需要將它們進行恢復才能訪問對應的值(Values)。為了簡化鏈下追蹤的過程,我們建議在值被存儲在映射中時觸發事件(emit events)。


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


    對此,我們準備了兩個幫助方案:第一,你可以掃描區塊鏈并自行檢索持有者;第二,你可以依靠以太坊區塊鏈的公開Goog BigTable 存檔。


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


    如果你沒有已經完成同步的區塊鏈,那么你可以使用Google BigQuery API。圖1展示了如何通過BigQuery來收集某個特定代幣的所有地址:


    圖1:利用Google BigQuery來恢復那些與在0x41424344這個地址中的代幣相關聯的Transfer事件的所有地址


    BigQuery提供對區塊號的訪問,因此你可以將查詢結果調整為返回特定區塊的交易。


    一旦你恢復了所有代幣持有者的地址,你就可以離線查詢 balanceOf 函數 [6] 以恢復與每個持有者相關的余額,同時過濾余額為零的帳戶。


    現在我們知道如何檢索將要遷移的數據,接下來我們要將數據寫入新合約。


    第二步:數據寫入


    完成數據收集后,你需要開啟新合約。


    對于簡單變量,你可以通過合約的構造函數來設置相應的值。


    如果你的數據無法保存在單筆交易中,那么情況會有點復雜,成本也會略高。每筆交易都包含在某個區塊中,該區塊限制了其交易可以使用的 gas 總量(即所謂的 GasLimit)。如果某筆交易的 gas 成本接近或超過此限制,那么礦工將不會將其打包進該區塊內。因此,如果想要遷移大量數據,那么你必須將數據遷移拆分成多筆交易。


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


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


    1. 在初始化狀態下部署合約,

    2. 遷移余額,

    3. 將合約的狀態移至生產狀態。


    初始化狀態可以通過使用 OpenZeppelin 提供的 Pausable 功能 [7] 和指示初始化狀態的布爾值(boolean)來實現。


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


    圖2:batchTransfer 函數示例


    關于遷移的擔憂


    在遷移合約時,會出現兩個主要問題:


    1. 需要花費多少遷移成本?

    2. 對交易所有什么影響?


    遷移成本


    數據恢復是在在鏈下完成的,因此是免費的;Ethereum-etl [8] 也可以在本地使用;谷歌的 BigQuery API [9] 提供足夠的免費額度來支付其使用費用。


    但是,發送到網絡中的每一筆交易和新合約存儲的每個字節都需要花費成本。


    使用圖2的 batchTransfer 函數,給200個賬戶轉賬的成本約為2.4M gas ,依照本文撰寫時的平均 gas 價格(10 Gwei)約為5.04美元(你也可以使用ETH Gas Station [10] 重新計算最新的數值) 。粗略計算,每遷移一個余額需要花費0.025美元。


    如果我們看看按市值排名的前五大 ERC20 代幣 [11] 的持有人數,我們可以得到:


    如果你想遷移其它信息(例如 allowance [12] 功能),那么成本會更高。即便如此,與這些代幣所擁有的金額以及升級失敗的潛在成本相比,所需的成本費用依舊很低。


    交易所


    部署新合約可能會產生一些操作后果。對于基于代幣的合約,其運營團隊在遷移期間與交易所的協作非常重要,他們需要確保新合約被上線,同時舊合約將被廢棄。


    幸運的是,先前的代幣遷移事件(例如Augur [13],Vechain [14]和Tron [15])表明:交易所基本都會合作。


    合約遷移 v.s. 可升級合約


    在之前的博文[16]中,我們討論了智能合約設計的趨勢:即在合約內增加可升級機制。


    可升級合約有幾個缺點:


    • 需要掌握詳細的EVM和Solidity底層專業知識。基于 delegatecall的代理要求開發者掌握EVM和Solidity內部學識。


    • 提高了復雜性和代碼量。合約更難進行審查,更有可能包含漏洞和安全問題。


    • 增加了需要掌握的密鑰數量。合約將需要多個授權用戶(擁有者,升級者)。授權用戶越多,攻擊面越大。


    • 提高了每筆交易的 gas 成本。相對于同一版本但沒有升級機制的合約,有升級機制的合約的競爭力下降。


    • 可升級合約鼓勵在合約部署后再解決問題。如果開發人員知道無法輕松地更新合約,他們往往會更徹底地對合約進行測試和審查。


    • 可升級合約減少了用戶對合約的信任。用戶需要信任合約的擁有者,但這會阻礙真正的去中心系統的發展。


    只有在存在強有力的論據時,合約才應具有可升級機制,例如:


    • 合約需要經常更新。如果合約需要定期修改,那么定期遷移的成本將會非常高,相比之下,可升級機制反而更加合理。


    • 合約需要一個固定的地址。合約的遷移需要使用新的地址,這可能會破壞與第三方的交互(例如與其它合約的交互)。


    合約遷移在實現升級所帶來的優點的同時,還避免了不少缺點。升級相對于遷移的主要優點是:升級的成本更低。然而,這種成本并不足以覆蓋其所有的缺點。


    建議


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


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


    如果你想要部署可升級合約,那么你必須準備好遷移程序,因為你的密鑰可能會受到損害,或者你的合約可能會受到錯誤且不可逆轉的操縱。


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


    正文中涉及的鏈接:

    [1]:https://blog.trailofbits.com/2018/09/05/contract-upgrade-anti-patterns/

    [2]:https://twitter.com/Bancor/status/1016420621666963457

    [3]:https://medium.com/@kickico/kickico-security-breach-issue-under-control-all-kickcoins-will-be-returned-ebe65a491dec

    [4]:https://github.com/ethereum/wiki/wiki/JavaScript-API#web3ethgetstorageat

    [5]:https://github.com/blockchain-etl/ethereum-etl

    [6]:https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#balanceof

    [7]:https://github.com/OpenZeppelin/openzeppelin-solidity/blob/03dfb2965c6a607e216b110910f9fce1c43d8c94/contracts/token/ERC20/ERC20Pausable.sol

    [8]:https://github.com/blockchain-etl/ethereum-etl

    [9]:https://cloud.google.com/blog/products/data-analytics/ethereum-bigquery-public-dataset-smart-contract-analytics

    [10]:https://ethgasstation.info/calculatorTxV.php

    [11]:https://etherscan.io/tokens

    [12]:https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#allowance

    [13]:https://medium.com/@AugurProject/deployment-details-rep-migration-e5413ff9fb65

    [14]:https://medium.com/@vechainofficial/vechainthor-wallet-ama-5650dea84ccb

    [15]:https://medium.com/tron-foundation/guide-to-independence-trx-token-migration-269302b6655c

    [16]:https://blog.trailofbits.com/2018/09/05/contract-upgrade-anti-patterns/


    作者:Trail of Bits Blog

    翻譯:喏唄爾

    原文鏈接:

    https://blog.trailofbits.com/2018/10/29/how-contract-migration-works/

    版權申明:本內容來自于互聯網,屬第三方匯集推薦平臺。本文的版權歸原作者所有,文章言論不代表鏈門戶的觀點,鏈門戶不承擔任何法律責任。如有侵權請聯系QQ:3341927519進行反饋。
    相關新聞
    發表評論

    請先 注冊/登錄 后參與評論

      回頂部
    • <option id="cacee"><noscript id="cacee"></noscript></option>
    • <table id="cacee"><noscript id="cacee"></noscript></table>
    • <td id="cacee"></td>
    • <option id="cacee"></option>
    • <table id="cacee"></table>
    • <option id="cacee"><option id="cacee"></option></option>
    • <table id="cacee"><source id="cacee"></source></table><td id="cacee"><rt id="cacee"></rt></td>
      <option id="cacee"><option id="cacee"></option></option>
      妖精视频