From 169e7fc330ab22deab36bfa26b78ad9d06fdf7d4 Mon Sep 17 00:00:00 2001 From: Jared Wasinger Date: Sun, 13 Oct 2024 20:59:29 +0700 Subject: [PATCH] remove unused sidechain logic from blockchain --- core/blockchain.go | 161 ++------------------------------------------- 1 file changed, 5 insertions(+), 156 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index f7c921fe64..d19a90c35f 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1184,7 +1184,6 @@ type WriteStatus byte const ( NonStatTy WriteStatus = iota CanonStatTy - SideStatTy ) // InsertReceiptChain attempts to complete an already existing header chain with @@ -1417,22 +1416,6 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ return 0, nil } -// writeBlockWithoutState 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) writeBlockWithoutState(block *types.Block, td *big.Int) (err error) { - if bc.insertStopped() { - return errInsertionInterrupted - } - batch := bc.db.NewBatch() - 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) - } - return nil -} - // writeKnownBlock updates the head block flag with a known block // and introduces chain reorg if necessary. func (bc *BlockChain) writeKnownBlock(block *types.Block) error { @@ -1681,16 +1664,9 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness switch { // First block is pruned case errors.Is(err, consensus.ErrPrunedAncestor): - if setHead { - // First block is pruned, insert as sidechain and reorg only if TD grows enough - log.Debug("Pruned ancestor, inserting as sidechain", "number", block.Number(), "hash", block.Hash()) - return bc.insertSideChain(block, it, makeWitness) - } else { - // We're post-merge and the parent is pruned, try to recover the parent state - log.Debug("Pruned ancestor", "number", block.Number(), "hash", block.Hash()) - _, err := bc.recoverAncestors(block, makeWitness) - return nil, it.index, err - } + log.Debug("Pruned ancestor", "number", block.Number(), "hash", block.Hash()) + _, err := bc.recoverAncestors(block, makeWitness) + return nil, it.index, err // Some other error(except ErrKnownBlock) occurred, abort. // ErrKnownBlock is allowed here since some known blocks // still need re-execution to generate snapshots that are missing @@ -1839,8 +1815,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness bc.gcproc += res.procTime return witness, it.index, nil // Direct block insertion of a single block } - switch res.status { - case CanonStatTy: + if res.status == CanonStatTy { log.Debug("Inserted new block", "number", block.Number(), "hash", block.Hash(), "uncles", len(block.Uncles()), "txs", len(block.Transactions()), "gas", block.GasUsed(), "elapsed", common.PrettyDuration(time.Since(start)), @@ -1850,14 +1825,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness // Only count canonical blocks for GC processing time bc.gcproc += res.procTime - - case SideStatTy: - log.Debug("Inserted forked block", "number", block.Number(), "hash", block.Hash(), - "diff", block.Difficulty(), "elapsed", common.PrettyDuration(time.Since(start)), - "txs", len(block.Transactions()), "gas", block.GasUsed(), "uncles", len(block.Uncles()), - "root", block.Root()) - - default: + } else { // This in theory is impossible, but lets be nice to our future selves and leave // a log, instead of trying to track down blocks imports that don't emit logs. log.Warn("Inserted block with unknown status", "number", block.Number(), "hash", block.Hash(), @@ -1987,125 +1955,6 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s return &blockProcessingResult{usedGas: res.GasUsed, procTime: proctime, status: status}, nil } -// insertSideChain is called when an import batch hits upon a pruned ancestor -// error, which happens when a sidechain with a sufficiently old fork-block is -// found. -// -// The method writes all (header-and-body-valid) blocks to disk, then tries to -// switch over to the new chain if the TD exceeded the current chain. -// insertSideChain is only used pre-merge. -func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator, makeWitness bool) (*stateless.Witness, int, error) { - var ( - externTd *big.Int - current = bc.CurrentBlock() - ) - // The first sidechain block error is already verified to be ErrPrunedAncestor. - // Since we don't import them here, we expect ErrUnknownAncestor for the remaining - // ones. Any other errors means that the block is invalid, and should not be written - // to disk. - err := consensus.ErrPrunedAncestor - for ; block != nil && errors.Is(err, consensus.ErrPrunedAncestor); block, err = it.next() { - // Check the canonical state root for that number - if number := block.NumberU64(); current.Number.Uint64() >= number { - canonical := bc.GetBlockByNumber(number) - if canonical != nil && canonical.Hash() == block.Hash() { - // Not a sidechain block, this is a re-import of a canon block which has it's state pruned - - // Collect the TD of the block. Since we know it's a canon one, - // we can get it directly, and not (like further below) use - // the parent and then add the block on top - externTd = bc.GetTd(block.Hash(), block.NumberU64()) - continue - } - if canonical != nil && canonical.Root() == block.Root() { - // This is most likely a shadow-state attack. When a fork is imported into the - // database, and it eventually reaches a block height which is not pruned, we - // just found that the state already exist! This means that the sidechain block - // refers to a state which already exists in our canon chain. - // - // If left unchecked, we would now proceed importing the blocks, without actually - // having verified the state of the previous blocks. - log.Warn("Sidechain ghost-state attack detected", "number", block.NumberU64(), "sideroot", block.Root(), "canonroot", canonical.Root()) - - // If someone legitimately side-mines blocks, they would still be imported as usual. However, - // we cannot risk writing unverified blocks to disk when they obviously target the pruning - // mechanism. - return nil, it.index, errors.New("sidechain ghost-state attack") - } - } - if externTd == nil { - externTd = bc.GetTd(block.ParentHash(), block.NumberU64()-1) - } - externTd = new(big.Int).Add(externTd, block.Difficulty()) - - if !bc.HasBlock(block.Hash(), block.NumberU64()) { - start := time.Now() - if err := bc.writeBlockWithoutState(block, externTd); err != nil { - return nil, it.index, err - } - log.Debug("Injected sidechain block", "number", block.Number(), "hash", block.Hash(), - "diff", block.Difficulty(), "elapsed", common.PrettyDuration(time.Since(start)), - "txs", len(block.Transactions()), "gas", block.GasUsed(), "uncles", len(block.Uncles()), - "root", block.Root()) - } - } - // Gather all the sidechain hashes (full blocks may be memory heavy) - var ( - hashes []common.Hash - numbers []uint64 - ) - parent := it.previous() - for parent != nil && !bc.HasState(parent.Root) { - if bc.stateRecoverable(parent.Root) { - if err := bc.triedb.Recover(parent.Root); err != nil { - return nil, 0, err - } - break - } - hashes = append(hashes, parent.Hash()) - numbers = append(numbers, parent.Number.Uint64()) - - parent = bc.GetHeader(parent.ParentHash, parent.Number.Uint64()-1) - } - if parent == nil { - return nil, it.index, errors.New("missing parent") - } - // Import all the pruned blocks to make the state available - var ( - blocks []*types.Block - memory uint64 - ) - for i := len(hashes) - 1; i >= 0; i-- { - // Append the next block to our batch - block := bc.GetBlock(hashes[i], numbers[i]) - - blocks = append(blocks, block) - memory += block.Size() - - // If memory use grew too large, import and continue. Sadly we need to discard - // all raised events and logs from notifications since we're too heavy on the - // memory here. - if len(blocks) >= 2048 || memory > 64*1024*1024 { - log.Info("Importing heavy sidechain segment", "blocks", len(blocks), "start", blocks[0].NumberU64(), "end", block.NumberU64()) - if _, _, err := bc.insertChain(blocks, true, false); err != nil { - return nil, 0, err - } - blocks, memory = blocks[:0], 0 - - // If the chain is terminating, stop processing blocks - if bc.insertStopped() { - log.Debug("Abort during blocks processing") - return nil, 0, nil - } - } - } - if len(blocks) > 0 { - log.Info("Importing sidechain segment", "start", blocks[0].NumberU64(), "end", blocks[len(blocks)-1].NumberU64()) - return bc.insertChain(blocks, true, makeWitness) - } - return nil, 0, nil -} - // recoverAncestors finds the closest ancestor with available state and re-execute // all the ancestor blocks since that. // recoverAncestors is only used post-merge.