了解彙編中引用類型的第一個 evm 詞
給定以下功能:
function getArrayItems(bytes calldata) external returns ( bytes4 _signature, bytes32 _wutIsThis, bytes32 _length, bytes32 _firstItem ) { assembly { _signature := calldataload(0x00) // trim the first 4 bytes _wutIsThis := calldataload(0x04) _length := calldataload(0x24) _firstItem := calldataload(0x44) } }
當我執行與輸入混合
0xcafe
的程式碼時,我得到以下輸出:{ "0": "bytes4: _signature 0x38626302", "1": "bytes32: _wutIsThis 0x0000000000000000000000000000000000000000000000000000000000000020", "2": "bytes32: _length 0x0000000000000000000000000000000000000000000000000000000000000002", "3": "bytes32: _firstItem 0xcafe000000000000000000000000000000000000000000000000000000000000" }
我完全理解第 1 項、第 3 項和第 4 項。
_length
很棘手,但根據文件:動態數組的長度儲存在數組的第一個槽中,然後是數組元素。
這是第二項,
_wutIsThis
這給我帶來了麻煩。我的預感是它與數組的數據位置有關。也就是說,數據偏移了0x0000000000000000000000000000000000000000000000000000000000000020
,這意味著數組的第一項位於 calldata 中所述位置的位置之後的 32 個字節(我知道,這是元數據)。那是對的嗎?如果是,我們為什麼要這樣做,我在哪裡可以找到更多的文件?關於類型數據位置的solidity 文件有點含糊,僅說明引用類型必須指定關鍵字(
memory
或storage
)keyword
。
那是對的嗎?如果是,我們為什麼要這樣做,我在哪裡可以找到更多的文件?
是的,你是對的。
交易根據合約 ABI 規范進行編碼。很難通過,但這些文件有你問題的所有答案。
有問題的事務是傳入一個動態參數 (
bytes
) 而不是靜態參數 (uint
,address
等)。在對參數進行編碼時,EVM 會查看參數是靜態的還是動態的。靜態參數以相當簡單的方式編碼——它們被轉換為十六進製表示,然後連接到輸入數據十六進製字元串中。
動態值更有趣。使用文件的這一部分來完全理解,但想法是編碼數據是數據的位置。在所有動態類型之後,編碼數據本身然後連接到輸入數據十六進製字元串的末尾。對於動態類型,然後包含參數的長度,然後是數據本身。
分解您發布的交易:
0x386263020000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002cafe000000000000000000000000000000000000000000000000000000000000
0x38626302
這是被呼叫函式的方法 ID(在本例中為
getArrayItems(bytes)
)
0x0000000000000000000000000000000000000000000000000000000000000020
這是第一個(動態)參數的位置。這是
calldata
生活的地方,但不是數據本身。
0x0000000000000000000000000000000000000000000000000000000000000002
這是動態的長度
calldata
。在這種情況下,長度為 2由於方式bytes
works。EVM 將您0xcafe
視為 [0xca
],[0xfe
],這就是長度為 2 的原因,即使只有一個參數傳入。
cafe000000000000000000000000000000000000000000000000000000000000
傳入的數據
calldata
。