Move EOF activation to Osaka

Add support for the Osaka fork and move all EOF activation and side effects to that fork.
This commit is contained in:
Danno Ferrin 2024-10-16 12:34:24 -06:00
parent 56ff85a808
commit 257e27c8ed
15 changed files with 95 additions and 23 deletions

View file

@ -32,7 +32,7 @@ import (
) )
func init() { func init() {
jt = vm.NewPragueEOFInstructionSetForTesting() jt = vm.NewOsakaEOFInstructionSetForTesting()
} }
var ( var (

View file

@ -43,7 +43,7 @@ func FuzzEofParsing(f *testing.F) {
// And do the fuzzing // And do the fuzzing
f.Fuzz(func(t *testing.T, data []byte) { f.Fuzz(func(t *testing.T, data []byte) {
var ( var (
jt = vm.NewPragueEOFInstructionSetForTesting() jt = vm.NewOsakaEOFInstructionSetForTesting()
c vm.Container c vm.Container
) )
cpy := common.CopyBytes(data) cpy := common.CopyBytes(data)

View file

@ -301,7 +301,7 @@ func applyEOFChecks(prestate *Prestate, chainConfig *params.ChainConfig) error {
) )
err = c.UnmarshalBinary(acc.Code, false) err = c.UnmarshalBinary(acc.Code, false)
if err == nil { if err == nil {
jt := vm.NewPragueEOFInstructionSetForTesting() jt := vm.NewOsakaEOFInstructionSetForTesting()
err = c.ValidateCode(&jt, false) err = c.ValidateCode(&jt, false)
} }
if err != nil { if err != nil {

View file

@ -277,6 +277,7 @@ func TestVerkleGenesisCommit(t *testing.T) {
ShanghaiTime: &verkleTime, ShanghaiTime: &verkleTime,
CancunTime: &verkleTime, CancunTime: &verkleTime,
PragueTime: &verkleTime, PragueTime: &verkleTime,
OsakaTime: &verkleTime,
VerkleTime: &verkleTime, VerkleTime: &verkleTime,
TerminalTotalDifficulty: big.NewInt(0), TerminalTotalDifficulty: big.NewInt(0),
TerminalTotalDifficultyPassed: true, TerminalTotalDifficultyPassed: true,

View file

@ -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 vmerr error // vm errors do not effect consensus and are therefore not assigned to err
) )
if contractCreation { 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 // Special case for EOF, if the initcode or deployed code is
// invalid, the tx is considered valid (so update nonce), but // invalid, the tx is considered valid (so update nonce), but
// gas for initcode execution is not consumed. // gas for initcode execution is not consumed.

View file

@ -251,7 +251,7 @@ func TestValidateCode(t *testing.T) {
data: make([]byte, 0), data: make([]byte, 0),
subContainers: make([]*Container, 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) { 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) 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() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_, err := validateCode(code, 0, container, &pragueEOFInstructionSet, false) _, err := validateCode(code, 0, container, &osakaEOFInstructionSet, false)
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
@ -309,7 +309,7 @@ func BenchmarkRJUMPV(b *testing.B) {
} }
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_, err := validateCode(code, 0, container, &pragueEOFInstructionSet, false) _, err := validateCode(code, 0, container, &osakaEOFInstructionSet, false)
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
@ -357,7 +357,7 @@ func BenchmarkEOFValidation(b *testing.B) {
if err := container2.UnmarshalBinary(bin, true); err != nil { if err := container2.UnmarshalBinary(bin, true); err != nil {
b.Fatal(err) b.Fatal(err)
} }
if err := container2.ValidateCode(&pragueEOFInstructionSet, false); err != nil { if err := container2.ValidateCode(&osakaEOFInstructionSet, false); err != nil {
b.Fatal(err) b.Fatal(err)
} }
} }
@ -412,7 +412,7 @@ func BenchmarkEOFValidation2(b *testing.B) {
if err := container2.UnmarshalBinary(bin, true); err != nil { if err := container2.UnmarshalBinary(bin, true); err != nil {
b.Fatal(err) b.Fatal(err)
} }
if err := container2.ValidateCode(&pragueEOFInstructionSet, false); err != nil { if err := container2.ValidateCode(&osakaEOFInstructionSet, false); err != nil {
b.Fatal(err) b.Fatal(err)
} }
} }
@ -468,7 +468,7 @@ func BenchmarkEOFValidation3(b *testing.B) {
if err := container2.UnmarshalBinary(bin, true); err != nil { if err := container2.UnmarshalBinary(bin, true); err != nil {
b.Fatal(err) b.Fatal(err)
} }
if err := container2.ValidateCode(&pragueEOFInstructionSet, false); err != nil { if err := container2.ValidateCode(&osakaEOFInstructionSet, false); err != nil {
b.Fatal(err) b.Fatal(err)
} }
} }
@ -494,7 +494,7 @@ func BenchmarkRJUMPI_2(b *testing.B) {
} }
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_, err := validateCode(code, 0, container, &pragueEOFInstructionSet, false) _, err := validateCode(code, 0, container, &osakaEOFInstructionSet, false)
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
@ -512,6 +512,6 @@ func FuzzValidate(f *testing.F) {
f.Fuzz(func(_ *testing.T, code []byte, maxStack uint16) { f.Fuzz(func(_ *testing.T, code []byte, maxStack uint16) {
var container Container var container Container
container.types = append(container.types, &functionMetadata{inputs: 0, outputs: 0x80, maxStackHeight: maxStack}) container.types = append(container.types, &functionMetadata{inputs: 0, outputs: 0x80, maxStackHeight: maxStack})
validateCode(code, 0, &container, &pragueEOFInstructionSet, true) validateCode(code, 0, &container, &osakaEOFInstructionSet, true)
}) })
} }

View file

@ -578,8 +578,8 @@ func (evm *EVM) initNewContract(contract *Contract, address common.Address, valu
// Reject code starting with 0xEF if EIP-3541 is enabled. // Reject code starting with 0xEF if EIP-3541 is enabled.
if len(ret) >= 1 && HasEOFByte(ret) { if len(ret) >= 1 && HasEOFByte(ret) {
if evm.chainRules.IsPrague && isInitcodeEOF { if evm.chainRules.IsOsaka && isInitcodeEOF {
// Don't reject EOF contracts after Prague // Don't reject EOF contracts after Osaka
} else if evm.chainRules.IsLondon { } else if evm.chainRules.IsLondon {
return ret, ErrInvalidCode 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. // 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 { func (evm *EVM) parseContainer(b []byte) *Container {
if evm.chainRules.IsPrague { if evm.chainRules.IsOsaka {
var c Container var c Container
if err := c.UnmarshalBinary(b, false); err != nil && strings.HasPrefix(err.Error(), "invalid magic") { if err := c.UnmarshalBinary(b, false); err != nil && strings.HasPrefix(err.Error(), "invalid magic") {
return nil return nil

View file

@ -175,7 +175,7 @@ func NewEVMInterpreter(evm *EVM) *EVMInterpreter {
} }
} }
evm.Config.ExtraEips = extraEips 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 // Run loops and evaluates the contract's code with the given input data and returns

View file

@ -60,8 +60,8 @@ var (
mergeInstructionSet = newMergeInstructionSet() mergeInstructionSet = newMergeInstructionSet()
shanghaiInstructionSet = newShanghaiInstructionSet() shanghaiInstructionSet = newShanghaiInstructionSet()
cancunInstructionSet = newCancunInstructionSet() cancunInstructionSet = newCancunInstructionSet()
osakaEOFInstructionSet = newOsakaEOFInstructionSet()
verkleInstructionSet = newVerkleInstructionSet() verkleInstructionSet = newVerkleInstructionSet()
pragueEOFInstructionSet = newPragueEOFInstructionSet()
) )
// JumpTable contains the EVM opcodes supported at a given fork. // JumpTable contains the EVM opcodes supported at a given fork.
@ -91,11 +91,11 @@ func newVerkleInstructionSet() JumpTable {
return validate(instructionSet) return validate(instructionSet)
} }
func NewPragueEOFInstructionSetForTesting() JumpTable { func NewOsakaEOFInstructionSetForTesting() JumpTable {
return newPragueEOFInstructionSet() return newOsakaEOFInstructionSet()
} }
func newPragueEOFInstructionSet() JumpTable { func newOsakaEOFInstructionSet() JumpTable {
instructionSet := newCancunInstructionSet() instructionSet := newCancunInstructionSet()
enableEOF(&instructionSet) enableEOF(&instructionSet)
return validate(instructionSet) return validate(instructionSet)

View file

@ -28,6 +28,8 @@ func LookupInstructionSet(rules params.Rules) (JumpTable, error) {
switch { switch {
case rules.IsVerkle: case rules.IsVerkle:
return newCancunInstructionSet(), errors.New("verkle-fork not defined yet") return newCancunInstructionSet(), errors.New("verkle-fork not defined yet")
case rules.IsOsaka:
return newCancunInstructionSet(), errors.New("osaka-fork not defined yet")
case rules.IsPrague: case rules.IsPrague:
return newCancunInstructionSet(), errors.New("prague-fork not defined yet") return newCancunInstructionSet(), errors.New("prague-fork not defined yet")
case rules.IsCancun: case rules.IsCancun:

View file

@ -184,7 +184,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {
input, input,
cfg.GasLimit, cfg.GasLimit,
uint256.MustFromBig(cfg.Value), uint256.MustFromBig(cfg.Value),
rules.IsPrague, rules.IsOsaka,
) )
return code, address, leftOverGas, err return code, address, leftOverGas, err
} }

View file

@ -1098,6 +1098,10 @@ func overrideConfig(original *params.ChainConfig, override *params.ChainConfig)
copy.PragueTime = timestamp copy.PragueTime = timestamp
canon = false canon = false
} }
if timestamp := override.OsakaTime; timestamp != nil {
copy.OsakaTime = timestamp
canon = false
}
if timestamp := override.VerkleTime; timestamp != nil { if timestamp := override.VerkleTime; timestamp != nil {
copy.VerkleTime = timestamp copy.VerkleTime = timestamp
canon = false canon = false

View file

@ -134,6 +134,7 @@ var (
ShanghaiTime: nil, ShanghaiTime: nil,
CancunTime: nil, CancunTime: nil,
PragueTime: nil, PragueTime: nil,
OsakaTime: nil,
VerkleTime: nil, VerkleTime: nil,
TerminalTotalDifficulty: nil, TerminalTotalDifficulty: nil,
TerminalTotalDifficultyPassed: true, TerminalTotalDifficultyPassed: true,
@ -185,6 +186,7 @@ var (
ShanghaiTime: nil, ShanghaiTime: nil,
CancunTime: nil, CancunTime: nil,
PragueTime: nil, PragueTime: nil,
OsakaTime: nil,
VerkleTime: nil, VerkleTime: nil,
TerminalTotalDifficulty: nil, TerminalTotalDifficulty: nil,
TerminalTotalDifficultyPassed: false, TerminalTotalDifficultyPassed: false,
@ -215,6 +217,7 @@ var (
ShanghaiTime: nil, ShanghaiTime: nil,
CancunTime: nil, CancunTime: nil,
PragueTime: nil, PragueTime: nil,
OsakaTime: nil,
VerkleTime: nil, VerkleTime: nil,
TerminalTotalDifficulty: nil, TerminalTotalDifficulty: nil,
TerminalTotalDifficultyPassed: false, TerminalTotalDifficultyPassed: false,
@ -245,6 +248,7 @@ var (
ShanghaiTime: newUint64(0), ShanghaiTime: newUint64(0),
CancunTime: newUint64(0), CancunTime: newUint64(0),
PragueTime: nil, PragueTime: nil,
OsakaTime: nil,
VerkleTime: nil, VerkleTime: nil,
TerminalTotalDifficulty: big.NewInt(0), TerminalTotalDifficulty: big.NewInt(0),
TerminalTotalDifficultyPassed: true, TerminalTotalDifficultyPassed: true,
@ -274,7 +278,7 @@ var (
MergeNetsplitBlock: nil, MergeNetsplitBlock: nil,
ShanghaiTime: nil, ShanghaiTime: nil,
CancunTime: nil, CancunTime: nil,
PragueTime: nil, OsakaTime: nil,
VerkleTime: nil, VerkleTime: nil,
TerminalTotalDifficulty: nil, TerminalTotalDifficulty: nil,
TerminalTotalDifficultyPassed: false, TerminalTotalDifficultyPassed: false,
@ -325,6 +329,7 @@ type ChainConfig struct {
ShanghaiTime *uint64 `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 *uint64 `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 *uint64 `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)
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) VerkleTime *uint64 `json:"verkleTime,omitempty"` // Verkle switch time (nil = no fork, 0 = already on verkle)
// TerminalTotalDifficulty is the amount of total difficulty reached by // TerminalTotalDifficulty is the amount of total difficulty reached by
@ -450,6 +455,9 @@ func (c *ChainConfig) Description() string {
if c.PragueTime != nil { if c.PragueTime != nil {
banner += fmt.Sprintf(" - Prague: @%-10v\n", *c.PragueTime) banner += fmt.Sprintf(" - Prague: @%-10v\n", *c.PragueTime)
} }
if c.OsakaTime != nil {
banner += fmt.Sprintf(" - Osaka: @%-10v\n", *c.OsakaTime)
}
if c.VerkleTime != nil { if c.VerkleTime != nil {
banner += fmt.Sprintf(" - Verkle: @%-10v\n", *c.VerkleTime) 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) 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. // IsVerkle returns whether time is either equal to the Verkle fork time or greater.
func (c *ChainConfig) IsVerkle(num *big.Int, time uint64) bool { func (c *ChainConfig) IsVerkle(num *big.Int, time uint64) bool {
return c.IsLondon(num) && isTimestampForked(c.VerkleTime, time) return c.IsLondon(num) && isTimestampForked(c.VerkleTime, time)
@ -615,6 +628,7 @@ func (c *ChainConfig) CheckConfigForkOrder() error {
{name: "shanghaiTime", timestamp: c.ShanghaiTime}, {name: "shanghaiTime", timestamp: c.ShanghaiTime},
{name: "cancunTime", timestamp: c.CancunTime, optional: true}, {name: "cancunTime", timestamp: c.CancunTime, optional: true},
{name: "pragueTime", timestamp: c.PragueTime, optional: true}, {name: "pragueTime", timestamp: c.PragueTime, optional: true},
{name: "osakaTime", timestamp: c.OsakaTime, optional: true},
{name: "verkleTime", timestamp: c.VerkleTime, optional: true}, {name: "verkleTime", timestamp: c.VerkleTime, optional: true},
} { } {
if lastFork.name != "" { if lastFork.name != "" {
@ -719,6 +733,9 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, headNumber *big.Int,
if isForkTimestampIncompatible(c.PragueTime, newcfg.PragueTime, headTimestamp) { if isForkTimestampIncompatible(c.PragueTime, newcfg.PragueTime, headTimestamp) {
return newTimestampCompatError("Prague fork timestamp", c.PragueTime, newcfg.PragueTime) 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) { if isForkTimestampIncompatible(c.VerkleTime, newcfg.VerkleTime, headTimestamp) {
return newTimestampCompatError("Verkle fork timestamp", c.VerkleTime, newcfg.VerkleTime) return newTimestampCompatError("Verkle fork timestamp", c.VerkleTime, newcfg.VerkleTime)
} }
@ -741,6 +758,8 @@ func (c *ChainConfig) LatestFork(time uint64) forks.Fork {
london := c.LondonBlock london := c.LondonBlock
switch { switch {
case c.IsOsaka(london, time):
return forks.Osaka
case c.IsPrague(london, time): case c.IsPrague(london, time):
return forks.Prague return forks.Prague
case c.IsCancun(london, time): case c.IsCancun(london, time):
@ -892,7 +911,7 @@ type Rules struct {
IsEIP2929, IsEIP4762 bool IsEIP2929, IsEIP4762 bool
IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool
IsBerlin, IsLondon bool IsBerlin, IsLondon bool
IsMerge, IsShanghai, IsCancun, IsPrague bool IsMerge, IsShanghai, IsCancun, IsPrague, IsOsaka bool
IsVerkle 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), IsShanghai: isMerge && c.IsShanghai(num, timestamp),
IsCancun: isMerge && c.IsCancun(num, timestamp), IsCancun: isMerge && c.IsCancun(num, timestamp),
IsPrague: isMerge && c.IsPrague(num, timestamp), IsPrague: isMerge && c.IsPrague(num, timestamp),
IsOsaka: isMerge && c.IsOsaka(num, timestamp),
IsVerkle: isVerkle, IsVerkle: isVerkle,
IsEIP4762: isVerkle, IsEIP4762: isVerkle,
} }

View file

@ -39,4 +39,5 @@ const (
Shanghai Shanghai
Cancun Cancun
Prague Prague
Osaka
) )

View file

@ -396,6 +396,50 @@ var Forks = map[string]*params.ChainConfig{
PragueTime: u64(15_000), PragueTime: u64(15_000),
DepositContractAddress: params.MainnetChainConfig.DepositContractAddress, 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 // AvailableForks returns the set of defined fork names