mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
core, eth: skip transaction indexing during fast sync if required
This commit is contained in:
parent
24192a95c0
commit
89ad90d335
5 changed files with 62 additions and 40 deletions
|
|
@ -457,7 +457,7 @@ func (bc *BlockChain) SetHead(head uint64) error {
|
||||||
|
|
||||||
// FastSyncCommitHead sets the current head block to the one defined by the hash
|
// FastSyncCommitHead sets the current head block to the one defined by the hash
|
||||||
// irrelevant what the chain contents were prior.
|
// irrelevant what the chain contents were prior.
|
||||||
func (bc *BlockChain) FastSyncCommitHead(hash common.Hash) error {
|
func (bc *BlockChain) FastSyncCommitHead(hash common.Hash, from uint64, ancient uint64) error {
|
||||||
// Make sure that both the block as well at its state trie exists
|
// Make sure that both the block as well at its state trie exists
|
||||||
block := bc.GetBlockByHash(hash)
|
block := bc.GetBlockByHash(hash)
|
||||||
if block == nil {
|
if block == nil {
|
||||||
|
|
@ -472,6 +472,22 @@ func (bc *BlockChain) FastSyncCommitHead(hash common.Hash) error {
|
||||||
headBlockGauge.Update(int64(block.NumberU64()))
|
headBlockGauge.Update(int64(block.NumberU64()))
|
||||||
bc.chainmu.Unlock()
|
bc.chainmu.Unlock()
|
||||||
|
|
||||||
|
// Write tx indices tail if it doesn't exist in database.
|
||||||
|
// The tx index tail can only be one of the following two options:
|
||||||
|
// * the start point of fast sync:
|
||||||
|
// in this case all blocks imported during fast sync have been indexed
|
||||||
|
// * ancient - limit:
|
||||||
|
// in this case the block before ancient-limit won't be indexed
|
||||||
|
if tail := rawdb.ReadTxIndexTail(bc.db); tail == nil {
|
||||||
|
if bc.txLookupLimit != 0 && ancient >= bc.txLookupLimit && ancient-bc.txLookupLimit > from {
|
||||||
|
rawdb.WriteTxIndexTail(bc.db, ancient-bc.txLookupLimit)
|
||||||
|
} else {
|
||||||
|
if from == 1 {
|
||||||
|
from = 0
|
||||||
|
}
|
||||||
|
rawdb.WriteTxIndexTail(bc.db, from)
|
||||||
|
}
|
||||||
|
}
|
||||||
log.Info("Committed new head block", "number", block.Number(), "hash", hash)
|
log.Info("Committed new head block", "number", block.Number(), "hash", hash)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -1091,11 +1107,14 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
|
||||||
// Flush data into ancient database.
|
// Flush data into ancient database.
|
||||||
size += rawdb.WriteAncientBlock(bc.db, block, receiptChain[i], bc.GetTd(block.Hash(), block.NumberU64()))
|
size += rawdb.WriteAncientBlock(bc.db, block, receiptChain[i], bc.GetTd(block.Hash(), block.NumberU64()))
|
||||||
|
|
||||||
// We don't write tx lookup indices here because Geth can offer a CLI flag `txlookuplimt`
|
// Write tx indices if any condition is satisfied:
|
||||||
// with which user can choose to drop historical indices data and only keep latest indices.
|
// * If user requires to reserve all tx indices(txlookuplimit=0)
|
||||||
// After the fast sync, we will reconstruct all missing indices even user requires to keep
|
// * If all ancient tx indices are required to be reserved(txlookuplimit is even higher than ancientlimit)
|
||||||
// all historical indices.
|
// * If block number is large enough to be regarded as a recent block
|
||||||
|
// It means blocks below the ancientLimit-txlookupLimit won't be indexed.
|
||||||
|
if bc.txLookupLimit == 0 || ancientLimit <= bc.txLookupLimit || block.NumberU64() >= ancientLimit-bc.txLookupLimit {
|
||||||
|
rawdb.WriteTxLookupEntries(batch, block)
|
||||||
|
}
|
||||||
stats.processed++
|
stats.processed++
|
||||||
}
|
}
|
||||||
// Flush all tx-lookup index data.
|
// Flush all tx-lookup index data.
|
||||||
|
|
@ -1169,11 +1188,8 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
|
||||||
// Write all the data out into the database
|
// Write all the data out into the database
|
||||||
rawdb.WriteBody(batch, block.Hash(), block.NumberU64(), block.Body())
|
rawdb.WriteBody(batch, block.Hash(), block.NumberU64(), block.Body())
|
||||||
rawdb.WriteReceipts(batch, block.Hash(), block.NumberU64(), receiptChain[i])
|
rawdb.WriteReceipts(batch, block.Hash(), block.NumberU64(), receiptChain[i])
|
||||||
|
// We always write tx indices for live block since we assume the indices are needed.
|
||||||
// We don't write tx lookup indices here because Geth can offer a CLI flag `txlookuplimt`
|
rawdb.WriteTxLookupEntries(batch, block)
|
||||||
// with which user can choose to drop historical indices data and only keep latest indices.
|
|
||||||
// After the fast sync, we will reconstruct all missing indices even user requires to keep
|
|
||||||
// all historical indices.
|
|
||||||
|
|
||||||
stats.processed++
|
stats.processed++
|
||||||
if batch.ValueSize() >= ethdb.IdealBatchSize {
|
if batch.ValueSize() >= ethdb.IdealBatchSize {
|
||||||
|
|
@ -2056,10 +2072,12 @@ func (bc *BlockChain) update() {
|
||||||
// The user can adjust the txlookuplimit value for each launch, Geth will
|
// The user can adjust the txlookuplimit value for each launch, Geth will
|
||||||
// automatically construct the missing indices and delete the extra indices.
|
// automatically construct the missing indices and delete the extra indices.
|
||||||
func (bc *BlockChain) maintainTxIndex() {
|
func (bc *BlockChain) maintainTxIndex() {
|
||||||
// initialiseIndices inits txlookup indices into the database.
|
// initialiseIndices inits tx indices into the database if `TxIndexTail`
|
||||||
// If there already exists some indices, this function will find
|
// is missing in database.
|
||||||
// the oldest block which has been indexed and start indexing from
|
// Note for archive sync or fast sync, this code path will only be triggered
|
||||||
// this point.
|
// after importing the first batch of blocks(e.g. 1024). But these block
|
||||||
|
// actually are already indexed. So a binary search will be performed to
|
||||||
|
// skip reindexing.
|
||||||
initialiseIndices := func(head uint64, done chan struct{}) {
|
initialiseIndices := func(head uint64, done chan struct{}) {
|
||||||
defer func() { done <- struct{}{} }()
|
defer func() { done <- struct{}{} }()
|
||||||
|
|
||||||
|
|
@ -2067,27 +2085,26 @@ func (bc *BlockChain) maintainTxIndex() {
|
||||||
if bc.txLookupLimit != 0 && head > bc.txLookupLimit {
|
if bc.txLookupLimit != 0 && head > bc.txLookupLimit {
|
||||||
from = head - bc.txLookupLimit
|
from = head - bc.txLookupLimit
|
||||||
}
|
}
|
||||||
// Find oldest indexed block via binary search when we don't
|
if tail := rawdb.FindTxIndexTail(bc.db, from, to); tail != nil {
|
||||||
// have this flag in database.
|
// Special case here is genesis block doesn't contain any transaction
|
||||||
start := time.Now()
|
// that will be regarded as unindexed.
|
||||||
oldest := rawdb.FindTxIndexTail(bc.db, from, to)
|
if *tail == from || (from == 0 && *tail == 1) {
|
||||||
log.Debug("Find oldest indexed block", "oldest", oldest, "elapsed", common.PrettyDuration(time.Since(start)))
|
rawdb.WriteTxIndexTail(bc.db, from)
|
||||||
|
|
||||||
// Re-construct missing tx indices.
|
|
||||||
if oldest == nil {
|
|
||||||
rawdb.IndexTxLookup(bc.db, from, to) // No block has been indexed.
|
|
||||||
} else {
|
|
||||||
rawdb.IndexTxLookup(bc.db, from, *oldest)
|
|
||||||
|
|
||||||
// Drop all useless tx indices below the HEAD-limit.
|
// Drop all useless tx indices below the HEAD-limit.
|
||||||
if from > 0 {
|
if from > 0 {
|
||||||
oldest := rawdb.FindTxIndexTail(bc.db, 0, from)
|
rawdb.RemoveTxsLookup(bc.db, 0, from)
|
||||||
if oldest != nil {
|
}
|
||||||
rawdb.RemoveTxsLookup(bc.db, *oldest, from)
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Re-construct missing tx indices.
|
||||||
|
rawdb.IndexTxLookup(bc.db, from, to)
|
||||||
|
|
||||||
|
// Drop all useless tx indices below the HEAD-limit.
|
||||||
|
if from > 0 {
|
||||||
|
rawdb.RemoveTxsLookup(bc.db, 0, from)
|
||||||
}
|
}
|
||||||
log.Debug("Initialised transaction indices", "elapsed", common.PrettyDuration(time.Since(start)))
|
|
||||||
}
|
}
|
||||||
// indexBlocks reindex or unindex transaction indices depends
|
// indexBlocks reindex or unindex transaction indices depends
|
||||||
// on user's requirement.
|
// on user's requirement.
|
||||||
|
|
@ -2131,10 +2148,10 @@ func (bc *BlockChain) maintainTxIndex() {
|
||||||
case head := <-headCh:
|
case head := <-headCh:
|
||||||
if done == nil {
|
if done == nil {
|
||||||
done = make(chan struct{})
|
done = make(chan struct{})
|
||||||
if number := rawdb.ReadTxIndexTail(bc.db); number == nil {
|
if tail := rawdb.ReadTxIndexTail(bc.db); tail == nil {
|
||||||
go initialiseIndices(head.Block.NumberU64(), done)
|
go initialiseIndices(head.Block.NumberU64(), done)
|
||||||
} else {
|
} else {
|
||||||
go indexBlocks(*number, head.Block.NumberU64(), done)
|
go indexBlocks(*tail, head.Block.NumberU64(), done)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case <-done:
|
case <-done:
|
||||||
|
|
|
||||||
|
|
@ -199,15 +199,16 @@ func IndexTxLookup(db ethdb.Database, from uint64, to uint64) {
|
||||||
// writeIndices injects txlookup indices into the database.
|
// writeIndices injects txlookup indices into the database.
|
||||||
writeIndices := func(batch ethdb.Batch, block *types.Block) {
|
writeIndices := func(batch ethdb.Batch, block *types.Block) {
|
||||||
WriteTxLookupEntries(batch, block)
|
WriteTxLookupEntries(batch, block)
|
||||||
if block.NumberU64()%1000000 == 0 {
|
if block.NumberU64()%100000 == 0 {
|
||||||
WriteTxIndexTail(batch, block.NumberU64())
|
WriteTxIndexTail(batch, block.NumberU64())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
start := time.Now()
|
||||||
if err := iterateCanonicalChain(db, from, to, "txlookup", hashTxs, writeIndices, true, true); err != nil {
|
if err := iterateCanonicalChain(db, from, to, "txlookup", hashTxs, writeIndices, true, true); err != nil {
|
||||||
log.Crit("Failed to iterate canonical chain", "err", err)
|
log.Crit("Failed to iterate canonical chain", "err", err)
|
||||||
}
|
}
|
||||||
WriteTxIndexTail(db, from)
|
WriteTxIndexTail(db, from)
|
||||||
log.Info("Constructed transaction indices", "from", from, "to", to, "count", to-from)
|
log.Info("Constructed transaction indices", "from", from, "to", to, "count", to-from, "elapsed", common.PrettyDuration(time.Since(start)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveTxsLookup removes txlookup indices of the specified range blocks.
|
// RemoveTxsLookup removes txlookup indices of the specified range blocks.
|
||||||
|
|
|
||||||
|
|
@ -200,7 +200,7 @@ type BlockChain interface {
|
||||||
CurrentFastBlock() *types.Block
|
CurrentFastBlock() *types.Block
|
||||||
|
|
||||||
// FastSyncCommitHead directly commits the head block to a certain entity.
|
// FastSyncCommitHead directly commits the head block to a certain entity.
|
||||||
FastSyncCommitHead(common.Hash) error
|
FastSyncCommitHead(common.Hash, uint64, uint64) error
|
||||||
|
|
||||||
// InsertChain inserts a batch of blocks into the local chain.
|
// InsertChain inserts a batch of blocks into the local chain.
|
||||||
InsertChain(types.Blocks) (int, error)
|
InsertChain(types.Blocks) (int, error)
|
||||||
|
|
@ -1721,7 +1721,11 @@ func (d *Downloader) commitPivotBlock(result *fetchResult) error {
|
||||||
if _, err := d.blockchain.InsertReceiptChain([]*types.Block{block}, []types.Receipts{result.Receipts}, d.ancientLimit); err != nil {
|
if _, err := d.blockchain.InsertReceiptChain([]*types.Block{block}, []types.Receipts{result.Receipts}, d.ancientLimit); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := d.blockchain.FastSyncCommitHead(block.Hash()); err != nil {
|
// Use origin block number + 1 as the number of the first inserted block.
|
||||||
|
d.syncStatsLock.RLock()
|
||||||
|
from := d.syncStatsChainOrigin + 1
|
||||||
|
d.syncStatsLock.RUnlock()
|
||||||
|
if err := d.blockchain.FastSyncCommitHead(block.Hash(), from, d.ancientLimit); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
atomic.StoreInt32(&d.committed, 1)
|
atomic.StoreInt32(&d.committed, 1)
|
||||||
|
|
|
||||||
|
|
@ -218,7 +218,7 @@ func (dl *downloadTester) CurrentFastBlock() *types.Block {
|
||||||
}
|
}
|
||||||
|
|
||||||
// FastSyncCommitHead manually sets the head block to a given hash.
|
// FastSyncCommitHead manually sets the head block to a given hash.
|
||||||
func (dl *downloadTester) FastSyncCommitHead(hash common.Hash) error {
|
func (dl *downloadTester) FastSyncCommitHead(hash common.Hash, from uint64, ancient uint64) error {
|
||||||
// For now only check that the state trie is correct
|
// For now only check that the state trie is correct
|
||||||
if block := dl.GetBlockByHash(hash); block != nil {
|
if block := dl.GetBlockByHash(hash); block != nil {
|
||||||
_, err := trie.NewSecure(block.Root(), trie.NewDatabase(dl.stateDb))
|
_, err := trie.NewSecure(block.Root(), trie.NewDatabase(dl.stateDb))
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ const (
|
||||||
// The number is referenced from the size of tx pool.
|
// The number is referenced from the size of tx pool.
|
||||||
txChanSize = 4096
|
txChanSize = 4096
|
||||||
|
|
||||||
// minimim number of peers to broadcast new blocks to
|
// minBroadcastPeers is the minimal number of peers to broadcast new blocks to.
|
||||||
minBroadcastPeers = 4
|
minBroadcastPeers = 4
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue