跳至內容
0%

如何在 Yul 中讀取與寫入 packed storage 變數

發布於 2023年8月1日閱讀時間 1 分鐘

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 中 MemoryStorage 以及 Smart Contract Calls 的運作方式。

Background gradient

打造區塊鏈魔法

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