From 51390a57ba40fce9a7e1ec3c8b94e1267fcf9332 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 19 Nov 2019 21:24:28 +0800 Subject: [PATCH] core, light: address comments --- core/blockchain.go | 53 +++++++++++++++++++++++---------------------- core/headerchain.go | 22 +++++-------------- light/lightchain.go | 22 +++++++++++++------ 3 files changed, 47 insertions(+), 50 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 1beba9fc32..805197aab4 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -538,21 +538,21 @@ func (bc *BlockChain) ResetWithGenesisBlock(genesis *types.Block) error { // Prepare the genesis block and reinitialise the chain batch := bc.db.NewBatch() - bc.hc.WriteTd(batch, genesis.Hash(), genesis.NumberU64(), genesis.Difficulty()) + rawdb.WriteTd(batch, genesis.Hash(), genesis.NumberU64(), genesis.Difficulty()) rawdb.WriteBlock(batch, genesis) if err := batch.Write(); err != nil { log.Crit("Failed to write genesis block", "err", err) } - bc.genesisBlock = genesis - bc.writeHeadBlock(bc.genesisBlock) + bc.writeHeadBlock(genesis) + // Last update all in-memory chain markers + bc.genesisBlock = genesis bc.currentBlock.Store(bc.genesisBlock) headBlockGauge.Update(int64(bc.genesisBlock.NumberU64())) bc.hc.SetGenesis(bc.genesisBlock.Header()) bc.hc.SetCurrentHeader(bc.genesisBlock.Header()) bc.currentFastBlock.Store(bc.genesisBlock) headFastBlockGauge.Update(int64(bc.genesisBlock.NumberU64())) - return nil } @@ -621,28 +621,28 @@ func (bc *BlockChain) writeHeadBlock(block *types.Block) { updateHeads := rawdb.ReadCanonicalHash(bc.db, block.NumberU64()) != block.Hash() // Add the block to the canonical chain number scheme and mark as the head - // First write all header chain relative indexes batch := bc.db.NewBatch() rawdb.WriteCanonicalHash(batch, block.Hash(), block.NumberU64()) - if updateHeads { - bc.hc.WriteHeadHeader(batch, block.Header()) - } - // Then write all block chain relative indexes rawdb.WriteTxLookupEntries(batch, block) rawdb.WriteHeadBlockHash(batch, block.Hash()) - bc.currentBlock.Store(block) - headBlockGauge.Update(int64(block.NumberU64())) - // If the block is better than our head or is on a different chain, force update heads if updateHeads { + rawdb.WriteHeadHeaderHash(batch, block.Hash()) rawdb.WriteHeadFastBlockHash(batch, block.Hash()) - bc.currentFastBlock.Store(block) - headFastBlockGauge.Update(int64(block.NumberU64())) } + // Flush the whole batch into the disk, exit the node if failed if err := batch.Write(); err != nil { log.Crit("Failed to update chain indexes and markers", "err", err) } + // Update all in-memory chain markers in the last step + if updateHeads { + bc.hc.SetCurrentHeader(block.Header()) + bc.currentFastBlock.Store(block) + headFastBlockGauge.Update(int64(block.NumberU64())) + } + bc.currentBlock.Store(block) + headBlockGauge.Update(int64(block.NumberU64())) } // Genesis retrieves the chain's genesis block. @@ -892,9 +892,15 @@ func (bc *BlockChain) Rollback(chain []common.Hash) { for i := len(chain) - 1; i >= 0; i-- { hash := chain[i] + // Degrade the chain markers if they are explictly reverted. + // In thoery we should update all in-memory markers in the + // last step, however the direction of rollback is from high + // to low, so it's safe the update in-memory markers directly. currentHeader := bc.hc.CurrentHeader() if currentHeader.Hash() == hash { - bc.hc.WriteHeadHeader(batch, bc.GetHeader(currentHeader.ParentHash, currentHeader.Number.Uint64()-1)) + newHeadHeader := bc.GetHeader(currentHeader.ParentHash, currentHeader.Number.Uint64()-1) + rawdb.WriteHeadHeaderHash(batch, currentHeader.ParentHash) + bc.hc.SetCurrentHeader(newHeadHeader) } if currentFastBlock := bc.CurrentFastBlock(); currentFastBlock.Hash() == hash { newFastBlock := bc.GetBlock(currentFastBlock.ParentHash(), currentFastBlock.NumberU64()-1) @@ -1240,15 +1246,15 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ var lastWrite uint64 -// writeSideBlock writes only the block and its metadata to the database, +// writeBlockWithState writes only the block and its metadata to the database, // but does not write any state. This is used to construct competing side forks // up to the point where they exceed the canonical total difficulty. -func (bc *BlockChain) writeSideBlock(block *types.Block, td *big.Int) (err error) { +func (bc *BlockChain) writeBlockWithoutState(block *types.Block, td *big.Int) (err error) { bc.wg.Add(1) defer bc.wg.Done() batch := bc.db.NewBatch() - bc.hc.WriteTd(batch, block.Hash(), block.NumberU64(), td) + rawdb.WriteTd(batch, block.Hash(), block.NumberU64(), td) rawdb.WriteBlock(batch, block) if err := batch.Write(); err != nil { log.Crit("Failed to write block into disk", "err", err) @@ -1301,11 +1307,10 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. // Note all the components of block(td, hash->number map, header, body, receipts) // should be written atomically. BlockBatch is used for containing all components. blockBatch := bc.db.NewBatch() - if err := bc.hc.WriteTd(blockBatch, block.Hash(), block.NumberU64(), externTd); err != nil { - return NonStatTy, err - } + rawdb.WriteTd(blockBatch, block.Hash(), block.NumberU64(), externTd) rawdb.WriteBlock(blockBatch, block) rawdb.WriteReceipts(blockBatch, block.Hash(), block.NumberU64(), receipts) + rawdb.WritePreimages(blockBatch, state.Preimages()) if err := blockBatch.Write(); err != nil { log.Crit("Failed to write block into disk", "err", err) } @@ -1393,10 +1398,6 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. return NonStatTy, err } } - // Preimages is a specical helper data, we don't need to - // consider the atomicity. - rawdb.WritePreimages(bc.db, state.Preimages()) - status = CanonStatTy } else { status = SideStatTy @@ -1801,7 +1802,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i if !bc.HasBlock(block.Hash(), block.NumberU64()) { start := time.Now() - if err := bc.writeSideBlock(block, externTd); err != nil { + if err := bc.writeBlockWithoutState(block, externTd); err != nil { return it.index, nil, nil, err } log.Debug("Injected sidechain block", "number", block.Number(), "hash", block.Hash(), diff --git a/core/headerchain.go b/core/headerchain.go index a45360658a..d129e479c4 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -157,7 +157,7 @@ func (hc *HeaderChain) WriteHeader(header *types.Header) (status WriteStatus, er // Note all the components of header(td, hash->number index and header) should // be written atomically. headerBatch := hc.chainDb.NewBatch() - hc.WriteTd(headerBatch, hash, number, externTd) + rawdb.WriteTd(headerBatch, hash, number, externTd) rawdb.WriteHeader(headerBatch, header) if err := headerBatch.Write(); err != nil { log.Crit("Failed to write header into disk", "err", err) @@ -200,6 +200,7 @@ func (hc *HeaderChain) WriteHeader(header *types.Header) (status WriteStatus, er if err := markerBatch.Write(); err != nil { log.Crit("Failed to write header markers into disk", "err", err) } + // Last step update all in-memory head header markers hc.currentHeaderHash = hash hc.currentHeader.Store(types.CopyHeader(header)) headHeaderGauge.Update(header.Number.Int64()) @@ -208,6 +209,7 @@ func (hc *HeaderChain) WriteHeader(header *types.Header) (status WriteStatus, er } else { status = SideStatTy } + hc.tdCache.Add(hash, externTd) hc.headerCache.Add(hash, header) hc.numberCache.Add(hash, number) return @@ -411,14 +413,6 @@ func (hc *HeaderChain) GetTdByHash(hash common.Hash) *big.Int { return hc.GetTd(hash, *number) } -// WriteTd stores a block's total difficulty into the database, also caching it -// along the way. -func (hc *HeaderChain) WriteTd(db ethdb.KeyValueWriter, hash common.Hash, number uint64, td *big.Int) error { - rawdb.WriteTd(db, hash, number, td) - hc.tdCache.Add(hash, new(big.Int).Set(td)) - return nil -} - // GetHeader retrieves a block header from the database by hash and number, // caching it if found. func (hc *HeaderChain) GetHeader(hash common.Hash, number uint64) *types.Header { @@ -475,20 +469,14 @@ func (hc *HeaderChain) CurrentHeader() *types.Header { return hc.currentHeader.Load().(*types.Header) } -// SetCurrentHeader sets the current head header of the canonical chain. +// SetCurrentHeader sets the in-memory head header marker of the canonical chan +// as the given header. func (hc *HeaderChain) SetCurrentHeader(head *types.Header) { hc.currentHeader.Store(head) hc.currentHeaderHash = head.Hash() headHeaderGauge.Update(head.Number.Int64()) } -// WriteHeadHeader sets the current head header of the canonical chain -// and write the marker into database. -func (hc *HeaderChain) WriteHeadHeader(db ethdb.KeyValueWriter, head *types.Header) { - rawdb.WriteHeadHeaderHash(db, head.Hash()) - hc.SetCurrentHeader(head) -} - type ( // UpdateHeadBlocksCallback is a callback function that is called by SetHead // before head header is updated. diff --git a/light/lightchain.go b/light/lightchain.go index 32055fca4f..864356cf93 100644 --- a/light/lightchain.go +++ b/light/lightchain.go @@ -200,14 +200,12 @@ func (lc *LightChain) ResetWithGenesisBlock(genesis *types.Block) { batch := lc.chainDb.NewBatch() rawdb.WriteTd(batch, genesis.Hash(), genesis.NumberU64(), genesis.Difficulty()) rawdb.WriteBlock(batch, genesis) - - lc.genesisBlock = genesis - lc.hc.SetGenesis(lc.genesisBlock.Header()) - lc.hc.WriteHeadHeader(batch, lc.genesisBlock.Header()) - + rawdb.WriteHeadHeaderHash(batch, genesis.Hash()) if err := batch.Write(); err != nil { log.Crit("Failed to reset genesis block", "err", err) } + lc.genesisBlock = genesis + lc.hc.SetGenesis(lc.genesisBlock.Header()) } // Accessors @@ -327,13 +325,22 @@ func (lc *LightChain) Rollback(chain []common.Hash) { lc.chainmu.Lock() defer lc.chainmu.Unlock() + batch := lc.chainDb.NewBatch() for i := len(chain) - 1; i >= 0; i-- { hash := chain[i] + // Degrade the chain markers if they are explictly reverted. + // In thoery we should update all in-memory markers in the + // last step, however the direction of rollback is from high + // to low, so it's safe the update in-memory markers directly. if head := lc.hc.CurrentHeader(); head.Hash() == hash { - lc.hc.WriteHeadHeader(lc.chainDb, lc.GetHeader(head.ParentHash, head.Number.Uint64()-1)) + rawdb.WriteHeadHeaderHash(batch, head.ParentHash) + lc.hc.SetCurrentHeader(lc.GetHeader(head.ParentHash, head.Number.Uint64()-1)) } } + if err := batch.Write(); err != nil { + log.Crit("Failed to rollback light chain", "error", err) + } } // postChainEvents iterates over the events generated by a chain insertion and @@ -497,7 +504,8 @@ func (lc *LightChain) SyncCheckpoint(ctx context.Context, checkpoint *params.Tru // Ensure the chain didn't move past the latest block while retrieving it if lc.hc.CurrentHeader().Number.Uint64() < header.Number.Uint64() { log.Info("Updated latest header based on CHT", "number", header.Number, "hash", header.Hash(), "age", common.PrettyAge(time.Unix(int64(header.Time), 0))) - lc.hc.WriteHeadHeader(lc.chainDb, header) + rawdb.WriteHeadHeaderHash(lc.chainDb, header.Hash()) + lc.hc.SetCurrentHeader(header) } return true }