Solidity的Bytecode和Opcode简介
Solidity的Bytecode和Opcode簡介
隨著我們更深入地編寫智能合約,我們將遇到諸如“ PUSH1”,“ SSTORE”,“ CALLVALUE”等術(shù)語。 他們是什么,我們什么時候應(yīng)該使用到他們?
要了解這些命令,我們必須更深入地了解以太坊虛擬機(EVM)。本文將會嘗試盡可能簡單地解釋一些EVM基礎(chǔ)。希望大家都有所收獲。
像許多其他流行的編程語言一樣,Solidity是一種高級編程語言。 我們可以讀懂,但是機器卻不能夠。 如果大家學(xué)過諸如java,c++等編程語言,應(yīng)該會很容易明白這個道理。
當(dāng)我們安裝諸如geth之類的以太坊客戶端時,它還附帶了以太坊虛擬機,這是專門為運行智能合約而創(chuàng)建的輕量級操作系統(tǒng)。
當(dāng)我們使用solc編譯器編譯Solidity代碼時,它將代碼轉(zhuǎn)換為只有EVM可以理解的字節(jié)碼。
讓我們以一個非常簡單的合同為例:
pragma solidity ^0.4.26; contract OpcodeContract {uint i = (10 + 2) * 2; }如果我們在remix瀏覽器中運行此代碼,然后單擊合同詳細(xì)信息,則會看到很多信息。
在這種情況下,編譯后的代碼為:
BYTECODE {"linkReferences": {},"object": "60806040526018600055348015601457600080fd5b5060358060226000396000f3006080604052600080fd00a165627a7a72305820db1d567e501f1682876df36eea80a02d25a8b2adb186da705e2e98e134b08cc60029","opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x18 PUSH1 0x0 SSTORE CALLVALUE DUP1 ISZERO PUSH1 0x14 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x35 DUP1 PUSH1 0x22 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN STOP PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x0 DUP1 REVERT STOP LOG1 PUSH6 0x627A7A723058 KECCAK256 0xdb SAR JUMP PUSH31 0x501F1682876DF36EEA80A02D25A8B2ADB186DA705E2E98E134B08CC6002900 ","sourceMap": "25:54:0:-;;;64:12;55:21;;25:54;8:9:-1;5:2;;;30:1;27;20:12;5:2;25:54:0;;;;;;;" }其中object就是編譯后的代碼。他們是最終合同的十六進制表示形式,也稱為字節(jié)碼。
在remix瀏覽器的“ Web3 Deploy”部分下,我們看到:
var opcodecontractContract = web3.eth.contract([]); var opcodecontract = opcodecontractContract.new({from: web3.eth.accounts[0], data: '0x60806040526018600055348015601457600080fd5b5060358060226000396000f3006080604052600080fd00a165627a7a72305820db1d567e501f1682876df36eea80a02d25a8b2adb186da705e2e98e134b08cc60029', gas: '4700000'}, function (e, contract){console.log(e, contract);if (typeof contract.address !== 'undefined') {console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);}})簡單來說,這意味著當(dāng)我們部署合同時,我們需要將編譯后的16進制碼當(dāng)成data傳遞,并且建議的gas為4700000。
任何以“ 0x”開頭的內(nèi)容都表示該值采用十六進制格式。 十六進制前面的“ 0x”并不是強制的,因為EVM會將任何值都視為十六進制。
我們還看到了操作代碼(又稱Opcode):
"opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x18 PUSH1 0x0 SSTORE CALLVALUE DUP1 ISZERO PUSH1 0x14 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x35 DUP1 PUSH1 0x22 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN STOP PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x0 DUP1 REVERT STOP LOG1 PUSH6 0x627A7A723058 KECCAK256 0xdb SAR JUMP PUSH31 0x501F1682876DF36EEA80A02D25A8B2ADB186DA705E2E98E134B08CC6002900 ",操作碼是程序的低級可讀指令。 所有操作碼都具有對應(yīng)的十六進制值,例如“ MSTORE”為“ 0x52”,SSTORE”為“ 0x55”……等等。
具體的操作碼對應(yīng)的數(shù)值可以參考以太坊相關(guān)資料。
EVM虛擬機是一中堆棧虛擬機,所謂堆棧就是后進先出結(jié)構(gòu),用計算機科學(xué)術(shù)語來說,我們稱為LIFO。
舉個例子,上面的智能合約,如果在普通算術(shù)中,我們這樣寫方程式:
// Answer is 14. we do multiplication before addition. 10 + 2 * 2在EVM堆棧虛擬機中,它按照LIFO原理工作,所以我們需要這樣寫:
2 2 * 10 +這意味著,首先將“ 2”放入堆棧,然后再放入另一個“ 2”,然后再進行乘法運算。 結(jié)果是“ 4”放在在堆棧頂部。 現(xiàn)在在“ 4”的頂部加上數(shù)字“ 10”,最后將兩個數(shù)字加在一起。 堆棧的最終值為14。
這種算術(shù)類型稱為后綴表示法。
將數(shù)據(jù)放入堆棧的動作稱為“ PUSH”指令,將數(shù)據(jù)從堆棧中刪除的動作稱為“ POP”指令。 很明顯,我們在上面的示例中看到的最常見的操作碼是“ PUSH1”,這意味著將1個字節(jié)的數(shù)據(jù)放入堆棧中。
因此,此指令:
表示將1字節(jié)值“ 0x80”放入堆棧中。 “ PUSH1”的十六進制值恰是“ 0x60”。 刪除非強制性的“ 0x”,我們可以將此邏輯以字節(jié)碼形式寫為“ 6080”。
讓我們更進一步。
再次查看以太坊的操作碼圖表,我們看到MSTORE(0x52)接受2個輸入,但不產(chǎn)生任何輸出。 上面的操作碼表示:
PUSH1(0x60):將0x80放入堆棧。
PUSH1(0x40):將0x40放入堆棧。
MSTORE(0x52):分配0x80的內(nèi)存空間并移至0x40的位置。
結(jié)果字節(jié)碼為:
實際上,在任何固定字節(jié)碼的開頭,我們總會看到這個魔術(shù)數(shù)字“ 6080604052”,因為它是智能合約引導(dǎo)的方式。
請注意,這里不能將0x40或0x60解釋為實數(shù)40或60。由于它們是十六進制,所以40實際上等于十進制的64(16 x 4),而80等于十進制的128(16 x 8)。
簡而言之,“ PUSH1 0x80 PUSH1 0x40 MSTORE”正在做的是分配128個字節(jié)的內(nèi)存并將指針移到第64個字節(jié)的開頭。現(xiàn)在,我們有64個字節(jié)用于暫存空間,而64個字節(jié)用于臨時內(nèi)存存儲。
在EVM中,有3個地方可以存儲數(shù)據(jù)。首先,在堆棧中,按照上面的示例,我們剛剛使用了“ PUSH”操作碼在此處存儲數(shù)據(jù)。其次,在使用“ MSTORE”操作碼的內(nèi)存(RAM)中,最后在使用“ SSTORE”存儲數(shù)據(jù)的磁盤存儲中。將數(shù)據(jù)存儲到磁盤存儲所需的gas最昂貴,而將數(shù)據(jù)存儲到堆棧中的gas則最便宜。
我們在Solidity中的智能合約中,有時候也會用到Assembly Language,這個Assembly Language就是使用這樣的匯編Opcode來操作EVM字節(jié)碼。他理解起來比較難,但是通過使用它可以節(jié)省燃料和做一些無法通過Solidity完成的事情。
本文僅介紹了字節(jié)碼和一些操作碼的基礎(chǔ)。后面會有更多的文章來詳細(xì)介紹Assembly Language和EVM虛擬機。 敬請期待。
更多精彩內(nèi)容且看:
- 區(qū)塊鏈從入門到放棄系列教程-涵蓋密碼學(xué),超級賬本,以太坊,Libra,比特幣等持續(xù)更新
- Spring Boot 2.X系列教程:七天從無到有掌握Spring Boot-持續(xù)更新
- Spring 5.X系列教程:滿足你對Spring5的一切想象-持續(xù)更新
- java程序員從小工到專家成神之路(2020版)-持續(xù)更新中,附詳細(xì)文章教程
更多教程請參考 flydean的博客
總結(jié)
以上是生活随笔為你收集整理的Solidity的Bytecode和Opcode简介的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Fabric的6大特性
- 下一篇: 使用IBM Blockchain Pla