Solidity

這個範例合約的缺陷是什麼?

  • June 1, 2020

我目前正在寫一篇關於標記化的論文/文章,在開頭我介紹了智能合約。為此,我以以下合約為例:

pragma solidity ^0.6.0;

contract SplitPot {
 address payable[] beneficiaries = [
   0x498898b3F52DAba1bB304a4b4D2EA31a111484B1,
   0xAcb19c763EB67ea757Efd8Cd8b6ecceb28F1284B,
   0xD5d3f3650C4DdE7B8034671129443A596Ce8ed57
 ];

 receive() external payable {
   uint individualAmount = msg.value / beneficiaries.length;

   for (uint i = 0; i < beneficiaries.length; i++) {
     beneficiaries[i].transfer(individualAmount);
   }
 }
}

顯然,該合約的目的是將發送給它的所有 Ether 平均分配給三個受益人(都是我創建的測試網帳戶)。它適用於測試網。

對於這個特定的目的,即解釋什麼是智能合約,我相信這是一個非常好的合約

  • 它非常簡短易懂。
  • 它做的事情通常是由受信任的第三方促成的——現在已經過時了。

我也知道這是一個非常糟糕的契約,因為它有嚴重的缺點。例如:如果交易失敗怎麼辦?Afaik,受益人無法收回他們的 Ether 份額,並且契約不會重新嘗試將其發送給他們。另外:我不知道合約是否也能在主網上正確執行。

我想告訴我的讀者,這實際上是一份有缺陷的契約,我想讓他們知道具體會出現什麼問題。當我剛開始了解乙太坊時,如果你能幫助我找出這些缺陷,我將非常感激——尤其是在氣體經濟學和編碼風格方面。

論文/文章將獲得 CC BY-SA 4.0 的許可,所以我不是在尋求商業工作的幫助!

您應該確保該函式receive不能被重新輸入,例如:

contract SplitPot {
   ...

   bool private locked = false;

   function receive() external payable {
       require(!locked, "reentrancy attempted");
       locked = true;
       ... // put your actual code here
       locked = false;
   }
}

請注意,您似乎忘記function了在程式碼中聲明之前receive() external payable,並且我已在此處添加它。


解釋重入保護:

你的函式執行beneficiaries[i].transfer(individualAmount);

如果beneficiaries[i]是合約地址,則呼叫該合約的回退函式;隨後,該函式可以呼叫您的函式並濫用其預期目標。


更新:

根據@blockrookie 的評論,該receive關鍵字是在 solc 0.6.x 中引入的。

通常稱為“備份函式”的未命名函式被拆分為使用關鍵字定義的新備份函式fallback和使用關鍵字定義的接收乙太函式receive

這兩個函式都是在沒有function關鍵字的情況下聲明的,因此我上面的註釋(“您似乎忘記在程式碼中聲明function之前receive() external payable”)在 solc 0.5.x 或更低版本下是相關的,但在 solc 0.6.x 或更高版本下不相關。

關於這個函式/關鍵字的更多細節可以在官方文件中找到。

引用自:https://ethereum.stackexchange.com/questions/83782