Solidity陷阱:以太坊的隨機數生成

tualala發表於2018-12-07

Solidity是一種相當新的語言,因為沒有程式碼是完美的,它包含與程式碼相關的問題以及你希望用它完成的任務。本文將指導你使用隨機數作為以太坊智慧合約的輸入時的最佳實踐和陷阱。

Solidity隨機數生成

Solidity無法建立隨機數。實際上,每個建立隨機數的演算法都是偽隨機的——沒有語言能夠建立完全隨機的數字。Solidity的問題在於複雜的演算法成本太高,因此使用了更基本的解決方案。除此之外,Solidity程式碼應該是確定性的,因為它將在多個節點上執行。我們需要一種能夠生成一次隨機數的演算法,並在多個節點上使用它。像時鐘時間這樣的東西不能用於生成隨機數,因此我們必須檢視其他選項。作為開發人員,你應該瞭解此問題,因為攻擊者能夠在某些特定情況下預測結果。

最常用的演算法之一是“線性同餘發生器”(LCG)。它是最古老的演算法之一,快速且易於理解。LCG是嵌入式系統的一個很好的選擇,因為它們的記憶體有限。但是,它不適合加密安全應用程式。雖然,這仍然在智慧合約中使用,因為快速演算法在氣體成本方面實施起來便宜得多。

演算法本身執行以下步驟:

  • 接受輸入。
  • 在輸入上執行演算法。
  • 取輸出模數(除以你需要的範圍內的最大數量)。
  • 在你需要的範圍內輸出0到最大數字。

讓我們探討使用彩票智慧合約示例建立隨機數的不同方法。使用者可以通過向合約傳送0.1以太以及0到250之間的整數來加入彩票。

1.Block.timestamp&Block.difficulty

每當他確認交易時,礦工就會分配一個block.timestamp。我們的彩票合約的任何玩家都無法控制它。讓我們看看這段程式碼來建立一個隨機數。

function random() private view returns (uint8) {
       return uint8(uint256(keccak256(block.timestamp, block.difficulty))%251);
   }

這段程式碼首先hash了一個塊時間戳和難度。接下來,我們將hash轉換為整數並將其除以251以獲得0到250之間的整數。但是,這段程式碼的問題在於我們不應該信任礦工來挑選勝利者。

2.彩票輸入任意資料

我們需要更多任意資料來挑選我們的贏家。我們可以使用已經進入我們的彩票智慧合約的玩家的地址,但是我們必須將其隱藏在其他玩家之外,因為他們可以濫用它。隱藏此資訊是不可能的,因為它全部記錄在區塊鏈上。

提交給我們的彩票智慧合約的號碼可以使用。使用者必須將他們選擇的號碼與他們的以太坊地址一起hash。這給了我們一個相當隨機的數字。

3.其他機制

3.1以太坊鬧鐘

開發人員需要考慮何時選擇勝利者。時間之類的東西在以太坊虛擬機器中不可用,因為程式碼將在不同的時間在多個節點上執行。這使得挑選勝利者變得更加困難。實現這一目標的一種方法是在智慧合約中實施一項功能,該功能將關閉彩票並選擇獲勝者。這不像我們希望的那樣去中心化。合約的所有者在確定他們的朋友將獲勝時可以關閉彩票。我們想避免這種作弊行為。

更好的選擇是使用以太坊鬧鐘。它是一種允許稍後在以太坊區塊鏈上執行排程事務的服務。這項服務完全沒有信任,這意味著整個服務作為智慧合約運作。基本上,以太坊鬧鐘使用塊號來安排交易。注意,這並不意味著合約本身就會被喚醒。它依賴於有興趣的使用者(以太獎勵)來呼叫“挑選獲勝者”功能。當然,如果沒有人打電話給你的功能,你的彩票就會失敗。

3.2隨機資料輸入

Random.org提供了一個API,通過JSON為你提供隨機資料來源。以太坊智慧合約可以使用此資料來源來提供選擇隨機數的演算法。由於安全性很重要,因此可以使用數字簽名。隨機資料將由Random.org簽署。你可以驗證資料的完整性,以便證明它確實來自Random.org並且資料未被篡改。

RANDAO是區塊鏈領域的一個新專案,專注於提供隨機數。他們使用oracles和智慧合約的組合為你提供隨機數字。但是,RANDAO服務目前相當緩慢。如果你擁有經常使用的應用程式,這並不理想。

3.3 Blocknumber Watcher

你還可以在程式碼中使用觀察程式,它會檢查程式段編號,直到它與你設定的目標編號相匹配。

