為什么要使用 transaction data?

2021-05-12 21:05:22

可能你也注意到了,在跟智能合約交互(例如發送 token)時,你的事務會自動包含 input data(“輸入數據”)。在 MyCrypto 錢包界面,這些數據有個簡單的標籤:“Data(數據)” —— 它是做什么的呢?

這篇文章就是從技術上解釋事務輸入數據是怎么一回事,它實質是什么,又是怎么工作的。

為什么要使用 transaction data?

- MyCrypto 錢包的高級事務設定 -

什么是 Input Data?

我們先來看看這筆 token 轉账交易。某個人發送了 0 ETH 到 0xd26114cd6ee289accf82350c8d8487fedb8a0c07(OmiseGo 合約地址),而且 Etherscan 網站呈現了這是一筆意圖發送 0.19 OMG token 到這個地址的事務。那么,EVM (以太坊虛擬機)究竟是怎么知道,這個人想要轉账某個數額的 token 到另一地址的呢?

你再仔細看 Etherscan,就能看到這筆事務帶着 input data。input data 是發送者為這筆事務附加的額外數據,既可以是普通的文本,也可以是數字(以十六進制的形式編碼)。但在這筆交易中,發送者使用這部分數據來 “告訴” 合約,讓合約運行特定的函數。智能合約本身是由一系列函數組成的。舉例而言,一個 ERC-20 token 合約使用比如 “transfer” 來把 token 從 A 账戶轉移到 B账戶,使用 “balancerOf” 函數來獲得某個地址的余額,等等。在我們研究的這筆交易中,你可以看到它調用了 transfer(address_to, uint256_value) 函數。

這筆事務的輸入數據為0xa9059cbb0000000000000000000000004bbeeb066ed09b7aed07bf39eee0460dfa26152000000000000000000000000000000000000000000000000002a34892d36d6c74。你可以把這一長串的 十六進制 數據分解一下。开頭的 0x 表示這是一個十六進制數值,緊接着的 8 個字節(a9059cbb)是函數標識符,再然後就全部是以 32 字節(也就是 64 個 16 進制字符)為一組的函數參數。所以第一組是 0000000000000000000000004bbeeb066ed09b7aed07bf39eee0460dfa261520 而第二組是 000000000000000000000000000000000000000000000000002a34892d36d6c74

為什么要使用 transaction data?

- Input Data 分解 -

如果你在 Etherscan 上查看這些數據,你會看到它以下文這個形式呈現

為什么要使用 transaction data?

十六進制是啥?

十六進制是一種計數系統,就像十進制和二進制一樣;十六進制使用數字 0 到 9 和字母 A 到 F(不區分大小寫),來對應表示十進制的 0 到 15。下面這種圖展現的就是這樣的對應關系。十六進制常常用來更直觀地表示大數字。

為什么要使用 transaction data?

- 十進制數字與對應的十六進制字符 -

單個十六進制字符所能表示的最大數值是 15,長度是 4 個比特(bit)。多個十六進制字符相連時,你要把每個字符的二進制表示前後拼接在一起,才能得到其十進制數值。舉個例子,0x5C,可以寫成 0101 (=5) 和 1100 (=C),前後拼接就是 01011100,這就是二進制形式的 92,所以十六進制數 0x5C 的數值就是 92。

大多數編程語言都使用前綴 0x 作為絕對標識符(arbitrary identifier),將十六進制數與其他的計數類型(比如普通的十進制、二進制等)區別开來。這個前綴本身沒有任何意義,只是為了清晰。我們這篇文章也會採取一樣的做法,十六進制數都用 0x 开頭。

講完這些,我們繼續。如果你還是沒能理解十六進制,也不用擔心 —— 對於理解 input data 來說不是必需的。

Input Data 與智能合約

