Skip to content

Commit cec238d

Browse files
authored
Merge branch 'ethereum:master' into gethintegration
2 parents 4a5771a + 13b157a commit cec238d

32 files changed

+544
-192
lines changed

.github/CODEOWNERS

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,11 @@ beacon/light/ @zsfelfoldi
99
beacon/merkle/ @zsfelfoldi
1010
beacon/types/ @zsfelfoldi @fjl
1111
beacon/params/ @zsfelfoldi @fjl
12-
cmd/clef/ @holiman
13-
cmd/evm/ @holiman @MariusVanDerWijden @lightclient
14-
core/state/ @rjl493456442 @holiman
15-
crypto/ @gballet @jwasinger @holiman @fjl
16-
core/ @holiman @rjl493456442
17-
eth/ @holiman @rjl493456442
12+
cmd/evm/ @MariusVanDerWijden @lightclient
13+
core/state/ @rjl493456442
14+
crypto/ @gballet @jwasinger @fjl
15+
core/ @rjl493456442
16+
eth/ @rjl493456442
1817
eth/catalyst/ @MariusVanDerWijden @lightclient @fjl @jwasinger
1918
eth/tracers/ @s1na
2019
ethclient/ @fjl
@@ -26,11 +25,9 @@ core/tracing/ @s1na
2625
graphql/ @s1na
2726
internal/ethapi/ @fjl @s1na @lightclient
2827
internal/era/ @lightclient
29-
metrics/ @holiman
30-
miner/ @MariusVanDerWijden @holiman @fjl @rjl493456442
28+
miner/ @MariusVanDerWijden @fjl @rjl493456442
3129
node/ @fjl
3230
p2p/ @fjl @zsfelfoldi
3331
rlp/ @fjl
34-
params/ @fjl @holiman @karalabe @gballet @rjl493456442 @zsfelfoldi
35-
rpc/ @fjl @holiman
36-
signer/ @holiman
32+
params/ @fjl @karalabe @gballet @rjl493456442 @zsfelfoldi
33+
rpc/ @fjl