function f( blocknumber, to_address, value_) { 
  var filter = web3.eth.filter(`latest`).watch(
    function(err, blockHash) { 

      var target=blocknumber; 

      if(web3.eth.blockNumber==target) { 
        filter.stopWatching(); // your function here 
        web3.eth.sendTransaction({to:to_address, from:web3.eth.coinbase, value: web3.toWei(value_,"ether")});
        filter = null; 

        console.warn(`Block reached`); 

        if (callback) return callback(false);
        else return false;

      } else { 
        console.log(`Waiting the block`); 
      } 
  }); 
};

3.4 iOlite智慧合約建立

iOlite正在建立一種接受自然語言來建立智慧合約的產品。它使用稱為快速自適應引擎(FAE)的史丹佛自然語言處理(NLP)引擎。iOlite依靠Solidity專家的社群培訓。Solidity專家(貢獻者)可以定義包含一個或多個句子的結構,並將其附加到相應的智慧合約程式碼。

史丹佛NLP引擎的建立是為了理解複雜的語言。語言複雜程度取決於機器培訓的數量。經過適當的培訓,引擎將能夠建立複雜的智慧合約。FAE能夠建立此類合約,因為複雜的合約實際上並不複雜。專家可以將請求拆分為多個較小的程式碼並將其附加到一個句子中。

當有人輸入多個句子時,它會尋找相應的結構/句子來建立“複雜”的合約。貢獻者將通過新結構的挖掘過程獲得iOlite代幣獎勵。

使用iOlite的好處是智慧合約專家可以像生成隨機數一樣為你解決難題。你可以在iOlite.io上找到更多資訊。

結論

如你所見,生成真正的隨機輸入並非易事。不要依賴block.timestamp,現在和block.blockhash作為隨機源。一個好的解決方案包括幾個偽隨機資料輸入的組合以及使用oracles或智慧合約來使其更可靠。你需要100%確定沒有人可以篡改輸入智慧合約的資料。

在實現隨機數生成邏輯之前要小心並三思而後行。

======================================================================

分享一些以太坊、EOS、比特幣等區塊鏈相關的互動式線上程式設計實戰教程:

  • java以太坊開發教程,主要是針對java和android程式設計師進行區塊鏈以太坊開發的web3j詳解。
  • python以太坊,主要是針對python工程師使用web3.py進行區塊鏈以太坊開發的詳解。
  • php以太坊,主要是介紹使用php進行智慧合約開發互動,進行賬號建立、交易、轉賬、代幣開發以及過濾器和交易等內容。
  • 以太坊入門教程,主要介紹智慧合約與dapp應用開發,適合入門。
  • 以太坊開發進階教程,主要是介紹使用node.js、mongodb、區塊鏈、ipfs實現去中心化電商DApp實戰,適合進階。
  • C#以太坊,主要講解如何使用C#開發基於.Net的以太坊應用,包括賬戶管理、狀態與交易、智慧合約開發與互動、過濾器和交易等。
  • EOS教程,本課程幫助你快速入門EOS區塊鏈去中心化應用的開發,內容涵蓋EOS工具鏈、賬戶與錢包、發行代幣、智慧合約開發與部署、使用程式碼與智慧合約互動等核心知識點,最後綜合運用各知識點完成一個便籤DApp的開發。
  • java比特幣開發教程,本課程面向初學者,內容即涵蓋比特幣的核心概念,例如區塊鏈儲存、去中心化共識機制、金鑰與指令碼、交易與UTXO等,同時也詳細講解如何在Java程式碼中整合比特幣支援功能,例如建立地址、管理錢包、構造裸交易等,是Java工程師不可多得的比特幣開發學習課程。
  • php比特幣開發教程,本課程面向初學者,內容即涵蓋比特幣的核心概念,例如區塊鏈儲存、去中心化共識機制、金鑰與指令碼、交易與UTXO等,同時也詳細講解如何在Php程式碼中整合比特幣支援功能,例如建立地址、管理錢包、構造裸交易等,是Php工程師不可多得的比特幣開發學習課程。
  • tendermint區塊鏈開發詳解,本課程適合希望使用tendermint進行區塊鏈開發的工程師,課程內容即包括tendermint應用開發模型中的核心概念,例如ABCI介面、默克爾樹、多版本狀態庫等,也包括代幣發行等豐富的實操程式碼,是go語言工程師快速入門區塊鏈開發的最佳選擇。

匯智網原創翻譯,轉載請標明出處。這裡是原文Solidity陷阱:以太坊的隨機數生成

相關文章