Input Data 的首要用途就是與智能合約交互。大部分智能合約都使用 合約 ABI 規範,使得 Etherscan 這樣的網站能自動解碼 input data 並顯示事務所調用的具體操作。在我們上面那個例子中,這是一筆有關代幣合約的事務,而且代幣合約遵循 ERC-20 標准。這也就意味着,我們都知曉所有可能調用的函數,以及它們的 籤名。舉例,用於 ERC-20 合約的 transfer(轉账)函數的完整籤名總是 transfer(address, uint256),意味着這個函數需要兩個參數,所傳入的第一個參數會被解讀為一個地址,第二個參數會被解讀為一個未籤名的 256 位的數字(大小上限為 2256-1)。

Solidity 語言有多種參數類型。如果你有興趣學習 Solidity 語言和智能合約,你可以在Solidity 文檔頁面了解更多。

函數籤名

如你所見,transfer 函數的籤名是 transfer(address, uint256),這個對所有 ERC-20 合約都是一樣的。如果某個合約給轉账函數安排不一樣的參數類型,比如一個地址和一個 uint128(未籤名的 128 位整數),這個合約就不是 “ERC-20 兼容” 的。

要獲得一個函數的籤名的十六進制形式,我們先要獲得這個函數的 SHA-3(或者說 Keccak-256)哈希值的前面 4 個字節(也就是 8 個十六進制字符)。而要想知道一個數據的 Keccak-256 哈希值,你可以使用 JavaSceript 語言的 web3 庫,或者求助於這樣的在线工具。在這個工具頁面填入 transfer(address,uint256),它會顯示 0xa9059cbb2ab09eb219583f4a59a5d0623ade346d962bcd4e46b11da047c9049b 作為結果。取前 8 個字符(忽略掉 0x),就是 a9059cbb,恰好跟上述事務的 MethodID 一致。

另一個例子:ERC-20 標准合約的 approve(許可)函數的函數籤名是 approve(address,uint256),其 SHA-3 哈希值是 0x095ea7b334ae44009aa867bfb386f5c3b4b443ac6f0ee573fa91c4608fbadfba,首 8 個字符是 095ea7b3,因此,調用許可函數的 input data 开頭就會是 0x095ea7b3。這筆發往 DAI token 合約的事務就是如此。

地址和數量

每一個參數(除了 列表/數組 和純文本 —— 這些我們後文再說)的長度都是 32 字節,或者說 64 個十六進制字符。但以太坊地址只有 40 個字節長(不算 0x 的話)。為了解決這個問題,地址參數要用 0 來填充。在十六進制裏面,0x0000123 和 0x123 是一樣的,因此 0x0000000000000000000000004bbeeb066ed09b7aed07bf39eee0460dfa261520(上述事務中的地址參數)等同於 0x4bbeeb066ed09b7aed07bf39eee0460dfa261520,而且 0x00000000000000000000000000000000000000000000000002a34892d36d6c74 也就等於 0x2a34892d36d6c74。那為什么我們要填充這些 0 呢?

就像我們上面說到的,Solidity 合約可以接受的最大數值是 2256 - 1,剛好是 32 字節。使用固定的長度可以讓 EVM 和其他應用在解碼數據時候更輕松,因為你可以假設每一個參數的長度都是一樣的。

那數組和字符串呢?

如上所述,在 input data 中使用數組和字符串,情形會有些許不同。因為數組本質是多個東西組成的一個列表。舉個例子,1、2、3 三個數所組成的列表在大多數編程語言中都可以寫為 [1, 2, 3]。要在事務中發送這種數據,列表中的每一個對象都要作為 32 字節一組的數據發送,列在 input data 的結尾。指明數組長度的指針就作為參數。

假定我們有一個叫做 calledmyFunction 的函數,接收一個地址和數字的數組作為參數,即 myFunction(address,uint256[])。該函數的函數籤名是 0x4b294170。地址這一項,我們照上面所說的操作。因為我們的數組包含 3 個對象,數組的長度用十六進制表示為 0x3。然後每個對象都要佔據恰好 32 自己的空間,且數組要放在所有其它參數之後,所以數組會從 32+32 = 64 字節之後开始。

為什么要使用 transaction data?

- 例子:input 數據要按照 32 字節一組來切分 -

