EVM 如何辨識函式 calldata 中的動態類型?
因此,根據 Solidity Docs 中提到的 ABI 編碼規範,對於動態數組,首先指定數據位置(以字節為單位,用於數據部分),然後是先前指定位置的數組長度,然後是由實際數據值。
文件中的範例:
要呼叫的函式:
function sam(bytes memory, bool, uint[] memory) public pure {}
sam (“dave”, true,$$ 1, 2, 3 $$) :
0xa5643bf2 00000000000000000000000000000000000000000000000000000000000060 000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a0 0000000000000000000000000000000000000000000000000000000000000004 646176650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
這裡,第一組粗體字節表示“dave”字節值的位置。第二組粗體值是實際數據(從數據的長度開始,這裡是 4)。
那麼,在解釋 calldata 時,EVM 與動態數據的位置和普通變數值有何不同?即在這裡,如何將 0x00…60 標識為位置值,而不是可能是靜態 uint?
回答我自己的問題。
所以,我顯然錯過了 abi-encoding 函式遵循頭尾編碼機制的事實。然後,abi-decoding 函式跟踪參數類型——實際上它檢查數據類型是否具有預定義的大小,如果沒有,則將手頭的值視為起始位置。
這是decode_abi的一個非常清晰的pyethereum實現。
這是函式的神奇部分:
for i, typ in enumerate(types): if sizes[i] is None: start_positions[i] = big_endian_to_int(data[pos:pos + 32]) j = i - 1 while j >= 0 and start_positions[j] is None: start_positions[j] = start_positions[i] j -= 1 pos += 32 else: outs[i] = data[pos:pos + sizes[i]] pos += sizes[i]