cmd/geth/chaincmd.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ import (
3131
"github.com/ethereum/go-ethereum/common"
3232
"github.com/ethereum/go-ethereum/common/hexutil"
3333
"github.com/ethereum/go-ethereum/core"
34+
"github.com/ethereum/go-ethereum/core/history"
3435
"github.com/ethereum/go-ethereum/core/rawdb"
3536
"github.com/ethereum/go-ethereum/core/state"
3637
"github.com/ethereum/go-ethereum/core/types"
3738
"github.com/ethereum/go-ethereum/crypto"
38-
"github.com/ethereum/go-ethereum/eth/ethconfig"
3939
"github.com/ethereum/go-ethereum/ethdb"
4040
"github.com/ethereum/go-ethereum/internal/debug"
4141
"github.com/ethereum/go-ethereum/internal/era"
@@ -625,7 +625,7 @@ func pruneHistory(ctx *cli.Context) error {
625625
defer chain.Stop()
626626

627627
// Determine the prune point. This will be the first PoS block.
628-
prunePoint, ok := ethconfig.HistoryPrunePoints[chain.Genesis().Hash()]
628+
prunePoint, ok := history.PrunePoints[chain.Genesis().Hash()]
629629
if !ok || prunePoint == nil {
630630
return errors.New("prune point not found")
631631
}

cmd/geth/main.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@ var (
100100
utils.LightNoSyncServeFlag, // deprecated
101101
utils.EthRequiredBlocksFlag,
102102
utils.LegacyWhitelistFlag, // deprecated
103-
utils.BloomFilterSizeFlag,
104103
utils.CacheFlag,
105104
utils.CacheDatabaseFlag,
106105
utils.CacheTrieFlag,

cmd/workload/testsuite.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import (
2323
"os"
2424
"slices"
2525

26-
"github.com/ethereum/go-ethereum/eth/ethconfig"
26+
"github.com/ethereum/go-ethereum/core/history"
2727
"github.com/ethereum/go-ethereum/internal/flags"
2828
"github.com/ethereum/go-ethereum/internal/utesting"
2929
"github.com/ethereum/go-ethereum/log"
@@ -124,13 +124,13 @@ func testConfigFromCLI(ctx *cli.Context) (cfg testConfig) {
124124
cfg.filterQueryFile = "queries/filter_queries_mainnet.json"
125125
cfg.historyTestFile = "queries/history_mainnet.json"
126126
cfg.historyPruneBlock = new(uint64)
127-
*cfg.historyPruneBlock = ethconfig.HistoryPrunePoints[params.MainnetGenesisHash].BlockNumber
127+
*cfg.historyPruneBlock = history.PrunePoints[params.MainnetGenesisHash].BlockNumber
128128
case ctx.Bool(testSepoliaFlag.Name):
129129
cfg.fsys = builtinTestFiles
130130
cfg.filterQueryFile = "queries/filter_queries_sepolia.json"
131131
cfg.historyTestFile = "queries/history_sepolia.json"
132132
cfg.historyPruneBlock = new(uint64)
133-
*cfg.historyPruneBlock = ethconfig.HistoryPrunePoints[params.SepoliaGenesisHash].BlockNumber
133+
*cfg.historyPruneBlock = history.PrunePoints[params.SepoliaGenesisHash].BlockNumber
134134
default:
135135
cfg.fsys = os.DirFS(".")
136136
cfg.filterQueryFile = ctx.String(filterQueryFileFlag.Name)

core/block_validator_test.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,11 @@ func testHeaderVerification(t *testing.T, scheme string) {
5050
headers[i] = block.Header()
5151
}
5252
// Run the header checker for blocks one-by-one, checking for both valid and invalid nonces
53-
chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
53+
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
5454
defer chain.Stop()
55+
if err != nil {
56+
t.Fatal(err)
57+
}
5558

5659
for i := 0; i < len(blocks); i++ {
5760
for j, valid := range []bool{true, false} {
@@ -163,8 +166,11 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) {
163166
postHeaders[i] = block.Header()
164167
}
165168
// Run the header checker for blocks one-by-one, checking for both valid and invalid nonces
166-
chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil)
169+
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil)
167170
defer chain.Stop()
171+
if err != nil {
172+
t.Fatal(err)
173+
}
168174

169175
// Verify the blocks before the merging
170176
for i := 0; i < len(preBlocks); i++ {

core/blockchain.go

Lines changed: 125 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"errors"
2222
"fmt"
2323
"io"
24+
"math"
2425
"math/big"
2526
"runtime"
2627
"slices"
@@ -36,6 +37,7 @@ import (
3637
"github.com/ethereum/go-ethereum/common/prque"
3738
"github.com/ethereum/go-ethereum/consensus"
3839
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
40+
"github.com/ethereum/go-ethereum/core/history"
3941
"github.com/ethereum/go-ethereum/core/rawdb"
4042
"github.com/ethereum/go-ethereum/core/state"
4143
"github.com/ethereum/go-ethereum/core/state/snapshot"
@@ -99,6 +101,10 @@ var (
99101
errInvalidNewChain = errors.New("invalid new chain")
100102
)
101103

104+
var (
105+
forkReadyInterval = 3 * time.Minute
106+
)
107+
102108
const (
103109
bodyCacheLimit = 256
104110
blockCacheLimit = 256
@@ -158,8 +164,7 @@ type CacheConfig struct {
158164

159165
// This defines the cutoff block for history expiry.
160166
// Blocks before this number may be unavailable in the chain database.
161-
HistoryPruningCutoffNumber uint64
162-
HistoryPruningCutoffHash common.Hash
167+
ChainHistoryMode history.HistoryMode
163168
}
164169

165170
// triedbConfig derives the configures for trie database.
@@ -255,6 +260,7 @@ type BlockChain struct {
255260
currentSnapBlock atomic.Pointer[types.Header] // Current head of snap-sync
256261
currentFinalBlock atomic.Pointer[types.Header] // Latest (consensus) finalized block
257262
currentSafeBlock atomic.Pointer[types.Header] // Latest (consensus) safe block
263+
historyPrunePoint atomic.Pointer[history.PrunePoint]
258264

259265
bodyCache *lru.Cache[common.Hash, *types.Body]
260266
bodyRLPCache *lru.Cache[common.Hash, rlp.RawValue]
@@ -274,6 +280,8 @@ type BlockChain struct {
274280
processor Processor // Block transaction processor interface
275281
vmConfig vm.Config
276282
logger *tracing.Hooks
283+
284+
lastForkReadyAlert time.Time // Last time there was a fork readiness print out
277285
}
278286

279287
// NewBlockChain returns a fully initialised block chain using information
@@ -513,26 +521,46 @@ func (bc *BlockChain) loadLastState() error {
513521
log.Warn("Empty database, resetting chain")
514522
return bc.Reset()
515523
}
516-
// Make sure the entire head block is available
517-
headBlock := bc.GetBlockByHash(head)
524+
headHeader := bc.GetHeaderByHash(head)
525+
if headHeader == nil {
526+
// Corrupt or empty database, init from scratch
527+
log.Warn("Head header missing, resetting chain", "hash", head)
528+
return bc.Reset()
529+
}
530+
531+
var headBlock *types.Block
532+
if cmp := headHeader.Number.Cmp(new(big.Int)); cmp == 1 {
533+
// Make sure the entire head block is available.
534+
headBlock = bc.GetBlockByHash(head)
535+
} else if cmp == 0 {
536+
// On a pruned node the block body might not be available. But a pruned
537+
// block should never be the head block. The only exception is when, as
538+
// a last resort, chain is reset to genesis.
539+
headBlock = bc.genesisBlock
540+
}
518541
if headBlock == nil {
519542
// Corrupt or empty database, init from scratch
520543
log.Warn("Head block missing, resetting chain", "hash", head)
521544
return bc.Reset()
522545
}
523546
// Everything seems to be fine, set as the head block
524-
bc.currentBlock.Store(headBlock.Header())
547+
bc.currentBlock.Store(headHeader)
525548
headBlockGauge.Update(int64(headBlock.NumberU64()))
526549

527550
// Restore the last known head header
528-
headHeader := headBlock.Header()
529551
if head := rawdb.ReadHeadHeaderHash(bc.db); head != (common.Hash{}) {
530552
if header := bc.GetHeaderByHash(head); header != nil {
531553
headHeader = header
532554
}
533555
}
534556
bc.hc.SetCurrentHeader(headHeader)
535557

558+
// Initialize history pruning.
559+
latest := max(headBlock.NumberU64(), headHeader.Number.Uint64())
560+
if err := bc.initializeHistoryPruning(latest); err != nil {
561+
return err
562+
}
563+
536564
// Restore the last known head snap block
537565
bc.currentSnapBlock.Store(headBlock.Header())
538566
headFastBlockGauge.Update(int64(headBlock.NumberU64()))
@@ -555,6 +583,7 @@ func (bc *BlockChain) loadLastState() error {
555583
headSafeBlockGauge.Update(int64(block.NumberU64()))
556584
}
557585
}
586+
558587
// Issue a status log for the user
559588
var (
560589
currentSnapBlock = bc.CurrentSnapBlock()
@@ -573,9 +602,57 @@ func (bc *BlockChain) loadLastState() error {
573602
if pivot := rawdb.ReadLastPivotNumber(bc.db); pivot != nil {
574603
log.Info("Loaded last snap-sync pivot marker", "number", *pivot)
575604
}
605+
if pruning := bc.historyPrunePoint.Load(); pruning != nil {
606+
log.Info("Chain history is pruned", "earliest", pruning.BlockNumber, "hash", pruning.BlockHash)
607+
}
576608
return nil
577609
}
578610

611+
// initializeHistoryPruning sets bc.historyPrunePoint.
612+
func (bc *BlockChain) initializeHistoryPruning(latest uint64) error {
613+
freezerTail, _ := bc.db.Tail()
614+
615+
switch bc.cacheConfig.ChainHistoryMode {
616+
case history.KeepAll:
617+
if freezerTail == 0 {
618+
return nil
619+
}
620+
// The database was pruned somehow, so we need to figure out if it's a known
621+
// configuration or an error.
622+
predefinedPoint := history.PrunePoints[bc.genesisBlock.Hash()]
623+
if predefinedPoint == nil || freezerTail != predefinedPoint.BlockNumber {
624+
log.Error("Chain history database is pruned with unknown configuration", "tail", freezerTail)
625+
return fmt.Errorf("unexpected database tail")
626+
}
627+
bc.historyPrunePoint.Store(predefinedPoint)
628+
return nil
629+
630+
case history.KeepPostMerge:
631+
if freezerTail == 0 && latest != 0 {
632+
// This is the case where a user is trying to run with --history.chain
633+
// postmerge directly on an existing DB. We could just trigger the pruning
634+
// here, but it'd be a bit dangerous since they may not have intended this
635+
// action to happen. So just tell them how to do it.
636+
log.Error(fmt.Sprintf("Chain history mode is configured as %q, but database is not pruned.", bc.cacheConfig.ChainHistoryMode.String()))
637+
log.Error(fmt.Sprintf("Run 'geth prune-history' to prune pre-merge history."))
638+
return fmt.Errorf("history pruning requested via configuration")
639+
}
640+
predefinedPoint := history.PrunePoints[bc.genesisBlock.Hash()]
641+
if predefinedPoint == nil {
642+
log.Error("Chain history pruning is not supported for this network", "genesis", bc.genesisBlock.Hash())
643+
return fmt.Errorf("history pruning requested for unknown network")
644+
} else if freezerTail > 0 && freezerTail != predefinedPoint.BlockNumber {
645+
log.Error("Chain history database is pruned to unknown block", "tail", freezerTail)
646+
return fmt.Errorf("unexpected database tail")
647+
}
648+
bc.historyPrunePoint.Store(predefinedPoint)
649+
return nil
650+
651+
default:
652+
return fmt.Errorf("invalid history mode: %d", bc.cacheConfig.ChainHistoryMode)
653+
}
654+
}
655+
579656
// SetHead rewinds the local chain to a new head. Depending on whether the node
580657
// was snap synced or full synced and in which state, the method will try to
581658
// delete minimal data from disk whilst retaining chain consistency.
@@ -586,11 +663,15 @@ func (bc *BlockChain) SetHead(head uint64) error {
586663
// Send chain head event to update the transaction pool
587664
header := bc.CurrentBlock()
588665
if block := bc.GetBlock(header.Hash(), header.Number.Uint64()); block == nil {
589-
// This should never happen. In practice, previously currentBlock
590-
// contained the entire block whereas now only a "marker", so there
591-
// is an ever so slight chance for a race we should handle.
592-
log.Error("Current block not found in database", "block", header.Number, "hash", header.Hash())
593-
return fmt.Errorf("current block missing: #%d [%x..]", header.Number, header.Hash().Bytes()[:4])
666+
// In a pruned node the genesis block will not exist in the freezer.
667+
// It should not happen that we set head to any other pruned block.
668+
if header.Number.Uint64() > 0 {
669+
// This should never happen. In practice, previously currentBlock
670+
// contained the entire block whereas now only a "marker", so there
671+
// is an ever so slight chance for a race we should handle.
672+
log.Error("Current block not found in database", "block", header.Number, "hash", header.Hash())
673+
return fmt.Errorf("current block missing: #%d [%x..]", header.Number, header.Hash().Bytes()[:4])
674+
}
594675
}
595676
bc.chainHeadFeed.Send(ChainHeadEvent{Header: header})
596677
return nil
@@ -607,11 +688,15 @@ func (bc *BlockChain) SetHeadWithTimestamp(timestamp uint64) error {
607688
// Send chain head event to update the transaction pool
608689
header := bc.CurrentBlock()
609690
if block := bc.GetBlock(header.Hash(), header.Number.Uint64()); block == nil {
610-
// This should never happen. In practice, previously currentBlock
611-
// contained the entire block whereas now only a "marker", so there
612-
// is an ever so slight chance for a race we should handle.
613-
log.Error("Current block not found in database", "block", header.Number, "hash", header.Hash())
614-
return fmt.Errorf("current block missing: #%d [%x..]", header.Number, header.Hash().Bytes()[:4])
691+
// In a pruned node the genesis block will not exist in the freezer.
692+
// It should not happen that we set head to any other pruned block.
693+
if header.Number.Uint64() > 0 {
694+
// This should never happen. In practice, previously currentBlock
695+
// contained the entire block whereas now only a "marker", so there
696+
// is an ever so slight chance for a race we should handle.
697+
log.Error("Current block not found in database", "block", header.Number, "hash", header.Hash())
698+
return fmt.Errorf("current block missing: #%d [%x..]", header.Number, header.Hash().Bytes()[:4])
699+
}
615700
}
616701
bc.chainHeadFeed.Send(ChainHeadEvent{Header: header})
617702
return nil
@@ -1014,7 +1099,9 @@ func (bc *BlockChain) ResetWithGenesisBlock(genesis *types.Block) error {
10141099
bc.hc.SetCurrentHeader(bc.genesisBlock.Header())
10151100
bc.currentSnapBlock.Store(bc.genesisBlock.Header())
10161101
headFastBlockGauge.Update(int64(bc.genesisBlock.NumberU64()))
1017-
return nil
1102+
1103+
// Reset history pruning status.
1104+
return bc.initializeHistoryPruning(0)
10181105
}
10191106

10201107
// Export writes the active chain to the given writer.
@@ -1804,6 +1891,9 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness
18041891
trieDiffNodes, trieBufNodes, _ := bc.triedb.Size()
18051892
stats.report(chain, it.index, snapDiffItems, snapBufItems, trieDiffNodes, trieBufNodes, setHead)
18061893

1894+
// Print confirmation that a future fork is scheduled, but not yet active.
1895+
bc.logForkReadiness(block)
1896+
18071897
if !setHead {
18081898
// After merge we expect few side chains. Simply count
18091899
// all blocks the CL gives us for GC processing time
@@ -1837,6 +1927,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness
18371927
"root", block.Root())
18381928
}
18391929
}
1930+
18401931
stats.ignored += it.remaining()
18411932
return witness, it.index, err
18421933
}
@@ -2434,6 +2525,23 @@ func (bc *BlockChain) reportBlock(block *types.Block, res *ProcessResult, err er
24342525
log.Error(summarizeBadBlock(block, receipts, bc.Config(), err))
24352526
}
24362527

2528+
// logForkReadiness will write a log when a future fork is scheduled, but not
2529+
// active. This is useful so operators know their client is ready for the fork.
2530+
func (bc *BlockChain) logForkReadiness(block *types.Block) {
2531+
c := bc.Config()
2532+
current, last := c.LatestFork(block.Time()), c.LatestFork(math.MaxUint64)
2533+
t := c.Timestamp(last)
2534+
if t == nil {
2535+
return
2536+
}
2537+
at := time.Unix(int64(*t), 0)
2538+
if current < last && time.Now().After(bc.lastForkReadyAlert.Add(forkReadyInterval)) {
2539+
log.Info("Ready for fork activation", "fork", last, "date", at.Format(time.RFC822),
2540+
"remaining", time.Until(at).Round(time.Second), "timestamp", at.Unix())
2541+
bc.lastForkReadyAlert = time.Now()
2542+
}
2543+
}
2544+
24372545
// summarizeBadBlock returns a string summarizing the bad block and other
24382546
// relevant information.
24392547
func summarizeBadBlock(block *types.Block, receipts []*types.Receipt, config *params.ChainConfig, err error) string {

core/blockchain_reader.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,11 @@ func (bc *BlockChain) TxIndexProgress() (TxIndexProgress, error) {
410410
// HistoryPruningCutoff returns the configured history pruning point.
411411
// Blocks before this might not be available in the database.
412412
func (bc *BlockChain) HistoryPruningCutoff() (uint64, common.Hash) {
413-
return bc.cacheConfig.HistoryPruningCutoffNumber, bc.cacheConfig.HistoryPruningCutoffHash
413+
pt := bc.historyPrunePoint.Load()
414+
if pt == nil {
415+
return 0, bc.genesisBlock.Hash()
416+
}
417+
return pt.BlockNumber, pt.BlockHash
414418
}
415419

416420
// TrieDB retrieves the low level trie database used for data storage.

0 commit comments

Comments
 (0)