因為字符串的長度是任意的(可能長過 32 字節),它們要按 32 字節一組來切分,處理方式跟數組相同。

像 Etherscan 這樣的網站是如何解碼 input data 的?

哈希函數是單向函數,所以如果你只有函數籤名的哈希值,是不可能會恢復出函數籤名的(你要試試暴力破解嗎老弟)。合約的所有者可以將合約的 ABI 作為 JSON 文件上傳,就像這個例子,這可以用來拿到函數籤名的哈希值。

即使合約的所有者不上傳合約的 ABI,也能夠解碼 input 數據(對大多數合約而言)。因為,ERC-20 合約函數的籤名都是一樣的,因此 Etherscan 只需使用一個預定義的合約 ABI 即可服務大部分合約。舉個例子,ERC 20 合約的轉账函數的合約 ABI 如下文所示:

為什么要使用 transaction data?

如果輸入數據裏的籤名與任意一個預定義的函數相匹配,Etherscan 都能解碼 input data。

input data 的大小有沒有什么限制?

既有,也沒有。以太坊協議沒有為 input data 的長度設固定的上限,但 input data 也消耗 gas。單個區塊可用的 Gas 數量是有上限的,在本文撰寫時是 800 萬(譯者注:原文撰寫於 2019 年 2 月,在 2021 年 4 月,已經上升到 1500 萬)。每一個 0 字節(0x00)都要消耗 4 gas,而非零的字節要消耗 68 gas。一筆標准的 ETH 轉账事務要消耗 21000 單位 gas,所以,如果不考慮調用合約的交易,當前 input data 的最大長度是 2 MB(全部由 0 組成),或者全部用非零字節的話,就是 0.12 MB。因為 input data 不會只有零,也不會一個 0 也沒有,所以實際的大小會在兩者之間。

如果你想看實時的 區塊 Gas 上限,可以看 ETHStats.net。

為什么要使用 transaction data?

- 特定區塊的 Gas 上限 -

只需將鼠標停留在 “Gas Limit” 部分的某個區塊上,就可以看到其 Gas 上限。

更多信息

  • 合約 ABI 規範

  • ERC-20 Token 標准

  • 以太坊虛擬機

參考

  • 以太坊黃皮書

  • Solidity 文檔

原文鏈接:

https://blog.mycrypto.com/why-do-we-need-transaction-data-/

作者: Maarten Zuidhoorn

翻譯: 阿劍

鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播信息之目的,不構成任何投資建議,如有侵權行為,請第一時間聯絡我們修改或刪除,多謝。

推薦文章

btc日內再次下跌 短线應當如何處理?

盡管以太坊現貨ETF獲批是個好消息,但市場反應卻不如預期。在消息公布後,以太坊價格出現了小幅下跌,...

加密蓮
185 4個月前

7月23日、BTC(合約)ETH(合約)行情分析及操作策略

昨日收益還是不錯的,日內給出的現價空單分別止盈我們目標點位,恭喜跟上的朋友喫肉。時間一晃到月底了,...

倪老師
184 4個月前

幣圈院士:血與淚的教訓!交易者為何總是撞死在同一棵樹上?

幣圈院士談。交易市場中的幾種“死法” 在幣圈市場鱗次櫛比的海洋,風起雲湧,時常讓人感到驚手不及。在...

幣圈院士
192 4個月前

7月23:Mt. Gox 比特幣錢包在市場緊縮的情況下轉移了價值 28.2 億美元的 BTC

7月23:Mt. Gox 比特幣錢包在市場緊縮的情況下轉移了價值 28.2 億美元的 BTC一個引...

168超神
189 4個月前

悅盈:比特幣68000的空完美落地反彈繼續看跌 以太坊破前高看回撤

一個人的自律中,藏着無限的可能性,你自律的程度,決定着你人生的高度。 人生沒有近路可走,但你走的每...

我是周悅盈
164 4個月前

btc完美盈利 晚間波動較大注意

昨日btc空單完美給到,最大化走出一千七百點空間~ btc: 日內开盤下跌繼續測試66000一线,...

加密蓮
173 4個月前