如何在 Yul 中讀取與寫入 packed storage 變數
Yul 是一種中介程式語言,可以用來在智能合約內撰寫組合語言。在了解 Yul 的語法以及 storage 的運作方式後,接下來要學的是如何在 Yul 中讀寫 packed storage 變數。
如何在 yul 中讀寫 packed storage 變數
假設你想把 var5 改成 4。我們知道 var5 位於 slot 3,所以你可能會試著這樣寫:
用 getValInHex(3) 查看,會發現 slot 3 被改寫成:
0x0000000000000000000000000000000000000000000000000000000000000004
這就有問題了,因為現在 var4 也被改寫成 0 了。這一節我們要說明如何讀寫 packed 變數,但在那之前得先多了解一些 Yul 的語法。
如果你不熟悉這些運算子也沒關係,我們會用範例一一說明。
先從 and() 開始。我們拿兩個 bytes32,試試 and() 運算子,看看會回傳什麼。
看輸出結果會發現:
0x0000000000000000000000009acc1d6aa9b846083e8a497a661853aae07f0f00
原因在於 and() 是逐一比對兩個輸入中每一個 bit 的值。
如果兩個 bit 都是 1(用二進位的角度來想:啟用或未啟用),那個 bit 就會保持原樣。
否則就會被設成 0。
接著看看 or() 的程式碼。
這次的輸出是:
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
這是因為 or() 檢查的是「兩者之一」的 bit 是否啟用。
再來看看如果把 mask 變數改成:
0x00ffffffffffffffffffffff0000000000000000000000000000000000000000
會發生什麼事。
如你所見,輸出變成了:
0x00ffffffffffffffffffffff9acc1d6aa9b846083e8a497a661853aae07f0f00
注意第一個 byte 是 0x00,因為兩個輸入在第一個 byte 都沒有任何啟用的 bit。
xor() 稍微不一樣。它要求其中一個 bit 是啟用(1),另一個 bit 是未啟用(0)。
以下是程式碼示範:
輸出是:
0xffffffffffffffffffffffff0000000000000000000000000000000000000000
主要的差異在於,輸出中只有在 0x00 和 0xff 對齊的位置才會出現啟用的 bit。
shl() 和 shr() 的運作方式非常相似。兩者都會把輸入值移動指定的 bit 數。shl() 是往左移,shr() 是往右移。
來看一些程式碼吧!
輸出:
ans1: 0x0000ffff00000000000000000000000000000000000000000000000000000000
ans2: 0x00000000000000000000000000000000000000000000000000000000ffff0000
先來看 ans1。我們對它做了 16 bit(2 byte)的 shr()。可以看到最後兩個 byte 從 0xffff 變成 0x0000,而前兩個 byte 則往右移了兩個 byte。了解這點之後,ans2 就很好理解了;差別只在於這次是往左移而不是往右移。
在寫入 var5 之前,我們先寫一個函式,讀取 var4 和 var5。
輸出結果如預期,分別是 1 和 2。
要取得 var4,我們只需用 mask 把值設成:
0x0000000000000000000000000000000000000000000000000000000000000001
然後回傳一個等於 1 的 uint128。
讀取 var5 時,我們需要把 var4 的部分移除,方法是往右移。
這樣就會得到以下結果,可以直接回傳:
0x0000000000000000000000000000000000000000000000000000000000000002
要注意的是,如果一個 storage slot 裡塞了超過兩個變數,有時候需要同時做 shift 和 mask 才能讀到正確的值。
好,現在終於可以把 var5 的值改成 4 了!
第一步是載入 storage slot 3。
接著,我們要建立一個 mask。
跟讀取 var4 時類似,我們要把值隔離成:
0x0000000000000000000000000000000000000000000000000000000000000001
下一步是把新值格式化到 var5 在該 slot 中的位置,變成這樣:
0x0000000000000000000000000000000400000000000000000000000000000000
跟讀取 var5 時不同,這次我們要把值往左移。
最後,我們用 or() 把這些值合併成 32 個 byte 的十六進位值,並把該值存入 slot 3。
我們可以呼叫 getValInHex(3) 來檢查結果。
回傳的會是這個,,正是我們預期的結果:
0x0000000000000000000000000000000400000000000000000000000000000001
太好了,你現在已經知道如何讀寫 packed storage slot 了!接下來,了解 Yul 中 Memory、Storage 以及 Smart Contract Calls 的運作方式。
相關總覽

打造區塊鏈魔法
Alchemy 結合最強大的 Web3 開發者產品與工具,並提供資源、社群與卓越的支援。


