Solidity

在建構子中使用儲存允許合約訪問先前分配的插槽

  • April 10, 2022

契約 1:捐贈時間戳和 etherAmount 在建構子外部聲明捐贈結構時分配到第二和第三個插槽。

pragma solidity ^0.4.21;

contract DonationChallenge {
   struct Donation {
       uint256 timestamp;
       uint256 etherAmount;
   }
   // Slot 0
   Donation[] public donations;

   // Slot 1
   address public owner;

   Donation donation;
       
   function DonationChallenge() public payable {       
       owner = msg.sender;
       donation.timestamp = now;
       donation.etherAmount = 10;
       
   }
}

契約 2:捐贈結構在建構子中聲明。現在,timestamp 和 etherAmount 被分配到第 0 個和第 1 個 slot。

contract DonationChallenge {
   struct Donation {
       uint256 timestamp;
       uint256 etherAmount;
   }
   Donation[] public donations;

   address public owner;
       
   function DonationChallenge() public payable {       
       owner = msg.sender;
   
       Donation donation;
   
       donation.timestamp = now;
       donation.etherAmount = 10;
       
   }
}

當我在建構子外部和內部聲明結構時,這種變化的原因是什麼(第一種情況下的插槽 2 和 3,第二種情況下的插槽 0 和 1)?

在這種情況下,Solidity 會發出警告,但我試圖了解這種行為的原因。

首先,您使用的是非常舊版本的solidity,自solidity 0.5.0以來不再允許該行為:

現在不允許未初始化的儲存變數。

在您的程式碼Donation donation;中是一個未初始化的儲存變數,現在它更像是Donation storage donation;.

無論如何,儲存變數非常簡單:它的值實際上是它所引用的儲存槽:從 0 到 2^256,格式類似於uint256,編譯器內部使用它的方式只是如何解釋它所指向的東西。

真正的問題是預設值是零值..所以一個未初始化的儲存變數預設指向儲存槽 0 並且給定您的結構佈局,donation.timestamp 被寫入槽 0 而donation.etherAmount 被寫入槽1.

這可能會用無效的數據覆蓋現有數據(就像您對donations和所做的那樣owner),或者更糟糕的是,為攻擊者提供了一種用他們選擇的地址/值覆蓋您的所有者插槽的方法,僅僅是因為您依賴於未定義的行為:使用未初始化的儲存變數。

所以不要這樣做,並使用更新/更安全的solidity版本,例如0.5.0+,它不允許你編寫這樣的程式碼。

我希望這能回答你的問題。

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