Skip to content

Commit 32fde3f

Browse files
authored
core/forkid: correctly compute forkid when timestamp fork is activated in genesis (#27895)
This changes the forkID calculation to ignore time-based forks that occurred before the genesis block. It's supposed to be done this way because the spec says: > If a chain is configured to start with a non-Frontier ruleset already in its genesis, that is NOT considered a fork.
1 parent a3e3541 commit 32fde3f

File tree

10 files changed

+76
-16
lines changed

10 files changed

+76
-16
lines changed

cmd/devp2p/internal/ethtest/chain.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ func (c *Chain) RootAt(height int) common.Hash {
7777

7878
// ForkID gets the fork id of the chain.
7979
func (c *Chain) ForkID() forkid.ID {
80-
return forkid.NewID(c.chainConfig, c.blocks[0].Hash(), uint64(c.Len()), c.blocks[0].Time())
80+
return forkid.NewID(c.chainConfig, c.blocks[0], uint64(c.Len()), c.blocks[0].Time())
8181
}
8282

8383
// Shorten returns a copy chain of a desired height from the imported

core/forkid/forkid.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,9 @@ type ID struct {
7373
type Filter func(id ID) error
7474

7575
// NewID calculates the Ethereum fork ID from the chain config, genesis hash, head and time.
76-
func NewID(config *params.ChainConfig, genesis common.Hash, head, time uint64) ID {
76+
func NewID(config *params.ChainConfig, genesis *types.Block, head, time uint64) ID {
7777
// Calculate the starting checksum from the genesis hash
78-
hash := crc32.ChecksumIEEE(genesis[:])
78+
hash := crc32.ChecksumIEEE(genesis.Hash().Bytes())
7979

8080
// Calculate the current fork checksum and the next fork block
8181
forksByBlock, forksByTime := gatherForks(config)
@@ -88,6 +88,10 @@ func NewID(config *params.ChainConfig, genesis common.Hash, head, time uint64) I
8888
return ID{Hash: checksumToBytes(hash), Next: fork}
8989
}
9090
for _, fork := range forksByTime {
91+
if fork <= genesis.Time() {
92+
// Fork active in genesis, skip in forkid calculation
93+
continue
94+
}
9195
if fork <= time {
9296
// Fork already passed, checksum the previous hash and fork timestamp
9397
hash = checksumUpdate(hash, fork)
@@ -104,7 +108,7 @@ func NewIDWithChain(chain Blockchain) ID {
104108

105109
return NewID(
106110
chain.Config(),
107-
chain.Genesis().Hash(),
111+
chain.Genesis(),
108112
head.Number.Uint64(),
109113
head.Time,
110114
)

core/forkid/forkid_test.go

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,14 @@ package forkid
1818

1919
import (
2020
"bytes"
21+
"hash/crc32"
2122
"math"
23+
"math/big"
2224
"testing"
2325

2426
"github.com/ethereum/go-ethereum/common"
27+
"github.com/ethereum/go-ethereum/core"
28+
"github.com/ethereum/go-ethereum/core/types"
2529
"github.com/ethereum/go-ethereum/params"
2630
"github.com/ethereum/go-ethereum/rlp"
2731
)
@@ -36,13 +40,13 @@ func TestCreation(t *testing.T) {
3640
}
3741
tests := []struct {
3842
config *params.ChainConfig
39-
genesis common.Hash
43+
genesis *types.Block
4044
cases []testcase
4145
}{
4246
// Mainnet test cases
4347
{
4448
params.MainnetChainConfig,
45-
params.MainnetGenesisHash,
49+
core.DefaultGenesisBlock().ToBlock(),
4650
[]testcase{
4751
{0, 0, ID{Hash: checksumToBytes(0xfc64ec04), Next: 1150000}}, // Unsynced
4852
{1149999, 0, ID{Hash: checksumToBytes(0xfc64ec04), Next: 1150000}}, // Last Frontier block
@@ -77,7 +81,7 @@ func TestCreation(t *testing.T) {
7781
// Goerli test cases
7882
{
7983
params.GoerliChainConfig,
80-
params.GoerliGenesisHash,
84+
core.DefaultGoerliGenesisBlock().ToBlock(),
8185
[]testcase{
8286
{0, 0, ID{Hash: checksumToBytes(0xa3f5ab08), Next: 1561651}}, // Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople and first Petersburg block
8387
{1561650, 0, ID{Hash: checksumToBytes(0xa3f5ab08), Next: 1561651}}, // Last Petersburg block
@@ -94,7 +98,7 @@ func TestCreation(t *testing.T) {
9498
// Sepolia test cases
9599
{
96100
params.SepoliaChainConfig,
97-
params.SepoliaGenesisHash,
101+
core.DefaultSepoliaGenesisBlock().ToBlock(),
98102
[]testcase{
99103
{0, 0, ID{Hash: checksumToBytes(0xfe3366e7), Next: 1735371}}, // Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople, Petersburg, Istanbul, Berlin and first London block
100104
{1735370, 0, ID{Hash: checksumToBytes(0xfe3366e7), Next: 1735371}}, // Last London block
@@ -382,3 +386,55 @@ func TestEncoding(t *testing.T) {
382386
}
383387
}
384388
}
389+
390+
// Tests that time-based forks which are active at genesis are not included in
391+
// forkid hash.
392+
func TestTimeBasedForkInGenesis(t *testing.T) {
393+
var (
394+
time = uint64(1690475657)
395+
genesis = types.NewBlockWithHeader(&types.Header{Time: time})
396+
forkidHash = checksumToBytes(crc32.ChecksumIEEE(genesis.Hash().Bytes()))
397+
config = func(shanghai, cancun uint64) *params.ChainConfig {
398+
return &params.ChainConfig{
399+
ChainID: big.NewInt(1337),
400+
HomesteadBlock: big.NewInt(0),
401+
DAOForkBlock: nil,
402+
DAOForkSupport: true,
403+
EIP150Block: big.NewInt(0),
404+
EIP155Block: big.NewInt(0),
405+
EIP158Block: big.NewInt(0),
406+
ByzantiumBlock: big.NewInt(0),
407+
ConstantinopleBlock: big.NewInt(0),
408+
PetersburgBlock: big.NewInt(0),
409+
IstanbulBlock: big.NewInt(0),
410+
MuirGlacierBlock: big.NewInt(0),
411+
BerlinBlock: big.NewInt(0),
412+
LondonBlock: big.NewInt(0),
413+
TerminalTotalDifficulty: big.NewInt(0),
414+
TerminalTotalDifficultyPassed: true,
415+
MergeNetsplitBlock: big.NewInt(0),
416+
ShanghaiTime: &shanghai,
417+
CancunTime: &cancun,
418+
Ethash: new(params.EthashConfig),
419+
}
420+
}
421+
)
422+
tests := []struct {
423+
config *params.ChainConfig
424+
want ID
425+
}{
426+
// Shanghai active before genesis, skip
427+
{config(time-1, time+1), ID{Hash: forkidHash, Next: time + 1}},
428+
429+
// Shanghai active at genesis, skip
430+
{config(time, time+1), ID{Hash: forkidHash, Next: time + 1}},
431+
432+
// Shanghai not active, skip
433+
{config(time+1, time+2), ID{Hash: forkidHash, Next: time + 1}},
434+
}
435+
for _, tt := range tests {
436+
if have := NewID(tt.config, genesis, 0, time); have != tt.want {
437+
t.Fatalf("incorrect forkid hash: have %x, want %x", have, tt.want)
438+
}
439+
}
440+
}

eth/handler.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error {
355355
number = head.Number.Uint64()
356356
td = h.chain.GetTd(hash, number)
357357
)
358-
forkID := forkid.NewID(h.chain.Config(), genesis.Hash(), number, head.Time)
358+
forkID := forkid.NewID(h.chain.Config(), genesis, number, head.Time)
359359
if err := peer.Handshake(h.networkID, td, hash, genesis.Hash(), forkID, h.forkFilter); err != nil {
360360
peer.Log().Debug("Ethereum handshake failed", "err", err)
361361
return err

eth/protocols/eth/discovery.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,6 @@ func StartENRUpdater(chain *core.BlockChain, ln *enode.LocalNode) {
6161
func currentENREntry(chain *core.BlockChain) *enrEntry {
6262
head := chain.CurrentHeader()
6363
return &enrEntry{
64-
ForkID: forkid.NewID(chain.Config(), chain.Genesis().Hash(), head.Number.Uint64(), head.Time),
64+
ForkID: forkid.NewID(chain.Config(), chain.Genesis(), head.Number.Uint64(), head.Time),
6565
}
6666
}

eth/protocols/eth/handshake_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ func testHandshake(t *testing.T, protocol uint) {
4040
genesis = backend.chain.Genesis()
4141
head = backend.chain.CurrentBlock()
4242
td = backend.chain.GetTd(head.Hash(), head.Number.Uint64())
43-
forkID = forkid.NewID(backend.chain.Config(), backend.chain.Genesis().Hash(), backend.chain.CurrentHeader().Number.Uint64(), backend.chain.CurrentHeader().Time)
43+
forkID = forkid.NewID(backend.chain.Config(), backend.chain.Genesis(), backend.chain.CurrentHeader().Number.Uint64(), backend.chain.CurrentHeader().Time)
4444
)
4545
tests := []struct {
4646
code uint64

les/client_handler.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ func (h *clientHandler) handle(p *serverPeer, noInitAnnounce bool) error {
6969
p.Log().Debug("Light Ethereum peer connected", "name", p.Name())
7070

7171
// Execute the LES handshake
72-
forkid := forkid.NewID(h.backend.blockchain.Config(), h.backend.genesis, h.backend.blockchain.CurrentHeader().Number.Uint64(), h.backend.blockchain.CurrentHeader().Time)
72+
forkid := forkid.NewID(h.backend.blockchain.Config(), h.backend.BlockChain().Genesis(), h.backend.blockchain.CurrentHeader().Number.Uint64(), h.backend.blockchain.CurrentHeader().Time)
7373
if err := p.Handshake(h.backend.blockchain.Genesis().Hash(), forkid, h.forkFilter); err != nil {
7474
p.Log().Debug("Light Ethereum handshake failed", "err", err)
7575
return err

les/peer_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,8 @@ func TestHandshake(t *testing.T) {
124124
genesis = common.HexToHash("cafebabe")
125125

126126
chain1, chain2 = &fakeChain{}, &fakeChain{}
127-
forkID1 = forkid.NewID(chain1.Config(), chain1.Genesis().Hash(), chain1.CurrentHeader().Number.Uint64(), chain1.CurrentHeader().Time)
128-
forkID2 = forkid.NewID(chain2.Config(), chain2.Genesis().Hash(), chain2.CurrentHeader().Number.Uint64(), chain2.CurrentHeader().Time)
127+
forkID1 = forkid.NewID(chain1.Config(), chain1.Genesis(), chain1.CurrentHeader().Number.Uint64(), chain1.CurrentHeader().Time)
128+
forkID2 = forkid.NewID(chain2.Config(), chain2.Genesis(), chain2.CurrentHeader().Number.Uint64(), chain2.CurrentHeader().Time)
129129
filter1, filter2 = forkid.NewFilter(chain1), forkid.NewFilter(chain2)
130130
)
131131

les/server_handler.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ func (h *serverHandler) handle(p *clientPeer) error {
116116
hash = head.Hash()
117117
number = head.Number.Uint64()
118118
td = h.blockchain.GetTd(hash, number)
119-
forkID = forkid.NewID(h.blockchain.Config(), h.blockchain.Genesis().Hash(), number, head.Time)
119+
forkID = forkid.NewID(h.blockchain.Config(), h.blockchain.Genesis(), number, head.Time)
120120
)
121121
if err := p.Handshake(td, hash, number, h.blockchain.Genesis().Hash(), forkID, h.forkFilter, h.server); err != nil {
122122
p.Log().Debug("Light Ethereum handshake failed", "err", err)

les/test_helper.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,7 @@ func (server *testServer) newRawPeer(t *testing.T, name string, version int) (*t
499499
head = server.handler.blockchain.CurrentHeader()
500500
td = server.handler.blockchain.GetTd(head.Hash(), head.Number.Uint64())
501501
)
502-
forkID := forkid.NewID(server.handler.blockchain.Config(), genesis.Hash(), head.Number.Uint64(), head.Time)
502+
forkID := forkid.NewID(server.handler.blockchain.Config(), genesis, head.Number.Uint64(), head.Time)
503503
tp.handshakeWithServer(t, td, head.Hash(), head.Number.Uint64(), genesis.Hash(), forkID)
504504

505505
// Ensure the connection is established or exits when any error occurs

0 commit comments

Comments
 (0)