溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

如何理解Solidity的Bytecode和Opcode

發(fā)布時(shí)間:2021-11-23 10:55:36 來(lái)源:億速云 閱讀:260 作者:柒染 欄目:互聯(lián)網(wǎng)科技

本篇文章為大家展示了如何理解Solidity的Bytecode和Opcode,內(nèi)容簡(jiǎn)明扼要并且容易理解,絕對(duì)能使你眼前一亮,通過(guò)這篇文章的詳細(xì)介紹希望你能有所收獲。

Solidity的Bytecode和Opcode

隨著我們更深入地編寫(xiě)智能合約,我們將遇到諸如“ PUSH1”,“ SSTORE”,“ CALLVALUE”等術(shù)語(yǔ)。 他們是什么,我們什么時(shí)候應(yīng)該使用到他們?

要了解這些命令,我們必須更深入地了解以太坊虛擬機(jī)(EVM)。本文將會(huì)嘗試盡可能簡(jiǎn)單地解釋一些EVM基礎(chǔ)。希望大家都有所收獲。

像許多其他流行的編程語(yǔ)言一樣,Solidity是一種高級(jí)編程語(yǔ)言。 我們可以讀懂,但是機(jī)器卻不能夠。 如果大家學(xué)過(guò)諸如java,c++等編程語(yǔ)言,應(yīng)該會(huì)很容易明白這個(gè)道理。

當(dāng)我們安裝諸如geth之類(lèi)的以太坊客戶(hù)端時(shí),它還附帶了以太坊虛擬機(jī),這是專(zhuān)門(mén)為運(yùn)行智能合約而創(chuàng)建的輕量級(jí)操作系統(tǒng)。

當(dāng)我們使用solc編譯器編譯Solidity代碼時(shí),它將代碼轉(zhuǎn)換為只有EVM可以理解的字節(jié)碼。

讓我們以一個(gè)非常簡(jiǎn)單的合同為例:

pragma solidity ^0.4.26;
contract OpcodeContract {
    uint i = (10 + 2) * 2;
}

如果我們?cè)趓emix瀏覽器中運(yùn)行此代碼,然后單擊合同詳細(xì)信息,則會(huì)看到很多信息。

如何理解Solidity的Bytecode和Opcode

在這種情況下,編譯后的代碼為:

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就是編譯后的代碼。他們是最終合同的十六進(jìn)制表示形式,也稱(chēng)為字節(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);
    }
 })

簡(jiǎn)單來(lái)說(shuō),這意味著當(dāng)我們部署合同時(shí),我們需要將編譯后的16進(jìn)制碼當(dāng)成data傳遞,并且建議的gas為4700000。

任何以“ 0x”開(kāi)頭的內(nèi)容都表示該值采用十六進(jìn)制格式。 十六進(jìn)制前面的“ 0x”并不是強(qiáng)制的,因?yàn)镋VM會(huì)將任何值都視為十六進(jìn)制。

我們還看到了操作代碼(又稱(chēng)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 ",

操作碼是程序的低級(jí)可讀指令。 所有操作碼都具有對(duì)應(yīng)的十六進(jìn)制值,例如“ MSTORE”為“ 0x52”,SSTORE”為“ 0x55”……等等。

具體的操作碼對(duì)應(yīng)的數(shù)值可以參考以太坊相關(guān)資料。

EVM虛擬機(jī)是一中堆棧虛擬機(jī),所謂堆棧就是后進(jìn)先出結(jié)構(gòu),用計(jì)算機(jī)科學(xué)術(shù)語(yǔ)來(lái)說(shuō),我們稱(chēng)為L(zhǎng)IFO。

舉個(gè)例子,上面的智能合約,如果在普通算術(shù)中,我們這樣寫(xiě)方程式:

// Answer is 14. we do multiplication before addition.
10 + 2 * 2

在EVM堆棧虛擬機(jī)中,它按照LIFO原理工作,所以我們需要這樣寫(xiě):

2 2 * 10 +

這意味著,首先將“ 2”放入堆棧,然后再放入另一個(gè)“ 2”,然后再進(jìn)行乘法運(yùn)算。 結(jié)果是“ 4”放在在堆棧頂部。 現(xiàn)在在“ 4”的頂部加上數(shù)字“ 10”,最后將兩個(gè)數(shù)字加在一起。 堆棧的最終值為14。

這種算術(shù)類(lèi)型稱(chēng)為后綴表示法。

將數(shù)據(jù)放入堆棧的動(dòng)作稱(chēng)為“ PUSH”指令,將數(shù)據(jù)從堆棧中刪除的動(dòng)作稱(chēng)為“ POP”指令。 很明顯,我們?cè)谏厦娴氖纠锌吹降淖畛R?jiàn)的操作碼是“ PUSH1”,這意味著將1個(gè)字節(jié)的數(shù)據(jù)放入堆棧中。
因此,此指令:

PUSH1 0x80

表示將1字節(jié)值“ 0x80”放入堆棧中。 “ PUSH1”的十六進(jìn)制值恰是“ 0x60”。 刪除非強(qiáng)制性的“ 0x”,我們可以將此邏輯以字節(jié)碼形式寫(xiě)為“ 6080”。
讓我們更進(jìn)一步。

PUSH1 0x80 PUSH1 0x40 MSTORE

再次查看以太坊的操作碼圖表,我們看到MSTORE(0x52)接受2個(gè)輸入,但不產(chǎn)生任何輸出。 上面的操作碼表示:
PUSH1(0x60):將0x80放入堆棧。
PUSH1(0x40):將0x40放入堆棧。
MSTORE(0x52):分配0x80的內(nèi)存空間并移至0x40的位置。
結(jié)果字節(jié)碼為:

6080604052

實(shí)際上,在任何固定字節(jié)碼的開(kāi)頭,我們總會(huì)看到這個(gè)魔術(shù)數(shù)字“ 6080604052”,因?yàn)樗侵悄芎霞s引導(dǎo)的方式。

請(qǐng)注意,這里不能將0x40或0x60解釋為實(shí)數(shù)40或60。由于它們是十六進(jìn)制,所以40實(shí)際上等于十進(jìn)制的64(16 x 4),而80等于十進(jìn)制的128(16 x 8)。

簡(jiǎn)而言之,“ PUSH1 0x80 PUSH1 0x40 MSTORE”正在做的是分配128個(gè)字節(jié)的內(nèi)存并將指針移到第64個(gè)字節(jié)的開(kāi)頭?,F(xiàn)在,我們有64個(gè)字節(jié)用于暫存空間,而64個(gè)字節(jié)用于臨時(shí)內(nèi)存存儲(chǔ)。

在EVM中,有3個(gè)地方可以存儲(chǔ)數(shù)據(jù)。首先,在堆棧中,按照上面的示例,我們剛剛使用了“ PUSH”操作碼在此處存儲(chǔ)數(shù)據(jù)。其次,在使用“ MSTORE”操作碼的內(nèi)存(RAM)中,最后在使用“ SSTORE”存儲(chǔ)數(shù)據(jù)的磁盤(pán)存儲(chǔ)中。將數(shù)據(jù)存儲(chǔ)到磁盤(pán)存儲(chǔ)所需的gas最昂貴,而將數(shù)據(jù)存儲(chǔ)到堆棧中的gas則最便宜。

我們?cè)赟olidity中的智能合約中,有時(shí)候也會(huì)用到Assembly Language,這個(gè)Assembly Language就是使用這樣的匯編Opcode來(lái)操作EVM字節(jié)碼。他理解起來(lái)比較難,但是通過(guò)使用它可以節(jié)省燃料和做一些無(wú)法通過(guò)Solidity完成的事情。

上述內(nèi)容就是如何理解Solidity的Bytecode和Opcode,你們學(xué)到知識(shí)或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識(shí)儲(chǔ)備,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI