all: make timestamp-based fork checks based on uint64 (#26474)

This PR changes the API so that uint64 is used for fork timestamps.
It's a good choice because types.Header also uses uint64 for time.

Co-authored-by: Felix Lange <fjl@twurst.com>
This commit is contained in:
Martin Holst Swende 2023-01-25 06:12:28 -05:00 committed by GitHub
parent 59a48e0289
commit 2b57a27d9e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 100 additions and 82 deletions

@ -138,7 +138,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
Transfer: core.Transfer, Transfer: core.Transfer,
Coinbase: pre.Env.Coinbase, Coinbase: pre.Env.Coinbase,
BlockNumber: new(big.Int).SetUint64(pre.Env.Number), BlockNumber: new(big.Int).SetUint64(pre.Env.Number),
Time: new(big.Int).SetUint64(pre.Env.Timestamp), Time: pre.Env.Timestamp,
Difficulty: pre.Env.Difficulty, Difficulty: pre.Env.Difficulty,
GasLimit: pre.Env.GasLimit, GasLimit: pre.Env.GasLimit,
GetHash: getHash, GetHash: getHash,

@ -140,7 +140,7 @@ func Transaction(ctx *cli.Context) error {
} }
// Check intrinsic gas // Check intrinsic gas
if gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, if gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil,
chainConfig.IsHomestead(new(big.Int)), chainConfig.IsIstanbul(new(big.Int)), chainConfig.IsShanghai(new(big.Int))); err != nil { chainConfig.IsHomestead(new(big.Int)), chainConfig.IsIstanbul(new(big.Int)), chainConfig.IsShanghai(0)); err != nil {
r.Error = err r.Error = err
results = append(results, r) results = append(results, r)
continue continue
@ -172,7 +172,7 @@ func Transaction(ctx *cli.Context) error {
r.Error = errors.New("gas * maxFeePerGas exceeds 256 bits") r.Error = errors.New("gas * maxFeePerGas exceeds 256 bits")
} }
// Check whether the init code size has been exceeded. // Check whether the init code size has been exceeded.
if chainConfig.IsShanghai(new(big.Int)) && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize { if chainConfig.IsShanghai(0) && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize {
r.Error = errors.New("max initcode size exceeded") r.Error = errors.New("max initcode size exceeded")
} }
results = append(results, r) results = append(results, r)

