mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-18 18:02:24 +00:00
remove unused sidechain logic from blockchain
This commit is contained in:
parent
283be23817
commit
169e7fc330
1 changed files with 5 additions and 156 deletions
|
|
@ -1184,7 +1184,6 @@ type WriteStatus byte
|
||||||
const (
|
const (
|
||||||
NonStatTy WriteStatus = iota
|
NonStatTy WriteStatus = iota
|
||||||
CanonStatTy
|
CanonStatTy
|
||||||
SideStatTy
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// InsertReceiptChain attempts to complete an already existing header chain with
|
// 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
|
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
|
// writeKnownBlock updates the head block flag with a known block
|
||||||
// and introduces chain reorg if necessary.
|
// and introduces chain reorg if necessary.
|
||||||
func (bc *BlockChain) writeKnownBlock(block *types.Block) error {
|
func (bc *BlockChain) writeKnownBlock(block *types.Block) error {
|
||||||
|
|
@ -1681,16 +1664,9 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness
|
||||||
switch {
|
switch {
|
||||||
// First block is pruned
|
// First block is pruned
|
||||||
case errors.Is(err, consensus.ErrPrunedAncestor):
|
case errors.Is(err, consensus.ErrPrunedAncestor):
|
||||||
if setHead {
|
log.Debug("Pruned ancestor", "number", block.Number(), "hash", block.Hash())
|
||||||
// First block is pruned, insert as sidechain and reorg only if TD grows enough
|
_, err := bc.recoverAncestors(block, makeWitness)
|
||||||
log.Debug("Pruned ancestor, inserting as sidechain", "number", block.Number(), "hash", block.Hash())
|
return nil, it.index, err
|
||||||
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
|
|
||||||
}
|
|
||||||
// Some other error(except ErrKnownBlock) occurred, abort.
|
// Some other error(except ErrKnownBlock) occurred, abort.
|
||||||
// ErrKnownBlock is allowed here since some known blocks
|
// ErrKnownBlock is allowed here since some known blocks
|
||||||
// still need re-execution to generate snapshots that are missing
|
// 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
|
bc.gcproc += res.procTime
|
||||||
return witness, it.index, nil // Direct block insertion of a single block
|
return witness, it.index, nil // Direct block insertion of a single block
|
||||||
}
|
}
|
||||||
switch res.status {
|
if res.status == CanonStatTy {
|
||||||
case CanonStatTy:
|
|
||||||
log.Debug("Inserted new block", "number", block.Number(), "hash", block.Hash(),
|
log.Debug("Inserted new block", "number", block.Number(), "hash", block.Hash(),
|
||||||
"uncles", len(block.Uncles()), "txs", len(block.Transactions()), "gas", block.GasUsed(),
|
"uncles", len(block.Uncles()), "txs", len(block.Transactions()), "gas", block.GasUsed(),
|
||||||
"elapsed", common.PrettyDuration(time.Since(start)),
|
"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
|
// Only count canonical blocks for GC processing time
|
||||||
bc.gcproc += res.procTime
|
bc.gcproc += res.procTime
|
||||||
|
} else {
|
||||||
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:
|
|
||||||
// This in theory is impossible, but lets be nice to our future selves and leave
|
// 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.
|
// 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(),
|
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
|
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
|
// recoverAncestors finds the closest ancestor with available state and re-execute
|
||||||
// all the ancestor blocks since that.
|
// all the ancestor blocks since that.
|
||||||
// recoverAncestors is only used post-merge.
|
// recoverAncestors is only used post-merge.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue