Solidity
在建構子中使用儲存允許合約訪問先前分配的插槽
契約 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+,它不允許你編寫這樣的程式碼。
我希望這能回答你的問題。