From 257e27c8edfcc7dda319bfa32bb95715e183d930 Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Wed, 16 Oct 2024 12:34:24 -0600 Subject: [PATCH] Move EOF activation to Osaka Add support for the Osaka fork and move all EOF activation and side effects to that fork. --- cmd/evm/eofparse.go | 2 +- cmd/evm/eofparse_test.go | 2 +- cmd/evm/internal/t8ntool/transition.go | 2 +- core/genesis_test.go | 1 + core/state_transition.go | 2 +- core/vm/eof_validation_test.go | 16 +++++----- core/vm/evm.go | 6 ++-- core/vm/interpreter.go | 2 +- core/vm/jump_table.go | 8 ++--- core/vm/jump_table_export.go | 2 ++ core/vm/runtime/runtime.go | 2 +- eth/tracers/api.go | 4 +++ params/config.go | 24 ++++++++++++-- params/forks/forks.go | 1 + tests/init.go | 44 ++++++++++++++++++++++++++ 15 files changed, 95 insertions(+), 23 deletions(-) diff --git a/cmd/evm/eofparse.go b/cmd/evm/eofparse.go index 2122270942..06525672d3 100644 --- a/cmd/evm/eofparse.go +++ b/cmd/evm/eofparse.go @@ -32,7 +32,7 @@ import ( ) func init() { - jt = vm.NewPragueEOFInstructionSetForTesting() + jt = vm.NewOsakaEOFInstructionSetForTesting() } var ( diff --git a/cmd/evm/eofparse_test.go b/cmd/evm/eofparse_test.go index 9b17039f5b..d2ca38283d 100644 --- a/cmd/evm/eofparse_test.go +++ b/cmd/evm/eofparse_test.go @@ -43,7 +43,7 @@ func FuzzEofParsing(f *testing.F) { // And do the fuzzing f.Fuzz(func(t *testing.T, data []byte) { var ( - jt = vm.NewPragueEOFInstructionSetForTesting() + jt = vm.NewOsakaEOFInstructionSetForTesting() c vm.Container ) cpy := common.CopyBytes(data) diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index b1fb8e4c7c..1ce1764c37 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -301,7 +301,7 @@ func applyEOFChecks(prestate *Prestate, chainConfig *params.ChainConfig) error { ) err = c.UnmarshalBinary(acc.Code, false) if err == nil { - jt := vm.NewPragueEOFInstructionSetForTesting() + jt := vm.NewOsakaEOFInstructionSetForTesting() err = c.ValidateCode(&jt, false) } if err != nil { diff --git a/core/genesis_test.go b/core/genesis_test.go index 0fee874138..685617945b 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -277,6 +277,7 @@ func TestVerkleGenesisCommit(t *testing.T) { ShanghaiTime: &verkleTime, CancunTime: &verkleTime, PragueTime: &verkleTime, + OsakaTime: &verkleTime, VerkleTime: &verkleTime, TerminalTotalDifficulty: big.NewInt(0), TerminalTotalDifficultyPassed: true, diff --git a/core/state_transition.go b/core/state_transition.go index ad1248a574..a927fb074b 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -445,7 +445,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { vmerr error // vm errors do not effect consensus and are therefore not assigned to err ) if contractCreation { - ret, _, st.gasRemaining, vmerr = st.evm.Create(sender, msg.Data, st.gasRemaining, value, rules.IsPrague) + ret, _, st.gasRemaining, vmerr = st.evm.Create(sender, msg.Data, st.gasRemaining, value, rules.IsOsaka) // Special case for EOF, if the initcode or deployed code is // invalid, the tx is considered valid (so update nonce), but // gas for initcode execution is not consumed. diff --git a/core/vm/eof_validation_test.go b/core/vm/eof_validation_test.go index 6680ca3a5d..4ce8d6fc80 100644 --- a/core/vm/eof_validation_test.go +++ b/core/vm/eof_validation_test.go @@ -251,7 +251,7 @@ func TestValidateCode(t *testing.T) { data: make([]byte, 0), subContainers: make([]*Container, 0), } - _, err := validateCode(test.code, test.section, container, &pragueEOFInstructionSet, false) + _, err := validateCode(test.code, test.section, container, &osakaEOFInstructionSet, false) if !errors.Is(err, test.err) { t.Errorf("test %d (%s): unexpected error (want: %v, got: %v)", i, common.Bytes2Hex(test.code), test.err, err) } @@ -277,7 +277,7 @@ func BenchmarkRJUMPI(b *testing.B) { } b.ResetTimer() for i := 0; i < b.N; i++ { - _, err := validateCode(code, 0, container, &pragueEOFInstructionSet, false) + _, err := validateCode(code, 0, container, &osakaEOFInstructionSet, false) if err != nil { b.Fatal(err) } @@ -309,7 +309,7 @@ func BenchmarkRJUMPV(b *testing.B) { } b.ResetTimer() for i := 0; i < b.N; i++ { - _, err := validateCode(code, 0, container, &pragueEOFInstructionSet, false) + _, err := validateCode(code, 0, container, &osakaEOFInstructionSet, false) if err != nil { b.Fatal(err) } @@ -357,7 +357,7 @@ func BenchmarkEOFValidation(b *testing.B) { if err := container2.UnmarshalBinary(bin, true); err != nil { b.Fatal(err) } - if err := container2.ValidateCode(&pragueEOFInstructionSet, false); err != nil { + if err := container2.ValidateCode(&osakaEOFInstructionSet, false); err != nil { b.Fatal(err) } } @@ -412,7 +412,7 @@ func BenchmarkEOFValidation2(b *testing.B) { if err := container2.UnmarshalBinary(bin, true); err != nil { b.Fatal(err) } - if err := container2.ValidateCode(&pragueEOFInstructionSet, false); err != nil { + if err := container2.ValidateCode(&osakaEOFInstructionSet, false); err != nil { b.Fatal(err) } } @@ -468,7 +468,7 @@ func BenchmarkEOFValidation3(b *testing.B) { if err := container2.UnmarshalBinary(bin, true); err != nil { b.Fatal(err) } - if err := container2.ValidateCode(&pragueEOFInstructionSet, false); err != nil { + if err := container2.ValidateCode(&osakaEOFInstructionSet, false); err != nil { b.Fatal(err) } } @@ -494,7 +494,7 @@ func BenchmarkRJUMPI_2(b *testing.B) { } b.ResetTimer() for i := 0; i < b.N; i++ { - _, err := validateCode(code, 0, container, &pragueEOFInstructionSet, false) + _, err := validateCode(code, 0, container, &osakaEOFInstructionSet, false) if err != nil { b.Fatal(err) } @@ -512,6 +512,6 @@ func FuzzValidate(f *testing.F) { f.Fuzz(func(_ *testing.T, code []byte, maxStack uint16) { var container Container container.types = append(container.types, &functionMetadata{inputs: 0, outputs: 0x80, maxStackHeight: maxStack}) - validateCode(code, 0, &container, &pragueEOFInstructionSet, true) + validateCode(code, 0, &container, &osakaEOFInstructionSet, true) }) } diff --git a/core/vm/evm.go b/core/vm/evm.go index bf11ffb7a6..62e0eb61f6 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -578,8 +578,8 @@ func (evm *EVM) initNewContract(contract *Contract, address common.Address, valu // Reject code starting with 0xEF if EIP-3541 is enabled. if len(ret) >= 1 && HasEOFByte(ret) { - if evm.chainRules.IsPrague && isInitcodeEOF { - // Don't reject EOF contracts after Prague + if evm.chainRules.IsOsaka && isInitcodeEOF { + // Don't reject EOF contracts after Osaka } else if evm.chainRules.IsLondon { return ret, ErrInvalidCode } @@ -669,7 +669,7 @@ func (evm *EVM) GetVMContext() *tracing.VMContext { // parseContainer tries to parse an EOF container if the Shanghai fork is active. It expects the code to already be validated. func (evm *EVM) parseContainer(b []byte) *Container { - if evm.chainRules.IsPrague { + if evm.chainRules.IsOsaka { var c Container if err := c.UnmarshalBinary(b, false); err != nil && strings.HasPrefix(err.Error(), "invalid magic") { return nil diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 42b2483ac1..5a96c11f79 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -175,7 +175,7 @@ func NewEVMInterpreter(evm *EVM) *EVMInterpreter { } } evm.Config.ExtraEips = extraEips - return &EVMInterpreter{evm: evm, table: table, tableEOF: &pragueEOFInstructionSet} + return &EVMInterpreter{evm: evm, table: table, tableEOF: &osakaEOFInstructionSet} } // Run loops and evaluates the contract's code with the given input data and returns diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 658014f24c..45e01b4bcb 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -60,8 +60,8 @@ var ( mergeInstructionSet = newMergeInstructionSet() shanghaiInstructionSet = newShanghaiInstructionSet() cancunInstructionSet = newCancunInstructionSet() + osakaEOFInstructionSet = newOsakaEOFInstructionSet() verkleInstructionSet = newVerkleInstructionSet() - pragueEOFInstructionSet = newPragueEOFInstructionSet() ) // JumpTable contains the EVM opcodes supported at a given fork. @@ -91,11 +91,11 @@ func newVerkleInstructionSet() JumpTable { return validate(instructionSet) } -func NewPragueEOFInstructionSetForTesting() JumpTable { - return newPragueEOFInstructionSet() +func NewOsakaEOFInstructionSetForTesting() JumpTable { + return newOsakaEOFInstructionSet() } -func newPragueEOFInstructionSet() JumpTable { +func newOsakaEOFInstructionSet() JumpTable { instructionSet := newCancunInstructionSet() enableEOF(&instructionSet) return validate(instructionSet) diff --git a/core/vm/jump_table_export.go b/core/vm/jump_table_export.go index b74109da0a..731530190b 100644 --- a/core/vm/jump_table_export.go +++ b/core/vm/jump_table_export.go @@ -28,6 +28,8 @@ func LookupInstructionSet(rules params.Rules) (JumpTable, error) { switch { case rules.IsVerkle: return newCancunInstructionSet(), errors.New("verkle-fork not defined yet") + case rules.IsOsaka: + return newCancunInstructionSet(), errors.New("osaka-fork not defined yet") case rules.IsPrague: return newCancunInstructionSet(), errors.New("prague-fork not defined yet") case rules.IsCancun: diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index 84e21ef358..f68126df18 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -184,7 +184,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { input, cfg.GasLimit, uint256.MustFromBig(cfg.Value), - rules.IsPrague, + rules.IsOsaka, ) return code, address, leftOverGas, err } diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 189afa48d4..21a4864018 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -1098,6 +1098,10 @@ func overrideConfig(original *params.ChainConfig, override *params.ChainConfig) copy.PragueTime = timestamp canon = false } + if timestamp := override.OsakaTime; timestamp != nil { + copy.OsakaTime = timestamp + canon = false + } if timestamp := override.VerkleTime; timestamp != nil { copy.VerkleTime = timestamp canon = false diff --git a/params/config.go b/params/config.go index 9ecf465bb6..58716c1f2f 100644 --- a/params/config.go +++ b/params/config.go @@ -134,6 +134,7 @@ var ( ShanghaiTime: nil, CancunTime: nil, PragueTime: nil, + OsakaTime: nil, VerkleTime: nil, TerminalTotalDifficulty: nil, TerminalTotalDifficultyPassed: true, @@ -185,6 +186,7 @@ var ( ShanghaiTime: nil, CancunTime: nil, PragueTime: nil, + OsakaTime: nil, VerkleTime: nil, TerminalTotalDifficulty: nil, TerminalTotalDifficultyPassed: false, @@ -215,6 +217,7 @@ var ( ShanghaiTime: nil, CancunTime: nil, PragueTime: nil, + OsakaTime: nil, VerkleTime: nil, TerminalTotalDifficulty: nil, TerminalTotalDifficultyPassed: false, @@ -245,6 +248,7 @@ var ( ShanghaiTime: newUint64(0), CancunTime: newUint64(0), PragueTime: nil, + OsakaTime: nil, VerkleTime: nil, TerminalTotalDifficulty: big.NewInt(0), TerminalTotalDifficultyPassed: true, @@ -274,7 +278,7 @@ var ( MergeNetsplitBlock: nil, ShanghaiTime: nil, CancunTime: nil, - PragueTime: nil, + OsakaTime: nil, VerkleTime: nil, TerminalTotalDifficulty: nil, TerminalTotalDifficultyPassed: false, @@ -325,6 +329,7 @@ type ChainConfig struct { ShanghaiTime *uint64 `json:"shanghaiTime,omitempty"` // Shanghai switch time (nil = no fork, 0 = already on shanghai) CancunTime *uint64 `json:"cancunTime,omitempty"` // Cancun switch time (nil = no fork, 0 = already on cancun) PragueTime *uint64 `json:"pragueTime,omitempty"` // Prague switch time (nil = no fork, 0 = already on prague) + OsakaTime *uint64 `json:"osakaTime,omitempty"` // Osaka switch time (nil = no fork, 0 = already on osaka) VerkleTime *uint64 `json:"verkleTime,omitempty"` // Verkle switch time (nil = no fork, 0 = already on verkle) // TerminalTotalDifficulty is the amount of total difficulty reached by @@ -450,6 +455,9 @@ func (c *ChainConfig) Description() string { if c.PragueTime != nil { banner += fmt.Sprintf(" - Prague: @%-10v\n", *c.PragueTime) } + if c.OsakaTime != nil { + banner += fmt.Sprintf(" - Osaka: @%-10v\n", *c.OsakaTime) + } if c.VerkleTime != nil { banner += fmt.Sprintf(" - Verkle: @%-10v\n", *c.VerkleTime) } @@ -551,6 +559,11 @@ func (c *ChainConfig) IsPrague(num *big.Int, time uint64) bool { return c.IsLondon(num) && isTimestampForked(c.PragueTime, time) } +// IsOsaka returns whether time is either equal to the Prague fork time or greater. +func (c *ChainConfig) IsOsaka(num *big.Int, time uint64) bool { + return c.IsLondon(num) && isTimestampForked(c.OsakaTime, time) +} + // IsVerkle returns whether time is either equal to the Verkle fork time or greater. func (c *ChainConfig) IsVerkle(num *big.Int, time uint64) bool { return c.IsLondon(num) && isTimestampForked(c.VerkleTime, time) @@ -615,6 +628,7 @@ func (c *ChainConfig) CheckConfigForkOrder() error { {name: "shanghaiTime", timestamp: c.ShanghaiTime}, {name: "cancunTime", timestamp: c.CancunTime, optional: true}, {name: "pragueTime", timestamp: c.PragueTime, optional: true}, + {name: "osakaTime", timestamp: c.OsakaTime, optional: true}, {name: "verkleTime", timestamp: c.VerkleTime, optional: true}, } { if lastFork.name != "" { @@ -719,6 +733,9 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, headNumber *big.Int, if isForkTimestampIncompatible(c.PragueTime, newcfg.PragueTime, headTimestamp) { return newTimestampCompatError("Prague fork timestamp", c.PragueTime, newcfg.PragueTime) } + if isForkTimestampIncompatible(c.OsakaTime, newcfg.OsakaTime, headTimestamp) { + return newTimestampCompatError("Osaka fork timestamp", c.OsakaTime, newcfg.OsakaTime) + } if isForkTimestampIncompatible(c.VerkleTime, newcfg.VerkleTime, headTimestamp) { return newTimestampCompatError("Verkle fork timestamp", c.VerkleTime, newcfg.VerkleTime) } @@ -741,6 +758,8 @@ func (c *ChainConfig) LatestFork(time uint64) forks.Fork { london := c.LondonBlock switch { + case c.IsOsaka(london, time): + return forks.Osaka case c.IsPrague(london, time): return forks.Prague case c.IsCancun(london, time): @@ -892,7 +911,7 @@ type Rules struct { IsEIP2929, IsEIP4762 bool IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool IsBerlin, IsLondon bool - IsMerge, IsShanghai, IsCancun, IsPrague bool + IsMerge, IsShanghai, IsCancun, IsPrague, IsOsaka bool IsVerkle bool } @@ -922,6 +941,7 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp uint64) Rules IsShanghai: isMerge && c.IsShanghai(num, timestamp), IsCancun: isMerge && c.IsCancun(num, timestamp), IsPrague: isMerge && c.IsPrague(num, timestamp), + IsOsaka: isMerge && c.IsOsaka(num, timestamp), IsVerkle: isVerkle, IsEIP4762: isVerkle, } diff --git a/params/forks/forks.go b/params/forks/forks.go index 4f50ff5aed..2d44e13b04 100644 --- a/params/forks/forks.go +++ b/params/forks/forks.go @@ -39,4 +39,5 @@ const ( Shanghai Cancun Prague + Osaka ) diff --git a/tests/init.go b/tests/init.go index 4bb83f9300..8429f38e44 100644 --- a/tests/init.go +++ b/tests/init.go @@ -396,6 +396,50 @@ var Forks = map[string]*params.ChainConfig{ PragueTime: u64(15_000), DepositContractAddress: params.MainnetChainConfig.DepositContractAddress, }, + "Osaka": { + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + 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), + ArrowGlacierBlock: big.NewInt(0), + MergeNetsplitBlock: big.NewInt(0), + TerminalTotalDifficulty: big.NewInt(0), + ShanghaiTime: u64(0), + CancunTime: u64(0), + PragueTime: u64(0), + OsakaTime: u64(0), + DepositContractAddress: params.MainnetChainConfig.DepositContractAddress, + }, + "PragueToOsakaAtTime15k": { + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + 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), + ArrowGlacierBlock: big.NewInt(0), + MergeNetsplitBlock: big.NewInt(0), + TerminalTotalDifficulty: big.NewInt(0), + ShanghaiTime: u64(0), + CancunTime: u64(0), + PragueTime: u64(0), + OsakaTime: u64(15_000), + DepositContractAddress: params.MainnetChainConfig.DepositContractAddress, + }, } // AvailableForks returns the set of defined fork names