func (bc *BlockChain) writeKnownBlock(tx kv.RwTx, block block2.IBlock) error {
writeKnownBlock使用已知块更新头块标志并在必要时引入链式重组。
bc.ChainDB.BeginRw(bc.ctx)
,有错就返回err。使用延迟回滚,并将notExternalTx标记为truecurrent := bc.CurrentBlock()
bc.reorg(tx, current, block)
(参考1.2)进行重组织操作。如果重组织失败,则返回错误信息bc.writeHeadBlock(tx, block)
将区块写入区块链头部。如果写入失败,则返回错误信息tx.Commit()
。如果提交失败,则返回错误信息。func (bc *BlockChain) reorg(tx kv.RwTx, oldBlock, newBlock block2.IBlock) error {
reorg获取两个块,一个旧链和一个新链,并将重构这些块并将它们插入到新规范链中,积累潜在的丢失事务并发布有关它们的事件。
注意,这里不会处理新的头块,调用者需要从外部处理它。
当两个区块链之间的差异较大时,这个函数会被调用来合并它们。
if oldBlock.Number64().Uint64() > newBlock.Number64().Uint64()
,将所有事务和日志收集为已删除的事务和日志,不断向前遍历(在不与新链相同且不为nil的情况下),将区块加入lodchain中,并且将每一个区块中的交易都记录为deleted:deletedTxs = append(deletedTxs, hash)
bc.ChainDB.BeginRw(bc.ctx)
开启一个事务,有错就返回err,使用延迟回滚。同时将非外部事务标志useExternalTx
标记为falsedeletedTxs = append(deletedTxs, h)
同时记录一个新区块newChain = append(newChain, newBlock)
rawdb.ReadBlock
bc.writeHeadBlock(tx, newChain[i])
,并收集新添加的交易addedTxs = append(addedTxs, h)
,注意添加顺序i := len(newChain) - 1
rawdb.DeleteTxLookupEntry(tx, t)
rawdb.ReadCanonicalHash
获取hash,通过rawdb.TruncateCanonicalHash
进行删除tx.Commit()
。如果在提交过程中发生错误,函数会返回错误。否则,它会返回nil表示成功完成重组织操作func (bc *BlockChain) Close() error {
bc.Quit()
return nil
}
调用Quit
来进行退出(参考1.4)
func (bc *BlockChain) Quit() <-chan struct{} {
return bc.ctx.Done()
}
该方法返回一个类型为chan struct{}
的通道,该通道通过调用bc.ctx.Done()
方法来获取。
这个方法的作用是提供一个退出信号给BlockChain结构体的上下文(ctx),以便在需要时停止执行相关操作。当调用此方法时,它会返回一个通道,可以通过该通道向上下文发送一个信号,表示需要退出。
func (bc *BlockChain) DB() kv.RwDB {
return bc.ChainDB
}
用该函数来返回一个数据库,用于执行数据库的操作
func (bc *BlockChain) GetDepositInfo(address types.Address) (*uint256.Int, *uint256.Int) {
var info *deposit.Info
bc.ChainDB.View(bc.ctx, func(tx kv.Tx) error {
info = deposit.GetDepositInfo(tx, address)
return nil
})
if nil == info {
return nil, nil
}
return info.RewardPerBlock, info.MaxRewardPerEpoch
}
bc.ChainDB.View
方法来访问区块链数据库,并在回调函数中获取指定地址的存款信息。回调函数通过调用deposit.GetDepositInfo
方法来获取存款信息,并将结果赋值给info变量func (bc *BlockChain) GetAccountRewardUnpaid(account types.Address) (*uint256.Int, error) {
var value *uint256.Int
var err error
bc.ChainDB.View(bc.ctx, func(tx kv.Tx) error {
value, err = rawdb.GetAccountReward(tx, account)
return nil
})
return value, err
}
该函数的作用是获取指定账户未支付的奖励金额。
value
,用于存储未支付的奖励金额,以及一个变量err
,用于存储错误信息。bc.ChainDB.View
方法来访问区块链数据库。在回调函数中,使用rawdb包中的rawdb.GetAccountReward
方法从数据库中获取指定账户的未支付奖励金额,并将其赋值给value
变量。同时,将错误信息赋值给err
变量value
和err
作为结果。type BlockValidator struct {
bc *BlockChain // Canonical block chain
engine consensus.Engine // Consensus engine used for validating
config *params.ChainConfig
}
这是一个名为BlockValidator的结构体,它包含以下字段:
bc
:指向BlockChain类型的指针,表示规范的区块链。engine
:consensus.Engine类型的变量,表示用于验证共识引擎。config
:指向params.ChainConfig类型的指针,表示链的配置参数。func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, engine consensus.Engine) *BlockValidator {
validator := &BlockValidator{
engine: engine,
bc: blockchain,
config: config,
}
return validator
}
该函数用于初始化一个验证器
func (v *BlockValidator) ValidateBody(b block.IBlock) error {
ValidateBody验证给定块的叔叔,并验证块头的事务和叔叔根。假设此时已经对标头进行了验证。
vfs := b.Body().Verifier()
bls.PublicKeyFromBytes
创建一个公钥,PublicKeyFromBytes从BigEndian字节切片创建BLS公钥。并将其存储在ss数组中ss[i] = blsP
v.config.IsBeijing(b.Number64().Uint64())
,(IsBeijing返回num是否等于IsBeijingfork块或更大)则使用bls.SignatureFromBytes
方法从从LittleEndian字节切片创建BLS签名,并使用FastAggregateVerify
方法验证签名是否有效。如果验证失败,记录日志并返回错误。bc.HasBlockAndState
。如果区块链中已经存在该区块及其状态,则返回ErrKnownBlock
错误。if hash := DeriveSha
。如果不匹配,则返回错误bc.HasBlockAndState
检查父区块是否存在v.bc.HasBlock
,返回不同的错误ErrPrunedAncestor
错误;否则返回ErrUnknownAncestor
错误。func (v *BlockValidator) ValidateState(iBlock block.IBlock, statedb *state.IntraBlockState, receipts block.Receipts, usedGas uint64) error {
ValidateState验证状态转换后发生的各种变化,如gasused、接收根和状态根本身。如果验证成功,ValidateState将返回数据库批处理,否则为零并返回错误。
ValidateState用于验证区块的状态。它接收四个参数:iBlock
(待验证的区块)、statedb
(状态数据库)、receipts
(交易收据)和usedGas
(已使用的gas)。
GasUsed
字段是否与传入的usedGas
相等。如果不相等,返回一个错误信息,表示远程和本地的gas使用量不一致。block.CreateBloom(receipts)
,并将其与区块头中的Bloom
字段进行比较。如果两者不相等if rbloom != header.Bloom
,返回一个错误信息,表示远程和本地的布隆过滤器不一致。receiptSha := DeriveSha(receipts)
,并将其与区块头中的ReceiptHash
字段进行比较。如果不相等,遍历区块中的所有交易,并记录相关信息,最后返回一个错误信息,表示远程和本地的交易收据根哈希不一致receiptSha := DeriveSha(receipts)
是否与接收到的状态根相匹配。如果不匹配,返回一个错误信息,表示远程和本地的默克尔根不一致nil
type insertIterator struct {
chain []block2.IBlock // Chain of blocks being iterated over
results <-chan error // Verification result sink from the consensus engine
errors []error // Header verification errors for the blocks
index int // Current offset of the iterator
validator Validator // Validator to run if verification succeeds
}
这是一个名为insertIterator
的结构体,它包含以下字段:
chain []block2.IBlock
:一个block2.IBlock
类型的切片,表示正在迭代的区块链。results <-chan error
:一个错误类型的通道,用于从共识引擎接收验证结果。errors []error
:一个错误类型的切片,用于存储区块头验证错误。index int
:一个整数,表示迭代器的当前偏移量,索引值validator Validator
:一个Validator
类型的变量,如果验证成功,将运行此验证器。func newInsertIterator(chain []block2.IBlock, results <-chan error, validator Validator) *insertIterator {
return &insertIterator{
chain: chain,
results: results,
errors: make([]error, 0, len(chain)),
index: -1,
validator: validator,
}
}
该函数用于创建一个迭代器,基于给定的块创建一个新的迭代器。
func (it *insertIterator) next() (block2.IBlock, error) {
next返回迭代器中的下一个块,以及该块的任何潜在验证错误。当到达终点时,它将返回(nil,nil)。在循环迭代器中有很大的用处
该方法的作用是获取下一个区块并进行验证。
if it.index+1 >= len(it.chain)
,如果是,则将索引设置为链的长度并返回空值和nil错误if it.errors[it.index] != nil
,则直接返回该区块和错误信息it.validator.ValidateBody
方法对区块的主体进行验证,并返回验证后的区块和验证结果。func (it *insertIterator) peek() (block2.IBlock, error) {
peek返回迭代器中的下一个块,以及该块的任何潜在验证错误,但不会推进迭代器。
头和正文验证错误(也为nil)都缓存到迭代器中,以避免重复以下next()调用的工作。该方法的作用是预览下一个区块(block)以及可能的错误信息。
方法的实现逻辑如下:
if it.index+1 >= len(it.chain)
,如果是,则返回空nil,表示没有下一个区块可以预览。it.errors = append(it.errors, <-it.results)
return it.chain[it.index+1], nil
func (it *insertIterator) previous() block2.IHeader {
if it.index < 1 {
return nil
}
return it.chain[it.index-1].Header()
}
previor返回正在处理的前一个标头return it.chain[it.index-1].Header()
,或nil(如果当前Index<1)
func (it *insertIterator) current() block2.IHeader {
if it.index == -1 || it.index >= len(it.chain) {
return nil
}
return it.chain[it.index].Header()
}
current返回正在处理的当前标头it.chain[it.index].Header()
,或nil(如果当前Index=-1
太靠前,或者index已经超过链的长度了it.index >= len(it.chain)
)
func (it *insertIterator) first() block2.IBlock {
return it.chain[0]
}
该函数返回第一个区块return it.chain[0]
func (it *insertIterator) remaining() int {
return len(it.chain) - it.index
}
remaining返回剩余块的数量。通过总长度减去当前索引值得到剩余的区块数量
func (it *insertIterator) processed() int {
return it.index + 1
}
该函数返回已经处理过的区块的数量,return it.index + 1
为当前Index+1