以太坊go-ethereum源码研读(一)从Process函数相关自定义类型和结构体开始

本文主要是介绍以太坊go-ethereum源码研读(一)从Process函数相关自定义类型和结构体开始,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

  • 写在前面
  • 一些自定义类型
  • 一些结构体
    • Receipt
    • Log
    • Header
    • ChainConfig
    • BlockChain
    • Transaction
    • Block
    • StateProcessor
    • BlockContext
    • evm
    • Message
    • StateDB
    • accessList
    • Engine
  • 相关函数
    • Process
    • NewEVMBlockContext
    • NewEVM
    • NewEVMInterpreter
    • AsMessage
    • Prepare
    • Finalize

写在前面

现在自己对其中一些代码的理解还不够,等我逐渐深入学习后回回来再修改的。
其中对于一些代码的理解参考了以太坊黄皮书的内容。
链接: https://ethereum.github.io/yellowpaper/paper.pdf

一些自定义类型

类型名位置定义
Hashcommon/types.go32byte
Addresscommon/types.go20byte
Bloomcore/types/bloom9.go256byte(filter)
GasPoolcore/gaspool.gouint64

一些结构体

Receipt

位于core\types\receipt.go
为了方便索引、搜索交易和对交易的零知识证明,将交易执行中的某些信息进行编码形成了Receipt
在这里插入图片描述
参考黄皮书4.3.1

名字定义
Type交易类型
PostStateStateDB的MPT树根,相当于当前Block事务执行后所有账户状态
Status当前交易的状态
CumulativeGasUsed累积的Gas使用量
Bloom布隆过滤器,用来快速验证给定Log是否为这个事务生成
Logs交易执行过程中生成的log集合
TxHash交易hash值
ContractAddress交易对应智能合约地址
GasUsed使用的Gas量
BlockHash区块hash
BlockNumber区块号
TransactionIndex交易索引

Log

位于core\types\log.go
以太坊中定义了event和log机制,用于表示一个合约的日志。
在这里插入图片描述

名字定义
Address对应事件的合约地址
Topics用于检索日志时使用
Data由合约提供的ABI编码的内容
BlockNumber区块号
TxHash交易hash
TxIndex该Log对应的交易在区块中的索引
BlockHash该Log对应的交易所在的区块hash
Index该Log在区块中的索引
Removed当发生了链重组导致log被恢复,该字段为真。故如果通过过滤器查询log时,要多注意该字段。

Header

在这里插入图片描述
位于core\types\block.go
表示区块头

名字定义
ParentHash父区块的hash值
UncleHash叔区块RLP编码hash
Coinbase矿工地址
Root世界状态的根hash
TxHash交易信息的根hash
ReceiptHash收据信息的根hash
Bloom布隆过滤器
Difficulty挖矿的难度系数
Number区块序号
GasLimit区块内Gas消耗上限
GasUsed区块交易完成后消耗Gas总量
Time区块生成的时间(貌似并不太精准)
Extra区块创建者(矿工)记录的信息
MixDigesthashimotoFull函数生成后的digest生成的hash值,可用于结合nonce进行工作量证明
NoncePow枚举猜测的值
BaseFeeEIP-1559新增的区块头可选项,允许协议强制执行最低费用,而不会激励矿工和交易方在链下交易,形成链外市场。

ChainConfig

位于params\config.go
代表区块链的配置
在这里插入图片描述

名字定义
DAOForkBlockDAO硬分叉的区块号
DAOForkSupport当前节点是否支持DAO硬分叉

BlockChain

在这里插入图片描述

位于core\blockchain.go
待补充

Transaction

在这里插入图片描述
在这里插入图片描述
位于core\types\transaction.go
其中txdata是一个接口,定义如下,位于相同位置
在这里插入图片描述

位于core\types\transaction.go

名字定义
inner交易相关共识内容
time交易时间
hash交易hash值
size交易大小
from交易发起方

Block


位于core\types\block.go
表示区块

名字定义
ParentHash父区块的hash值
UncleHash叔区块RLP编码hash
Coinbase矿工地址
Root世界状态的根hash
TxHash交易信息的根hash
ReceiptHash收据信息的根hash
Bloom布隆过滤器
Difficulty挖矿的难度系数

StateProcessor

在这里插入图片描述
位于core\state_processor.go

名字定义
config区块配置
bc区块链
engine用于区块奖励的共识引擎

BlockContext

位于core\vm\evm.go
表示区块上下文,很多属性和前面是重复的。
在这里插入图片描述

名字定义
CoinBase矿工地址
GasLimitGas的限制量
BlockNumber区块号
Time时间
Difficulty难度
BaseFee协议执行最低费用

evm

位于core\vm\evm.go
待补充
在这里插入图片描述

名字定义
interpreter解释编译程序

Message

在这里插入图片描述
位于core\types\transaction.go
派生的事务(待补充)

名字定义
nonce即为交易中的nonce,用来交易排序,交易校验以避免双花
gasLimit当前消息gas最大限制
gasPrice油价
gasFeeCap用户所能支付给矿工的最大单价限额
gasTipCap小费,即在网络拥堵的情况下支付给矿工的小费,这个也意味着矿工有优先选择权。支付该费用,则优先打包区块

StateDB

在这里插入图片描述
位于core\state\statedb.go
StateDB结构用于存储所有的与Merkle trie相关的存储, 包括一些循环state结构

accessList

在这里插入图片描述
位于core\state\access_list.go
每个事务的访问列表,在某些形式的 EVM 执行过程中会触及的账户和合约存储位置的列表

Engine

在这里插入图片描述
位于consensus\consensus.go
engine是一个算法无关的用作共识层面的引擎

相关函数

Process

位于core\state_processor.go

func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error) {var (receipts    types.ReceiptsusedGas     = new(uint64)header      = block.Header()blockHash   = block.Hash()blockNumber = block.Number()allLogs     []*types.Loggp          = new(GasPool).AddGas(block.GasLimit()))// Mutate the block and state according to any hard-fork specsif p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 {misc.ApplyDAOHardFork(statedb)}blockContext := NewEVMBlockContext(header, p.bc, nil)vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg)// Iterate over and process the individual transactionsfor i, tx := range block.Transactions() {msg, err := tx.AsMessage(types.MakeSigner(p.config, header.Number), header.BaseFee)if err != nil {return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)}statedb.Prepare(tx.Hash(), i)receipt, err := applyTransaction(msg, p.config, p.bc, nil, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv)if err != nil {return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)}receipts = append(receipts, receipt)allLogs = append(allLogs, receipt.Logs...)}// Finalize the block, applying any consensus engine specific extras (e.g. block rewards)p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles())return receipts, allLogs, *usedGas, nil
}

首先该函数判断当前区块是否为DAO硬分叉的区块,若是则调用ApplyDAOHardFork函数(待补充)。
然后调用NewEVMBlockContext函数为当前区块创立一个运行上下文。
随后调用NewEVM函数建立一个以太坊虚拟机,准备编译执行程序。
然后枚举区块中的交易并把它转换为消息格式,随后调用Prepare函数设置当前状态的交易hash和序号,随后调用applyTransaction在虚拟机中执行交易相关指令(见以太坊go-ethereum源码研读(二)进一步分析),得到返回的收据后,加入到列表中,并获取其中的日志加入到列表中,最后调用共识引擎的Finalize函数计算区块奖励并加入到最终状态中。

NewEVMBlockContext

位于core\evm.go
根据区块头信息,建立并返回一个BlockContext区块上下文信息结构体

func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common.Address) vm.BlockContext {var (beneficiary common.AddressbaseFee     *big.Int)// If we don't have an explicit author (i.e. not mining), extract from the headerif author == nil {beneficiary, _ = chain.Engine().Author(header) // Ignore error, we're past header validation} else {beneficiary = *author}if header.BaseFee != nil {baseFee = new(big.Int).Set(header.BaseFee)}return vm.BlockContext{CanTransfer: CanTransfer,Transfer:    Transfer,GetHash:     GetHashFn(header, chain),Coinbase:    beneficiary,BlockNumber: new(big.Int).Set(header.Number),Time:        new(big.Int).SetUint64(header.Time),Difficulty:  new(big.Int).Set(header.Difficulty),BaseFee:     baseFee,GasLimit:    header.GasLimit,}
}

NewEVM

位于core/vm/evm.go
根据之前的上下文信息,以及其他的配置和内容建立虚拟机,同时调用NewEVMInterpreter函数建立对应解释器。

// NewEVM returns a new EVM. The returned EVM is not thread safe and should
// only ever be used *once*.
func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config) *EVM {evm := &EVM{Context:     blockCtx,TxContext:   txCtx,StateDB:     statedb,Config:      config,chainConfig: chainConfig,chainRules:  chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil),}evm.interpreter = NewEVMInterpreter(evm, config)return evm
}

NewEVMInterpreter

根据采取的不同链规则不同来建立对应EVM解释器

// NewEVMInterpreter returns a new instance of the Interpreter.
func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {// If jump table was not initialised we set the default one.if cfg.JumpTable == nil {switch {case evm.chainRules.IsLondon:cfg.JumpTable = &londonInstructionSetcase evm.chainRules.IsBerlin:cfg.JumpTable = &berlinInstructionSetcase evm.chainRules.IsIstanbul:cfg.JumpTable = &istanbulInstructionSetcase evm.chainRules.IsConstantinople:cfg.JumpTable = &constantinopleInstructionSetcase evm.chainRules.IsByzantium:cfg.JumpTable = &byzantiumInstructionSetcase evm.chainRules.IsEIP158:cfg.JumpTable = &spuriousDragonInstructionSetcase evm.chainRules.IsEIP150:cfg.JumpTable = &tangerineWhistleInstructionSetcase evm.chainRules.IsHomestead:cfg.JumpTable = &homesteadInstructionSetdefault:cfg.JumpTable = &frontierInstructionSet}for i, eip := range cfg.ExtraEips {copy := *cfg.JumpTableif err := EnableEIP(eip, &copy); err != nil {// Disable it, so caller can check if it's activated or notcfg.ExtraEips = append(cfg.ExtraEips[:i], cfg.ExtraEips[i+1:]...)log.Error("EIP activation failed", "eip", eip, "error", err)}cfg.JumpTable = &copy}}return &EVMInterpreter{evm: evm,cfg: cfg,}
}

AsMessage

位于core\types\transaction.go
将交易返回为消息格式

// AsMessage returns the transaction as a core.Message.
func (tx *Transaction) AsMessage(s Signer, baseFee *big.Int) (Message, error) {msg := Message{nonce:      tx.Nonce(),gasLimit:   tx.Gas(),gasPrice:   new(big.Int).Set(tx.GasPrice()),gasFeeCap:  new(big.Int).Set(tx.GasFeeCap()),gasTipCap:  new(big.Int).Set(tx.GasTipCap()),to:         tx.To(),amount:     tx.Value(),data:       tx.Data(),accessList: tx.AccessList(),isFake:     false,}// If baseFee provided, set gasPrice to effectiveGasPrice.if baseFee != nil {msg.gasPrice = math.BigMin(msg.gasPrice.Add(msg.gasTipCap, baseFee), msg.gasFeeCap)}var err errormsg.from, err = Sender(s, tx)return msg, err
}

Prepare

位于core\state\statedb.go
在EVM需要生成新的状态时调用此函数来设置当前交易的hash和序号

// Prepare sets the current transaction hash and index which are
// used when the EVM emits new state logs.
func (s *StateDB) Prepare(thash common.Hash, ti int) {s.thash = thashs.txIndex = tis.accessList = newAccessList()
}

Finalize

// Finalize implements consensus.Engine, accumulating the block and uncle rewards,
// setting the final state on the header
func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) {// Accumulate any block and uncle rewards and commit the final state rootaccumulateRewards(chain.Config(), state, header, uncles)header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
}

位于consensus\ethash\consensus.go
该函数累积区块和叔块的奖励并设置在头部的最终状态中。

这篇关于以太坊go-ethereum源码研读(一)从Process函数相关自定义类型和结构体开始的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/203784

相关文章

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

hdu1171(母函数或多重背包)

题意:把物品分成两份,使得价值最接近 可以用背包,或者是母函数来解,母函数(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v) 其中指数为价值,每一项的数目为(该物品数+1)个 代码如下: #include<iostream>#include<algorithm>

sqlite3 相关知识

WAL 模式 VS 回滚模式 特性WAL 模式回滚模式(Rollback Journal)定义使用写前日志来记录变更。使用回滚日志来记录事务的所有修改。特点更高的并发性和性能;支持多读者和单写者。支持安全的事务回滚,但并发性较低。性能写入性能更好,尤其是读多写少的场景。写操作会造成较大的性能开销,尤其是在事务开始时。写入流程数据首先写入 WAL 文件,然后才从 WAL 刷新到主数据库。数据在开始

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、

自定义类型:结构体(续)

目录 一. 结构体的内存对齐 1.1 为什么存在内存对齐? 1.2 修改默认对齐数 二. 结构体传参 三. 结构体实现位段 一. 结构体的内存对齐 在前面的文章里我们已经讲过一部分的内存对齐的知识,并举出了两个例子,我们再举出两个例子继续说明: struct S3{double a;int b;char c;};int mian(){printf("%zd\n",s