摘要:前言以太坊是一個(gè)運(yùn)行智能合約的平臺(tái),被稱作可編程的區(qū)塊鏈,允許用戶將編寫的智能合約部署在區(qū)塊鏈上運(yùn)行。交易執(zhí)行以太坊是一個(gè)基于交易的狀態(tài)機(jī),一筆交易可以使以太坊從一個(gè)狀態(tài)切換到另一個(gè)狀態(tài),即交易的執(zhí)行伴隨著狀態(tài)的改變。
前言
以太坊是一個(gè)運(yùn)行智能合約的平臺(tái),被稱作可編程的區(qū)塊鏈,允許用戶將編寫的智能合約部署在區(qū)塊鏈上運(yùn)行。而運(yùn)行合約的主體便是以太坊虛擬機(jī)(EVM)
區(qū)塊 交易 合約區(qū)塊鏈由區(qū)塊(Block)組成,而區(qū)塊中打包一定數(shù)量的交易(Transaction),交易可能是一個(gè)單純的轉(zhuǎn)賬操作,也可能是調(diào)用一個(gè)智能合約,無論是哪一種,EVM在運(yùn)行(excute)交易時(shí)都會(huì)創(chuàng)建合約(Contract)
外部賬戶 合約賬戶以太坊中的賬戶有兩類
外部賬戶 由賬戶持有人的私鑰控制的真實(shí)存在的賬戶
合約賬戶 由合約代碼控制,保存著合約代碼
一筆交易總是有發(fā)送方(sender),接收方(recipient)和數(shù)額(value) 三要素。發(fā)送方將一定數(shù)額的ETH轉(zhuǎn)移到接收方的賬戶,在單純的轉(zhuǎn)賬交易中,接收方是外部賬戶。而在調(diào)用智能合約的交易時(shí),接收方是合約賬戶。
gas如同現(xiàn)實(shí)中的稅費(fèi)一樣,交易也需要將支付少量的費(fèi)用,稱為gas,費(fèi)用支付給礦工,這可以激勵(lì)礦工打包交易到區(qū)塊,也使得區(qū)塊鏈避免惡意運(yùn)算攻擊。gas由交易的發(fā)送者使用ETH購買,在執(zhí)行交易的每一步都會(huì)消耗gas,如果gas用完了,交易狀態(tài)會(huì)被回退,但消耗的gas不會(huì)返還。
交易執(zhí)行以太坊是一個(gè)基于交易的狀態(tài)機(jī),一筆交易可以使以太坊從一個(gè)狀態(tài)(state)切換到另一個(gè)狀態(tài),即交易的執(zhí)行伴隨著狀態(tài)的改變。
交易執(zhí)行的入口在 core/state_processor.go的Process()方法,下面是該方法的輪廓
func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts,[]*types.Log,uint64,error) { ...... var ( usedGas = new(uint) header = block.Header() gp = new(GasPool).AddGas(block.GasLimit()) ) for i, tx := range block.Transactions() { receipt, _, _ := ApplyTransaction(p.config, p.bc, nil, gp, statedb, header, tx, usedGas, cfg) receipts = append(receipts, receipt) allLogs = append(allLogs, receipt.Logs...) } p.engine.Finalize(p.bc. header, statedb, block.Transactions(), block.Uncles(), receipts) ...... }
Process()方法對(duì)block中的每個(gè)交易tx調(diào)用ApplyTransaction()來執(zhí)行交易,入?yún)?b>state存儲(chǔ)了各個(gè)賬戶的信息,如賬戶余額、合約代碼(僅對(duì)合約賬戶而言),我們姑且將其理解為一個(gè)內(nèi)存中的數(shù)據(jù)庫。其中每個(gè)賬戶以state object表示
ApplyTransaction()方法完成以下功能
調(diào)用AsMessage()用tx為參數(shù)生成core.Message。也就是將tx中的一些字段存入Message,再從tx的數(shù)字簽名中反解出tx的sender,重點(diǎn)關(guān)注其中的data字段:如果是普通的轉(zhuǎn)賬交易,該字段為空,如果是創(chuàng)建一個(gè)新的合約,該字段為新的合約的代碼,如果是執(zhí)行一個(gè)已經(jīng)在區(qū)塊鏈上存在的合約,該參數(shù)為合約代碼的輸入?yún)?shù)
調(diào)用NewEVMContext()創(chuàng)建一個(gè)EVM運(yùn)行上下文vm.Context。注意其中的Coinbase字段需要填入的礦工的地址,Transfer是具體的轉(zhuǎn)賬方法,其實(shí)就是操作sender和recipient的賬戶余額
調(diào)用NewEVM()創(chuàng)建一個(gè)虛擬機(jī)運(yùn)行環(huán)境EVM,它主要作用是匯集之前的信息以及創(chuàng)建一個(gè)代碼解釋器(Interpreter),這個(gè)解釋器之后會(huì)用來解釋并執(zhí)行合約代碼
接下來就是調(diào)用ApplyMessage()將以上的信息施加在以太坊當(dāng)前狀態(tài)上,使得狀態(tài)機(jī)發(fā)生狀態(tài)變換
ApplyMessage()的頂層比較簡單,它創(chuàng)建一個(gè)StateTransition結(jié)構(gòu)并調(diào)用其TransitionDb()方法,StateTransition表示一次以太訪的狀態(tài)轉(zhuǎn)移 其定義如下:
type StateTransition struct { gp *GasPool msg Message gas uint64 gasPrice *big,Int initialGas uint64 value *big.Int data []byte state vm.StateDB evm *vm.EVM }
其中的字段都是之前ApplyTransaction()方法中創(chuàng)建的結(jié)構(gòu)得到。一次狀態(tài)轉(zhuǎn)移包括以下流程
nonce檢查:交易的nonce值用于標(biāo)識(shí)這是sender發(fā)起的交易的序號(hào),該值總是等于上一筆交易的nonce值遞增1,當(dāng)我們檢查發(fā)現(xiàn)當(dāng)前Apply的這筆交易與該sender期待的nonce不一致時(shí),就會(huì)拒絕此次狀態(tài)轉(zhuǎn)換
gas預(yù)購:sender預(yù)購此次轉(zhuǎn)換需要的gas,簡單說來就是扣除sender賬戶的ETH(變化反映在stateDB),扣除的數(shù)量卻決于交易設(shè)定的gasPrice和gasLimit的乘積,單位是gwei。
合約賬戶創(chuàng)建: 如果交易的recipient為空的話,標(biāo)識(shí)這筆交易需要?jiǎng)?chuàng)建一個(gè)合約,那么就創(chuàng)建一個(gè)合約賬戶(反映在state object)
價(jià)值轉(zhuǎn)移:每筆交易都伴隨著價(jià)值轉(zhuǎn)移,即ETH從sender賬戶發(fā)送到receipt賬戶,如果創(chuàng)建了合約,還要執(zhí)行合約代碼
TransitionDB()完成這樣的狀態(tài)轉(zhuǎn)換,其實(shí)現(xiàn)流程如下:
最終由交易的receipt是否為空決定是使用evm.Create()還是evm.Call(),無論是哪種,最終都是創(chuàng)建一個(gè)Contract結(jié)構(gòu),然后調(diào)用run()方法運(yùn)行之。注意,即使是外部賬戶之間普通的轉(zhuǎn)賬也會(huì)調(diào)用Call()和run(),只是由于receipt上沒有代碼,運(yùn)行會(huì)很快結(jié)束而已。run()最終調(diào)用Interpreter的Run()方法。
前面提到過,在調(diào)用NewEVM()時(shí)創(chuàng)建了一個(gè)解釋器(Interpreter)
func NewInterpreter(evm *EVM,cfg Config) *Interpreter { switch { case evm.ChainConfig().IsConstantinople(evm.BlockNumber): cfg.JumpTable = constantinopleInstructionSet case evm.ChainConfig().IsByzantium(evm.BlockNumber): cfg.JumpTable = byzantiumInstructionSet case evm.ChainConfig().IsHomestead(evm.BlockNumber): cfg.JumpTable = homesteadInstructionSet default: cfg.JumpTable = fromtierInstructionSet } return &Interpreter{ evm: evm, cfg: cfg, ...... } }
根據(jù)當(dāng)前Block的高度,計(jì)算出它處于以太坊演進(jìn)的階段,得到該階段支持的指令集(InstructionSet),新的階段在兼容老的階段的所有指令前提下,再增加了獨(dú)特的新指令。最終存儲(chǔ)在Interpreter的cfg字段
合約代碼本質(zhì)上上是由Solidity語言編譯后形成的EVM字節(jié)碼,字節(jié)碼中的操作也正是指令集中定義的指令
再回到Run()方法,其大概流程如下
EVM逐字節(jié)的解析合約代碼并調(diào)用excute()方法運(yùn)行,直到運(yùn)行完成或者gas提前耗盡。
關(guān)于具體的EVM指令解釋方式和虛擬機(jī)內(nèi)部棧和內(nèi)存等內(nèi)部實(shí)現(xiàn),參考本系列文章
小結(jié)在以太坊中,交易的執(zhí)行是由EVM完成的,網(wǎng)絡(luò)中的所有全節(jié)點(diǎn)都會(huì)去執(zhí)行每一筆交易(這樣所有人的狀態(tài)才可以保持一致)
交易分為普通轉(zhuǎn)賬和執(zhí)行(創(chuàng)建)智能合約,兩者都由sender付費(fèi),后者相比前者,EVM要額外執(zhí)行合約的字節(jié)碼
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/24382.html
摘要:前言是以太坊封定義的一個(gè)接口,它的功能可以分為類驗(yàn)證區(qū)塊類,主要用在將區(qū)塊加入到區(qū)塊鏈前,對(duì)區(qū)塊進(jìn)行共識(shí)驗(yàn)證。輔助類生成以太坊共識(shí)相關(guān)的。被使用,是以太坊狀態(tài)管理服務(wù),當(dāng)報(bào)告數(shù)據(jù)的時(shí)候,需要獲取區(qū)塊的信息。 前言 engine是以太坊封定義的一個(gè)接口,它的功能可以分為3類: 驗(yàn)證區(qū)塊類,主要用在將區(qū)塊加入到區(qū)塊鏈前,對(duì)區(qū)塊進(jìn)行共識(shí)驗(yàn)證。 產(chǎn)生區(qū)塊類,主要用在挖礦時(shí)。 輔助類。 接下...
摘要:引言給迷失在如何學(xué)習(xí)區(qū)塊鏈技術(shù)的同學(xué)一個(gè)指引,區(qū)塊鏈技術(shù)是隨比特幣誕生,因此要搞明白區(qū)塊鏈技術(shù),應(yīng)該先了解下比特幣。但區(qū)塊鏈技術(shù)不單應(yīng)用于比特幣,還有非常多的現(xiàn)實(shí)應(yīng)用場(chǎng)景,想做區(qū)塊鏈應(yīng)用開發(fā),可進(jìn)一步閱讀以太坊系列。 本文始發(fā)于深入淺出區(qū)塊鏈社區(qū), 原文:區(qū)塊鏈技術(shù)學(xué)習(xí)指引 原文已更新,請(qǐng)讀者前往原文閱讀 本章的文章越來越多,本文是一個(gè)索引帖,方便找到自己感興趣的文章,你也可以使用左側(cè)...
摘要:前言以太坊是一個(gè)巨大的狀態(tài)機(jī),在網(wǎng)絡(luò)中,每一個(gè)全節(jié)點(diǎn)都保存著以太坊狀態(tài)機(jī)的全部歷史,只要愿意,我們可以查詢到任何時(shí)刻的狀態(tài)黃皮書中,而賬戶狀態(tài)便是其中的狀態(tài),這部分功能由主要由代碼中的包提供基本概念賬戶地址在以太坊中,無論是外部賬戶還是合約 前言 以太坊是一個(gè)巨大的狀態(tài)機(jī),在網(wǎng)絡(luò)中,每一個(gè)全節(jié)點(diǎn)都保存著以太坊狀態(tài)機(jī)的全部歷史,只要愿意,我們可以查詢到任何時(shí)刻的狀態(tài)(黃皮書中World ...
摘要:是以太坊中存儲(chǔ)區(qū)塊數(shù)據(jù)的核心數(shù)據(jù)結(jié)構(gòu),它和融合一個(gè)樹形結(jié)構(gòu),理解結(jié)構(gòu)對(duì)之后學(xué)習(xí)以太坊區(qū)塊以及智能合約狀態(tài)存儲(chǔ)結(jié)構(gòu)的模塊源碼很有幫助。 MPT(Merkle Patricia Tries)是以太坊中存儲(chǔ)區(qū)塊數(shù)據(jù)的核心數(shù)據(jù)結(jié)構(gòu),它Merkle Tree和Patricia Tree融合一個(gè)樹形結(jié)構(gòu),理解MPT結(jié)構(gòu)對(duì)之后學(xué)習(xí)以太坊區(qū)塊header以及智能合約狀態(tài)存儲(chǔ)結(jié)構(gòu)的模塊源碼很有幫助。 首...
摘要:接下來我們將從以下角度介紹礦工角色。我們分別使用礦長副礦長礦工進(jìn)行類比。副礦長,負(fù)責(zé)具體挖礦工作的安排,把挖礦任務(wù)安排給。礦工的主要函數(shù)介紹和的主要函數(shù),他們是礦工的具體運(yùn)作機(jī)制。負(fù)責(zé)處理外部事件。 前言 礦工在PoW中負(fù)責(zé)了產(chǎn)生區(qū)塊的工作,把一大堆交易交給它,它生成一個(gè)證明自己做了很多工作的區(qū)塊,然后將這個(gè)區(qū)塊加入到本地區(qū)塊鏈并且廣播給其他節(jié)點(diǎn)。 接下來我們將從以下角度介紹礦工: ...
閱讀 3149·2021-11-22 13:54
閱讀 3435·2021-11-15 11:37
閱讀 3598·2021-10-14 09:43
閱讀 3496·2021-09-09 11:52
閱讀 3595·2019-08-30 15:53
閱讀 2457·2019-08-30 13:50
閱讀 2055·2019-08-30 11:07
閱讀 886·2019-08-29 16:32