BSC区块生产流程深度解析
一、区块准备阶段
1. 准备工作
2. 出块机制
4. 交易填充
二、区块密封(Seal)流程
1. 任务提交
2. 签名流程
3. 投票收集
三、区块广播流程
四、区块接收流程
1. 消息处理链路
eth/protocols/eth/handler.go:Handle // 处理P2P消息
-> handlers.go:handleNewBlock // 解码区块
-> handler_eth.go:handleBlockBroadcast // 加入处理队列
-> block_fetcher.go:importBlocks // 导入区块
-> blockchain.go:InsertChain // 插入链上
-> blockchain.go:processBlock // 处理区块
2. 区块验证
// 基本字段验证
func (p *Parlia) verifyHeader(chain consensus.ChainHeaderReader, header *types.Header) error {
// 验证时间戳
if header.Time > uint64(time.Now().Unix()+maxTimeFutureBlocks) {
return consensus.ErrFutureBlock
}
// 验证难度值
if header.Difficulty == nil || header.Difficulty.Cmp(diffInTurn) != 0 {
return errInvalidDifficulty
}
// 验证投票证明
if err := p.verifyVoteAttestation(chain, header); err != nil {
return err
}
}
3. 区块持久化
执行区块中的交易:
func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (*ProcessResult, error) {
// 1. 初始化所需变量
var (
receipts = make([]*types.Receipt, 0) // 存储交易收据
usedGas = new(uint64) // 记录使用的gas总量
header = block.Header() // 区块头
blockHash = block.Hash() // 区块哈希
blockNumber = block.Number() // 区块号
allLogs []*types.Log // 所有日志
gp = new(GasPool).AddGas(block.GasLimit()) // gas池
)
// 2. 处理硬分叉相关的状态变更
if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 {
misc.ApplyDAOHardFork(statedb)
}
// 3. 获取父区块并更新系统合约
lastBlock := p.chain.GetHeaderByHash(block.ParentHash())
if lastBlock == nil {
return nil, errors.New("could not get parent block")
}
systemcontracts.TryUpdateBuildInSystemContract(p.config, blockNumber, lastBlock.Time, block.Time(), statedb, true)
// 4. 创建EVM执行环境
context = NewEVMBlockContext(header, p.chain, nil)
evm := vm.NewEVM(context, tracingStateDB, p.config, cfg)
// 5. 处理信标链根和父区块哈希(如果需要)
if beaconRoot := block.BeaconRoot(); beaconRoot != nil {
ProcessBeaconBlockRoot(*beaconRoot, evm)
}
if p.config.IsPrague(block.Number(), block.Time()) {
ProcessParentBlockHash(block.ParentHash(), evm)
}
// 6. 初始化交易处理相关变量
posa, isPoSA := p.chain.engine.(consensus.PoSA)
commonTxs := make([]*types.Transaction, 0, txNum)
systemTxs := make([]*types.Transaction, 0, 2)
// 7. 遍历处理每个交易
for i, tx := range block.Transactions() {
// 7.1 处理系统交易
if isPoSA {
if isSystemTx, err := posa.IsSystemTransaction(tx, block.Header()); err != nil {
return nil, err
} else if isSystemTx {
systemTxs = append(systemTxs, tx)
continue
}
}
// 7.2 将交易转换为消息
msg, err := TransactionToMessage(tx, signer, header.BaseFee)
if err != nil {
return nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
}
// 7.3 设置交易上下文并执行交易
statedb.SetTxContext(tx.Hash(), i)
receipt, err := ApplyTransactionWithEVM(msg, gp, statedb, blockNumber, blockHash, tx, usedGas, evm, bloomProcessors)
if err != nil {
return nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
}
// 7.4 收集交易结果
commonTxs = append(commonTxs, tx)
receipts = append(receipts, receipt)
}
// 8. 处理共识引擎相关的奖励
err = p.chain.engine.Finalize(p.chain, header, tracingStateDB, &commonTxs, block.Uncles(), block.Withdrawals(), &receipts, &systemTxs, usedGas, cfg.Tracer)
if err != nil {
return nil, err
}
// 9. 返回处理结果
return &ProcessResult{
Receipts: receipts,
Requests: requests,
Logs: allLogs,
GasUsed: *usedGas,
}, nil
}
持久化:
// 源码:bsc/core/blockchain.go:processBlock
// 将区块和状态写入数据库
if err := bc.writeBlockWithState(block, receipts, statedb); err != nil {
return nil, err
}
4. 奖励
五、区块投票流程
投票广播
- 有序的区块生产
- 安全的区块传播
- 可靠的状态更新
- 快速的共识达成

浙公网安备 33010602011771号