死磕以太坊源码分析之blockChain分析
配合以下代码进行阅读:https://github.com/blockchainGuide/
写文不易,给个小关注,有什么问题可以指出,便于大家交流学习。
blockchain关键元素
db
:持久化到底层数据储存,即leveldb
;
genesisBlock
:创始区块
currentBlock
:当前区块,blockchain
中并不是储存链所有的block
,而是通过currentBlock
向前回溯直到genesisBlock
,这样就构成了区块链
bodyCache
、bodyRLPCache
、blockCache
、futureBlocks
:区块链中的缓存结构,用于加快区块链的读取和构建;
hc
:headerchain
区块头链,由blockchain
额外维护的另一条链,由于Header
和Block
的储存空间是有很大差别的,但同时Block
的Hash
值就是Header
(RLP)的Hash
值,所以维护一个headerchain
可以用于快速延长链,验证通过后再下载blockchain
,或者可以与blockchain
进行相互验证;
processor
:执行区块链交易的接口,收到一个新的区块时,要对区块中的所有交易执行一遍,一方面是验证,一方面是更新世界状态;
validator
:验证数据有效性的接口
futureBlocks
:收到的区块时间大于当前头区块时间15s而小于30s的区块,可作为当前节点待处理的区块。
函数介绍
1 2 3 4 5
| func (bc *BlockChain) BadBlocks() []*types.Block {}
func (bc *BlockChain) addBadBlock(block *types.Block) {}
|
1 2 3 4 5 6 7 8
| func (bc *BlockChain) CurrentBlock() *types.Block {}
func (bc *BlockChain) CurrentHeader() *types.Header{}
func (bc *BlockChain) CurrentFastBlock() *types.Block {}
|
1 2 3
| func (bc *BlockChain) Export(w io.Writer) error {} func (bc *BlockChain) ExportN(w io.Writer, first uint64, last uint64) error {}
|
1 2
| func (bc *BlockChain) FastSyncCommitHead(hash common.Hash) error {}
|
1 2
| func (bc *BlockChain) GasLimit() uint64 {}
|
1 2
| func (bc *BlockChain) Genesis() *types.Block {}
|
1 2 3
| func (bc *BlockChain) GetBody(hash common.Hash) *types.Body {} func (bc *BlockChain) GetBodyRLP(hash common.Hash) rlp.RawValue {}
|
1 2 3 4 5 6
| func (bc *BlockChain) GetBlock(hash common.Hash, number uint64) *types.Block {}
func (bc *BlockChain) GetBlockByHash(hash common.Hash) *types.Block {}
func (bc *BlockChain) GetBlockByNumber(number uint64) *types.Block {}
|
1 2 3 4 5 6 7 8
| func (bc *BlockChain) GetHeader(hash common.Hash, number uint64) *types.Header{}
func (bc *BlockChain) GetHeaderByHash(hash common.Hash) *types.Header{}
func (bc *BlockChain) GetHeaderByNumber(number uint64) *types.Header{}
|
1 2 3 4 5 6 7 8 9 10 11
| func (bc *BlockChain) HasBlock(hash common.Hash, number uint64) bool {}
func (bc *BlockChain) HasHeader(hash common.Hash, number uint64) bool{}
func (bc *BlockChain) HasState(hash common.Hash) bool {}
func (bc *BlockChain) HasBlockAndState(hash common.Hash, number uint64) bool {}
|
1 2
| func (bc *BlockChain) GetTd(hash common.Hash, number uint64) *big.Int{}
|
1 2 3 4 5 6 7 8 9 10 11
| func (bc *BlockChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []common.Hash{}
func (bc *BlockChain) GetReceiptsByHash(hash common.Hash) types.Receipts {}
func (bc *BlockChain) GetBlocksFromHash(hash common.Hash, n int) (blocks []*types.Block) {}
func (bc *BlockChain) GetUnclesInChain(block *types.Block, length int) []*types.Header {}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
func (bc *BlockChain) insert(block *types.Block) {}
func (bc *BlockChain) InsertChain(chain types.Blocks) (int, error){}
func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*types.Log, error){}
func (bc *BlockChain) InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error){}
func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain []types.Receipts) (int, error) {}
|
1 2
| func (bc *BlockChain) loadLastState() error {}
|
1 2
| func (bc *BlockChain) Processor() Processor {}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| func (bc *BlockChain) Reset() error {}
func (bc *BlockChain) ResetWithGenesisBlock(genesis *types.Block) error {}
func (bc *BlockChain) repair(head **types.Block) error {}
func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error{}
func (bc *BlockChain) Rollback(chain []common.Hash) {}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
func SetReceiptsData(config *params.ChainConfig, block *types.Block, receipts types.Receipts) error {}
func (bc *BlockChain) SetHead(head uint64) error {}
func (bc *BlockChain) SetProcessor(processor Processor) {}
func (bc *BlockChain) SetValidator(validator Validator) {}
func (bc *BlockChain) State() (*state.StateDB, error) {}
func (bc *BlockChain) StateAt(root common.Hash) (*state.StateDB, error) {}
func (bc *BlockChain) Stop() {}
func (bc *BlockChain) TrieNode(hash common.Hash) ([]byte, error) {}
func (bc *BlockChain) Validator() Validator {}
|
1 2 3 4 5 6 7 8 9 10 11
| func (bc *BlockChain) WriteBlockWithoutState(block *types.Block, td *big.Int) (err error){}
func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.Receipt, state *state.StateDB) {}
func (bc *BlockChain) writeHeader(header *types.Header) error{}
func (bc *BlockChain) update() {}
|
blockchain初始化
主要步骤:
①:创建一个新的headerChain结构
1
| bc.hc, err = NewHeaderChain(db, chainConfig, engine, bc.getProcInterrupt)
|
- 根据number(0)获取genesisHeader
- 从rawdb中读取HeadBlock并存储在currentHeader中
②:获取genesisBlock
1
| bc.genesisBlock = bc.GetBlockByNumber(0)
|
③:如果链不为空,则用老的链数据初始化链
1 2 3
| if bc.empty() { rawdb.InitDatabaseFromFreezer(bc.db) }
|
④:加载最新的状态数据
1 2 3
| if err := bc.loadLastState(); err != nil { return nil, err }
|
⑤:检查区块哈希的当前状态,并确保链中没有任何坏块
1 2 3 4 5 6 7 8 9 10
| for hash := range BadHashes { if header := bc.GetHeaderByHash(hash); header != nil { headerByNumber := bc.GetHeaderByNumber(header.Number.Uint64()) if headerByNumber != nil && headerByNumber.Hash() == header.Hash() { log.Error("Found bad hash, rewinding chain", "number", header.Number, "hash", header.ParentHash) bc.SetHead(header.Number.Uint64() - 1) log.Error("Chain rewind was successful, resuming normal operation") } } }
|
⑥:定时处理future block
1 2 3
| go bc.update() ->procFutureBlocks ->InsertChain
|
总的来说做了以下几件事:
- 配置
cacheConfig
,创建各种lru缓存
- 初始化
triegc
- 初始化
stateDb
:state.NewDatabase(db)
- 初始化区块和状态验证:NewBlockValidator()
- 初始化状态处理器:NewStateProcessor()
- 初始化区块头部链:NewHeaderChain()
- 查找创世区块:bc.genesisBlock = bc.GetBlockByNumber(0)
- 加载最新的状态数据:bc.loadLastState()
- 检查区块哈希的当前状态,并确保链中没有任何坏块
go bc.update()
定时处理future block
加载区块链状态
①:从数据库中恢复headblock,如果空的话,触发reset chain
1 2 3 4 5
| head := rawdb.ReadHeadBlockHash(bc.db) if head == (common.Hash{}) { log.Warn("Empty database, resetting chain") return bc.Reset() }
|
②:确保整个head block是可以获取的,若为空,则触发reset chain
1 2 3 4 5 6
| currentBlock := bc.GetBlockByHash(head) if currentBlock == nil { log.Warn("Head block missing, resetting chain", "hash", head) return bc.Reset() }
|
③:从stateDb中打开最新区块的状态trie,如果打开失败调用bc.repair(¤tBlock)方法进行修复。修复方法就是从当前区块一个个的往前面找,直到找到好的区块,然后赋值给currentBlock。
1 2 3 4 5 6 7 8
| if _, err := state.New(currentBlock.Root(), bc.stateCache); err != nil { log.Warn("Head state missing, repairing chain", "number", currentBlock.Number(), "hash", currentBlock.Hash()) if err := bc.repair(¤tBlock); err != nil { return err } rawdb.WriteHeadBlockHash(bc.db, currentBlock.Hash()) }
|
④:存储当前的headblock和设置当前的headHeader以及头部快速块
1 2 3 4 5
| bc.currentBlock.Store(currentBlock) .... bc.hc.SetCurrentHeader(currentHeader) ... bc.currentFastBlock.Store(currentBlock)
|
参考
https://mindcarver.cn
https://github.com/blockchainGuide