智能合約的並行視角

3.1 引用

Sergey, Ilya, and Aquinas Hobor. "A concurrent perspective on smart contracts." International Conference on Financial Cryptography and Data Security. Springer, Cham, 2017.

3.2 摘要

在本文中,我們探討了加密貨幣中智能合約的多事務行為(如以太坊)與共享內存併發的經典問題之間的顯著相似性。 我們從以太坊區塊鏈中檢查了兩個真實世界的例子,並分析了它們如何容易受到與傳統併發程序中經常出現的錯誤相關的錯誤的影響。然後,我們詳細闡述了可觀察的合同行為與經過充分研究的併發主題之間的關係,例如原子性、干擾、同步和資源所有權。文中所描述的合同 - 併發 - 對象類比提供了對智能合同的潛在威脅的更深入理解,表明了更好的工程實踐,並且能夠應用現有的最先進的形式驗證技術。

3.3 技術介紹

儘管區塊鏈上的所有計算都是確定性的,但由於交易本身之間的 競爭(即礦工為給定區塊選擇了哪些交易),仍然會發生一定量的非確定性。我們將證明,非決定論可以被對抗方利用,並使合同行為變得不再確定,讓人聯想到傳統併發編程中涉及的已知挑戰。 在本文中,我們概述了一個強調其併發執行屬性的智能合約模型。 這樣的執行可以跨越多個區塊鏈交易(在同一個區塊內或多個區塊內)從而違反了僅使用合同的實施和本地狀態無法說明的所需安全屬性,正是現有驗證方法所關注的。 為了便於重用常見的編程直覺,我們提出以下類比: 在區塊鏈中使用智能合約的賬戶就像在共享內存中使用併發對象的線程。

在共享內存中使用併發對象的線程。對於併發對象,我們指的是廣泛 數據結構類,用於在多個線程(進程)併發運行之間交換數據並管 理它們之間的交互。併發對象的典型示例是鎖,隊列和原子計數器,通常通過流行的庫(如 java.util.concurrent)使用。在運行時, 這些併發對象分配在正在運行的線程可訪問的共享內存塊中。線程同時訪問對象所產生的行為可能非常難以預測,因此極難推理。 併發對象的實現沒有利用正確的同步(例如,使用鎖或障礙),可以在干擾下顯示數據爭用,從而導致內存完整性的損失。即使對於無競爭對象,從一個或多個客戶端的角度來看,在干擾下觀察到的行為可能是錯誤的。例如,特定線程可能不“預見”其他線程對共享對象採取的動作,因此可能不期望該對象以其在干擾下確實改變的所有方式改變。智能合約類似於併發對象。他們存在區塊鏈中,而不是在共享內存中;而不是由線程使用它們由帳戶(用戶或其他合同)調用。與併發對象一樣,它們具有內部可變狀態,管理資源(例如資金),並且可以由塊內和多個塊中的多方訪問。 與傳統的併發對象不同,由於計算的事務模型,智能合約的方法是原子的。也就是說,對合同的單次調用(或對一系列合同調用的一系列 調用)將按順序執行,沒有中斷,並在成功更新區塊鏈或中止之後終止並回滾到之前的配置之前。 然而,“免費原子性”的概念具有欺騙性,因為在區塊鏈的層面上仍然可以觀察到併發行為:包含在塊中的事務的順序不是在事務執行時確定的,因此,結果在很大程度上取決於相對於其他事務的排序。

在過去三十年中進行的併發和分佈式編程研究為編碼,指定,推理和正式驗證併發對象及其實現提 了大量理論和應用框架。因此,本文的目標是雙重的。首先,我們將簡要概述智能合約中可能出現的一些已知併發問題,並根據更傳統的併發抽象來描述問題。其次,我們的目標是建立一種“好”和 “壞”合同行為的直覺,可以使用為推理併發而開發的現有形式方法,相應地識別和驗證/檢測。

在這裡,我們討論已經部署在以太坊區塊鏈上的兩個合同,每個合同都說明了併發類型行為的不同方面。與今天以太坊區塊鏈上的許多其他人一樣,BlockKing合同實現了一個簡單的賭博遊戲。雖然 BlockKing 沒有被大量使用,但我們研究它是因為它展示了 Oraclize 服務的潛在用途,這是一種允許契約與區塊鏈之外的世界進行通信的服務,從而實現真正的併發。由於 Oraclize 服務的早期採用者將其 作為服務的演示並將其源代碼免費提供,因此許多其他希望使用 Oraclize 的合同可能會在其實現中反映出來。 我們討論的第二個例子是 DAO 合同中廣泛研究的錯誤。DAO 成立了一個業主管理的風險投資基金,超過 18,000 名投資者;在它的高度,它吸引了當時存在的所有以太幣的 14%以上。隨後的攻擊使投資者損失了大約 360 萬歐元,當時價值約為 5000 萬美元。DAO 採用了我們所謂的“不合作多任務處理”,因為當 DAO 向收件人匯款時,該收件人能夠運行代碼,干擾 (通過重入)DAO 的合同狀態,DAO 假設在呼叫期間不會改變。

