本關跟第8關Vault十分相似,都是從區塊中直接讀取資料,但需要對以太坊數據的排列更熟悉。多了解對編寫合約節省Gas 有非常大的好處,參考官方文檔。
Statically-sized variables (everything except mapping and dynamically-sized array types) are laid out contiguously in storage starting from position 0
. Multiple, contiguous items that need less than 32 bytes are packed into a single storage slot if possible, according to the following rules:
- The first item in a storage slot is stored lower-order aligned.
- Elementary types use only as many bytes as are necessary to store them.
- If an elementary type does not fit the remaining part of a storage slot, it is moved to the next storage slot.
- Structs and array data always start a new slot and occupy whole slots (but items inside a struct or array are packed tightly according to these rules).
以太坊在儲存時是以32 bytes為一格順序儲存的,所以定義變量的順序會影響花費Gas的多少,這是一大特色。
回到關卡合約,我們看到裏面定義了
bool public locked = true;
uint256 public ID = block.timestamp;
uint8 private flattening = 10;
uint8 private denomination = 255;
uint16 private awkwardness = uint16(now);
bytes32[3] private data;
依32 bytes 一格,會以下劃分:
Slot 0
bool public locked = true;
Slot 1
uint256 public ID = block.timestamp;
Slot 2
uint8 private flattening = 10;
uint8 private denomination = 255;
uint16 private awkwardness = uint16(now);
Slot 3-5
bytes32[3] private data;
我們的目標位於Slot 5,打開Console,輸入
> web3.eth.getStorageAt(instance, 5).then(console.log);
< 0xf8f7b3a3483669021dc62c871bd21917dd3cba5d3f2eccfe41d59b4008e623e6
然後把前16 bytes (0x後32 字元) 拿來做key呼叫unlock函數
> contract.unlock("0xf8f7b3a3483669021dc62c871bd21917")
最後按提交,本關完成。