mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-25 06:06:44 +00:00
Revert "all: nuke total difficulty (#30744)"
This reverts commit 39638c81c5.
This commit is contained in:
parent
b215cd470f
commit
6805024cad
42 changed files with 637 additions and 132 deletions
|
|
@ -143,7 +143,11 @@ func (c *Chain) ForkID() forkid.ID {
|
|||
// TD calculates the total difficulty of the chain at the
|
||||
// chain head.
|
||||
func (c *Chain) TD() *big.Int {
|
||||
return new(big.Int)
|
||||
sum := new(big.Int)
|
||||
for _, block := range c.blocks[:c.Len()] {
|
||||
sum.Add(sum, block.Difficulty())
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
// GetBlock returns the block at the specified number.
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import (
|
|||
"context"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"sync"
|
||||
"time"
|
||||
|
|
@ -77,6 +78,7 @@ func (s *Suite) EthTests() []utesting.Test {
|
|||
{Name: "GetBlockBodies", Fn: s.TestGetBlockBodies},
|
||||
// // malicious handshakes + status
|
||||
{Name: "MaliciousHandshake", Fn: s.TestMaliciousHandshake},
|
||||
{Name: "MaliciousStatus", Fn: s.TestMaliciousStatus},
|
||||
// test transactions
|
||||
{Name: "LargeTxRequest", Fn: s.TestLargeTxRequest, Slow: true},
|
||||
{Name: "Transaction", Fn: s.TestTransaction},
|
||||
|
|
@ -469,6 +471,42 @@ func (s *Suite) TestMaliciousHandshake(t *utesting.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *Suite) TestMaliciousStatus(t *utesting.T) {
|
||||
t.Log(`This test sends a malicious eth Status message to the node and expects a disconnect.`)
|
||||
|
||||
conn, err := s.dial()
|
||||
if err != nil {
|
||||
t.Fatalf("dial failed: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
if err := conn.handshake(); err != nil {
|
||||
t.Fatalf("handshake failed: %v", err)
|
||||
}
|
||||
// Create status with large total difficulty.
|
||||
status := ð.StatusPacket{
|
||||
ProtocolVersion: uint32(conn.negotiatedProtoVersion),
|
||||
NetworkID: s.chain.config.ChainID.Uint64(),
|
||||
TD: new(big.Int).SetBytes(randBuf(2048)),
|
||||
Head: s.chain.Head().Hash(),
|
||||
Genesis: s.chain.GetBlock(0).Hash(),
|
||||
ForkID: s.chain.ForkID(),
|
||||
}
|
||||
if err := conn.statusExchange(s.chain, status); err != nil {
|
||||
t.Fatalf("status exchange failed: %v", err)
|
||||
}
|
||||
// Wait for disconnect.
|
||||
code, _, err := conn.Read()
|
||||
if err != nil {
|
||||
t.Fatalf("error reading from connection: %v", err)
|
||||
}
|
||||
switch code {
|
||||
case discMsg:
|
||||
break
|
||||
default:
|
||||
t.Fatalf("expected disconnect, got: %d", code)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Suite) TestTransaction(t *utesting.T) {
|
||||
t.Log(`This test sends a valid transaction to the node and checks if the
|
||||
transaction gets propagated.`)
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
|
|
@ -455,10 +454,6 @@ func ExportHistory(bc *core.BlockChain, dir string, first, last, step uint64) er
|
|||
buf = bytes.NewBuffer(nil)
|
||||
checksums []string
|
||||
)
|
||||
td := new(big.Int)
|
||||
for i := uint64(0); i < first; i++ {
|
||||
td.Add(td, bc.GetHeaderByNumber(i).Difficulty)
|
||||
}
|
||||
for i := first; i <= last; i += step {
|
||||
err := func() error {
|
||||
filename := filepath.Join(dir, era.Filename(network, int(i/step), common.Hash{}))
|
||||
|
|
@ -481,8 +476,11 @@ func ExportHistory(bc *core.BlockChain, dir string, first, last, step uint64) er
|
|||
if receipts == nil {
|
||||
return fmt.Errorf("export failed on #%d: receipts not found", n)
|
||||
}
|
||||
td.Add(td, block.Difficulty())
|
||||
if err := w.Add(block, receipts, new(big.Int).Set(td)); err != nil {
|
||||
td := bc.GetTd(block.Hash(), block.NumberU64())
|
||||
if td == nil {
|
||||
return fmt.Errorf("export failed on #%d: total difficulty not found", n)
|
||||
}
|
||||
if err := w.Add(block, receipts, td); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,55 +93,67 @@ func (beacon *Beacon) Author(header *types.Header) (common.Address, error) {
|
|||
// VerifyHeader checks whether a header conforms to the consensus rules of the
|
||||
// stock Ethereum consensus engine.
|
||||
func (beacon *Beacon) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header) error {
|
||||
// During the live merge transition, the consensus engine used the terminal
|
||||
// total difficulty to detect when PoW (PoA) switched to PoS. Maintaining the
|
||||
// total difficulty values however require applying all the blocks from the
|
||||
// genesis to build up the TD. This stops being a possibility if the tail of
|
||||
// the chain is pruned already during sync.
|
||||
//
|
||||
// One heuristic that can be used to distinguish pre-merge and post-merge
|
||||
// blocks is whether their *difficulty* is >0 or ==0 respectively. This of
|
||||
// course would mean that we cannot prove anymore for a past chain that it
|
||||
// truly transitioned at the correct TTD, but if we consider that ancient
|
||||
// point in time finalized a long time ago, there should be no attempt from
|
||||
// the consensus client to rewrite very old history.
|
||||
//
|
||||
// One thing that's probably not needed but which we can add to make this
|
||||
// verification even stricter is to enforce that the chain can switch from
|
||||
// >0 to ==0 TD only once by forbidding an ==0 to be followed by a >0.
|
||||
|
||||
// Verify that we're not reverting to pre-merge from post-merge
|
||||
reached, err := IsTTDReached(chain, header.ParentHash, header.Number.Uint64()-1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !reached {
|
||||
return beacon.ethone.VerifyHeader(chain, header)
|
||||
}
|
||||
// Short circuit if the parent is not known
|
||||
parent := chain.GetHeader(header.ParentHash, header.Number.Uint64()-1)
|
||||
if parent == nil {
|
||||
return consensus.ErrUnknownAncestor
|
||||
}
|
||||
if parent.Difficulty.Sign() == 0 && header.Difficulty.Sign() > 0 {
|
||||
return consensus.ErrInvalidTerminalBlock
|
||||
}
|
||||
// Check >0 TDs with pre-merge, --0 TDs with post-merge rules
|
||||
if header.Difficulty.Sign() > 0 {
|
||||
return beacon.ethone.VerifyHeader(chain, header)
|
||||
}
|
||||
// Sanity checks passed, do a proper verification
|
||||
return beacon.verifyHeader(chain, header, parent)
|
||||
}
|
||||
|
||||
// errOut constructs an error channel with prefilled errors inside.
|
||||
func errOut(n int, err error) chan error {
|
||||
errs := make(chan error, n)
|
||||
for i := 0; i < n; i++ {
|
||||
errs <- err
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
// splitHeaders splits the provided header batch into two parts according to
|
||||
// the difficulty field.
|
||||
//
|
||||
// the configured ttd. It requires the parent of header batch along with its
|
||||
// td are stored correctly in chain. If ttd is not configured yet, all headers
|
||||
// will be treated legacy PoW headers.
|
||||
// Note, this function will not verify the header validity but just split them.
|
||||
func (beacon *Beacon) splitHeaders(headers []*types.Header) ([]*types.Header, []*types.Header) {
|
||||
func (beacon *Beacon) splitHeaders(chain consensus.ChainHeaderReader, headers []*types.Header) ([]*types.Header, []*types.Header, error) {
|
||||
// TTD is not defined yet, all headers should be in legacy format.
|
||||
ttd := chain.Config().TerminalTotalDifficulty
|
||||
ptd := chain.GetTd(headers[0].ParentHash, headers[0].Number.Uint64()-1)
|
||||
if ptd == nil {
|
||||
return nil, nil, consensus.ErrUnknownAncestor
|
||||
}
|
||||
// The entire header batch already crosses the transition.
|
||||
if ptd.Cmp(ttd) >= 0 {
|
||||
return nil, headers, nil
|
||||
}
|
||||
var (
|
||||
preHeaders = headers
|
||||
postHeaders []*types.Header
|
||||
td = new(big.Int).Set(ptd)
|
||||
tdPassed bool
|
||||
)
|
||||
for i, header := range headers {
|
||||
if header.Difficulty.Sign() == 0 {
|
||||
if tdPassed {
|
||||
preHeaders = headers[:i]
|
||||
postHeaders = headers[i:]
|
||||
break
|
||||
}
|
||||
td = td.Add(td, header.Difficulty)
|
||||
if td.Cmp(ttd) >= 0 {
|
||||
// This is the last PoW header, it still belongs to
|
||||
// the preHeaders, so we cannot split+break yet.
|
||||
tdPassed = true
|
||||
}
|
||||
}
|
||||
return preHeaders, postHeaders
|
||||
return preHeaders, postHeaders, nil
|
||||
}
|
||||
|
||||
// VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers
|
||||
|
|
@ -149,7 +161,10 @@ func (beacon *Beacon) splitHeaders(headers []*types.Header) ([]*types.Header, []
|
|||
// a results channel to retrieve the async verifications.
|
||||
// VerifyHeaders expect the headers to be ordered and continuous.
|
||||
func (beacon *Beacon) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header) (chan<- struct{}, <-chan error) {
|
||||
preHeaders, postHeaders := beacon.splitHeaders(headers)
|
||||
preHeaders, postHeaders, err := beacon.splitHeaders(chain, headers)
|
||||
if err != nil {
|
||||
return make(chan struct{}), errOut(len(headers), err)
|
||||
}
|
||||
if len(postHeaders) == 0 {
|
||||
return beacon.ethone.VerifyHeaders(chain, headers)
|
||||
}
|
||||
|
|
@ -329,7 +344,12 @@ func (beacon *Beacon) verifyHeaders(chain consensus.ChainHeaderReader, headers [
|
|||
// Prepare implements consensus.Engine, initializing the difficulty field of a
|
||||
// header to conform to the beacon protocol. The changes are done inline.
|
||||
func (beacon *Beacon) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error {
|
||||
if !isPostMerge(chain.Config(), header.Number.Uint64(), header.Time) {
|
||||
// Transition isn't triggered yet, use the legacy rules for preparation.
|
||||
reached, err := IsTTDReached(chain, header.ParentHash, header.Number.Uint64()-1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !reached {
|
||||
return beacon.ethone.Prepare(chain, header)
|
||||
}
|
||||
header.Difficulty = beaconDifficulty
|
||||
|
|
@ -440,7 +460,8 @@ func (beacon *Beacon) SealHash(header *types.Header) common.Hash {
|
|||
// the difficulty that a new block should have when created at time
|
||||
// given the parent block's time and difficulty.
|
||||
func (beacon *Beacon) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, parent *types.Header) *big.Int {
|
||||
if !isPostMerge(chain.Config(), parent.Number.Uint64()+1, time) {
|
||||
// Transition isn't triggered yet, use the legacy rules for calculation
|
||||
if reached, _ := IsTTDReached(chain, parent.Hash(), parent.Number.Uint64()); !reached {
|
||||
return beacon.ethone.CalcDifficulty(chain, time, parent)
|
||||
}
|
||||
return beaconDifficulty
|
||||
|
|
@ -481,3 +502,14 @@ func (beacon *Beacon) SetThreads(threads int) {
|
|||
th.SetThreads(threads)
|
||||
}
|
||||
}
|
||||
|
||||
// IsTTDReached checks if the TotalTerminalDifficulty has been surpassed on the `parentHash` block.
|
||||
// It depends on the parentHash already being stored in the database.
|
||||
// If the parentHash is not stored in the database a UnknownAncestor error is returned.
|
||||
func IsTTDReached(chain consensus.ChainHeaderReader, parentHash common.Hash, parentNumber uint64) (bool, error) {
|
||||
td := chain.GetTd(parentHash, parentNumber)
|
||||
if td == nil {
|
||||
return false, consensus.ErrUnknownAncestor
|
||||
}
|
||||
return td.Cmp(chain.Config().TerminalTotalDifficulty) >= 0, nil
|
||||
}
|
||||
|
|
|
|||
41
consensus/beacon/faker.go
Normal file
41
consensus/beacon/faker.go
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// Copyright 2023 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package beacon
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
// NewFaker creates a fake consensus engine for testing.
|
||||
// The fake engine simulates a merged network.
|
||||
// It can not be used to test the merge transition.
|
||||
// This type is needed since the fakeChainReader can not be used with
|
||||
// a normal beacon consensus engine.
|
||||
func NewFaker() consensus.Engine {
|
||||
return new(faker)
|
||||
}
|
||||
|
||||
type faker struct {
|
||||
Beacon
|
||||
}
|
||||
|
||||
func (f *faker) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, parent *types.Header) *big.Int {
|
||||
return beaconDifficulty
|
||||
}
|
||||
|
|
@ -45,6 +45,9 @@ type ChainHeaderReader interface {
|
|||
|
||||
// GetHeaderByHash retrieves a block header from the database by its hash.
|
||||
GetHeaderByHash(hash common.Hash) *types.Header
|
||||
|
||||
// GetTd retrieves the total difficulty from the database by hash and number.
|
||||
GetTd(hash common.Hash, number uint64) *big.Int
|
||||
}
|
||||
|
||||
// ChainReader defines a small collection of methods needed to access the local
|
||||
|
|
|
|||
|
|
@ -295,6 +295,7 @@ func makeChainForBench(db ethdb.Database, genesis *Genesis, full bool, count uin
|
|||
|
||||
rawdb.WriteHeader(db, header)
|
||||
rawdb.WriteCanonicalHash(db, hash, n)
|
||||
rawdb.WriteTd(db, hash, n, big.NewInt(int64(n+1)))
|
||||
|
||||
if n == 0 {
|
||||
rawdb.WriteChainConfig(db, hash, genesis.Config)
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ const (
|
|||
//
|
||||
// - Version 9
|
||||
// The following incompatible database changes were added:
|
||||
// * Total difficulty has been removed from both the key-value store and the ancient store.
|
||||
// * (not applicable for bor) Total difficulty has been removed from both the key-value store and the ancient store.
|
||||
// * The metadata structure of freezer is changed by adding 'flushOffset'
|
||||
BlockChainVersion uint64 = 9
|
||||
)
|
||||
|
|
@ -787,18 +787,23 @@ func (bc *BlockChain) loadLastState() error {
|
|||
var (
|
||||
currentSnapBlock = bc.CurrentSnapBlock()
|
||||
currentFinalBlock = bc.CurrentFinalBlock()
|
||||
|
||||
headerTd = bc.GetTd(headHeader.Hash(), headHeader.Number.Uint64())
|
||||
blockTd = bc.GetTd(headBlock.Hash(), headBlock.NumberU64())
|
||||
)
|
||||
|
||||
if headHeader.Hash() != headBlock.Hash() {
|
||||
log.Info("Loaded most recent local header", "number", headHeader.Number, "hash", headHeader.Hash(), "age", common.PrettyAge(time.Unix(int64(headHeader.Time), 0)))
|
||||
log.Info("Loaded most recent local header", "number", headHeader.Number, "hash", headHeader.Hash(), "td", headerTd, "age", common.PrettyAge(time.Unix(int64(headHeader.Time), 0)))
|
||||
}
|
||||
log.Info("Loaded most recent local block", "number", headBlock.Number(), "hash", headBlock.Hash(), "age", common.PrettyAge(time.Unix(int64(headBlock.Time()), 0)))
|
||||
log.Info("Loaded most recent local block", "number", headBlock.Number(), "hash", headBlock.Hash(), "td", blockTd, "age", common.PrettyAge(time.Unix(int64(headBlock.Time()), 0)))
|
||||
if headBlock.Hash() != currentSnapBlock.Hash() {
|
||||
log.Info("Loaded most recent local snap block", "number", currentSnapBlock.Number, "hash", currentSnapBlock.Hash(), "age", common.PrettyAge(time.Unix(int64(currentSnapBlock.Time), 0)))
|
||||
snapTd := bc.GetTd(currentSnapBlock.Hash(), currentSnapBlock.Number.Uint64())
|
||||
log.Info("Loaded most recent local snap block", "number", currentSnapBlock.Number, "hash", currentSnapBlock.Hash(), "td", snapTd, "age", common.PrettyAge(time.Unix(int64(currentSnapBlock.Time), 0)))
|
||||
}
|
||||
|
||||
if currentFinalBlock != nil {
|
||||
log.Info("Loaded most recent local finalized block", "number", currentFinalBlock.Number, "hash", currentFinalBlock.Hash(), "age", common.PrettyAge(time.Unix(int64(currentFinalBlock.Time), 0)))
|
||||
finalTd := bc.GetTd(currentFinalBlock.Hash(), currentFinalBlock.Number.Uint64())
|
||||
log.Info("Loaded most recent local finalized block", "number", currentFinalBlock.Number, "hash", currentFinalBlock.Hash(), "td", finalTd, "age", common.PrettyAge(time.Unix(int64(currentFinalBlock.Time), 0)))
|
||||
}
|
||||
|
||||
if pivot := rawdb.ReadLastPivotNumber(bc.db); pivot != nil {
|
||||
|
|
@ -1248,6 +1253,7 @@ func (bc *BlockChain) ResetWithGenesisBlock(genesis *types.Block) error {
|
|||
|
||||
// Prepare the genesis block and reinitialise the chain
|
||||
batch := bc.db.NewBatch()
|
||||
rawdb.WriteTd(batch, genesis.Hash(), genesis.NumberU64(), genesis.Difficulty())
|
||||
rawdb.WriteBlock(batch, genesis)
|
||||
|
||||
if err := batch.Write(); err != nil {
|
||||
|
|
@ -1550,7 +1556,8 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
|
|||
// Ensure genesis is in ancients.
|
||||
if first.NumberU64() == 1 {
|
||||
if frozen, _ := bc.db.Ancients(); frozen == 0 {
|
||||
writeSize, err := rawdb.WriteAncientBlocks(bc.db, []*types.Block{bc.genesisBlock}, []types.Receipts{nil})
|
||||
td := bc.genesisBlock.Difficulty()
|
||||
writeSize, err := rawdb.WriteAncientBlocks(bc.db, []*types.Block{bc.genesisBlock}, []types.Receipts{nil}, td)
|
||||
if err != nil {
|
||||
log.Error("Error writing genesis to ancients", "err", err)
|
||||
return 0, err
|
||||
|
|
@ -1579,7 +1586,9 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
|
|||
headers = append(headers, block.Header())
|
||||
}
|
||||
|
||||
writeSize, err := rawdb.WriteAncientBlocks(bc.db, blockChain, receiptChain)
|
||||
// Write all chain data to ancients.
|
||||
td := bc.GetTd(first.Hash(), first.NumberU64())
|
||||
writeSize, err := rawdb.WriteAncientBlocks(bc.db, blockChain, receiptChain, td)
|
||||
if err != nil {
|
||||
log.Error("Error importing chain data to ancients", "err", err)
|
||||
return 0, err
|
||||
|
|
@ -1776,11 +1785,12 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
|
|||
// 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) (err error) {
|
||||
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 {
|
||||
|
|
@ -1808,14 +1818,20 @@ func (bc *BlockChain) writeKnownBlock(block *types.Block) error {
|
|||
// writeBlockWithState writes block, metadata and corresponding state data to the
|
||||
// database.
|
||||
func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.Receipt, logs []*types.Log, statedb *state.StateDB) ([]*types.Log, error) {
|
||||
if !bc.HasHeader(block.ParentHash(), block.NumberU64()-1) {
|
||||
// Calculate the total difficulty of the block
|
||||
ptd := bc.GetTd(block.ParentHash(), block.NumberU64()-1)
|
||||
if ptd == nil {
|
||||
return consensus.ErrUnknownAncestor
|
||||
}
|
||||
// Make sure no inconsistent state is leaked during insertion
|
||||
externTd := new(big.Int).Add(block.Difficulty(), ptd)
|
||||
|
||||
// Irrelevant of the canonical status, write the block itself to the database.
|
||||
//
|
||||
// Note all the components of block(hash->number map, header, body, receipts)
|
||||
// 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()
|
||||
rawdb.WriteTd(blockBatch, block.Hash(), block.NumberU64(), externTd)
|
||||
rawdb.WriteBlock(blockBatch, block)
|
||||
rawdb.WriteReceipts(blockBatch, block.Hash(), block.NumberU64(), receipts)
|
||||
|
||||
|
|
@ -2312,6 +2328,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness
|
|||
if bc.logger != nil && bc.logger.OnSkippedBlock != nil {
|
||||
bc.logger.OnSkippedBlock(tracing.BlockEvent{
|
||||
Block: block,
|
||||
TD: bc.GetTd(block.ParentHash(), block.NumberU64()-1),
|
||||
Finalized: bc.CurrentFinalBlock(),
|
||||
Safe: bc.CurrentSafeBlock(),
|
||||
})
|
||||
|
|
@ -2547,8 +2564,10 @@ type blockProcessingResult struct {
|
|||
// nolint : unused
|
||||
func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, start time.Time, setHead bool) (_ *blockProcessingResult, blockEndErr error) {
|
||||
if bc.logger != nil && bc.logger.OnBlockStart != nil {
|
||||
td := bc.GetTd(block.ParentHash(), block.NumberU64()-1)
|
||||
bc.logger.OnBlockStart(tracing.BlockEvent{
|
||||
Block: block,
|
||||
TD: td,
|
||||
Finalized: bc.CurrentFinalBlock(),
|
||||
Safe: bc.CurrentSafeBlock(),
|
||||
})
|
||||
|
|
@ -2662,6 +2681,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator, ma
|
|||
lastBlock = block
|
||||
current = bc.CurrentBlock()
|
||||
headers []*types.Header
|
||||
externTd *big.Int
|
||||
)
|
||||
|
||||
// The first sidechain block error is already verified to be ErrPrunedAncestor.
|
||||
|
|
@ -2676,6 +2696,11 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator, ma
|
|||
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
|
||||
}
|
||||
|
||||
|
|
@ -2695,9 +2720,14 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator, ma
|
|||
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); err != nil {
|
||||
if err := bc.writeBlockWithoutState(block, externTd); err != nil {
|
||||
return nil, it.index, err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package core
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
|
|
@ -341,6 +342,12 @@ func (bc *BlockChain) GetTransactionLookup(hash common.Hash) (*rawdb.LegacyTxLoo
|
|||
return lookup, tx, nil
|
||||
}
|
||||
|
||||
// GetTd retrieves a block's total difficulty in the canonical chain from the
|
||||
// database by hash and number, caching it if found.
|
||||
func (bc *BlockChain) GetTd(hash common.Hash, number uint64) *big.Int {
|
||||
return bc.hc.GetTd(hash, number)
|
||||
}
|
||||
|
||||
// HasState checks if state trie is fully present in the database or not.
|
||||
func (bc *BlockChain) HasState(hash common.Hash) bool {
|
||||
_, err := bc.statedb.OpenTrie(hash)
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ func newGwei(n int64) *big.Int {
|
|||
}
|
||||
|
||||
// Test fork of length N starting from block i
|
||||
func testFork(t *testing.T, blockchain *BlockChain, i, n int, full bool, scheme string) {
|
||||
func testFork(t *testing.T, blockchain *BlockChain, i, n int, full bool, comparator func(td1, td2 *big.Int), scheme string) {
|
||||
// Copy old chain up to #i into a new db
|
||||
genDb, _, blockchain2, err := newCanonical(ethash.NewFaker(), i, full, scheme)
|
||||
if err != nil {
|
||||
|
|
@ -130,15 +130,27 @@ func testFork(t *testing.T, blockchain *BlockChain, i, n int, full bool, scheme
|
|||
}
|
||||
}
|
||||
// Sanity check that the forked chain can be imported into the original
|
||||
var tdPre, tdPost *big.Int
|
||||
|
||||
if full {
|
||||
cur := blockchain.CurrentBlock()
|
||||
tdPre = blockchain.GetTd(cur.Hash(), cur.Number.Uint64())
|
||||
if err := testBlockChainImport(blockChainB, blockchain); err != nil {
|
||||
t.Fatalf("failed to import forked block chain: %v", err)
|
||||
}
|
||||
last := blockChainB[len(blockChainB)-1]
|
||||
tdPost = blockchain.GetTd(last.Hash(), last.NumberU64())
|
||||
} else {
|
||||
cur := blockchain.CurrentHeader()
|
||||
tdPre = blockchain.GetTd(cur.Hash(), cur.Number.Uint64())
|
||||
if err := testHeaderChainImport(headerChainB, blockchain); err != nil {
|
||||
t.Fatalf("failed to import forked header chain: %v", err)
|
||||
}
|
||||
last := headerChainB[len(headerChainB)-1]
|
||||
tdPost = blockchain.GetTd(last.Hash(), last.Number.Uint64())
|
||||
}
|
||||
// Compare the total difficulties of the chains
|
||||
comparator(tdPre, tdPost)
|
||||
}
|
||||
|
||||
// testBlockChainImport tries to process a chain of blocks, writing them into
|
||||
|
|
@ -179,6 +191,7 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
|
|||
}
|
||||
|
||||
blockchain.chainmu.MustLock()
|
||||
rawdb.WriteTd(blockchain.db, block.Hash(), block.NumberU64(), new(big.Int).Add(block.Difficulty(), blockchain.GetTd(block.ParentHash(), block.NumberU64()-1)))
|
||||
rawdb.WriteBlock(blockchain.db, block)
|
||||
statedb.Commit(block.NumberU64(), false, false)
|
||||
blockchain.chainmu.Unlock()
|
||||
|
|
@ -296,6 +309,7 @@ func testHeaderChainImport(chain []*types.Header, blockchain *BlockChain) error
|
|||
}
|
||||
// Manually insert the header into the database, but don't reorganise (allows subsequent testing)
|
||||
blockchain.chainmu.MustLock()
|
||||
rawdb.WriteTd(blockchain.db, header.Hash(), header.Number.Uint64(), new(big.Int).Add(header.Difficulty, blockchain.GetTd(header.ParentHash, header.Number.Uint64()-1)))
|
||||
rawdb.WriteHeader(blockchain.db, header)
|
||||
blockchain.chainmu.Unlock()
|
||||
}
|
||||
|
|
@ -399,11 +413,17 @@ func testExtendCanonical(t *testing.T, full bool, scheme string) {
|
|||
}
|
||||
defer processor.Stop()
|
||||
|
||||
// Define the difficulty comparator
|
||||
better := func(td1, td2 *big.Int) {
|
||||
if td2.Cmp(td1) <= 0 {
|
||||
t.Errorf("total difficulty mismatch: have %v, expected more than %v", td2, td1)
|
||||
}
|
||||
}
|
||||
// Start fork from current height
|
||||
testFork(t, processor, length, 1, full, scheme)
|
||||
testFork(t, processor, length, 2, full, scheme)
|
||||
testFork(t, processor, length, 5, full, scheme)
|
||||
testFork(t, processor, length, 10, full, scheme)
|
||||
testFork(t, processor, length, 1, full, better, scheme)
|
||||
testFork(t, processor, length, 2, full, better, scheme)
|
||||
testFork(t, processor, length, 5, full, better, scheme)
|
||||
testFork(t, processor, length, 10, full, better, scheme)
|
||||
}
|
||||
|
||||
// Tests that given a starting canonical chain of a given size, it can be extended
|
||||
|
|
@ -452,13 +472,19 @@ func testShorterFork(t *testing.T, full bool, scheme string) {
|
|||
}
|
||||
defer processor.Stop()
|
||||
|
||||
// Define the difficulty comparator
|
||||
worse := func(td1, td2 *big.Int) {
|
||||
if td2.Cmp(td1) >= 0 {
|
||||
t.Errorf("total difficulty mismatch: have %v, expected less than %v", td2, td1)
|
||||
}
|
||||
}
|
||||
// Sum of numbers must be less than `length` for this to be a shorter fork
|
||||
testFork(t, processor, 0, 3, full, scheme)
|
||||
testFork(t, processor, 0, 7, full, scheme)
|
||||
testFork(t, processor, 1, 1, full, scheme)
|
||||
testFork(t, processor, 1, 7, full, scheme)
|
||||
testFork(t, processor, 5, 3, full, scheme)
|
||||
testFork(t, processor, 5, 4, full, scheme)
|
||||
testFork(t, processor, 0, 3, full, worse, scheme)
|
||||
testFork(t, processor, 0, 7, full, worse, scheme)
|
||||
testFork(t, processor, 1, 1, full, worse, scheme)
|
||||
testFork(t, processor, 1, 7, full, worse, scheme)
|
||||
testFork(t, processor, 5, 3, full, worse, scheme)
|
||||
testFork(t, processor, 5, 4, full, worse, scheme)
|
||||
}
|
||||
|
||||
// Tests that given a starting canonical chain of a given size, creating shorter
|
||||
|
|
@ -569,13 +595,19 @@ func testEqualFork(t *testing.T, full bool, scheme string) {
|
|||
}
|
||||
defer processor.Stop()
|
||||
|
||||
// Define the difficulty comparator
|
||||
equal := func(td1, td2 *big.Int) {
|
||||
if td2.Cmp(td1) != 0 {
|
||||
t.Errorf("total difficulty mismatch: have %v, want %v", td2, td1)
|
||||
}
|
||||
}
|
||||
// Sum of numbers must be equal to `length` for this to be an equal fork
|
||||
testFork(t, processor, 0, 10, full, scheme)
|
||||
testFork(t, processor, 1, 9, full, scheme)
|
||||
testFork(t, processor, 2, 8, full, scheme)
|
||||
testFork(t, processor, 5, 5, full, scheme)
|
||||
testFork(t, processor, 6, 4, full, scheme)
|
||||
testFork(t, processor, 9, 1, full, scheme)
|
||||
testFork(t, processor, 0, 10, full, equal, scheme)
|
||||
testFork(t, processor, 1, 9, full, equal, scheme)
|
||||
testFork(t, processor, 2, 8, full, equal, scheme)
|
||||
testFork(t, processor, 5, 5, full, equal, scheme)
|
||||
testFork(t, processor, 6, 4, full, equal, scheme)
|
||||
testFork(t, processor, 9, 1, full, equal, scheme)
|
||||
}
|
||||
|
||||
// Tests that given a starting canonical chain of a given size, creating equal
|
||||
|
|
@ -738,6 +770,19 @@ func testReorg(t *testing.T, first, second []int64, td int64, full bool, scheme
|
|||
}
|
||||
}
|
||||
}
|
||||
// Make sure the chain total difficulty is the correct one
|
||||
want := new(big.Int).Add(blockchain.genesisBlock.Difficulty(), big.NewInt(td))
|
||||
if full {
|
||||
cur := blockchain.CurrentBlock()
|
||||
if have := blockchain.GetTd(cur.Hash(), cur.Number.Uint64()); have.Cmp(want) != 0 {
|
||||
t.Errorf("total difficulty mismatch: have %v, want %v", have, want)
|
||||
}
|
||||
} else {
|
||||
cur := blockchain.CurrentHeader()
|
||||
if have := blockchain.GetTd(cur.Hash(), cur.Number.Uint64()); have.Cmp(want) != 0 {
|
||||
t.Errorf("total difficulty mismatch: have %v, want %v", have, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tests chain insertions in the face of one entity containing an invalid nonce.
|
||||
|
|
@ -893,6 +938,12 @@ func testFastVsFullChains(t *testing.T, scheme string) {
|
|||
for i := 0; i < len(blocks); i++ {
|
||||
num, hash, time := blocks[i].NumberU64(), blocks[i].Hash(), blocks[i].Time()
|
||||
|
||||
if ftd, atd := fast.GetTd(hash, num), archive.GetTd(hash, num); ftd.Cmp(atd) != 0 {
|
||||
t.Errorf("block #%d [%x]: td mismatch: fastdb %v, archivedb %v", num, hash, ftd, atd)
|
||||
}
|
||||
if antd, artd := ancient.GetTd(hash, num), archive.GetTd(hash, num); antd.Cmp(artd) != 0 {
|
||||
t.Errorf("block #%d [%x]: td mismatch: ancientdb %v, archivedb %v", num, hash, antd, artd)
|
||||
}
|
||||
if fheader, aheader := fast.GetHeaderByHash(hash), archive.GetHeaderByHash(hash); fheader.Hash() != aheader.Hash() {
|
||||
t.Errorf("block #%d [%x]: header mismatch: fastdb %v, archivedb %v", num, hash, fheader, aheader)
|
||||
}
|
||||
|
|
@ -4465,7 +4516,7 @@ func TestEIP3651(t *testing.T) {
|
|||
var (
|
||||
aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa")
|
||||
bb = common.HexToAddress("0x000000000000000000000000000000000000bbbb")
|
||||
engine = beacon.New(ethash.NewFaker())
|
||||
engine = beacon.NewFaker()
|
||||
|
||||
// A sender who makes transactions, has some funds
|
||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
|
|
@ -4585,7 +4636,7 @@ func TestPragueRequests(t *testing.T) {
|
|||
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||
config = *params.MergedTestChainConfig
|
||||
signer = types.LatestSigner(&config)
|
||||
engine = beacon.New(ethash.NewFaker())
|
||||
engine = beacon.NewFaker()
|
||||
)
|
||||
gspec := &Genesis{
|
||||
Config: &config,
|
||||
|
|
@ -4663,7 +4714,7 @@ func TestEIP7702(t *testing.T) {
|
|||
var (
|
||||
config = *params.MergedTestChainConfig
|
||||
signer = types.LatestSigner(&config)
|
||||
engine = beacon.New(ethash.NewFaker())
|
||||
engine = beacon.NewFaker()
|
||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
|
||||
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||
|
|
|
|||
|
|
@ -764,3 +764,7 @@ func (cm *chainMaker) GetHeader(hash common.Hash, number uint64) *types.Header {
|
|||
func (cm *chainMaker) GetBlock(hash common.Hash, number uint64) *types.Block {
|
||||
return cm.blockByNumber(number)
|
||||
}
|
||||
|
||||
func (cm *chainMaker) GetTd(hash common.Hash, number uint64) *big.Int {
|
||||
return nil // not supported
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,9 +76,8 @@ func TestGeneratePOSChain(t *testing.T) {
|
|||
Code: common.Hex2Bytes("600154600354"),
|
||||
}
|
||||
genesis := gspec.MustCommit(gendb, triedb.NewDatabase(gendb, triedb.HashDefaults))
|
||||
engine := beacon.New(ethash.NewFaker())
|
||||
|
||||
genchain, genreceipts := GenerateChain(gspec.Config, genesis, engine, gendb, 4, func(i int, gen *BlockGen) {
|
||||
genchain, genreceipts := GenerateChain(gspec.Config, genesis, beacon.NewFaker(), gendb, 4, func(i int, gen *BlockGen) {
|
||||
gen.SetParentBeaconRoot(common.Hash{byte(i + 1)})
|
||||
|
||||
// Add value transfer tx.
|
||||
|
|
@ -121,7 +120,7 @@ func TestGeneratePOSChain(t *testing.T) {
|
|||
})
|
||||
|
||||
// Import the chain. This runs all block validation rules.
|
||||
blockchain, _ := NewBlockChain(db, nil, gspec, nil, engine, vm.Config{}, nil, nil, nil)
|
||||
blockchain, _ := NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
|
||||
defer blockchain.Stop()
|
||||
|
||||
if i, err := blockchain.InsertChain(genchain); err != nil {
|
||||
|
|
|
|||
|
|
@ -576,6 +576,7 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Blo
|
|||
}
|
||||
batch := db.NewBatch()
|
||||
rawdb.WriteGenesisStateSpec(batch, block.Hash(), blob)
|
||||
rawdb.WriteTd(batch, block.Hash(), block.NumberU64(), block.Difficulty())
|
||||
rawdb.WriteBlock(batch, block)
|
||||
rawdb.WriteReceipts(batch, block.Hash(), block.NumberU64(), nil)
|
||||
rawdb.WriteCanonicalHash(batch, block.Hash(), block.NumberU64())
|
||||
|
|
|
|||
|
|
@ -203,7 +203,7 @@ func TestGenesisHashes(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestGenesisCommit(t *testing.T) {
|
||||
func TestGenesis_Commit(t *testing.T) {
|
||||
genesis := &Genesis{
|
||||
BaseFee: big.NewInt(params.InitialBaseFee),
|
||||
Config: params.TestChainConfig,
|
||||
|
|
@ -221,6 +221,13 @@ func TestGenesisCommit(t *testing.T) {
|
|||
if genesisBlock.Difficulty().Cmp(params.GenesisDifficulty) != 0 {
|
||||
t.Errorf("assumption wrong: want: %d, got: %v", params.GenesisDifficulty, genesisBlock.Difficulty())
|
||||
}
|
||||
|
||||
// Expect the stored total difficulty to be the difficulty of the genesis block.
|
||||
stored := rawdb.ReadTd(db, genesisBlock.Hash(), genesisBlock.NumberU64())
|
||||
|
||||
if stored.Cmp(genesisBlock.Difficulty()) != 0 {
|
||||
t.Errorf("inequal difficulty; stored: %v, genesisBlock: %v", stored, genesisBlock.Difficulty())
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadWriteGenesisAlloc(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ package core
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
|
|
@ -35,6 +36,7 @@ import (
|
|||
|
||||
const (
|
||||
headerCacheLimit = 512
|
||||
tdCacheLimit = 1024
|
||||
numberCacheLimit = 2048
|
||||
)
|
||||
|
||||
|
|
@ -63,7 +65,8 @@ type HeaderChain struct {
|
|||
currentHeaderHash common.Hash // Hash of the current head of the header chain (prevent recomputing all the time)
|
||||
|
||||
headerCache *lru.Cache[common.Hash, *types.Header]
|
||||
numberCache *lru.Cache[common.Hash, uint64] // most recent block numbers
|
||||
tdCache *lru.Cache[common.Hash, *big.Int] // most recent total difficulties
|
||||
numberCache *lru.Cache[common.Hash, uint64] // most recent block numbers
|
||||
|
||||
procInterrupt func() bool
|
||||
engine consensus.Engine
|
||||
|
|
@ -76,6 +79,7 @@ func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, engine c
|
|||
config: config,
|
||||
chainDb: chainDb,
|
||||
headerCache: lru.NewCache[common.Hash, *types.Header](headerCacheLimit),
|
||||
tdCache: lru.NewCache[common.Hash, *big.Int](tdCacheLimit),
|
||||
numberCache: lru.NewCache[common.Hash, uint64](numberCacheLimit),
|
||||
procInterrupt: procInterrupt,
|
||||
engine: engine,
|
||||
|
|
@ -210,13 +214,15 @@ func (hc *HeaderChain) WriteHeaders(headers []*types.Header) (int, error) {
|
|||
if len(headers) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
if !hc.HasHeader(headers[0].ParentHash, headers[0].Number.Uint64()-1) {
|
||||
ptd := hc.GetTd(headers[0].ParentHash, headers[0].Number.Uint64()-1)
|
||||
if ptd == nil {
|
||||
return 0, consensus.ErrUnknownAncestor
|
||||
}
|
||||
|
||||
var (
|
||||
inserted []rawdb.NumberHash // Ephemeral lookup of number/hash for the chain
|
||||
parentKnown = true // Set to true to force hc.HasHeader check the first iteration
|
||||
newTD = new(big.Int).Set(ptd) // Total difficulty of inserted chain
|
||||
inserted []rawdb.NumberHash // Ephemeral lookup of number/hash for the chain
|
||||
parentKnown = true // Set to true to force hc.HasHeader check the first iteration
|
||||
batch = hc.chainDb.NewBatch()
|
||||
)
|
||||
|
||||
|
|
@ -232,11 +238,16 @@ func (hc *HeaderChain) WriteHeaders(headers []*types.Header) (int, error) {
|
|||
}
|
||||
|
||||
number := header.Number.Uint64()
|
||||
newTD.Add(newTD, header.Difficulty)
|
||||
|
||||
// If the parent was not present, store it
|
||||
// If the header is already known, skip it, otherwise store
|
||||
alreadyKnown := parentKnown && hc.HasHeader(hash, number)
|
||||
if !alreadyKnown {
|
||||
// Irrelevant of the canonical status, write the TD and header to the database.
|
||||
rawdb.WriteTd(batch, hash, number, newTD)
|
||||
hc.tdCache.Add(hash, new(big.Int).Set(newTD))
|
||||
|
||||
rawdb.WriteHeader(batch, header)
|
||||
|
||||
inserted = append(inserted, rawdb.NumberHash{Number: number, Hash: hash})
|
||||
|
|
@ -442,6 +453,22 @@ func (hc *HeaderChain) GetAncestor(hash common.Hash, number, ancestor uint64, ma
|
|||
return hash, number
|
||||
}
|
||||
|
||||
// GetTd retrieves a block's total difficulty in the canonical chain from the
|
||||
// database by hash and number, caching it if found.
|
||||
func (hc *HeaderChain) GetTd(hash common.Hash, number uint64) *big.Int {
|
||||
// Short circuit if the td's already in the cache, retrieve otherwise
|
||||
if cached, ok := hc.tdCache.Get(hash); ok {
|
||||
return cached
|
||||
}
|
||||
td := rawdb.ReadTd(hc.chainDb, hash, number)
|
||||
if td == nil {
|
||||
return nil
|
||||
}
|
||||
// Cache the found body for next time and return
|
||||
hc.tdCache.Add(hash, td)
|
||||
return td
|
||||
}
|
||||
|
||||
// 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 {
|
||||
|
|
@ -677,6 +704,7 @@ func (hc *HeaderChain) setHead(headBlock uint64, headTime uint64, updateFn Updat
|
|||
}
|
||||
|
||||
rawdb.DeleteHeader(batch, hash, num)
|
||||
rawdb.DeleteTd(batch, hash, num)
|
||||
}
|
||||
|
||||
rawdb.DeleteCanonicalHash(batch, num)
|
||||
|
|
@ -688,6 +716,7 @@ func (hc *HeaderChain) setHead(headBlock uint64, headTime uint64, updateFn Updat
|
|||
}
|
||||
// Clear out any stale content from the caches
|
||||
hc.headerCache.Purge()
|
||||
hc.tdCache.Purge()
|
||||
hc.numberCache.Purge()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,10 @@ func verifyUnbrokenCanonchain(hc *HeaderChain) error {
|
|||
return fmt.Errorf("Canon hash chain broken, block %d got %x, expected %x",
|
||||
h.Number, canonHash[:8], exp[:8])
|
||||
}
|
||||
// Verify that we have the TD
|
||||
if td := rawdb.ReadTd(hc.chainDb, canonHash, h.Number.Uint64()); td == nil {
|
||||
return fmt.Errorf("Canon TD missing at block %d", h.Number)
|
||||
}
|
||||
if h.Number.Uint64() == 0 {
|
||||
break
|
||||
}
|
||||
|
|
|
|||
|
|
@ -601,6 +601,54 @@ func DeleteBody(db ethdb.KeyValueWriter, hash common.Hash, number uint64) {
|
|||
}
|
||||
}
|
||||
|
||||
// ReadTdRLP retrieves a block's total difficulty corresponding to the hash in RLP encoding.
|
||||
func ReadTdRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue {
|
||||
var data []byte
|
||||
db.ReadAncients(func(reader ethdb.AncientReaderOp) error {
|
||||
// Check if the data is in ancients
|
||||
if isCanon(reader, number, hash) {
|
||||
data, _ = reader.Ancient(ChainFreezerDifficultyTable, number)
|
||||
return nil
|
||||
}
|
||||
// If not, try reading from leveldb
|
||||
data, _ = db.Get(headerTDKey(number, hash))
|
||||
return nil
|
||||
})
|
||||
return data
|
||||
}
|
||||
|
||||
// ReadTd retrieves a block's total difficulty corresponding to the hash.
|
||||
func ReadTd(db ethdb.Reader, hash common.Hash, number uint64) *big.Int {
|
||||
data := ReadTdRLP(db, hash, number)
|
||||
if len(data) == 0 {
|
||||
return nil
|
||||
}
|
||||
td := new(big.Int)
|
||||
if err := rlp.DecodeBytes(data, td); err != nil {
|
||||
log.Error("Invalid block total difficulty RLP", "hash", hash, "err", err)
|
||||
return nil
|
||||
}
|
||||
return td
|
||||
}
|
||||
|
||||
// WriteTd stores the total difficulty of a block into the database.
|
||||
func WriteTd(db ethdb.KeyValueWriter, hash common.Hash, number uint64, td *big.Int) {
|
||||
data, err := rlp.EncodeToBytes(td)
|
||||
if err != nil {
|
||||
log.Crit("Failed to RLP encode block total difficulty", "err", err)
|
||||
}
|
||||
if err := db.Put(headerTDKey(number, hash), data); err != nil {
|
||||
log.Crit("Failed to store block total difficulty", "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteTd removes all block total difficulty data associated with a hash.
|
||||
func DeleteTd(db ethdb.KeyValueWriter, hash common.Hash, number uint64) {
|
||||
if err := db.Delete(headerTDKey(number, hash)); err != nil {
|
||||
log.Crit("Failed to delete block total difficulty", "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
// HasReceipts verifies the existence of all the transaction receipts belonging
|
||||
// to a block.
|
||||
func HasReceipts(db ethdb.Reader, hash common.Hash, number uint64) bool {
|
||||
|
|
@ -801,8 +849,9 @@ func WriteBlock(db ethdb.KeyValueWriter, block *types.Block) {
|
|||
}
|
||||
|
||||
// WriteAncientBlocks writes entire block data into ancient store and returns the total written size.
|
||||
func WriteAncientBlocks(db ethdb.AncientWriter, blocks []*types.Block, receipts []types.Receipts, borReceipts []types.Receipts) (int64, error) {
|
||||
func WriteAncientBlocks(db ethdb.AncientWriter, blocks []*types.Block, receipts []types.Receipts, borReceipts []types.Receipts, td *big.Int) (int64, error) {
|
||||
var (
|
||||
tdSum = new(big.Int).Set(td)
|
||||
stReceipts []*types.ReceiptForStorage
|
||||
borStReceipts []*types.ReceiptForStorage
|
||||
)
|
||||
|
|
@ -823,7 +872,10 @@ func WriteAncientBlocks(db ethdb.AncientWriter, blocks []*types.Block, receipts
|
|||
|
||||
header := block.Header()
|
||||
|
||||
if err := writeAncientBlock(op, block, header, stReceipts, borStReceipts); err != nil {
|
||||
if i > 0 {
|
||||
tdSum.Add(tdSum, header.Difficulty)
|
||||
}
|
||||
if err := writeAncientBlock(op, block, header, stReceipts, borStReceipts, tdSum); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
@ -832,7 +884,7 @@ func WriteAncientBlocks(db ethdb.AncientWriter, blocks []*types.Block, receipts
|
|||
})
|
||||
}
|
||||
|
||||
func writeAncientBlock(op ethdb.AncientWriteOp, block *types.Block, header *types.Header, receipts []*types.ReceiptForStorage, borReceipts []*types.ReceiptForStorage) error {
|
||||
func writeAncientBlock(op ethdb.AncientWriteOp, block *types.Block, header *types.Header, receipts []*types.ReceiptForStorage, borReceipts []*types.ReceiptForStorage, td *big.Int) error {
|
||||
num := block.NumberU64()
|
||||
if err := op.AppendRaw(ChainFreezerHashTable, num, block.Hash().Bytes()); err != nil {
|
||||
return fmt.Errorf("can't add block %d hash: %v", num, err)
|
||||
|
|
@ -854,6 +906,9 @@ func writeAncientBlock(op ethdb.AncientWriteOp, block *types.Block, header *type
|
|||
return fmt.Errorf("can't append block %d borReceipts: %v", num, err)
|
||||
}
|
||||
|
||||
if err := op.Append(ChainFreezerDifficultyTable, num, td); err != nil {
|
||||
return fmt.Errorf("can't append block %d total difficulty: %v", num, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -862,6 +917,7 @@ func DeleteBlock(db ethdb.KeyValueWriter, hash common.Hash, number uint64) {
|
|||
DeleteReceipts(db, hash, number)
|
||||
DeleteHeader(db, hash, number)
|
||||
DeleteBody(db, hash, number)
|
||||
DeleteTd(db, hash, number)
|
||||
|
||||
// delete bor receipt
|
||||
DeleteBorReceipt(db, hash, number)
|
||||
|
|
@ -873,6 +929,7 @@ func DeleteBlockWithoutNumber(db ethdb.KeyValueWriter, hash common.Hash, number
|
|||
DeleteReceipts(db, hash, number)
|
||||
deleteHeaderWithoutNumber(db, hash, number)
|
||||
DeleteBody(db, hash, number)
|
||||
DeleteTd(db, hash, number)
|
||||
|
||||
// delete bor receipt
|
||||
DeleteBorReceipt(db, hash, number)
|
||||
|
|
|
|||
|
|
@ -281,6 +281,29 @@ func TestBadBlockStorage(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// Tests block total difficulty storage and retrieval operations.
|
||||
func TestTdStorage(t *testing.T) {
|
||||
db := NewMemoryDatabase()
|
||||
|
||||
// Create a test TD to move around the database and make sure it's really new
|
||||
hash, td := common.Hash{}, big.NewInt(314)
|
||||
if entry := ReadTd(db, hash, 0); entry != nil {
|
||||
t.Fatalf("Non existent TD returned: %v", entry)
|
||||
}
|
||||
// Write and verify the TD in the database
|
||||
WriteTd(db, hash, 0, td)
|
||||
if entry := ReadTd(db, hash, 0); entry == nil {
|
||||
t.Fatalf("Stored TD not found")
|
||||
} else if entry.Cmp(td) != 0 {
|
||||
t.Fatalf("Retrieved TD mismatch: have %v, want %v", entry, td)
|
||||
}
|
||||
// Delete the TD and verify the execution
|
||||
DeleteTd(db, hash, 0)
|
||||
if entry := ReadTd(db, hash, 0); entry != nil {
|
||||
t.Fatalf("Deleted TD returned: %v", entry)
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that canonical numbers can be mapped to hashes and retrieved.
|
||||
func TestCanonicalMappingStorage(t *testing.T) {
|
||||
db := NewMemoryDatabase()
|
||||
|
|
@ -472,9 +495,12 @@ func TestAncientStorage(t *testing.T) {
|
|||
if blob := ReadReceiptsRLP(db, hash, number); len(blob) > 0 {
|
||||
t.Fatalf("non existent receipts returned")
|
||||
}
|
||||
if blob := ReadTdRLP(db, hash, number); len(blob) > 0 {
|
||||
t.Fatalf("non existent td returned")
|
||||
}
|
||||
|
||||
// Write and verify the header in the database
|
||||
WriteAncientBlocks(db, []*types.Block{block}, []types.Receipts{nil}, []types.Receipts{nil})
|
||||
WriteAncientBlocks(db, []*types.Block{block}, []types.Receipts{nil}, []types.Receipts{nil}, big.NewInt(100))
|
||||
|
||||
if blob := ReadHeaderRLP(db, hash, number); len(blob) == 0 {
|
||||
t.Fatalf("no header returned")
|
||||
|
|
@ -487,6 +513,9 @@ func TestAncientStorage(t *testing.T) {
|
|||
if blob := ReadReceiptsRLP(db, hash, number); len(blob) == 0 {
|
||||
t.Fatalf("no receipts returned")
|
||||
}
|
||||
if blob := ReadTdRLP(db, hash, number); len(blob) == 0 {
|
||||
t.Fatalf("no td returned")
|
||||
}
|
||||
|
||||
// Use a fake hash for data retrieval, nothing should be returned.
|
||||
fakeHash := common.BytesToHash([]byte{0x01, 0x02, 0x03})
|
||||
|
|
@ -501,6 +530,9 @@ func TestAncientStorage(t *testing.T) {
|
|||
if blob := ReadReceiptsRLP(db, fakeHash, number); len(blob) != 0 {
|
||||
t.Fatalf("invalid receipts returned")
|
||||
}
|
||||
if blob := ReadTdRLP(db, fakeHash, number); len(blob) != 0 {
|
||||
t.Fatalf("invalid td returned")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCanonicalHashIteration(t *testing.T) {
|
||||
|
|
@ -526,6 +558,7 @@ func TestCanonicalHashIteration(t *testing.T) {
|
|||
// Fill database with testing data.
|
||||
for i := uint64(1); i <= 8; i++ {
|
||||
WriteCanonicalHash(db, common.Hash{}, i)
|
||||
WriteTd(db, common.Hash{}, i, big.NewInt(10)) // Write some interferential data
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
|
|
@ -613,6 +646,7 @@ func BenchmarkWriteAncientBlocks(b *testing.B) {
|
|||
// The benchmark loop writes batches of blocks, but note that the total block count is
|
||||
// b.N. This means the resulting ns/op measurement is the time it takes to write a
|
||||
// single block and its associated data.
|
||||
var td = big.NewInt(55)
|
||||
var totalSize int64
|
||||
|
||||
for i := 0; i < b.N; i += batchSize {
|
||||
|
|
@ -624,7 +658,7 @@ func BenchmarkWriteAncientBlocks(b *testing.B) {
|
|||
blocks := allBlocks[i : i+length]
|
||||
receipts := batchReceipts[:length]
|
||||
|
||||
writeSize, err := WriteAncientBlocks(db, blocks, receipts, []types.Receipts{nil})
|
||||
writeSize, err := WriteAncientBlocks(db, blocks, receipts, []types.Receipts{nil}, td)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
|
@ -950,7 +984,7 @@ func TestHeadersRLPStorage(t *testing.T) {
|
|||
var borReceipts []types.Receipts = make([]types.Receipts, 100)
|
||||
|
||||
// Write first half to ancients
|
||||
WriteAncientBlocks(db, chain[:50], receipts[:50], borReceipts[:50])
|
||||
WriteAncientBlocks(db, chain[:50], receipts[:50], borReceipts[:50], big.NewInt(100))
|
||||
// Write second half to db
|
||||
for i := 50; i < 100; i++ {
|
||||
WriteCanonicalHash(db, chain[i].Hash(), chain[i].NumberU64())
|
||||
|
|
|
|||
|
|
@ -35,6 +35,9 @@ const (
|
|||
|
||||
// ChainFreezerReceiptTable indicates the name of the freezer receipts table.
|
||||
ChainFreezerReceiptTable = "receipts"
|
||||
|
||||
// ChainFreezerDifficultyTable indicates the name of the freezer total difficulty table.
|
||||
ChainFreezerDifficultyTable = "diffs"
|
||||
)
|
||||
|
||||
// chainFreezerTableConfigs configures the settings for tables in the chain freezer.
|
||||
|
|
@ -42,11 +45,12 @@ const (
|
|||
// tail truncation is disabled for the header and hash tables, as these are intended
|
||||
// to be retained long-term.
|
||||
var chainFreezerTableConfigs = map[string]freezerTableConfig{
|
||||
ChainFreezerHeaderTable: {noSnappy: false, prunable: false},
|
||||
ChainFreezerHashTable: {noSnappy: true, prunable: false},
|
||||
ChainFreezerBodiesTable: {noSnappy: false, prunable: true},
|
||||
ChainFreezerReceiptTable: {noSnappy: false, prunable: true},
|
||||
freezerBorReceiptTable: {noSnappy: false, prunable: true},
|
||||
ChainFreezerHeaderTable: {noSnappy: false, prunable: false},
|
||||
ChainFreezerHashTable: {noSnappy: true, prunable: false},
|
||||
ChainFreezerBodiesTable: {noSnappy: false, prunable: true},
|
||||
ChainFreezerReceiptTable: {noSnappy: false, prunable: true},
|
||||
ChainFreezerDifficultyTable: {noSnappy: false, prunable: true},
|
||||
freezerBorReceiptTable: {noSnappy: false, prunable: true},
|
||||
}
|
||||
|
||||
// freezerTableConfig contains the settings for a freezer table.
|
||||
|
|
|
|||
|
|
@ -348,6 +348,11 @@ func (f *chainFreezer) freezeRange(nfdb *nofreezedb, number, limit uint64) (hash
|
|||
if len(receipts) == 0 {
|
||||
return fmt.Errorf("block receipts missing, can't freeze block %d", number)
|
||||
}
|
||||
td := ReadTdRLP(nfdb, hash, number)
|
||||
if len(td) == 0 {
|
||||
return fmt.Errorf("total difficulty missing, can't freeze block %d", number)
|
||||
}
|
||||
|
||||
// Write to the batch.
|
||||
if err := op.AppendRaw(ChainFreezerHashTable, number, hash[:]); err != nil {
|
||||
return fmt.Errorf("can't write hash to Freezer: %v", err)
|
||||
|
|
@ -371,6 +376,9 @@ func (f *chainFreezer) freezeRange(nfdb *nofreezedb, number, limit uint64) (hash
|
|||
return fmt.Errorf("can't write bor-receipt to freezer: %v", err)
|
||||
}
|
||||
|
||||
if err := op.AppendRaw(ChainFreezerDifficultyTable, number, td); err != nil {
|
||||
return fmt.Errorf("can't write td to Freezer: %v", err)
|
||||
}
|
||||
hashes = append(hashes, hash)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -669,7 +669,7 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error {
|
|||
{"Key-Value store", "Headers", headers.Size(), headers.Count()},
|
||||
{"Key-Value store", "Bodies", bodies.Size(), bodies.Count()},
|
||||
{"Key-Value store", "Receipt lists", receipts.Size(), receipts.Count()},
|
||||
{"Key-Value store", "Difficulties (deprecated)", tds.Size(), tds.Count()},
|
||||
{"Key-Value store", "Difficulties", tds.Size(), tds.Count()},
|
||||
{"Key-Value store", "Block number->hash", numHashPairings.Size(), numHashPairings.Count()},
|
||||
{"Key-Value store", "Block hash->number", hashNumPairings.Size(), hashNumPairings.Count()},
|
||||
{"Key-Value store", "Transaction index", txLookups.Size(), txLookups.Count()},
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ var (
|
|||
|
||||
// Data item prefixes (use single byte to avoid mixing data types, avoid `i`, used for indexes).
|
||||
headerPrefix = []byte("h") // headerPrefix + num (uint64 big endian) + hash -> header
|
||||
headerTDSuffix = []byte("t") // headerPrefix + num (uint64 big endian) + hash + headerTDSuffix -> td (deprecated)
|
||||
headerTDSuffix = []byte("t") // headerPrefix + num (uint64 big endian) + hash + headerTDSuffix -> td
|
||||
headerHashSuffix = []byte("n") // headerPrefix + num (uint64 big endian) + headerHashSuffix -> hash
|
||||
headerNumberPrefix = []byte("H") // headerNumberPrefix + hash -> num (uint64 big endian)
|
||||
|
||||
|
|
@ -181,6 +181,11 @@ func headerKey(number uint64, hash common.Hash) []byte {
|
|||
return append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
|
||||
}
|
||||
|
||||
// headerTDKey = headerPrefix + num (uint64 big endian) + hash + headerTDSuffix
|
||||
func headerTDKey(number uint64, hash common.Hash) []byte {
|
||||
return append(headerKey(number, hash), headerTDSuffix...)
|
||||
}
|
||||
|
||||
// headerHashKey = headerPrefix + num (uint64 big endian) + headerHashSuffix
|
||||
func headerHashKey(number uint64) []byte {
|
||||
return append(append(headerPrefix, encodeBlockNumber(number)...), headerHashSuffix...)
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ type VMContext struct {
|
|||
// It contains the block as well as consensus related information.
|
||||
type BlockEvent struct {
|
||||
Block *types.Block
|
||||
TD *big.Int
|
||||
Finalized *types.Header
|
||||
Safe *types.Header
|
||||
}
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@ func TestTxIndexerRepair(t *testing.T) {
|
|||
}
|
||||
for _, c := range cases {
|
||||
db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
|
||||
rawdb.WriteAncientBlocks(db, append([]*types.Block{gspec.ToBlock()}, blocks...), append([]types.Receipts{{}}, receipts...))
|
||||
rawdb.WriteAncientBlocks(db, append([]*types.Block{gspec.ToBlock()}, blocks...), append([]types.Receipts{{}}, receipts...), big.NewInt(0))
|
||||
|
||||
// Index the initial blocks from ancient store
|
||||
indexer := &txIndexer{
|
||||
|
|
|
|||
|
|
@ -277,6 +277,13 @@ func (b *EthAPIBackend) GetLogs(ctx context.Context, hash common.Hash, number ui
|
|||
return rawdb.ReadLogs(b.eth.chainDb, hash, number), nil
|
||||
}
|
||||
|
||||
func (b *EthAPIBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int {
|
||||
if header := b.eth.blockchain.GetHeaderByHash(hash); header != nil {
|
||||
return b.eth.blockchain.GetTd(hash, header.Number.Uint64())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *EthAPIBackend) GetEVM(ctx context.Context, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) *vm.EVM {
|
||||
if vmConfig == nil {
|
||||
vmConfig = b.eth.blockchain.GetVMConfig()
|
||||
|
|
|
|||
|
|
@ -364,12 +364,21 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl
|
|||
}
|
||||
// Block is known locally, just sanity check that the beacon client does not
|
||||
// attempt to push us back to before the merge.
|
||||
if block.Difficulty().BitLen() > 0 && block.NumberU64() > 0 {
|
||||
ph := api.eth.BlockChain().GetHeader(block.ParentHash(), block.NumberU64()-1)
|
||||
if ph == nil {
|
||||
return engine.STATUS_INVALID, errors.New("parent unavailable for difficulty check")
|
||||
if block.Difficulty().BitLen() > 0 || block.NumberU64() == 0 {
|
||||
var (
|
||||
td = api.eth.BlockChain().GetTd(update.HeadBlockHash, block.NumberU64())
|
||||
ptd = api.eth.BlockChain().GetTd(block.ParentHash(), block.NumberU64()-1)
|
||||
ttd = api.eth.BlockChain().Config().TerminalTotalDifficulty
|
||||
)
|
||||
if td == nil || (block.NumberU64() > 0 && ptd == nil) {
|
||||
log.Error("TDs unavailable for TTD check", "number", block.NumberU64(), "hash", update.HeadBlockHash, "td", td, "parent", block.ParentHash(), "ptd", ptd)
|
||||
return engine.STATUS_INVALID, errors.New("TDs unavailable for TDD check")
|
||||
}
|
||||
if ph.Difficulty.Sign() == 0 && block.Difficulty().Sign() > 0 {
|
||||
if td.Cmp(ttd) < 0 {
|
||||
log.Error("Refusing beacon update to pre-merge", "number", block.NumberU64(), "hash", update.HeadBlockHash, "diff", block.Difficulty(), "age", common.PrettyAge(time.Unix(int64(block.Time()), 0)))
|
||||
return engine.ForkChoiceResponse{PayloadStatus: engine.INVALID_TERMINAL_BLOCK, PayloadID: nil}, nil
|
||||
}
|
||||
if block.NumberU64() > 0 && ptd.Cmp(ttd) >= 0 {
|
||||
log.Error("Parent block is already post-ttd", "number", block.NumberU64(), "hash", update.HeadBlockHash, "diff", block.Difficulty(), "age", common.PrettyAge(time.Unix(int64(block.Time()), 0)))
|
||||
return engine.ForkChoiceResponse{PayloadStatus: engine.INVALID_TERMINAL_BLOCK, PayloadID: nil}, nil
|
||||
}
|
||||
|
|
@ -893,6 +902,21 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashe
|
|||
if parent == nil {
|
||||
return api.delayPayloadImport(block), nil
|
||||
}
|
||||
// We have an existing parent, do some sanity checks to avoid the beacon client
|
||||
// triggering too early
|
||||
var (
|
||||
ptd = api.eth.BlockChain().GetTd(parent.Hash(), parent.NumberU64())
|
||||
ttd = api.eth.BlockChain().Config().TerminalTotalDifficulty
|
||||
gptd = api.eth.BlockChain().GetTd(parent.ParentHash(), parent.NumberU64()-1)
|
||||
)
|
||||
if ptd.Cmp(ttd) < 0 {
|
||||
log.Warn("Ignoring pre-merge payload", "number", params.Number, "hash", params.BlockHash, "td", ptd, "ttd", ttd)
|
||||
return engine.INVALID_TERMINAL_BLOCK, nil
|
||||
}
|
||||
if parent.Difficulty().BitLen() > 0 && gptd != nil && gptd.Cmp(ttd) >= 0 {
|
||||
log.Error("Ignoring pre-merge parent block", "number", params.Number, "hash", params.BlockHash, "td", ptd, "ttd", ttd)
|
||||
return engine.INVALID_TERMINAL_BLOCK, nil
|
||||
}
|
||||
if block.Time() <= parent.Time() {
|
||||
log.Warn("Invalid timestamp", "parent", block.Time(), "block", block.Time())
|
||||
return api.invalid(errors.New("invalid timestamp"), parent.Header()), nil
|
||||
|
|
|
|||
|
|
@ -32,7 +32,8 @@ import (
|
|||
"github.com/ethereum/go-ethereum/beacon/engine"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/consensus/beacon"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
beaconConsensus "github.com/ethereum/go-ethereum/consensus/beacon"
|
||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
|
|
@ -61,13 +62,10 @@ var (
|
|||
|
||||
func generateMergeChain(n int, merged bool) (*core.Genesis, []*types.Block) {
|
||||
config := *params.AllEthashProtocolChanges
|
||||
engine := beacon.New(ethash.NewFaker())
|
||||
engine := consensus.Engine(beaconConsensus.New(ethash.NewFaker()))
|
||||
if merged {
|
||||
config.TerminalTotalDifficulty = common.Big0
|
||||
config.MergeNetsplitBlock = common.Big0
|
||||
} else {
|
||||
// When !merged, the tests expect the next block after the generated chain to be in PoS.
|
||||
config.MergeNetsplitBlock = big.NewInt(int64(n + 1))
|
||||
engine = beaconConsensus.NewFaker()
|
||||
}
|
||||
|
||||
genesis := &core.Genesis{
|
||||
|
|
@ -104,6 +102,7 @@ func generateMergeChain(n int, merged bool) (*core.Genesis, []*types.Block) {
|
|||
}
|
||||
config.TerminalTotalDifficulty = totalDifficulty
|
||||
}
|
||||
|
||||
return genesis, blocks
|
||||
}
|
||||
|
||||
|
|
@ -166,6 +165,24 @@ func TestEth2AssembleBlockWithAnotherBlocksTxs(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestSetHeadBeforeTotalDifficulty(t *testing.T) {
|
||||
genesis, blocks := generateMergeChain(10, false)
|
||||
n, ethservice := startEthService(t, genesis, blocks)
|
||||
defer n.Close()
|
||||
|
||||
api := NewConsensusAPI(ethservice)
|
||||
fcState := engine.ForkchoiceStateV1{
|
||||
HeadBlockHash: blocks[5].Hash(),
|
||||
SafeBlockHash: common.Hash{},
|
||||
FinalizedBlockHash: common.Hash{},
|
||||
}
|
||||
if resp, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil {
|
||||
t.Errorf("fork choice updated should not error: %v", err)
|
||||
} else if resp.PayloadStatus.Status != engine.INVALID_TERMINAL_BLOCK.Status {
|
||||
t.Errorf("fork choice updated before total terminal difficulty should be INVALID")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEth2PrepareAndGetPayload(t *testing.T) {
|
||||
genesis, blocks := generateMergeChain(10, false)
|
||||
// We need to properly set the terminal total difficulty
|
||||
|
|
@ -887,6 +904,70 @@ func TestInvalidBloom(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) {
|
||||
genesis, preMergeBlocks := generateMergeChain(100, false)
|
||||
n, ethservice := startEthService(t, genesis, preMergeBlocks)
|
||||
defer n.Close()
|
||||
api := NewConsensusAPI(ethservice)
|
||||
|
||||
// Test parent already post TTD in FCU
|
||||
parent := preMergeBlocks[len(preMergeBlocks)-2]
|
||||
fcState := engine.ForkchoiceStateV1{
|
||||
HeadBlockHash: parent.Hash(),
|
||||
SafeBlockHash: common.Hash{},
|
||||
FinalizedBlockHash: common.Hash{},
|
||||
}
|
||||
resp, err := api.ForkchoiceUpdatedV1(fcState, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("error sending forkchoice, err=%v", err)
|
||||
}
|
||||
if resp.PayloadStatus != engine.INVALID_TERMINAL_BLOCK {
|
||||
t.Fatalf("error sending invalid forkchoice, invalid status: %v", resp.PayloadStatus.Status)
|
||||
}
|
||||
|
||||
// Test parent already post TTD in NewPayload
|
||||
args := &miner.BuildPayloadArgs{
|
||||
Parent: parent.Hash(),
|
||||
Timestamp: parent.Time() + 1,
|
||||
Random: crypto.Keccak256Hash([]byte{byte(1)}),
|
||||
FeeRecipient: parent.Coinbase(),
|
||||
}
|
||||
payload, err := api.eth.Miner().BuildPayload(args, false)
|
||||
if err != nil {
|
||||
t.Fatalf("error preparing payload, err=%v", err)
|
||||
}
|
||||
data := *payload.Resolve().ExecutionPayload
|
||||
// We need to recompute the blockhash, since the miner computes a wrong (correct) blockhash
|
||||
txs, _ := decodeTransactions(data.Transactions)
|
||||
header := &types.Header{
|
||||
ParentHash: data.ParentHash,
|
||||
UncleHash: types.EmptyUncleHash,
|
||||
Coinbase: data.FeeRecipient,
|
||||
Root: data.StateRoot,
|
||||
TxHash: types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)),
|
||||
ReceiptHash: data.ReceiptsRoot,
|
||||
Bloom: types.BytesToBloom(data.LogsBloom),
|
||||
Difficulty: common.Big0,
|
||||
Number: new(big.Int).SetUint64(data.Number),
|
||||
GasLimit: data.GasLimit,
|
||||
GasUsed: data.GasUsed,
|
||||
Time: data.Timestamp,
|
||||
BaseFee: data.BaseFeePerGas,
|
||||
Extra: data.ExtraData,
|
||||
MixDigest: data.Random,
|
||||
}
|
||||
block := types.NewBlockWithHeader(header).WithBody(types.Body{Transactions: txs})
|
||||
data.BlockHash = block.Hash()
|
||||
// Send the new payload
|
||||
resp2, err := api.NewPayloadV1(data)
|
||||
if err != nil {
|
||||
t.Fatalf("error sending NewPayload, err=%v", err)
|
||||
}
|
||||
if resp2 != engine.INVALID_TERMINAL_BLOCK {
|
||||
t.Fatalf("error sending invalid forkchoice, invalid status: %v", resp.PayloadStatus.Status)
|
||||
}
|
||||
}
|
||||
|
||||
// TestSimultaneousNewBlock does several parallel inserts, both as
|
||||
// newPayLoad and forkchoiceUpdate. This is to test that the api behaves
|
||||
// well even of the caller is not being 'serial'.
|
||||
|
|
|
|||
|
|
@ -186,6 +186,9 @@ type LightChain interface {
|
|||
// CurrentHeader retrieves the head header from the local chain.
|
||||
CurrentHeader() *types.Header
|
||||
|
||||
// GetTd returns the total difficulty of a local block.
|
||||
GetTd(common.Hash, uint64) *big.Int
|
||||
|
||||
// InsertHeaderChain inserts a batch of headers into the local chain.
|
||||
InsertHeaderChain([]*types.Header) (int, error)
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ package downloader
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"math/big"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
|
|
@ -56,6 +57,7 @@ type peerConnection struct {
|
|||
|
||||
// Peer encapsulates the methods required to synchronise with a remote full peer.
|
||||
type Peer interface {
|
||||
Head() (common.Hash, *big.Int)
|
||||
RequestHeadersByHash(common.Hash, int, int, bool, chan *eth.Response) (*eth.Request, error)
|
||||
RequestHeadersByNumber(uint64, int, int, bool, chan *eth.Response) (*eth.Request, error)
|
||||
|
||||
|
|
|
|||
|
|
@ -157,6 +157,7 @@ func newTestBackend(t *testing.T, londonBlock *big.Int, cancunBlock *big.Int, pe
|
|||
// config.MergeNetsplitBlock = cancunBlock
|
||||
// }
|
||||
// engine := beacon.New(ethash.NewFaker())
|
||||
config.TerminalTotalDifficulty = common.Big0
|
||||
engine := ethash.NewFaker()
|
||||
|
||||
// if cancunBlock != nil {
|
||||
|
|
|
|||
|
|
@ -321,9 +321,10 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error {
|
|||
head = h.chain.CurrentHeader()
|
||||
hash = head.Hash()
|
||||
number = head.Number.Uint64()
|
||||
td = h.chain.GetTd(hash, number)
|
||||
)
|
||||
forkID := forkid.NewID(h.chain.Config(), genesis, number, head.Time)
|
||||
if err := peer.Handshake(h.networkID, hash, genesis.Hash(), forkID, h.forkFilter); err != nil {
|
||||
if err := peer.Handshake(h.networkID, td, hash, genesis.Hash(), forkID, h.forkFilter); err != nil {
|
||||
peer.Log().Debug("Ethereum handshake failed", "err", err)
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -272,8 +272,9 @@ func testRecvTransactions(t *testing.T, protocol uint) {
|
|||
var (
|
||||
genesis = handler.chain.Genesis()
|
||||
head = handler.chain.CurrentBlock()
|
||||
td = handler.chain.GetTd(head.Hash(), head.Number.Uint64())
|
||||
)
|
||||
if err := src.Handshake(1, head.Hash(), genesis.Hash(), forkid.NewIDWithChain(handler.chain), forkid.NewFilter(handler.chain)); err != nil {
|
||||
if err := src.Handshake(1, td, head.Hash(), genesis.Hash(), forkid.NewIDWithChain(handler.chain), forkid.NewFilter(handler.chain)); err != nil {
|
||||
t.Fatalf("failed to run protocol handshake")
|
||||
}
|
||||
// Send the transaction to the sink and verify that it's added to the tx pool
|
||||
|
|
@ -332,8 +333,9 @@ func testSendTransactions(t *testing.T, protocol uint) {
|
|||
var (
|
||||
genesis = handler.chain.Genesis()
|
||||
head = handler.chain.CurrentBlock()
|
||||
td = handler.chain.GetTd(head.Hash(), head.Number.Uint64())
|
||||
)
|
||||
if err := sink.Handshake(1, head.Hash(), genesis.Hash(), forkid.NewIDWithChain(handler.chain), forkid.NewFilter(handler.chain)); err != nil {
|
||||
if err := sink.Handshake(1, td, head.Hash(), genesis.Hash(), forkid.NewIDWithChain(handler.chain), forkid.NewFilter(handler.chain)); err != nil {
|
||||
t.Fatalf("failed to run protocol handshake")
|
||||
}
|
||||
// After the handshake completes, the source handler should stream the sink
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package eth
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
|
@ -124,10 +125,11 @@ func MakeProtocols(backend Backend, network uint64, disc enode.Iterator) []p2p.P
|
|||
// NodeInfo represents a short summary of the `eth` sub-protocol metadata
|
||||
// known about the host peer.
|
||||
type NodeInfo struct {
|
||||
Network uint64 `json:"network"` // Ethereum network ID (1=Mainnet, Holesky=17000)
|
||||
Genesis common.Hash `json:"genesis"` // SHA3 hash of the host's genesis block
|
||||
Config *params.ChainConfig `json:"config"` // Chain configuration for the fork rules
|
||||
Head common.Hash `json:"head"` // Hex hash of the host's best owned block
|
||||
Network uint64 `json:"network"` // Ethereum network ID (1=Mainnet, Holesky=17000)
|
||||
Difficulty *big.Int `json:"difficulty"` // Total difficulty of the host's blockchain
|
||||
Genesis common.Hash `json:"genesis"` // SHA3 hash of the host's genesis block
|
||||
Config *params.ChainConfig `json:"config"` // Chain configuration for the fork rules
|
||||
Head common.Hash `json:"head"` // Hex hash of the host's best owned block
|
||||
}
|
||||
|
||||
// nodeInfo retrieves some `eth` protocol metadata about the running host node.
|
||||
|
|
@ -136,10 +138,11 @@ func nodeInfo(chain *core.BlockChain, network uint64) *NodeInfo {
|
|||
hash := head.Hash()
|
||||
|
||||
return &NodeInfo{
|
||||
Network: network,
|
||||
Genesis: chain.Genesis().Hash(),
|
||||
Config: chain.Config(),
|
||||
Head: hash,
|
||||
Network: network,
|
||||
Difficulty: chain.GetTd(hash, head.Number.Uint64()),
|
||||
Genesis: chain.Genesis().Hash(),
|
||||
Config: chain.Config(),
|
||||
Head: hash,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/consensus/beacon"
|
||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
|
|
@ -74,10 +75,11 @@ func newTestBackend(blocks int) *testBackend {
|
|||
func newTestBackendWithGenerator(blocks int, shanghai bool, cancun bool, generator func(int, *core.BlockGen)) *testBackend {
|
||||
var (
|
||||
// Create a database pre-initialize with a genesis block
|
||||
db = rawdb.NewMemoryDatabase()
|
||||
config = params.TestChainConfig
|
||||
engine = beacon.New(ethash.NewFaker())
|
||||
db = rawdb.NewMemoryDatabase()
|
||||
config = params.TestChainConfig
|
||||
engine consensus.Engine = ethash.NewFaker()
|
||||
)
|
||||
|
||||
if shanghai {
|
||||
config = ¶ms.ChainConfig{
|
||||
ChainID: big.NewInt(1),
|
||||
|
|
@ -102,6 +104,7 @@ func newTestBackendWithGenerator(blocks int, shanghai bool, cancun bool, generat
|
|||
Ethash: new(params.EthashConfig),
|
||||
Bor: params.TestChainConfig.Bor,
|
||||
}
|
||||
engine = beacon.NewFaker()
|
||||
}
|
||||
|
||||
gspec := &core.Genesis{
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ const (
|
|||
|
||||
// Handshake executes the eth protocol handshake, negotiating version number,
|
||||
// network IDs, difficulties, head and genesis blocks.
|
||||
func (p *Peer) Handshake(network uint64, head common.Hash, genesis common.Hash, forkID forkid.ID, forkFilter forkid.Filter) error {
|
||||
func (p *Peer) Handshake(network uint64, td *big.Int, head common.Hash, genesis common.Hash, forkID forkid.ID, forkFilter forkid.Filter) error {
|
||||
// Send out own handshake in a new thread
|
||||
errc := make(chan error, 2)
|
||||
|
||||
|
|
@ -46,7 +46,7 @@ func (p *Peer) Handshake(network uint64, head common.Hash, genesis common.Hash,
|
|||
errc <- p2p.Send(p.rw, StatusMsg, &StatusPacket{
|
||||
ProtocolVersion: uint32(p.version),
|
||||
NetworkID: network,
|
||||
TD: new(big.Int), // unknown for post-merge tail=pruned networks
|
||||
TD: td,
|
||||
Head: head,
|
||||
Genesis: genesis,
|
||||
ForkID: forkID,
|
||||
|
|
@ -71,6 +71,13 @@ func (p *Peer) Handshake(network uint64, head common.Hash, genesis common.Hash,
|
|||
return p2p.DiscReadTimeout
|
||||
}
|
||||
}
|
||||
p.td, p.head = status.TD, status.Head
|
||||
|
||||
// TD at mainnet block #7753254 is 76 bits. If it becomes 100 million times
|
||||
// larger, it will still fit within 100 bits
|
||||
if tdlen := p.td.BitLen(); tdlen > 100 {
|
||||
return fmt.Errorf("too large total difficulty: bitlen %d", tdlen)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ package eth
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
|
@ -41,6 +40,7 @@ func testHandshake(t *testing.T, protocol uint) {
|
|||
var (
|
||||
genesis = backend.chain.Genesis()
|
||||
head = backend.chain.CurrentBlock()
|
||||
td = backend.chain.GetTd(head.Hash(), head.Number.Uint64())
|
||||
forkID = forkid.NewID(backend.chain.Config(), backend.chain.Genesis(), backend.chain.CurrentHeader().Number.Uint64(), backend.chain.CurrentHeader().Time)
|
||||
)
|
||||
|
||||
|
|
@ -54,19 +54,19 @@ func testHandshake(t *testing.T, protocol uint) {
|
|||
want: errNoStatusMsg,
|
||||
},
|
||||
{
|
||||
code: StatusMsg, data: StatusPacket{10, 1, new(big.Int), head.Hash(), genesis.Hash(), forkID},
|
||||
code: StatusMsg, data: StatusPacket{10, 1, td, head.Hash(), genesis.Hash(), forkID},
|
||||
want: errProtocolVersionMismatch,
|
||||
},
|
||||
{
|
||||
code: StatusMsg, data: StatusPacket{uint32(protocol), 999, new(big.Int), head.Hash(), genesis.Hash(), forkID},
|
||||
code: StatusMsg, data: StatusPacket{uint32(protocol), 999, td, head.Hash(), genesis.Hash(), forkID},
|
||||
want: errNetworkIDMismatch,
|
||||
},
|
||||
{
|
||||
code: StatusMsg, data: StatusPacket{uint32(protocol), 1, new(big.Int), head.Hash(), common.Hash{3}, forkID},
|
||||
code: StatusMsg, data: StatusPacket{uint32(protocol), 1, td, head.Hash(), common.Hash{3}, forkID},
|
||||
want: errGenesisMismatch,
|
||||
},
|
||||
{
|
||||
code: StatusMsg, data: StatusPacket{uint32(protocol), 1, new(big.Int), head.Hash(), genesis.Hash(), forkid.ID{Hash: [4]byte{0x00, 0x01, 0x02, 0x03}}},
|
||||
code: StatusMsg, data: StatusPacket{uint32(protocol), 1, td, head.Hash(), genesis.Hash(), forkid.ID{Hash: [4]byte{0x00, 0x01, 0x02, 0x03}}},
|
||||
want: errForkIDRejected,
|
||||
},
|
||||
}
|
||||
|
|
@ -82,7 +82,7 @@ func testHandshake(t *testing.T, protocol uint) {
|
|||
// Send the junk test with one peer, check the handshake failure
|
||||
go p2p.Send(app, test.code, test.data)
|
||||
|
||||
err := peer.Handshake(1, head.Hash(), genesis.Hash(), forkID, forkid.NewFilter(backend.chain))
|
||||
err := peer.Handshake(1, td, head.Hash(), genesis.Hash(), forkID, forkid.NewFilter(backend.chain))
|
||||
if err == nil {
|
||||
t.Errorf("test %d: protocol returned nil error, want %q", i, test.want)
|
||||
} else if !errors.Is(err, test.want) {
|
||||
|
|
|
|||
|
|
@ -1289,7 +1289,7 @@ func TestTraceChain(t *testing.T) {
|
|||
func newTestMergedBackend(t *testing.T, n int, gspec *core.Genesis, generator func(i int, b *core.BlockGen)) *testBackend {
|
||||
backend := &testBackend{
|
||||
chainConfig: gspec.Config,
|
||||
engine: beacon.New(ethash.NewFaker()),
|
||||
engine: beacon.NewFaker(),
|
||||
chaindb: rawdb.NewMemoryDatabase(),
|
||||
}
|
||||
// Generate blocks for testing
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ type backend interface {
|
|||
SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription
|
||||
CurrentHeader() *types.Header
|
||||
HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error)
|
||||
GetTd(ctx context.Context, hash common.Hash) *big.Int
|
||||
Stats() (pending int, queued int)
|
||||
SyncProgress() ethereum.SyncProgress
|
||||
|
||||
|
|
@ -707,6 +708,7 @@ func (s *Service) reportBlock(conn *connWrapper, header *types.Header) error {
|
|||
func (s *Service) assembleBlockStats(header *types.Header) *blockStats {
|
||||
// Gather the block infos from the local blockchain
|
||||
var (
|
||||
td *big.Int
|
||||
txs []txStats
|
||||
uncles []*types.Header
|
||||
)
|
||||
|
|
@ -722,6 +724,8 @@ func (s *Service) assembleBlockStats(header *types.Header) *blockStats {
|
|||
if block == nil {
|
||||
return nil
|
||||
}
|
||||
td = fullBackend.GetTd(context.Background(), header.Hash())
|
||||
|
||||
txs = make([]txStats, len(block.Transactions()))
|
||||
for i, tx := range block.Transactions() {
|
||||
txs[i].Hash = tx.Hash()
|
||||
|
|
@ -733,6 +737,7 @@ func (s *Service) assembleBlockStats(header *types.Header) *blockStats {
|
|||
if header == nil {
|
||||
header = s.backend.CurrentHeader()
|
||||
}
|
||||
td = s.backend.GetTd(context.Background(), header.Hash())
|
||||
txs = []txStats{}
|
||||
}
|
||||
// Assemble and return the block stats
|
||||
|
|
@ -747,7 +752,7 @@ func (s *Service) assembleBlockStats(header *types.Header) *blockStats {
|
|||
GasUsed: header.GasUsed,
|
||||
GasLimit: header.GasLimit,
|
||||
Diff: header.Difficulty.String(),
|
||||
TotalDiff: "0", // unknown post-merge with pruned chain tail
|
||||
TotalDiff: td.String(),
|
||||
Txs: txs,
|
||||
TxHash: header.TxHash,
|
||||
Root: header.Root,
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/consensus/beacon"
|
||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
|
|
@ -466,7 +467,7 @@ func newGQLService(t *testing.T, stack *node.Node, shanghai bool, gspec *core.Ge
|
|||
RPCGasCap: 1000000,
|
||||
StateScheme: rawdb.HashScheme,
|
||||
}
|
||||
var engine = beacon.New(ethash.NewFaker())
|
||||
var engine consensus.Engine = ethash.NewFaker()
|
||||
if shanghai {
|
||||
engine = beacon.NewFaker()
|
||||
gspec.Config.TerminalTotalDifficulty = common.Big0
|
||||
|
|
|
|||
|
|
@ -564,6 +564,12 @@ func (b testBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.R
|
|||
receipts := rawdb.ReadReceipts(b.db, hash, header.Number.Uint64(), header.Time, b.chain.Config())
|
||||
return receipts, nil
|
||||
}
|
||||
func (b testBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int {
|
||||
if b.pending != nil && hash == b.pending.Hash() {
|
||||
return nil
|
||||
}
|
||||
return big.NewInt(1)
|
||||
}
|
||||
func (b testBackend) GetEVM(ctx context.Context, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockContext *vm.BlockContext) *vm.EVM {
|
||||
if vmConfig == nil {
|
||||
vmConfig = b.chain.GetVMConfig()
|
||||
|
|
|
|||
|
|
@ -380,6 +380,7 @@ func (b *backendMock) GetLogs(ctx context.Context, blockHash common.Hash, number
|
|||
//nolint:nilnil
|
||||
return nil, nil
|
||||
}
|
||||
func (b *backendMock) GetTd(ctx context.Context, hash common.Hash) *big.Int { return nil }
|
||||
func (b *backendMock) GetEVM(ctx context.Context, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) *vm.EVM {
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,8 +57,8 @@ func TestBlockchain(t *testing.T) {
|
|||
bt.skipLoad(`.*InvalidBlocks*`)
|
||||
bt.skipLoad(`.*TransitionTests*`)
|
||||
|
||||
// With chain history removal, TDs become unavailable, this transition tests based on TTD are unrunnable
|
||||
bt.skipLoad(`.*bcArrowGlacierToParis/powToPosBlockRejection.json`)
|
||||
// // With chain history removal, TDs become unavailable, this transition tests based on TTD are unrunnable
|
||||
// bt.skipLoad(`.*bcArrowGlacierToParis/powToPosBlockRejection.json`)
|
||||
|
||||
// This directory contains no test.
|
||||
bt.skipLoad(`.*\.meta/.*`)
|
||||
|
|
|
|||
Loading…
Reference in a new issue