以太坊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

一些自定义类型

类型名 位置 定义
Hash common/types.go 32byte
Address common/types.go 20byte
Bloom core/types/bloom9.go 256byte(filter)
GasPool core/gaspool.go uint64

一些结构体

Receipt

位于core\types\receipt.go
为了方便索引、搜索交易和对交易的零知识证明,将交易执行中的某些信息进行编码形成了Receipt
以太坊go-ethereum源码研读(一)从Process函数相关自定义类型和结构体开始_第1张图片
参考黄皮书4.3.1

名字 定义
Type 交易类型
PostState StateDB的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机制,用于表示一个合约的日志。
以太坊go-ethereum源码研读(一)从Process函数相关自定义类型和结构体开始_第2张图片

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

Header

以太坊go-ethereum源码研读(一)从Process函数相关自定义类型和结构体开始_第3张图片
位于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 区块创建者(矿工)记录的信息
MixDigest hashimotoFull函数生成后的digest生成的hash值,可用于结合nonce进行工作量证明
Nonce Pow枚举猜测的值
BaseFee EIP-1559新增的区块头可选项,允许协议强制执行最低费用,而不会激励矿工和交易方在链下交易,形成链外市场。

ChainConfig

位于params\config.go
代表区块链的配置
以太坊go-ethereum源码研读(一)从Process函数相关自定义类型和结构体开始_第4张图片

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

BlockChain

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

位于core\blockchain.go
待补充

Transaction

以太坊go-ethereum源码研读(一)从Process函数相关自定义类型和结构体开始_第6张图片
在这里插入图片描述
位于core\types\transaction.go
其中txdata是一个接口,定义如下,位于相同位置
以太坊go-ethereum源码研读(一)从Process函数相关自定义类型和结构体开始_第7张图片

位于core\types\transaction.go

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

Block

以太坊go-ethereum源码研读(一)从Process函数相关自定义类型和结构体开始_第8张图片
位于core\types\block.go
表示区块

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

StateProcessor

以太坊go-ethereum源码研读(一)从Process函数相关自定义类型和结构体开始_第9张图片
位于core\state_processor.go

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

BlockContext

位于core\vm\evm.go
表示区块上下文,很多属性和前面是重复的。
以太坊go-ethereum源码研读(一)从Process函数相关自定义类型和结构体开始_第10张图片

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

evm

位于core\vm\evm.go
待补充
以太坊go-ethereum源码研读(一)从Process函数相关自定义类型和结构体开始_第11张图片

名字 定义
interpreter 解释编译程序

Message

以太坊go-ethereum源码研读(一)从Process函数相关自定义类型和结构体开始_第12张图片
位于core\types\transaction.go
派生的事务(待补充)

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

StateDB

以太坊go-ethereum源码研读(一)从Process函数相关自定义类型和结构体开始_第13张图片
位于core\state\statedb.go
StateDB结构用于存储所有的与Merkle trie相关的存储, 包括一些循环state结构

accessList

以太坊go-ethereum源码研读(一)从Process函数相关自定义类型和结构体开始_第14张图片
位于core\state\access_list.go
每个事务的访问列表,在某些形式的 EVM 执行过程中会触及的账户和合约存储位置的列表

Engine

以太坊go-ethereum源码研读(一)从Process函数相关自定义类型和结构体开始_第15张图片
位于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.Receipts
		usedGas     = new(uint64)
		header      = block.Header()
		blockHash   = block.Hash()
		blockNumber = block.Number()
		allLogs     []*types.Log
		gp          = new(GasPool).AddGas(block.GasLimit())
	)
	// Mutate the block and state according to any hard-fork specs
	if 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 transactions
	for 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.Address
		baseFee     *big.Int
	)

	// If we don't have an explicit author (i.e. not mining), extract from the header
	if 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 = &londonInstructionSet
		case evm.chainRules.IsBerlin:
			cfg.JumpTable = &berlinInstructionSet
		case evm.chainRules.IsIstanbul:
			cfg.JumpTable = &istanbulInstructionSet
		case evm.chainRules.IsConstantinople:
			cfg.JumpTable = &constantinopleInstructionSet
		case evm.chainRules.IsByzantium:
			cfg.JumpTable = &byzantiumInstructionSet
		case evm.chainRules.IsEIP158:
			cfg.JumpTable = &spuriousDragonInstructionSet
		case evm.chainRules.IsEIP150:
			cfg.JumpTable = &tangerineWhistleInstructionSet
		case evm.chainRules.IsHomestead:
			cfg.JumpTable = &homesteadInstructionSet
		default:
			cfg.JumpTable = &frontierInstructionSet
		}
		for i, eip := range cfg.ExtraEips {
			copy := *cfg.JumpTable
			if err := EnableEIP(eip, &copy); err != nil {
				// Disable it, so caller can check if it's activated or not
				cfg.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 error
	msg.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 = thash
	s.txIndex = ti
	s.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 root
	accumulateRewards(chain.Config(), state, header, uncles)
	header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
}

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

你可能感兴趣的:(go-ethereum源码研读,以太坊,golang,区块链)