@ -209,7 +209,7 @@ func runCmd(ctx *cli.Context) error {
GasPrice: flags.GlobalBig(ctx, PriceFlag.Name), GasPrice: flags.GlobalBig(ctx, PriceFlag.Name),
Value: flags.GlobalBig(ctx, ValueFlag.Name), Value: flags.GlobalBig(ctx, ValueFlag.Name),
Difficulty: genesisConfig.Difficulty, Difficulty: genesisConfig.Difficulty,
Time: new(big.Int).SetUint64(genesisConfig.Timestamp), Time: genesisConfig.Timestamp,
Coinbase: genesisConfig.Coinbase, Coinbase: genesisConfig.Coinbase,
BlockNumber: new(big.Int).SetUint64(genesisConfig.Number), BlockNumber: new(big.Int).SetUint64(genesisConfig.Number),
EVMConfig: vm.Config{ EVMConfig: vm.Config{

@ -159,7 +159,8 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) {
func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
stack, cfg := makeConfigNode(ctx) stack, cfg := makeConfigNode(ctx)
if ctx.IsSet(utils.OverrideShanghai.Name) { if ctx.IsSet(utils.OverrideShanghai.Name) {
cfg.Eth.OverrideShanghai = flags.GlobalBig(ctx, utils.OverrideShanghai.Name) v := ctx.Uint64(utils.OverrideShanghai.Name)
cfg.Eth.OverrideShanghai = &v
} }
backend, eth := utils.RegisterEthService(stack, &cfg.Eth) backend, eth := utils.RegisterEthService(stack, &cfg.Eth)

@ -267,7 +267,7 @@ var (
Value: 2048, Value: 2048,
Category: flags.EthCategory, Category: flags.EthCategory,
} }
OverrideShanghai = &flags.BigFlag{ OverrideShanghai = &cli.Uint64Flag{
Name: "override.shanghai", Name: "override.shanghai",
Usage: "Manually specify the Shanghai fork timestamp, overriding the bundled setting", Usage: "Manually specify the Shanghai fork timestamp, overriding the bundled setting",
Category: flags.EthCategory, Category: flags.EthCategory,

@ -4275,7 +4275,7 @@ func TestEIP3651(t *testing.T) {
gspec.Config.BerlinBlock = common.Big0 gspec.Config.BerlinBlock = common.Big0
gspec.Config.LondonBlock = common.Big0 gspec.Config.LondonBlock = common.Big0
gspec.Config.ShanghaiTime = common.Big0 gspec.Config.ShanghaiTime = u64(0)
signer := types.LatestSigner(gspec.Config) signer := types.LatestSigner(gspec.Config)
_, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) { _, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) {

@ -61,7 +61,7 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common
GetHash: GetHashFn(header, chain), GetHash: GetHashFn(header, chain),
Coinbase: beneficiary, Coinbase: beneficiary,
BlockNumber: new(big.Int).Set(header.Number), BlockNumber: new(big.Int).Set(header.Number),
Time: new(big.Int).SetUint64(header.Time), Time: header.Time,
Difficulty: new(big.Int).Set(header.Difficulty), Difficulty: new(big.Int).Set(header.Difficulty),
BaseFee: baseFee, BaseFee: baseFee,
GasLimit: header.GasLimit, GasLimit: header.GasLimit,

@ -244,7 +244,7 @@ func gatherForks(config *params.ChainConfig) ([]uint64, []uint64) {
// Gather all the fork block numbers via reflection // Gather all the fork block numbers via reflection
kind := reflect.TypeOf(params.ChainConfig{}) kind := reflect.TypeOf(params.ChainConfig{})
conf := reflect.ValueOf(config).Elem() conf := reflect.ValueOf(config).Elem()
x := uint64(0)
var ( var (
forksByBlock []uint64 forksByBlock []uint64
forksByTime []uint64 forksByTime []uint64
@ -257,15 +257,15 @@ func gatherForks(config *params.ChainConfig) ([]uint64, []uint64) {
if !time && !strings.HasSuffix(field.Name, "Block") { if !time && !strings.HasSuffix(field.Name, "Block") {
continue continue
} }
if field.Type != reflect.TypeOf(new(big.Int)) {
continue
}
// Extract the fork rule block number or timestamp and aggregate it // Extract the fork rule block number or timestamp and aggregate it
rule := conf.Field(i).Interface().(*big.Int) if field.Type == reflect.TypeOf(&x) {
if rule != nil { if rule := conf.Field(i).Interface().(*uint64); rule != nil {
if time { forksByTime = append(forksByTime, *rule)
forksByTime = append(forksByTime, rule.Uint64()) }
} else { }
if field.Type == reflect.TypeOf(new(big.Int)) {
if rule := conf.Field(i).Interface().(*big.Int); rule != nil {
forksByBlock = append(forksByBlock, rule.Uint64()) forksByBlock = append(forksByBlock, rule.Uint64())
} }
} }

@ -19,7 +19,6 @@ package forkid
import ( import (
"bytes" "bytes"
"math" "math"
"math/big"
"testing" "testing"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -27,12 +26,14 @@ import (
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
) )
func u64(val uint64) *uint64 { return &val }
// TestCreation tests that different genesis and fork rule combinations result in // TestCreation tests that different genesis and fork rule combinations result in
// the correct fork ID. // the correct fork ID.
func TestCreation(t *testing.T) { func TestCreation(t *testing.T) {
// Temporary non-existent scenario TODO(karalabe): delete when Shanghai is enabled // Temporary non-existent scenario TODO(karalabe): delete when Shanghai is enabled
timestampedConfig := *params.MainnetChainConfig timestampedConfig := *params.MainnetChainConfig
timestampedConfig.ShanghaiTime = big.NewInt(1668000000) timestampedConfig.ShanghaiTime = u64(1668000000)
type testcase struct { type testcase struct {
head uint64 head uint64
@ -201,7 +202,7 @@ func TestCreation(t *testing.T) {
func TestValidation(t *testing.T) { func TestValidation(t *testing.T) {
// Temporary non-existent scenario TODO(karalabe): delete when Shanghai is enabled // Temporary non-existent scenario TODO(karalabe): delete when Shanghai is enabled
timestampedConfig := *params.MainnetChainConfig timestampedConfig := *params.MainnetChainConfig
timestampedConfig.ShanghaiTime = big.NewInt(1668000000) timestampedConfig.ShanghaiTime = u64(1668000000)
tests := []struct { tests := []struct {
config *params.ChainConfig config *params.ChainConfig

@ -269,7 +269,7 @@ func (e *GenesisMismatchError) Error() string {
// ChainOverrides contains the changes to chain config. // ChainOverrides contains the changes to chain config.
type ChainOverrides struct { type ChainOverrides struct {
OverrideShanghai *big.Int OverrideShanghai *uint64
} }
// SetupGenesisBlock writes or updates the genesis block in db. // SetupGenesisBlock writes or updates the genesis block in db.

@ -35,6 +35,8 @@ import (
"golang.org/x/crypto/sha3" "golang.org/x/crypto/sha3"
) )
func u64(val uint64) *uint64 { return &val }
// TestStateProcessorErrors tests the output from the 'core' errors // TestStateProcessorErrors tests the output from the 'core' errors
// as defined in core/error.go. These errors are generated when the // as defined in core/error.go. These errors are generated when the
// blockchain imports bad blocks, meaning blocks which have valid headers but // blockchain imports bad blocks, meaning blocks which have valid headers but
@ -327,7 +329,7 @@ func TestStateProcessorErrors(t *testing.T) {
ArrowGlacierBlock: big.NewInt(0), ArrowGlacierBlock: big.NewInt(0),
GrayGlacierBlock: big.NewInt(0), GrayGlacierBlock: big.NewInt(0),
MergeNetsplitBlock: big.NewInt(0), MergeNetsplitBlock: big.NewInt(0),
ShanghaiTime: big.NewInt(0), ShanghaiTime: u64(0),
}, },
Alloc: GenesisAlloc{ Alloc: GenesisAlloc{
common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): GenesisAccount{ common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): GenesisAccount{

@ -1312,7 +1312,7 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) {
pool.istanbul = pool.chainconfig.IsIstanbul(next) pool.istanbul = pool.chainconfig.IsIstanbul(next)
pool.eip2718 = pool.chainconfig.IsBerlin(next) pool.eip2718 = pool.chainconfig.IsBerlin(next)
pool.eip1559 = pool.chainconfig.IsLondon(next) pool.eip1559 = pool.chainconfig.IsLondon(next)
pool.shanghai = pool.chainconfig.IsShanghai(big.NewInt(time.Now().Unix())) pool.shanghai = pool.chainconfig.IsShanghai(uint64(time.Now().Unix()))
} }
// promoteExecutables moves transactions that have become processable from the // promoteExecutables moves transactions that have become processable from the

@ -71,7 +71,7 @@ type BlockContext struct {
Coinbase common.Address // Provides information for COINBASE Coinbase common.Address // Provides information for COINBASE
GasLimit uint64 // Provides information for GASLIMIT GasLimit uint64 // Provides information for GASLIMIT
BlockNumber *big.Int // Provides information for NUMBER BlockNumber *big.Int // Provides information for NUMBER
Time *big.Int // Provides information for TIME Time uint64 // Provides information for TIME
Difficulty *big.Int // Provides information for DIFFICULTY Difficulty *big.Int // Provides information for DIFFICULTY
BaseFee *big.Int // Provides information for BASEFEE BaseFee *big.Int // Provides information for BASEFEE
Random *common.Hash // Provides information for PREVRANDAO Random *common.Hash // Provides information for PREVRANDAO

@ -460,8 +460,7 @@ func opCoinbase(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
} }
func opTimestamp(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func opTimestamp(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
v, _ := uint256.FromBig(interpreter.evm.Context.Time) scope.Stack.push(new(uint256.Int).SetUint64(interpreter.evm.Context.Time))
scope.Stack.push(v)
return nil, nil return nil, nil
} }

@ -19,7 +19,6 @@ package runtime
import ( import (
"math" "math"
"math/big" "math/big"
"time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
@ -37,7 +36,7 @@ type Config struct {
Origin common.Address Origin common.Address
Coinbase common.Address Coinbase common.Address
BlockNumber *big.Int BlockNumber *big.Int
Time *big.Int Time uint64
GasLimit uint64 GasLimit uint64
GasPrice *big.Int GasPrice *big.Int
Value *big.Int Value *big.Int
@ -74,9 +73,6 @@ func setDefaults(cfg *Config) {
if cfg.Difficulty == nil { if cfg.Difficulty == nil {
cfg.Difficulty = new(big.Int) cfg.Difficulty = new(big.Int)
} }
if cfg.Time == nil {
cfg.Time = big.NewInt(time.Now().Unix())
}
if cfg.GasLimit == 0 { if cfg.GasLimit == 0 {
cfg.GasLimit = math.MaxUint64 cfg.GasLimit = math.MaxUint64
} }

@ -48,9 +48,6 @@ func TestDefaults(t *testing.T) {
t.Error("expected difficulty to be non nil") t.Error("expected difficulty to be non nil")
} }
if cfg.Time == nil {
t.Error("expected time to be non nil")
}
if cfg.GasLimit == 0 { if cfg.GasLimit == 0 {
t.Error("didn't expect gaslimit to be zero") t.Error("didn't expect gaslimit to be zero")
} }
@ -174,7 +171,7 @@ func benchmarkEVM_Create(bench *testing.B, code string) {
State: statedb, State: statedb,
GasLimit: 10000000, GasLimit: 10000000,
Difficulty: big.NewInt(0x200000), Difficulty: big.NewInt(0x200000),
Time: new(big.Int).SetUint64(0), Time: 0,
Coinbase: common.Address{}, Coinbase: common.Address{},
BlockNumber: new(big.Int).SetUint64(1), BlockNumber: new(big.Int).SetUint64(1),
ChainConfig: &params.ChainConfig{ ChainConfig: &params.ChainConfig{

@ -18,7 +18,6 @@
package ethconfig package ethconfig
import ( import (
"math/big"
"os" "os"
"os/user" "os/user"
"path/filepath" "path/filepath"
@ -207,7 +206,7 @@ type Config struct {
CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"`
// OverrideShanghai (TODO: remove after the fork) // OverrideShanghai (TODO: remove after the fork)
OverrideShanghai *big.Int `toml:",omitempty"` OverrideShanghai *uint64 `toml:",omitempty"`
} }
// CreateConsensusEngine creates a consensus engine for the given chain configuration. // CreateConsensusEngine creates a consensus engine for the given chain configuration.

@ -3,7 +3,6 @@
package ethconfig package ethconfig
import ( import (
"math/big"
"time" "time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -61,7 +60,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
RPCTxFeeCap float64 RPCTxFeeCap float64
Checkpoint *params.TrustedCheckpoint `toml:",omitempty"` Checkpoint *params.TrustedCheckpoint `toml:",omitempty"`
CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"`
OverrideShanghai *big.Int `toml:",omitempty"` OverrideShanghai *uint64 `toml:",omitempty"`
} }
var enc Config var enc Config
enc.Genesis = c.Genesis enc.Genesis = c.Genesis
@ -155,7 +154,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
RPCTxFeeCap *float64 RPCTxFeeCap *float64
Checkpoint *params.TrustedCheckpoint `toml:",omitempty"` Checkpoint *params.TrustedCheckpoint `toml:",omitempty"`
CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"`
OverrideShanghai *big.Int `toml:",omitempty"` OverrideShanghai *uint64 `toml:",omitempty"`
} }
var dec Config var dec Config
if err := unmarshal(&dec); err != nil { if err := unmarshal(&dec); err != nil {

@ -133,7 +133,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
Transfer: core.Transfer, Transfer: core.Transfer,
Coinbase: test.Context.Miner, Coinbase: test.Context.Miner,
BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)), BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)),
Time: new(big.Int).SetUint64(uint64(test.Context.Time)), Time: uint64(test.Context.Time),
Difficulty: (*big.Int)(test.Context.Difficulty), Difficulty: (*big.Int)(test.Context.Difficulty),
GasLimit: uint64(test.Context.GasLimit), GasLimit: uint64(test.Context.GasLimit),
BaseFee: test.Genesis.BaseFee, BaseFee: test.Genesis.BaseFee,
@ -234,7 +234,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
Transfer: core.Transfer, Transfer: core.Transfer,
Coinbase: test.Context.Miner, Coinbase: test.Context.Miner,
BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)), BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)),
Time: new(big.Int).SetUint64(uint64(test.Context.Time)), Time: uint64(test.Context.Time),
Difficulty: (*big.Int)(test.Context.Difficulty), Difficulty: (*big.Int)(test.Context.Difficulty),
GasLimit: uint64(test.Context.GasLimit), GasLimit: uint64(test.Context.GasLimit),
} }
@ -288,7 +288,7 @@ func TestZeroValueToNotExitCall(t *testing.T) {
Transfer: core.Transfer, Transfer: core.Transfer,
Coinbase: common.Address{}, Coinbase: common.Address{},
BlockNumber: new(big.Int).SetUint64(8000000), BlockNumber: new(big.Int).SetUint64(8000000),
Time: new(big.Int).SetUint64(5), Time: 5,
Difficulty: big.NewInt(0x30000), Difficulty: big.NewInt(0x30000),
GasLimit: uint64(6000000), GasLimit: uint64(6000000),
} }

@ -103,7 +103,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) {
Transfer: core.Transfer, Transfer: core.Transfer,
Coinbase: test.Context.Miner, Coinbase: test.Context.Miner,
BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)), BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)),
Time: new(big.Int).SetUint64(uint64(test.Context.Time)), Time: uint64(test.Context.Time),
Difficulty: (*big.Int)(test.Context.Difficulty), Difficulty: (*big.Int)(test.Context.Difficulty),
GasLimit: uint64(test.Context.GasLimit), GasLimit: uint64(test.Context.GasLimit),
BaseFee: test.Genesis.BaseFee, BaseFee: test.Genesis.BaseFee,

@ -56,7 +56,7 @@ func BenchmarkTransactionTrace(b *testing.B) {
Transfer: core.Transfer, Transfer: core.Transfer,
Coinbase: common.Address{}, Coinbase: common.Address{},
BlockNumber: new(big.Int).SetUint64(uint64(5)), BlockNumber: new(big.Int).SetUint64(uint64(5)),
Time: new(big.Int).SetUint64(uint64(5)), Time: 5,
Difficulty: big.NewInt(0xffffffff), Difficulty: big.NewInt(0xffffffff),
GasLimit: gas, GasLimit: gas,
BaseFee: big.NewInt(8), BaseFee: big.NewInt(8),

@ -920,7 +920,7 @@ func (diff *StateOverride) Apply(state *state.StateDB) error {
type BlockOverrides struct { type BlockOverrides struct {
Number *hexutil.Big Number *hexutil.Big
Difficulty *hexutil.Big Difficulty *hexutil.Big
Time *hexutil.Big Time *hexutil.Uint64
GasLimit *hexutil.Uint64 GasLimit *hexutil.Uint64
Coinbase *common.Address Coinbase *common.Address
Random *common.Hash Random *common.Hash
@ -939,7 +939,7 @@ func (diff *BlockOverrides) Apply(blockCtx *vm.BlockContext) {
blockCtx.Difficulty = diff.Difficulty.ToInt() blockCtx.Difficulty = diff.Difficulty.ToInt()
} }
if diff.Time != nil { if diff.Time != nil {
blockCtx.Time = diff.Time.ToInt() blockCtx.Time = uint64(*diff.Time)
} }
if diff.GasLimit != nil { if diff.GasLimit != nil {
blockCtx.GasLimit = uint64(*diff.GasLimit) blockCtx.GasLimit = uint64(*diff.GasLimit)
@ -1444,7 +1444,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH
} }
isPostMerge := header.Difficulty.Cmp(common.Big0) == 0 isPostMerge := header.Difficulty.Cmp(common.Big0) == 0
// Retrieve the precompiles since they don't need to be added to the access list // Retrieve the precompiles since they don't need to be added to the access list
precompiles := vm.ActivePrecompiles(b.ChainConfig().Rules(header.Number, isPostMerge, new(big.Int).SetUint64(header.Time))) precompiles := vm.ActivePrecompiles(b.ChainConfig().Rules(header.Number, isPostMerge, header.Time))
// Create an initial tracer // Create an initial tracer
prevTracer := logger.NewAccessListTracer(nil, args.from(), to, precompiles) prevTracer := logger.NewAccessListTracer(nil, args.from(), to, precompiles)

@ -318,7 +318,7 @@ func (pool *TxPool) setNewHead(head *types.Header) {
next := new(big.Int).Add(head.Number, big.NewInt(1)) next := new(big.Int).Add(head.Number, big.NewInt(1))
pool.istanbul = pool.config.IsIstanbul(next) pool.istanbul = pool.config.IsIstanbul(next)
pool.eip2718 = pool.config.IsBerlin(next) pool.eip2718 = pool.config.IsBerlin(next)
pool.shanghai = pool.config.IsShanghai(big.NewInt(time.Now().Unix())) pool.shanghai = pool.config.IsShanghai(uint64(time.Now().Unix()))
} }
// Stop stops the light transaction pool // Stop stops the light transaction pool

@ -383,7 +383,7 @@ var (
Ethash: new(EthashConfig), Ethash: new(EthashConfig),
Clique: nil, Clique: nil,
} }
TestRules = TestChainConfig.Rules(new(big.Int), false, new(big.Int)) TestRules = TestChainConfig.Rules(new(big.Int), false, 0)
) )
// NetworkNames are user friendly names to use in the chain spec banner. // NetworkNames are user friendly names to use in the chain spec banner.
@ -476,9 +476,9 @@ type ChainConfig struct {
// Fork scheduling was switched from blocks to timestamps here // Fork scheduling was switched from blocks to timestamps here
ShanghaiTime *big.Int `json:"shanghaiTime,omitempty"` // Shanghai switch time (nil = no fork, 0 = already on shanghai) ShanghaiTime *uint64 `json:"shanghaiTime,omitempty"` // Shanghai switch time (nil = no fork, 0 = already on shanghai)
CancunTime *big.Int `json:"cancunTime,omitempty"` // Cancun switch time (nil = no fork, 0 = already on cancun) CancunTime *uint64 `json:"cancunTime,omitempty"` // Cancun switch time (nil = no fork, 0 = already on cancun)
PragueTime *big.Int `json:"pragueTime,omitempty"` // Prague switch time (nil = no fork, 0 = already on prague) PragueTime *uint64 `json:"pragueTime,omitempty"` // Prague switch time (nil = no fork, 0 = already on prague)
// TerminalTotalDifficulty is the amount of total difficulty reached by // TerminalTotalDifficulty is the amount of total difficulty reached by
// the network that triggers the consensus upgrade. // the network that triggers the consensus upgrade.
@ -683,17 +683,17 @@ func (c *ChainConfig) IsTerminalPoWBlock(parentTotalDiff *big.Int, totalDiff *bi
} }
// IsShanghai returns whether time is either equal to the Shanghai fork time or greater. // IsShanghai returns whether time is either equal to the Shanghai fork time or greater.
func (c *ChainConfig) IsShanghai(time *big.Int) bool { func (c *ChainConfig) IsShanghai(time uint64) bool {
return isTimestampForked(c.ShanghaiTime, time) return isTimestampForked(c.ShanghaiTime, time)
} }
// IsCancun returns whether num is either equal to the Cancun fork time or greater. // IsCancun returns whether num is either equal to the Cancun fork time or greater.
func (c *ChainConfig) IsCancun(time *big.Int) bool { func (c *ChainConfig) IsCancun(time uint64) bool {
return isTimestampForked(c.CancunTime, time) return isTimestampForked(c.CancunTime, time)
} }
// IsPrague returns whether num is either equal to the Prague fork time or greater. // IsPrague returns whether num is either equal to the Prague fork time or greater.
func (c *ChainConfig) IsPrague(time *big.Int) bool { func (c *ChainConfig) IsPrague(time uint64) bool {
return isTimestampForked(c.PragueTime, time) return isTimestampForked(c.PragueTime, time)
} }
@ -702,7 +702,7 @@ func (c *ChainConfig) IsPrague(time *big.Int) bool {
func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64, time uint64) *ConfigCompatError { func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64, time uint64) *ConfigCompatError {
var ( var (
bhead = new(big.Int).SetUint64(height) bhead = new(big.Int).SetUint64(height)
btime = new(big.Int).SetUint64(time) btime = time
) )
// Iterate checkCompatible to find the lowest conflict. // Iterate checkCompatible to find the lowest conflict.
var lasterr *ConfigCompatError var lasterr *ConfigCompatError
@ -714,7 +714,7 @@ func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64, time u
lasterr = err lasterr = err
if err.RewindToTime > 0 { if err.RewindToTime > 0 {
btime.SetUint64(err.RewindToTime) btime = err.RewindToTime
} else { } else {
bhead.SetUint64(err.RewindToBlock) bhead.SetUint64(err.RewindToBlock)
} }
@ -728,7 +728,7 @@ func (c *ChainConfig) CheckConfigForkOrder() error {
type fork struct { type fork struct {
name string name string
block *big.Int // forks up to - and including the merge - were defined with block numbers block *big.Int // forks up to - and including the merge - were defined with block numbers
timestamp *big.Int // forks after the merge are scheduled using timestamps timestamp *uint64 // forks after the merge are scheduled using timestamps
optional bool // if true, the fork may be nil and next fork is still allowed optional bool // if true, the fork may be nil and next fork is still allowed
} }
var lastFork fork var lastFork fork
@ -769,7 +769,7 @@ func (c *ChainConfig) CheckConfigForkOrder() error {
if lastFork.block != nil && lastFork.block.Cmp(cur.block) > 0 { if lastFork.block != nil && lastFork.block.Cmp(cur.block) > 0 {
return fmt.Errorf("unsupported fork ordering: %v enabled at block %v, but %v enabled at block %v", return fmt.Errorf("unsupported fork ordering: %v enabled at block %v, but %v enabled at block %v",
lastFork.name, lastFork.block, cur.name, cur.block) lastFork.name, lastFork.block, cur.name, cur.block)
} else if lastFork.timestamp != nil && lastFork.timestamp.Cmp(cur.timestamp) > 0 { } else if lastFork.timestamp != nil && *lastFork.timestamp > *cur.timestamp {
return fmt.Errorf("unsupported fork ordering: %v enabled at timestamp %v, but %v enabled at timestamp %v", return fmt.Errorf("unsupported fork ordering: %v enabled at timestamp %v, but %v enabled at timestamp %v",
lastFork.name, lastFork.timestamp, cur.name, cur.timestamp) lastFork.name, lastFork.timestamp, cur.name, cur.timestamp)
} }
@ -789,7 +789,7 @@ func (c *ChainConfig) CheckConfigForkOrder() error {
return nil return nil
} }
func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, headNumber *big.Int, headTimestamp *big.Int) *ConfigCompatError { func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, headNumber *big.Int, headTimestamp uint64) *ConfigCompatError {
if isForkBlockIncompatible(c.HomesteadBlock, newcfg.HomesteadBlock, headNumber) { if isForkBlockIncompatible(c.HomesteadBlock, newcfg.HomesteadBlock, headNumber) {
return newBlockCompatError("Homestead fork block", c.HomesteadBlock, newcfg.HomesteadBlock) return newBlockCompatError("Homestead fork block", c.HomesteadBlock, newcfg.HomesteadBlock)
} }
@ -895,28 +895,28 @@ func configBlockEqual(x, y *big.Int) bool {
// isForkTimestampIncompatible returns true if a fork scheduled at timestamp s1 // isForkTimestampIncompatible returns true if a fork scheduled at timestamp s1
// cannot be rescheduled to timestamp s2 because head is already past the fork. // cannot be rescheduled to timestamp s2 because head is already past the fork.
func isForkTimestampIncompatible(s1, s2, head *big.Int) bool { func isForkTimestampIncompatible(s1, s2 *uint64, head uint64) bool {
return (isTimestampForked(s1, head) || isTimestampForked(s2, head)) && !configTimestampEqual(s1, s2) return (isTimestampForked(s1, head) || isTimestampForked(s2, head)) && !configTimestampEqual(s1, s2)
} }
// isTimestampForked returns whether a fork scheduled at timestamp s is active // isTimestampForked returns whether a fork scheduled at timestamp s is active
// at the given head timestamp. Whilst this method is the same as isBlockForked, // at the given head timestamp. Whilst this method is the same as isBlockForked,
// they are explicitly separate for clearer reading. // they are explicitly separate for clearer reading.
func isTimestampForked(s, head *big.Int) bool { func isTimestampForked(s *uint64, head uint64) bool {
if s == nil || head == nil { if s == nil {
return false return false
} }
return s.Cmp(head) <= 0 return *s <= head
} }
func configTimestampEqual(x, y *big.Int) bool { func configTimestampEqual(x, y *uint64) bool {
if x == nil { if x == nil {
return y == nil return y == nil
} }
if y == nil { if y == nil {
return x == nil return x == nil
} }
return x.Cmp(y) == 0 return *x == *y
} }
// ConfigCompatError is raised if the locally-stored blockchain is initialised with a // ConfigCompatError is raised if the locally-stored blockchain is initialised with a
@ -928,7 +928,7 @@ type ConfigCompatError struct {
StoredBlock, NewBlock *big.Int StoredBlock, NewBlock *big.Int
// timestamps of the stored and new configurations if time based forking // timestamps of the stored and new configurations if time based forking
StoredTime, NewTime *big.Int StoredTime, NewTime *uint64
// the block number to which the local chain must be rewound to correct the error // the block number to which the local chain must be rewound to correct the error
RewindToBlock uint64 RewindToBlock uint64
@ -959,12 +959,12 @@ func newBlockCompatError(what string, storedblock, newblock *big.Int) *ConfigCom
return err return err
} }
func newTimestampCompatError(what string, storedtime, newtime *big.Int) *ConfigCompatError { func newTimestampCompatError(what string, storedtime, newtime *uint64) *ConfigCompatError {
var rew *big.Int var rew *uint64
switch { switch {
case storedtime == nil: case storedtime == nil:
rew = newtime rew = newtime
case newtime == nil || storedtime.Cmp(newtime) < 0: case newtime == nil || *storedtime < *newtime:
rew = storedtime rew = storedtime
default: default:
rew = newtime rew = newtime
@ -975,8 +975,8 @@ func newTimestampCompatError(what string, storedtime, newtime *big.Int) *ConfigC
NewTime: newtime, NewTime: newtime,
RewindToTime: 0, RewindToTime: 0,
} }
if rew != nil && rew.Sign() > 0 { if rew != nil {
err.RewindToTime = rew.Uint64() - 1 err.RewindToTime = *rew - 1
} }
return err return err
} }
@ -1002,7 +1002,7 @@ type Rules struct {
} }
// Rules ensures c's ChainID is not nil. // Rules ensures c's ChainID is not nil.
func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp *big.Int) Rules { func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp uint64) Rules {
chainID := c.ChainID chainID := c.ChainID
if chainID == nil { if chainID == nil {
chainID = new(big.Int) chainID = new(big.Int)

@ -21,8 +21,12 @@ import (
"reflect" "reflect"
"testing" "testing"
"time" "time"
"github.com/ethereum/go-ethereum/common/math"
) )
func u64(val uint64) *uint64 { return &val }
func TestCheckCompatible(t *testing.T) { func TestCheckCompatible(t *testing.T) {
type test struct { type test struct {
stored, new *ChainConfig stored, new *ChainConfig
@ -91,19 +95,19 @@ func TestCheckCompatible(t *testing.T) {
}, },
}, },
{ {
stored: &ChainConfig{ShanghaiTime: big.NewInt(10)}, stored: &ChainConfig{ShanghaiTime: u64(10)},
new: &ChainConfig{ShanghaiTime: big.NewInt(20)}, new: &ChainConfig{ShanghaiTime: u64(20)},
headTimestamp: 9, headTimestamp: 9,
wantErr: nil, wantErr: nil,
}, },
{ {
stored: &ChainConfig{ShanghaiTime: big.NewInt(10)}, stored: &ChainConfig{ShanghaiTime: u64(10)},
new: &ChainConfig{ShanghaiTime: big.NewInt(20)}, new: &ChainConfig{ShanghaiTime: u64(20)},
headTimestamp: 25, headTimestamp: 25,
wantErr: &ConfigCompatError{ wantErr: &ConfigCompatError{
What: "Shanghai fork timestamp", What: "Shanghai fork timestamp",
StoredTime: big.NewInt(10), StoredTime: u64(10),
NewTime: big.NewInt(20), NewTime: u64(20),
RewindToTime: 9, RewindToTime: 9,
}, },
}, },
@ -116,3 +120,21 @@ func TestCheckCompatible(t *testing.T) {
} }
} }
} }
func TestConfigRules(t *testing.T) {
c := &ChainConfig{
ShanghaiTime: u64(500),
}
var stamp uint64
if r := c.Rules(big.NewInt(0), true, stamp); r.IsShanghai {
t.Errorf("expected %v to not be shanghai", stamp)
}
stamp = 500
if r := c.Rules(big.NewInt(0), true, stamp); !r.IsShanghai {
t.Errorf("expected %v to be shanghai", stamp)
}
stamp = math.MaxInt64
if r := c.Rules(big.NewInt(0), true, stamp); !r.IsShanghai {
t.Errorf("expected %v to be shanghai", stamp)
}
}

@ -24,6 +24,8 @@ import (
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
func u64(val uint64) *uint64 { return &val }
// Forks table defines supported forks and their chain config. // Forks table defines supported forks and their chain config.
var Forks = map[string]*params.ChainConfig{ var Forks = map[string]*params.ChainConfig{
"Frontier": { "Frontier": {
@ -264,7 +266,7 @@ var Forks = map[string]*params.ChainConfig{
ArrowGlacierBlock: big.NewInt(0), ArrowGlacierBlock: big.NewInt(0),
MergeNetsplitBlock: big.NewInt(0), MergeNetsplitBlock: big.NewInt(0),
TerminalTotalDifficulty: big.NewInt(0), TerminalTotalDifficulty: big.NewInt(0),
ShanghaiTime: big.NewInt(0), ShanghaiTime: u64(0),
}, },
} }

@ -183,7 +183,7 @@ func runBenchmark(b *testing.B, t *StateTest) {
b.Error(err) b.Error(err)
return return
} }
var rules = config.Rules(new(big.Int), false, new(big.Int)) var rules = config.Rules(new(big.Int), false, 0)
vmconfig.ExtraEips = eips vmconfig.ExtraEips = eips
block := t.genesis(config).ToBlock() block := t.genesis(config).ToBlock()