3.3.1 BlockKing 合約

BlockKing 的賭博工作原理如下。在任何給定時間都有一個指定的“Block King”(最初是合同的作者)。當發送者 s 將錢發送給合同時,在 1 和 9 之間產生隨機數 j。如果模 10 的當前塊號等於 j,則 s 成為新的塊王。之 後,Block King 在合同中獲得一定比例的資金(從 50%到 90%,具體取決 於各種參數),合同的作者將獲得餘額。 在確定性系統中,通常很難生成高質量的隨機數,特別是在所有數據都是公開存儲的情況下,並且其中存在針對攻擊者的經濟激勵。因此, BlockKing 利用受信任方 Wolfram Alpha 的服務,使用 Oraclize 服務生成其隨機數。假設 Oraclize 表現良好,那麼隨機數選擇策略應該是攻擊者難以預測的。 BlockKing 的代碼長度為 365 行,但特別感興趣的行如圖 1 所示;這裡的行號是指 Etherscan給出的合同的實際源代碼。當錢被髮送到合同時調用 enter 函數。它設置了一些合約變量(第 299-301 行),然後向 Oraclize 服務發送查詢(第 303 行)。 oraclize_query 函數在返回其調用者之前引發在“真實世界”中可見的 事件,然後該調用者退出(行 304)。在現實世界中,Oraclize 服務器監視事件日誌,為請求提供服務(在這種情況下通過聯繫 Wolfram Alpha Web 服務),然後在指定的回調點(BlockKing 中的第 306 行)重新調用原始合同。在事件和它的回調之間,很多事情都可能發生,因為區塊鏈可以在 oraclize_query 調用和回調控制恢復之間推進幾個塊。在此期間,區塊鏈的狀態,甚至 BlockKing 合同本身的狀態都會發生巨大變化。換句話說, 這是區塊鏈上的真正併發行為。 什麼可能出錯?假設多個賭徒希望在短時間內(即使在同一個區 塊內)試試運氣。合同不會嘗試跟蹤此行為。因此,每個新參與者將在第 299-301 行覆蓋前一個數據(關鍵 warriorBlock 和 warrior 變量)。當回調確實最終發生時,批次中的最後一個參賽者將有多 次機會贏得那批支付其他回調的早期參賽者的寶座!罪魁禍首是來自 process_payment 函數的第 339-347 行,稱為最後一行第 309 行中的回調函數。

智能合約的並行視角

圖1 BlockKing 代碼片段

每次調用 process_payment 函數時,計算 warriorBlock 的最低有效位並將其存儲到變量 singleDigitBlock 中。6 每次通過回調調用 process_payment 函數時,他都有新機會匹配第 339 行中的隨機數。 如果數字確實匹配,然後最終的選手在 345 號線上加冕。

3.3.2 DAO合約

DAO 的源代碼是 1,239 行,明顯比 BlockKing 複雜[23]。由於已經 有很多關於這個 bug 的文章(例如[9,27]),我們在圖 2 中只給出了關鍵線。問題是第 1012 行的順序(通過一系列進一步的函數調用) 將 Ether 發送到 msg.sender,第 1014 行將 msg.sender 帳戶的餘額 清零。 在順序程序中,重新排序兩個獨立的操作對程序的最終行為沒有影響。但是,在併發程序中,順序無害的重新排序的效果會產生顯著的影響,因為操作發生的順序會影響線程的干擾方式。在 DAO 中, 在某些多任務處理中,將 1010 行中的以太網“發送”控制到位於 msg.sender 的任意(因此可能是惡意的)合同。

智能合約的並行視角

圖2 DAO代碼片段

不幸的是,DAO 內部狀態仍然表明該帳戶已獲得資金,因為其帳戶餘額尚未在第 1014 行歸零。因此,惡意的 msg.sender 可以通過回 調 DAO 合同來啟動第二次撤銷,該合同將在當控制再次到達第 1012 行時,轉向發送第二筆付款。實際上,惡意的 msg.sender 然後可以 發起第三次,第四次等撤銷,所有這些都將導致付款。只有在結束時,他的賬戶在支付了原始餘額的許多倍後才歸零。 以前對此錯誤的分析表明問題是由於遞歸或意外的重入。從狹義上講,這是事實,但從更廣泛的意義上說,正在發生的事情是順序代碼在許多意義上的併發環境中運行。

3.4 本文主要貢獻

我們相信,我們在智能合約和併發對象之間的類比可以提供新視角,激發研究,並允許有效地重用現有結果,工具和見解,以便理解,調試和驗證分佈式分類帳中的複雜合同行為。任何類比,我們不應該逐字逐句: 一方面,確實存在併發問題,這在合同編程中似乎難以觀察到;另一方面,智能合約實施者也應該注意在併發領域沒有直接對應物的概念,例如Gas限制執行和資金管理。


分享到:


相關文章: