摘要:前言以太坊是一個運行智能合約的平臺,被稱作可編程的區塊鏈,允許用戶將編寫的智能合約部署在區塊鏈上運行。交易執行以太坊是一個基于交易的狀態機,一筆交易可以使以太坊從一個狀態切換到另一個狀態,即交易的執行伴隨著狀態的改變。
前言
以太坊是一個運行智能合約的平臺,被稱作可編程的區塊鏈,允許用戶將編寫的智能合約部署在區塊鏈上運行。而運行合約的主體便是以太坊虛擬機(EVM)
區塊 交易 合約區塊鏈由區塊(Block)組成,而區塊中打包一定數量的交易(Transaction),交易可能是一個單純的轉賬操作,也可能是調用一個智能合約,無論是哪一種,EVM在運行(excute)交易時都會創建合約(Contract)
外部賬戶 合約賬戶以太坊中的賬戶有兩類
外部賬戶 由賬戶持有人的私鑰控制的真實存在的賬戶
合約賬戶 由合約代碼控制,保存著合約代碼
一筆交易總是有發送方(sender),接收方(recipient)和數額(value) 三要素。發送方將一定數額的ETH轉移到接收方的賬戶,在單純的轉賬交易中,接收方是外部賬戶。而在調用智能合約的交易時,接收方是合約賬戶。
gas如同現實中的稅費一樣,交易也需要將支付少量的費用,稱為gas,費用支付給礦工,這可以激勵礦工打包交易到區塊,也使得區塊鏈避免惡意運算攻擊。gas由交易的發送者使用ETH購買,在執行交易的每一步都會消耗gas,如果gas用完了,交易狀態會被回退,但消耗的gas不會返還。
交易執行以太坊是一個基于交易的狀態機,一筆交易可以使以太坊從一個狀態(state)切換到另一個狀態,即交易的執行伴隨著狀態的改變。
交易執行的入口在 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()方法對block中的每個交易tx調用ApplyTransaction()來執行交易,入參state存儲了各個賬戶的信息,如賬戶余額、合約代碼(僅對合約賬戶而言),我們姑且將其理解為一個內存中的數據庫。其中每個賬戶以state object表示
ApplyTransaction()方法完成以下功能
調用AsMessage()用tx為參數生成core.Message。也就是將tx中的一些字段存入Message,再從tx的數字簽名中反解出tx的sender,重點關注其中的data字段:如果是普通的轉賬交易,該字段為空,如果是創建一個新的合約,該字段為新的合約的代碼,如果是執行一個已經在區塊鏈上存在的合約,該參數為合約代碼的輸入參數
調用NewEVMContext()創建一個EVM運行上下文vm.Context。注意其中的Coinbase字段需要填入的礦工的地址,Transfer是具體的轉賬方法,其實就是操作sender和recipient的賬戶余額
調用NewEVM()創建一個虛擬機運行環境EVM,它主要作用是匯集之前的信息以及創建一個代碼解釋器(Interpreter),這個解釋器之后會用來解釋并執行合約代碼
接下來就是調用ApplyMessage()將以上的信息施加在以太坊當前狀態上,使得狀態機發生狀態變換
ApplyMessage()的頂層比較簡單,它創建一個StateTransition結構并調用其TransitionDb()方法,StateTransition表示一次以太訪的狀態轉移 其定義如下:
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()方法中創建的結構得到。一次狀態轉移包括以下流程
nonce檢查:交易的nonce值用于標識這是sender發起的交易的序號,該值總是等于上一筆交易的nonce值遞增1,當我們檢查發現當前Apply的這筆交易與該sender期待的nonce不一致時,就會拒絕此次狀態轉換
gas預購:sender預購此次轉換需要的gas,簡單說來就是扣除sender賬戶的ETH(變化反映在stateDB),扣除的數量卻決于交易設定的gasPrice和gasLimit的乘積,單位是gwei。
合約賬戶創建: 如果交易的recipient為空的話,標識這筆交易需要創建一個合約,那么就創建一個合約賬戶(反映在state object)
價值轉移:每筆交易都伴隨著價值轉移,即ETH從sender賬戶發送到receipt賬戶,如果創建了合約,還要執行合約代碼
TransitionDB()完成這樣的狀態轉換,其實現流程如下:
最終由交易的receipt是否為空決定是使用evm.Create()還是evm.Call(),無論是哪種,最終都是創建一個Contract結構,然后調用run()方法運行之。注意,即使是外部賬戶之間普通的轉賬也會調用Call()和run(),只是由于receipt上沒有代碼,運行會很快結束而已。run()最終調用Interpreter的Run()方法。
前面提到過,在調用NewEVM()時創建了一個解釋器(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, ...... } }
根據當前Block的高度,計算出它處于以太坊演進的階段,得到該階段支持的指令集(InstructionSet),新的階段在兼容老的階段的所有指令前提下,再增加了獨特的新指令。最終存儲在Interpreter的cfg字段
合約代碼本質上上是由Solidity語言編譯后形成的EVM字節碼,字節碼中的操作也正是指令集中定義的指令
再回到Run()方法,其大概流程如下
EVM逐字節的解析合約代碼并調用excute()方法運行,直到運行完成或者gas提前耗盡。
關于具體的EVM指令解釋方式和虛擬機內部棧和內存等內部實現,參考本系列文章
小結在以太坊中,交易的執行是由EVM完成的,網絡中的所有全節點都會去執行每一筆交易(這樣所有人的狀態才可以保持一致)
交易分為普通轉賬和執行(創建)智能合約,兩者都由sender付費,后者相比前者,EVM要額外執行合約的字節碼
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/24382.html
摘要:前言是以太坊封定義的一個接口,它的功能可以分為類驗證區塊類,主要用在將區塊加入到區塊鏈前,對區塊進行共識驗證。輔助類生成以太坊共識相關的。被使用,是以太坊狀態管理服務,當報告數據的時候,需要獲取區塊的信息。 前言 engine是以太坊封定義的一個接口,它的功能可以分為3類: 驗證區塊類,主要用在將區塊加入到區塊鏈前,對區塊進行共識驗證。 產生區塊類,主要用在挖礦時。 輔助類。 接下...
摘要:前言以太坊是一個巨大的狀態機,在網絡中,每一個全節點都保存著以太坊狀態機的全部歷史,只要愿意,我們可以查詢到任何時刻的狀態黃皮書中,而賬戶狀態便是其中的狀態,這部分功能由主要由代碼中的包提供基本概念賬戶地址在以太坊中,無論是外部賬戶還是合約 前言 以太坊是一個巨大的狀態機,在網絡中,每一個全節點都保存著以太坊狀態機的全部歷史,只要愿意,我們可以查詢到任何時刻的狀態(黃皮書中World ...
摘要:是以太坊中存儲區塊數據的核心數據結構,它和融合一個樹形結構,理解結構對之后學習以太坊區塊以及智能合約狀態存儲結構的模塊源碼很有幫助。 MPT(Merkle Patricia Tries)是以太坊中存儲區塊數據的核心數據結構,它Merkle Tree和Patricia Tree融合一個樹形結構,理解MPT結構對之后學習以太坊區塊header以及智能合約狀態存儲結構的模塊源碼很有幫助。 首...
摘要:接下來我們將從以下角度介紹礦工角色。我們分別使用礦長副礦長礦工進行類比。副礦長,負責具體挖礦工作的安排,把挖礦任務安排給。礦工的主要函數介紹和的主要函數,他們是礦工的具體運作機制。負責處理外部事件。 前言 礦工在PoW中負責了產生區塊的工作,把一大堆交易交給它,它生成一個證明自己做了很多工作的區塊,然后將這個區塊加入到本地區塊鏈并且廣播給其他節點。 接下來我們將從以下角度介紹礦工: ...
閱讀 3154·2021-11-22 13:54
閱讀 3443·2021-11-15 11:37
閱讀 3609·2021-10-14 09:43
閱讀 3506·2021-09-09 11:52
閱讀 3608·2019-08-30 15:53
閱讀 2467·2019-08-30 13:50
閱讀 2062·2019-08-30 11:07
閱讀 892·2019-08-29 16:32