forked from cerc-io/plugeth
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.
This commit is contained in:
@@ -73,9 +73,9 @@ type ID struct {
|
||||
type Filter func(id ID) error
|
||||
|
||||
// NewID calculates the Ethereum fork ID from the chain config, genesis hash, head and time.
|
||||
func NewID(config *params.ChainConfig, genesis common.Hash, head, time uint64) ID {
|
||||
func NewID(config *params.ChainConfig, genesis *types.Block, head, time uint64) ID {
|
||||
// Calculate the starting checksum from the genesis hash
|
||||
hash := crc32.ChecksumIEEE(genesis[:])
|
||||
hash := crc32.ChecksumIEEE(genesis.Hash().Bytes())
|
||||
|
||||
// Calculate the current fork checksum and the next fork block
|
||||
forksByBlock, forksByTime := gatherForks(config)
|
||||
@@ -88,6 +88,10 @@ func NewID(config *params.ChainConfig, genesis common.Hash, head, time uint64) I
|
||||
return ID{Hash: checksumToBytes(hash), Next: fork}
|
||||
}
|
||||
for _, fork := range forksByTime {
|
||||
if fork <= genesis.Time() {
|
||||
// Fork active in genesis, skip in forkid calculation
|
||||
continue
|
||||
}
|
||||
if fork <= time {
|
||||
// Fork already passed, checksum the previous hash and fork timestamp
|
||||
hash = checksumUpdate(hash, fork)
|
||||
@@ -104,7 +108,7 @@ func NewIDWithChain(chain Blockchain) ID {
|
||||
|
||||
return NewID(
|
||||
chain.Config(),
|
||||
chain.Genesis().Hash(),
|
||||
chain.Genesis(),
|
||||
head.Number.Uint64(),
|
||||
head.Time,
|
||||
)
|
||||
|
||||
@@ -18,10 +18,14 @@ package forkid
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"hash/crc32"
|
||||
"math"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
@@ -36,13 +40,13 @@ func TestCreation(t *testing.T) {
|
||||
}
|
||||
tests := []struct {
|
||||
config *params.ChainConfig
|
||||
genesis common.Hash
|
||||
genesis *types.Block
|
||||
cases []testcase
|
||||
}{
|
||||
// Mainnet test cases
|
||||
{
|
||||
params.MainnetChainConfig,
|
||||
params.MainnetGenesisHash,
|
||||
core.DefaultGenesisBlock().ToBlock(),
|
||||
[]testcase{
|
||||
{0, 0, ID{Hash: checksumToBytes(0xfc64ec04), Next: 1150000}}, // Unsynced
|
||||
{1149999, 0, ID{Hash: checksumToBytes(0xfc64ec04), Next: 1150000}}, // Last Frontier block
|
||||
@@ -77,7 +81,7 @@ func TestCreation(t *testing.T) {
|
||||
// Goerli test cases
|
||||
{
|
||||
params.GoerliChainConfig,
|
||||
params.GoerliGenesisHash,
|
||||
core.DefaultGoerliGenesisBlock().ToBlock(),
|
||||
[]testcase{
|
||||
{0, 0, ID{Hash: checksumToBytes(0xa3f5ab08), Next: 1561651}}, // Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople and first Petersburg block
|
||||
{1561650, 0, ID{Hash: checksumToBytes(0xa3f5ab08), Next: 1561651}}, // Last Petersburg block
|
||||
@@ -94,7 +98,7 @@ func TestCreation(t *testing.T) {
|
||||
// Sepolia test cases
|
||||
{
|
||||
params.SepoliaChainConfig,
|
||||
params.SepoliaGenesisHash,
|
||||
core.DefaultSepoliaGenesisBlock().ToBlock(),
|
||||
[]testcase{
|
||||
{0, 0, ID{Hash: checksumToBytes(0xfe3366e7), Next: 1735371}}, // Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople, Petersburg, Istanbul, Berlin and first London block
|
||||
{1735370, 0, ID{Hash: checksumToBytes(0xfe3366e7), Next: 1735371}}, // Last London block
|
||||
@@ -382,3 +386,55 @@ func TestEncoding(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that time-based forks which are active at genesis are not included in
|
||||
// forkid hash.
|
||||
func TestTimeBasedForkInGenesis(t *testing.T) {
|
||||
var (
|
||||
time = uint64(1690475657)
|
||||
genesis = types.NewBlockWithHeader(&types.Header{Time: time})
|
||||
forkidHash = checksumToBytes(crc32.ChecksumIEEE(genesis.Hash().Bytes()))
|
||||
config = func(shanghai, cancun uint64) *params.ChainConfig {
|
||||
return ¶ms.ChainConfig{
|
||||
ChainID: big.NewInt(1337),
|
||||
HomesteadBlock: big.NewInt(0),
|
||||
DAOForkBlock: nil,
|
||||
DAOForkSupport: true,
|
||||
EIP150Block: big.NewInt(0),
|
||||
EIP155Block: big.NewInt(0),
|
||||
EIP158Block: big.NewInt(0),
|
||||
ByzantiumBlock: big.NewInt(0),
|
||||
ConstantinopleBlock: big.NewInt(0),
|
||||
PetersburgBlock: big.NewInt(0),
|
||||
IstanbulBlock: big.NewInt(0),
|
||||
MuirGlacierBlock: big.NewInt(0),
|
||||
BerlinBlock: big.NewInt(0),
|
||||
LondonBlock: big.NewInt(0),
|
||||
TerminalTotalDifficulty: big.NewInt(0),
|
||||
TerminalTotalDifficultyPassed: true,
|
||||
MergeNetsplitBlock: big.NewInt(0),
|
||||
ShanghaiTime: &shanghai,
|
||||
CancunTime: &cancun,
|
||||
Ethash: new(params.EthashConfig),
|
||||
}
|
||||
}
|
||||
)
|
||||
tests := []struct {
|
||||
config *params.ChainConfig
|
||||
want ID
|
||||
}{
|
||||
// Shanghai active before genesis, skip
|
||||
{config(time-1, time+1), ID{Hash: forkidHash, Next: time + 1}},
|
||||
|
||||
// Shanghai active at genesis, skip
|
||||
{config(time, time+1), ID{Hash: forkidHash, Next: time + 1}},
|
||||
|
||||
// Shanghai not active, skip
|
||||
{config(time+1, time+2), ID{Hash: forkidHash, Next: time + 1}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
if have := NewID(tt.config, genesis, 0, time); have != tt.want {
|
||||
t.Fatalf("incorrect forkid hash: have %x, want %x", have, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user