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() {
jt = vm.NewPragueEOFInstructionSetForTesting()
jt = vm.NewOsakaEOFInstructionSetForTesting()
}
var (

View file

@ -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)

View file

@ -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 {

View file

@ -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,

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
)
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.

View file

@ -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)
})
}

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.
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

View file

@ -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

View file

@ -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)

View file

@ -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:

View file

@ -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
}

View file

@ -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

View file

@ -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,
}

View file

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

View file

@ -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