Solidity
字節變數已連接
為什麼這些變數會混淆?返回的結果表明兩個循環都影響了兩個字節變數(
second
返回相同的結果)。function mix() public returns (bytes) { bytes first; for (uint8 cnt = 0; cnt<8; cnt++) { first.push(9) } bytes second; for (uint8 cnt2 = 0; cnt2<8; cnt2++) { second.push(8); } return first; }
返回結果:
'0x09090909090909090808080808080808'
這需要花一些時間來解釋。
程式碼看起來很無辜,但是有一個關於未初始化儲存指針的編譯器警告。警告不應被忽視。
明確寫出來,應該是
bytes storage first;
儲存指針可能開始看起來有點手感。考慮一下:
MyStruct s = structsMap[key]; s.someVal = false;
儲存空間
structsMap[key]
將設置為false
因為s
是儲存指針(又名引用變數)。它不是保存值,而是保存一個指向儲存的指針。當您寫入時s
,您正在寫入任何插槽s
所指的實際儲存,它在初始化時得到。您的
bytes first;
語句右側 (of ) 沒有任何內容=
,因此未初始化,因此預設為 slot0
。這是警告的“未初始化”部分。bytes second
獲得相同的插槽0
。哎呀!現在,我們在同一個儲存插槽上看到了看起來分開的東西。這裡是龍。如果我們在 global 部分聲明儲存,它將按預期工作:
contract NoMixing { bytes public first; bytes public second; function mix() public returns (bytes, bytes) { for (uint8 cnt = 0; cnt<8; cnt++) { first.push(9); } for (uint8 cnt2 = 0; cnt2<8; cnt2++) { second.push(8); } return (first,second); } }
我不是儲存指針的忠實擁護者,因為像您這樣的程式碼看起來應該可以工作。看到這個:https ://vessenes.com/solidity-frustrations-references-and-mapping/
一些一般安全提示:
- 聲明儲存外部函式。
memory
從索引類型 ( ) 分配某些內容時顯式使用[]
。這會使您的push
方法失敗,但至少您會收到有關該問題的警報。- 使用
x
after時要格外小心,x = somethingInStorage[index];
這樣你就不會覆蓋你不想改變的東西。希望能幫助到你。
更新
這是一個非常有趣的例子,我決定在部落格上討論這個問題。這是關於 Solidity 中儲存指針的解釋器,並提供了一些避免這種混淆的安全建議:https ://blog.b9lab.com/storage-pointers-in-solidity-7dcfaa536089