智能合約基本上由狀態變量和函數組成。有些函數是私有的,只能從合約內部訪問,但許多函數是公共的,可以從合約外部訪問。也就是說,應用程序(和人)可以向合約發送數據並從合約中檢索數據。

要將數據發送到合約,我們需要以合約可以讀取的方式發送數據。也就是說,它們需要被編碼。如何執行這種編碼的規則由以太坊虛擬機(EVM)的實現定義。

在本文中,我們將學習一些關於編碼規則的知識,以及如何使用solidity對必須作為函數參數發送的數據進行編碼和解碼。

使用abi.encode()對函數的參數進行編碼

Solidity有一個名為abi的全局變量,它有一個encode方法,因此我們可以使用它對任何函數的參數進行編碼。讓我們從一個簡單的例子開始。假設我們有下面這個函數

function myFunction(address _myAddress, uint _myNumber)...

我們只對函數的參數進行編碼,即地址和整數。我們可以使用remix 來創建一個執行此操作的函數。

部署這個合約,並使用以下地址和無符號整數的值調用函數encode(…):(0x5b38da6a701c568545dcfcb03fcb875f56bedddc4, 127),我們得到了結果

0x0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4000000000000000000000000000000000000000000000000000000000000007f

對結果的快速分析顯示,它有64個字節。這是因為編碼是以32字節的倍數進行的:

0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4 000000000000000000000000000000000000000000000000000000000000007f

前32個字節包含地址(20個字節),其餘32個字節包含整數7f。編碼總是十六進制,十六進制的7f是127。

使用abi.decode()解碼函數的參數

現在讓我們使用Solidity來解碼函數的參數。注意,沒有必要識別我們正在處理的函數,因為它的簽名將在編碼參數之前。為了使問題更加複雜,讓我們使用動態變量作為參數。

讓我們使用以下合約來解碼一組值:string、uint和string。

contract Encode {function encode(string memory _string1, uint _uint, string memory _string2) public pure returns (bytes memory) { return (abi.encode(_string1, _uint, _string2)); }function decode(bytes memory data) public pure returns (string memory _str1, uint _number, string memory _str2) { (_str1, _number, _str2) = abi.decode(data, (string, uint, string)); }}

部署,然後使用以下參數(João,3,Paulo)調用函數encode(…),我們有以下返回:

0x0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000054a6fc3a36f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000055061756c6f000000000000000000000000000000000000000000000000000000

我們可能期望返回96個字節(3 x 32),因為我們有3個變量。但是,這3個變量中有2個是動態的,對動態變量的編碼就沒那麼簡單了。讓我把上面的值分解成32字節的數據塊。

0000000000000000000000000000000000000000000000000000000000000060 0000000000000000000000000000000000000000000000000000000000000003 00000000000000000000000000000000000000000000000000000000000000a0 0000000000000000000000000000000000000000000000000000000000000005 4a6fc3a36f000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000005 5061756c6f000000000000000000000000000000000000000000000000000000

我將快速解釋一下字符串的編碼是如何完成的。第一行指向第一個變量,第二行指向第二個變量,第三行指向第三個變量。因為第二個變量的類型是value,所以我們可以直接在第二行檢索它的值3。

對於變量類型字符串,第一行包含的數據是關於第一個字符串的信息。在本例中,十六進制數據為60,十進制數據為96。但這意味著什麼呢?這意味著第一個字符串的信息是在從數據開始的96個字節之後找到的。

在92字節之後,32字節的塊有一個數字:5。這是字符串所佔用的字節數,從下一行開始,以utf-8編碼:4a6fc3a36f。從十六進制轉換為UTF-8,我們檢索到單詞“João”。

按照相同的模式,可以檢索a0字節之後的第三個字符串,也就是從數據開始的160字節之後的字符串。它說它也有5個字節,它的值是5061756c6f, 是'Paulo' 的UTF-8 編碼。

現在,我們已經看到瞭如何手動完成此操作,現在看看如何通過solidity來完成此操作。使用我們在合約中寫的函數decode(bytes memory data),可以檢索編碼後的信息:

還可以使用其他庫對變量進行編碼和解碼,比如web3.eth.abi。目前也有一個在線網站可以用於此,abi.hashex.org/。

Source:https://medium.com/coinmonks/abi-encode-and-decode-using-solidity-2d372a03e110