Skip to content

Commit 4b23bca

Browse files
committed
Revert "consensus, cmd, core, eth: remove support for non-merge mode of operation (#29169)"
This reverts commit a6eb14b.
1 parent a6eb14b commit 4b23bca

24 files changed

+2357
-237
lines changed

cmd/geth/testdata/clique.json

-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
"byzantiumBlock": 0,
99
"constantinopleBlock": 0,
1010
"petersburgBlock": 0,
11-
"terminalTotalDifficultyPassed": true,
1211
"clique": {
1312
"period": 5,
1413
"epoch": 30000

consensus/merger.go

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// Copyright 2021 The go-ethereum Authors
2+
// This file is part of the go-ethereum library.
3+
//
4+
// The go-ethereum library is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Lesser General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// The go-ethereum library is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Lesser General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Lesser General Public License
15+
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
16+
17+
package consensus
18+
19+
import (
20+
"fmt"
21+
"sync"
22+
23+
"github.com/ethereum/go-ethereum/core/rawdb"
24+
"github.com/ethereum/go-ethereum/ethdb"
25+
"github.com/ethereum/go-ethereum/log"
26+
"github.com/ethereum/go-ethereum/rlp"
27+
)
28+
29+
// transitionStatus describes the status of eth1/2 transition. This switch
30+
// between modes is a one-way action which is triggered by corresponding
31+
// consensus-layer message.
32+
type transitionStatus struct {
33+
LeftPoW bool // The flag is set when the first NewHead message received
34+
EnteredPoS bool // The flag is set when the first FinalisedBlock message received
35+
}
36+
37+
// Merger is an internal help structure used to track the eth1/2 transition status.
38+
// It's a common structure can be used in both full node and light client.
39+
type Merger struct {
40+
db ethdb.KeyValueStore
41+
status transitionStatus
42+
mu sync.RWMutex
43+
}
44+
45+
// NewMerger creates a new Merger which stores its transition status in the provided db.
46+
func NewMerger(db ethdb.KeyValueStore) *Merger {
47+
var status transitionStatus
48+
blob := rawdb.ReadTransitionStatus(db)
49+
if len(blob) != 0 {
50+
if err := rlp.DecodeBytes(blob, &status); err != nil {
51+
log.Crit("Failed to decode the transition status", "err", err)
52+
}
53+
}
54+
return &Merger{
55+
db: db,
56+
status: status,
57+
}
58+
}
59+
60+
// ReachTTD is called whenever the first NewHead message received
61+
// from the consensus-layer.
62+
func (m *Merger) ReachTTD() {
63+
m.mu.Lock()
64+
defer m.mu.Unlock()
65+
66+
if m.status.LeftPoW {
67+
return
68+
}
69+
m.status = transitionStatus{LeftPoW: true}
70+
blob, err := rlp.EncodeToBytes(m.status)
71+
if err != nil {
72+
panic(fmt.Sprintf("Failed to encode the transition status: %v", err))
73+
}
74+
rawdb.WriteTransitionStatus(m.db, blob)
75+
log.Info("Left PoW stage")
76+
}
77+
78+
// FinalizePoS is called whenever the first FinalisedBlock message received
79+
// from the consensus-layer.
80+
func (m *Merger) FinalizePoS() {
81+
m.mu.Lock()
82+
defer m.mu.Unlock()
83+
84+
if m.status.EnteredPoS {
85+
return
86+
}
87+
m.status = transitionStatus{LeftPoW: true, EnteredPoS: true}
88+
blob, err := rlp.EncodeToBytes(m.status)
89+
if err != nil {
90+
panic(fmt.Sprintf("Failed to encode the transition status: %v", err))
91+
}
92+
rawdb.WriteTransitionStatus(m.db, blob)
93+
log.Info("Entered PoS stage")
94+
}
95+
96+
// TDDReached reports whether the chain has left the PoW stage.
97+
func (m *Merger) TDDReached() bool {
98+
m.mu.RLock()
99+
defer m.mu.RUnlock()
100+
101+
return m.status.LeftPoW
102+
}
103+
104+
// PoSFinalized reports whether the chain has entered the PoS stage.
105+
func (m *Merger) PoSFinalized() bool {
106+
m.mu.RLock()
107+
defer m.mu.RUnlock()
108+
109+
return m.status.EnteredPoS
110+
}

core/block_validator_test.go

+6
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) {
9494
preBlocks []*types.Block
9595
postBlocks []*types.Block
9696
engine consensus.Engine
97+
merger = consensus.NewMerger(rawdb.NewMemoryDatabase())
9798
)
9899
if isClique {
99100
var (
@@ -185,6 +186,11 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) {
185186
}
186187
chain.InsertChain(preBlocks[i : i+1])
187188
}
189+
190+
// Make the transition
191+
merger.ReachTTD()
192+
merger.FinalizePoS()
193+
188194
// Verify the blocks after the merging
189195
for i := 0; i < len(postBlocks); i++ {
190196
_, results := engine.VerifyHeaders(chain, []*types.Header{postHeaders[i]})

core/blockchain.go

+73-34
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ import (
5656
"github.com/ethereum/go-ethereum/triedb"
5757
"github.com/ethereum/go-ethereum/triedb/hashdb"
5858
"github.com/ethereum/go-ethereum/triedb/pathdb"
59+
"golang.org/x/exp/slices"
5960
)
6061

6162
var (
@@ -109,7 +110,6 @@ var (
109110
)
110111

111112
const (
112-
<<<<<<< HEAD
113113
bodyCacheLimit = 256
114114
blockCacheLimit = 256
115115
diffLayerCacheLimit = 1024
@@ -127,13 +127,6 @@ const (
127127
maxDiffForkDist = 11 // Maximum allowed backward distance from the chain head
128128

129129
rewindBadBlockInterval = 1 * time.Second
130-
=======
131-
bodyCacheLimit = 256
132-
blockCacheLimit = 256
133-
receiptsCacheLimit = 32
134-
txLookupCacheLimit = 1024
135-
TriesInMemory = 128
136-
>>>>>>> f4d53133f (consensus, cmd, core, eth: remove support for non-merge mode of operation (#29169))
137130

138131
// BlockChainVersion ensures that an incompatible database forces a resync from scratch.
139132
//
@@ -299,7 +292,6 @@ type BlockChain struct {
299292
txLookupCache *lru.Cache[common.Hash, txLookup]
300293
sidecarsCache *lru.Cache[common.Hash, types.BlobSidecars]
301294

302-
<<<<<<< HEAD
303295
// future blocks are blocks added for later processing
304296
futureBlocks *lru.Cache[common.Hash, *types.Block]
305297
// Cache for the blocks that failed to pass MPT root verification
@@ -312,8 +304,6 @@ type BlockChain struct {
312304
diffQueueBuffer chan *types.DiffLayer
313305
diffLayerFreezerBlockLimit uint64
314306

315-
=======
316-
>>>>>>> f4d53133f (consensus, cmd, core, eth: remove support for non-merge mode of operation (#29169))
317307
wg sync.WaitGroup
318308
dbWg sync.WaitGroup
319309
quit chan struct{} // shutdown signal, closed in Stop.
@@ -373,7 +363,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
373363
*/
374364

375365
bc := &BlockChain{
376-
<<<<<<< HEAD
377366
chainConfig: chainConfig,
378367
cacheConfig: cacheConfig,
379368
db: db,
@@ -396,22 +385,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
396385
vmConfig: vmConfig,
397386
diffQueue: prque.New[int64, *types.DiffLayer](nil),
398387
diffQueueBuffer: make(chan *types.DiffLayer),
399-
=======
400-
chainConfig: chainConfig,
401-
cacheConfig: cacheConfig,
402-
db: db,
403-
triedb: triedb,
404-
triegc: prque.New[int64, common.Hash](nil),
405-
quit: make(chan struct{}),
406-
chainmu: syncx.NewClosableMutex(),
407-
bodyCache: lru.NewCache[common.Hash, *types.Body](bodyCacheLimit),
408-
bodyRLPCache: lru.NewCache[common.Hash, rlp.RawValue](bodyCacheLimit),
409-
receiptsCache: lru.NewCache[common.Hash, []*types.Receipt](receiptsCacheLimit),
410-
blockCache: lru.NewCache[common.Hash, *types.Block](blockCacheLimit),
411-
txLookupCache: lru.NewCache[common.Hash, txLookup](txLookupCacheLimit),
412-
engine: engine,
413-
vmConfig: vmConfig,
414-
>>>>>>> f4d53133f (consensus, cmd, core, eth: remove support for non-merge mode of operation (#29169))
415388
}
416389
bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit))
417390
bc.forker = NewForkChoice(bc, shouldPreserve)
@@ -577,7 +550,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
577550
return nil, err
578551
}
579552
}
580-
<<<<<<< HEAD
581553
// Start future block processor.
582554
bc.wg.Add(1)
583555
go bc.updateFutureBlocks()
@@ -598,8 +570,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
598570
go bc.startDoubleSignMonitor()
599571
}
600572

601-
=======
602-
>>>>>>> f4d53133f (consensus, cmd, core, eth: remove support for non-merge mode of operation (#29169))
603573
// Rewind the chain in case of an incompatible config upgrade.
604574
if compat, ok := genesisErr.(*params.ConfigCompatError); ok {
605575
log.Warn("Rewinding chain to upgrade configuration", "err", compat)
@@ -1187,6 +1157,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
11871157
bc.sidecarsCache.Purge()
11881158
bc.blockCache.Purge()
11891159
bc.txLookupCache.Purge()
1160+
bc.futureBlocks.Purge()
11901161

11911162
if finalized := bc.CurrentFinalBlock(); finalized != nil && head < finalized.Number.Uint64() {
11921163
log.Error("SetHead invalidated finalized block")
@@ -1474,6 +1445,24 @@ func (bc *BlockChain) insertStopped() bool {
14741445
return bc.procInterrupt.Load()
14751446
}
14761447

1448+
func (bc *BlockChain) procFutureBlocks() {
1449+
blocks := make([]*types.Block, 0, bc.futureBlocks.Len())
1450+
for _, hash := range bc.futureBlocks.Keys() {
1451+
if block, exist := bc.futureBlocks.Peek(hash); exist {
1452+
blocks = append(blocks, block)
1453+
}
1454+
}
1455+
if len(blocks) > 0 {
1456+
slices.SortFunc(blocks, func(a, b *types.Block) int {
1457+
return a.Number().Cmp(b.Number())
1458+
})
1459+
// Insert one by one as chain insertion needs contiguous ancestry between blocks
1460+
for i := range blocks {
1461+
bc.InsertChain(blocks[i : i+1])
1462+
}
1463+
}
1464+
}
1465+
14771466
// WriteStatus status of write
14781467
type WriteStatus byte
14791468

@@ -1970,6 +1959,8 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types
19701959
if status == CanonStatTy {
19711960
bc.writeHeadBlock(block)
19721961
}
1962+
bc.futureBlocks.Remove(block.Hash())
1963+
19731964
if status == CanonStatTy {
19741965
bc.chainFeed.Send(ChainEvent{Block: block, Hash: block.Hash(), Logs: logs})
19751966
if len(logs) > 0 {
@@ -1998,6 +1989,25 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types
19981989
return status, nil
19991990
}
20001991

1992+
// addFutureBlock checks if the block is within the max allowed window to get
1993+
// accepted for future processing, and returns an error if the block is too far
1994+
// ahead and was not added.
1995+
//
1996+
// TODO after the transition, the future block shouldn't be kept. Because
1997+
// it's not checked in the Geth side anymore.
1998+
func (bc *BlockChain) addFutureBlock(block *types.Block) error {
1999+
max := uint64(time.Now().Unix() + maxTimeFutureBlocks)
2000+
if block.Time() > max {
2001+
return fmt.Errorf("future block timestamp %v > allowed %v", block.Time(), max)
2002+
}
2003+
if block.Difficulty().Cmp(common.Big0) == 0 {
2004+
// Never add PoS blocks into the future queue
2005+
return nil
2006+
}
2007+
bc.futureBlocks.Add(block.Hash(), block)
2008+
return nil
2009+
}
2010+
20012011
// InsertChain attempts to insert the given batch of blocks in to the canonical
20022012
// chain or, otherwise, create a fork. If an error is returned it will return
20032013
// the index number of the failing block as well an error describing what went
@@ -2152,10 +2162,26 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
21522162
_, err := bc.recoverAncestors(block)
21532163
return it.index, err
21542164
}
2165+
// First block is future, shove it (and all children) to the future queue (unknown ancestor)
2166+
case errors.Is(err, consensus.ErrFutureBlock) || (errors.Is(err, consensus.ErrUnknownAncestor) && bc.futureBlocks.Contains(it.first().ParentHash())):
2167+
for block != nil && (it.index == 0 || errors.Is(err, consensus.ErrUnknownAncestor)) {
2168+
log.Debug("Future block, postponing import", "number", block.Number(), "hash", block.Hash())
2169+
if err := bc.addFutureBlock(block); err != nil {
2170+
return it.index, err
2171+
}
2172+
block, err = it.next()
2173+
}
2174+
stats.queued += it.processed()
2175+
stats.ignored += it.remaining()
2176+
2177+
// If there are any still remaining, mark as ignored
2178+
return it.index, err
2179+
21552180
// Some other error(except ErrKnownBlock) occurred, abort.
21562181
// ErrKnownBlock is allowed here since some known blocks
21572182
// still need re-execution to generate snapshots that are missing
21582183
case err != nil && !errors.Is(err, ErrKnownBlock):
2184+
bc.futureBlocks.Remove(block.Hash())
21592185
stats.ignored += len(it.chain)
21602186
bc.reportBlock(block, nil, err)
21612187
return it.index, err
@@ -2354,7 +2380,23 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
23542380
}
23552381
bc.chainBlockFeed.Send(ChainHeadEvent{block})
23562382
}
2383+
2384+
// Any blocks remaining here? The only ones we care about are the future ones
2385+
if block != nil && errors.Is(err, consensus.ErrFutureBlock) {
2386+
if err := bc.addFutureBlock(block); err != nil {
2387+
return it.index, err
2388+
}
2389+
block, err = it.next()
2390+
2391+
for ; block != nil && errors.Is(err, consensus.ErrUnknownAncestor); block, err = it.next() {
2392+
if err := bc.addFutureBlock(block); err != nil {
2393+
return it.index, err
2394+
}
2395+
stats.queued++
2396+
}
2397+
}
23572398
stats.ignored += it.remaining()
2399+
23582400
return it.index, err
23592401
}
23602402

@@ -2833,7 +2875,6 @@ func (bc *BlockChain) SetCanonical(head *types.Block) (common.Hash, error) {
28332875
return head.Hash(), nil
28342876
}
28352877

2836-
<<<<<<< HEAD
28372878
func (bc *BlockChain) updateFutureBlocks() {
28382879
futureTimer := time.NewTicker(5 * time.Second)
28392880
defer futureTimer.Stop()
@@ -2960,8 +3001,6 @@ func (bc *BlockChain) startDoubleSignMonitor() {
29603001
}
29613002
}
29623003

2963-
=======
2964-
>>>>>>> f4d53133f (consensus, cmd, core, eth: remove support for non-merge mode of operation (#29169))
29653004
// skipBlock returns 'true', if the block being imported can be skipped over, meaning
29663005
// that the block does not need to be processed but can be considered already fully 'done'.
29673006
func (bc *BlockChain) skipBlock(err error, it *insertIterator) bool {

core/blockchain_insert.go

+5
Original file line numberDiff line numberDiff line change
@@ -187,3 +187,8 @@ func (it *insertIterator) first() *types.Block {
187187
func (it *insertIterator) remaining() int {
188188
return len(it.chain) - it.index
189189
}
190+
191+
// processed returns the number of processed blocks.
192+
func (it *insertIterator) processed() int {
193+
return it.index + 1
194+
}

0 commit comments

Comments
 (0)