diff --git a/core/vm/contracts.go b/core/vm/contracts.go index e82d95fd7..ef2ef16d8 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -82,6 +82,41 @@ var PrecompiledContractsIstanbul = map[common.Address]PrecompiledContract{ // PrecompiledContractsBerlin contains the default set of pre-compiled Ethereum // contracts used in the Berlin release. var PrecompiledContractsBerlin = map[common.Address]PrecompiledContract{ + common.BytesToAddress([]byte{0x01}): &ecrecover{}, + common.BytesToAddress([]byte{0x02}): &sha256hash{}, + common.BytesToAddress([]byte{0x03}): &ripemd160hash{}, + common.BytesToAddress([]byte{0x04}): &dataCopy{}, + common.BytesToAddress([]byte{0x05}): &bigModExp{eip2565: true}, + common.BytesToAddress([]byte{0x06}): &bn256AddIstanbul{}, + common.BytesToAddress([]byte{0x07}): &bn256ScalarMulIstanbul{}, + common.BytesToAddress([]byte{0x08}): &bn256PairingIstanbul{}, + common.BytesToAddress([]byte{0x09}): &blake2F{}, +} + +// PrecompiledContractsPrague contains the set of pre-compiled Ethereum +// contracts activated in the Prague fork. These are exported for testing purposes. +var PrecompiledContractsPrague = map[common.Address]PrecompiledContract{ + common.BytesToAddress([]byte{0x01}): &ecrecover{}, + common.BytesToAddress([]byte{0x02}): &sha256hash{}, + common.BytesToAddress([]byte{0x03}): &ripemd160hash{}, + common.BytesToAddress([]byte{0x04}): &dataCopy{}, + common.BytesToAddress([]byte{0x05}): &bigModExp{eip2565: true}, + common.BytesToAddress([]byte{0x06}): &bn256AddIstanbul{}, + common.BytesToAddress([]byte{0x07}): &bn256ScalarMulIstanbul{}, + common.BytesToAddress([]byte{0x08}): &bn256PairingIstanbul{}, + common.BytesToAddress([]byte{0x09}): &blake2F{}, + common.BytesToAddress([]byte{0x0b}): &bls12381G1Add{}, + common.BytesToAddress([]byte{0x0c}): &bls12381G1MultiExp{}, + common.BytesToAddress([]byte{0x0d}): &bls12381G2Add{}, + common.BytesToAddress([]byte{0x0e}): &bls12381G2MultiExp{}, + common.BytesToAddress([]byte{0x0f}): &bls12381Pairing{}, + common.BytesToAddress([]byte{0x10}): &bls12381MapG1{}, + common.BytesToAddress([]byte{0x11}): &bls12381MapG2{}, +} + +// PrecompiledContractsOsaka contains the set of pre-compiled Ethereum +// contracts activated in the Osaka fork. +var PrecompiledContractsOsaka = map[common.Address]PrecompiledContract{ common.BytesToAddress([]byte{0x01}): &ecrecover{}, common.BytesToAddress([]byte{0x02}): &sha256hash{}, common.BytesToAddress([]byte{0x03}): &ripemd160hash{}, @@ -101,20 +136,10 @@ var PrecompiledContractsBerlin = map[common.Address]PrecompiledContract{ common.BytesToAddress([]byte{0x01, 0x00}): &p256Verify{}, } -// PrecompiledContractsBLS contains the set of pre-compiled Ethereum -// contracts specified in EIP-2537. These are exported for testing purposes. -var PrecompiledContractsBLS = map[common.Address]PrecompiledContract{ - common.BytesToAddress([]byte{0x0b}): &bls12381G1Add{}, - common.BytesToAddress([]byte{0x0c}): &bls12381G1MultiExp{}, - common.BytesToAddress([]byte{0x0d}): &bls12381G2Add{}, - common.BytesToAddress([]byte{0x0e}): &bls12381G2MultiExp{}, - common.BytesToAddress([]byte{0x0f}): &bls12381Pairing{}, - common.BytesToAddress([]byte{0x10}): &bls12381MapG1{}, - common.BytesToAddress([]byte{0x11}): &bls12381MapG2{}, -} - var ( PrecompiledAddressesBerlin []common.Address + PrecompiledAddressesPrague []common.Address + PrecompiledAddressesOsaka []common.Address PrecompiledAddressesIstanbul []common.Address PrecompiledAddressesByzantium []common.Address PrecompiledAddressesHomestead []common.Address @@ -133,12 +158,22 @@ func init() { for k := range PrecompiledContractsBerlin { PrecompiledAddressesBerlin = append(PrecompiledAddressesBerlin, k) } + for k := range PrecompiledContractsPrague { + PrecompiledAddressesPrague = append(PrecompiledAddressesPrague, k) + } + for k := range PrecompiledContractsOsaka { + PrecompiledAddressesOsaka = append(PrecompiledAddressesOsaka, k) + } } // ActivePrecompiles returns the precompiles enabled with the current configuration. func ActivePrecompiles(rules params.Rules) []common.Address { var result []common.Address switch { + case rules.IsOsaka: + result = PrecompiledAddressesOsaka + case rules.IsPrague: + result = PrecompiledAddressesPrague case rules.IsBerlin: result = PrecompiledAddressesBerlin case rules.IsIstanbul: @@ -148,6 +183,7 @@ func ActivePrecompiles(rules params.Rules) []common.Address { default: result = PrecompiledAddressesHomestead } + result = append([]common.Address{}, result...) if rules.IsPrivacyPrecompile { result = append(result, common.QuorumPrivacyPrecompileContractAddress()) } diff --git a/core/vm/evm.go b/core/vm/evm.go index ffdd9043b..d297fd318 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -60,6 +60,10 @@ type ( func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) { var precompiles map[common.Address]PrecompiledContract switch { + case evm.chainRules.IsOsaka: + precompiles = PrecompiledContractsOsaka + case evm.chainRules.IsPrague: + precompiles = PrecompiledContractsPrague case evm.chainRules.IsBerlin: precompiles = PrecompiledContractsBerlin case evm.chainRules.IsIstanbul: diff --git a/core/vm/evm_test.go b/core/vm/evm_test.go index 73994ff7d..038c5e1a5 100644 --- a/core/vm/evm_test.go +++ b/core/vm/evm_test.go @@ -22,6 +22,85 @@ func TestActivePrecompiles(t *testing.T) { IsPrivacyPrecompile: false, }, }, + want: []common.Address{ + common.BytesToAddress([]byte{0x01}), + common.BytesToAddress([]byte{0x02}), + common.BytesToAddress([]byte{0x03}), + common.BytesToAddress([]byte{0x04}), + common.BytesToAddress([]byte{0x05}), + common.BytesToAddress([]byte{0x06}), + common.BytesToAddress([]byte{0x07}), + common.BytesToAddress([]byte{0x08}), + common.BytesToAddress([]byte{0x09}), + }, + }, + { + name: "berlin-plus-prague", + evm: &EVM{ + chainRules: params.Rules{ + IsBerlin: true, + IsPrague: true, + IsPrivacyPrecompile: false, + }, + }, + want: []common.Address{ + common.BytesToAddress([]byte{0x01}), + common.BytesToAddress([]byte{0x02}), + common.BytesToAddress([]byte{0x03}), + common.BytesToAddress([]byte{0x04}), + common.BytesToAddress([]byte{0x05}), + common.BytesToAddress([]byte{0x06}), + common.BytesToAddress([]byte{0x07}), + common.BytesToAddress([]byte{0x08}), + common.BytesToAddress([]byte{0x09}), + common.BytesToAddress([]byte{0x0b}), + common.BytesToAddress([]byte{0x0c}), + common.BytesToAddress([]byte{0x0d}), + common.BytesToAddress([]byte{0x0e}), + common.BytesToAddress([]byte{0x0f}), + common.BytesToAddress([]byte{0x10}), + common.BytesToAddress([]byte{0x11}), + }, + }, + { + name: "berlin-plus-osaka", + evm: &EVM{ + chainRules: params.Rules{ + IsBerlin: true, + IsOsaka: true, + IsPrivacyPrecompile: false, + }, + }, + want: []common.Address{ + common.BytesToAddress([]byte{0x01}), + common.BytesToAddress([]byte{0x02}), + common.BytesToAddress([]byte{0x03}), + common.BytesToAddress([]byte{0x04}), + common.BytesToAddress([]byte{0x05}), + common.BytesToAddress([]byte{0x06}), + common.BytesToAddress([]byte{0x07}), + common.BytesToAddress([]byte{0x08}), + common.BytesToAddress([]byte{0x09}), + common.BytesToAddress([]byte{0x0b}), + common.BytesToAddress([]byte{0x0c}), + common.BytesToAddress([]byte{0x0d}), + common.BytesToAddress([]byte{0x0e}), + common.BytesToAddress([]byte{0x0f}), + common.BytesToAddress([]byte{0x10}), + common.BytesToAddress([]byte{0x11}), + common.BytesToAddress([]byte{0x01, 0x00}), + }, + }, + { + name: "berlin-plus-prague-and-osaka", + evm: &EVM{ + chainRules: params.Rules{ + IsBerlin: true, + IsPrague: true, + IsOsaka: true, + IsPrivacyPrecompile: false, + }, + }, want: []common.Address{ common.BytesToAddress([]byte{0x01}), common.BytesToAddress([]byte{0x02}), diff --git a/params/config.go b/params/config.go index b6352baca..5731d04a0 100644 --- a/params/config.go +++ b/params/config.go @@ -248,21 +248,21 @@ var ( // // This configuration is intentionally not using keyed fields to force anyone // adding flags to the config to also have to set these fields. - AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, new(EthashConfig), nil, nil, nil, nil, nil, false, 32, 35, big.NewInt(0), big.NewInt(0), nil, nil, false, nil, nil} + AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, new(EthashConfig), nil, nil, nil, nil, nil, false, 32, 35, big.NewInt(0), big.NewInt(0), nil, nil, false, nil, nil} // AllCliqueProtocolChanges contains every protocol change (EIPs) introduced // and accepted by the Ethereum core developers into the Clique consensus. // // This configuration is intentionally not using keyed fields to force anyone // adding flags to the config to also have to set these fields. - AllCliqueProtocolChanges = &ChainConfig{big.NewInt(10), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}, nil, nil, nil, nil, false, 32, 32, big.NewInt(0), big.NewInt(0), nil, nil, false, nil, nil} + AllCliqueProtocolChanges = &ChainConfig{big.NewInt(10), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}, nil, nil, nil, nil, false, 32, 32, big.NewInt(0), big.NewInt(0), nil, nil, false, nil, nil} // Quorum chainID should 10 - TestChainConfig = &ChainConfig{big.NewInt(10), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, new(EthashConfig), nil, nil, nil, nil, nil, false, 32, 32, big.NewInt(0), big.NewInt(0), nil, nil, false, nil, nil} + TestChainConfig = &ChainConfig{big.NewInt(10), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, new(EthashConfig), nil, nil, nil, nil, nil, false, 32, 32, big.NewInt(0), big.NewInt(0), nil, nil, false, nil, nil} TestRules = TestChainConfig.Rules(new(big.Int)) - QuorumTestChainConfig = &ChainConfig{big.NewInt(10), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, nil, new(EthashConfig), nil, nil, nil, nil, nil, true, 64, 32, big.NewInt(0), big.NewInt(0), nil, big.NewInt(0), false, nil, nil} - QuorumMPSTestChainConfig = &ChainConfig{big.NewInt(10), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, nil, new(EthashConfig), nil, nil, nil, nil, nil, true, 64, 32, big.NewInt(0), big.NewInt(0), nil, big.NewInt(0), true, nil, nil} + QuorumTestChainConfig = &ChainConfig{big.NewInt(10), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, nil, nil, nil, new(EthashConfig), nil, nil, nil, nil, nil, true, 64, 32, big.NewInt(0), big.NewInt(0), nil, big.NewInt(0), false, nil, nil} + QuorumMPSTestChainConfig = &ChainConfig{big.NewInt(10), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, nil, nil, nil, new(EthashConfig), nil, nil, nil, nil, nil, true, 64, 32, big.NewInt(0), big.NewInt(0), nil, big.NewInt(0), true, nil, nil} ) // TrustedCheckpoint represents a set of post-processed trie roots (CHT and @@ -344,6 +344,8 @@ type ChainConfig struct { IstanbulBlock *big.Int `json:"istanbulBlock,omitempty"` // Istanbul switch block (nil = no fork, 0 = already on istanbul) MuirGlacierBlock *big.Int `json:"muirGlacierBlock,omitempty"` // Eip-2384 (bomb delay) switch block (nil = no fork, 0 = already activated) BerlinBlock *big.Int `json:"berlinBlock,omitempty"` // Berlin switch block (nil = no fork, 0 = already on berlin) + PragueBlock *big.Int `json:"pragueBlock,omitempty"` // Prague switch block (nil = no fork, 0 = already on prague) + OsakaBlock *big.Int `json:"osakaBlock,omitempty"` // Osaka switch block (nil = no fork, 0 = already on osaka) YoloV3Block *big.Int `json:"yoloV3Block,omitempty"` // YOLO v3: Gas repricings TODO @holiman add EIP references EWASMBlock *big.Int `json:"ewasmBlock,omitempty"` // EWASM switch block (nil = no fork, 0 = already activated) @@ -486,7 +488,7 @@ func (c *ChainConfig) String() string { default: engine = "unknown" } - return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v Byzantium: %v IsQuorum: %v Constantinople: %v TransactionSizeLimit: %v MaxCodeSize: %v Petersburg: %v Istanbul: %v, Muir Glacier: %v, Berlin: %v Catalyst: %v YOLO v3: %v PrivacyEnhancements: %v PrivacyPrecompile: %v EnableGasPriceBlock: %v Engine: %v}", + return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v Byzantium: %v IsQuorum: %v Constantinople: %v TransactionSizeLimit: %v MaxCodeSize: %v Petersburg: %v Istanbul: %v, Muir Glacier: %v, Berlin: %v, Prague: %v, Osaka: %v Catalyst: %v YOLO v3: %v PrivacyEnhancements: %v PrivacyPrecompile: %v EnableGasPriceBlock: %v Engine: %v}", c.ChainID, c.HomesteadBlock, c.DAOForkBlock, @@ -503,6 +505,8 @@ func (c *ChainConfig) String() string { c.IstanbulBlock, c.MuirGlacierBlock, c.BerlinBlock, + c.PragueBlock, + c.OsakaBlock, c.CatalystBlock, c.YoloV3Block, c.PrivacyEnhancementsBlock, //Quorum @@ -582,6 +586,16 @@ func (c *ChainConfig) IsBerlin(num *big.Int) bool { return isForked(c.BerlinBlock, num) || isForked(c.YoloV3Block, num) } +// IsPrague returns whether num is either equal to the Prague fork block or greater. +func (c *ChainConfig) IsPrague(num *big.Int) bool { + return c.IsBerlin(num) && isForked(c.PragueBlock, num) +} + +// IsOsaka returns whether num is either equal to the Osaka fork block or greater. +func (c *ChainConfig) IsOsaka(num *big.Int) bool { + return c.IsPrague(num) && isForked(c.OsakaBlock, num) +} + // IsCatalyst returns whether num is either equal to the Merge fork block or greater. func (c *ChainConfig) IsCatalyst(num *big.Int) bool { return isForked(c.CatalystBlock, num) @@ -1060,6 +1074,26 @@ func (c *ChainConfig) CheckConfigForkOrder() error { lastFork = cur } } + if c.PragueBlock != nil { + if c.BerlinBlock == nil { + return fmt.Errorf("unsupported fork ordering: berlinBlock not enabled, but pragueBlock enabled at %v", + c.PragueBlock) + } + if c.BerlinBlock.Cmp(c.PragueBlock) > 0 { + return fmt.Errorf("unsupported fork ordering: berlinBlock enabled at %v, but pragueBlock enabled at %v", + c.BerlinBlock, c.PragueBlock) + } + } + if c.OsakaBlock != nil { + if c.PragueBlock == nil { + return fmt.Errorf("unsupported fork ordering: pragueBlock not enabled, but osakaBlock enabled at %v", + c.OsakaBlock) + } + if c.PragueBlock.Cmp(c.OsakaBlock) > 0 { + return fmt.Errorf("unsupported fork ordering: pragueBlock enabled at %v, but osakaBlock enabled at %v", + c.PragueBlock, c.OsakaBlock) + } + } return nil } @@ -1110,6 +1144,12 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int, isQuor if isForkIncompatible(c.BerlinBlock, newcfg.BerlinBlock, head) { return newCompatError("Berlin fork block", c.BerlinBlock, newcfg.BerlinBlock) } + if isForkIncompatible(c.PragueBlock, newcfg.PragueBlock, head) { + return newCompatError("Prague fork block", c.PragueBlock, newcfg.PragueBlock) + } + if isForkIncompatible(c.OsakaBlock, newcfg.OsakaBlock, head) { + return newCompatError("Osaka fork block", c.OsakaBlock, newcfg.OsakaBlock) + } if isForkIncompatible(c.YoloV3Block, newcfg.YoloV3Block, head) { return newCompatError("YOLOv3 fork block", c.YoloV3Block, newcfg.YoloV3Block) } @@ -1201,7 +1241,7 @@ type Rules struct { ChainID *big.Int IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool - IsBerlin, IsCatalyst bool + IsBerlin, IsPrague, IsOsaka, IsCatalyst bool // Quorum IsPrivacyEnhancementsEnabled bool IsPrivacyPrecompile bool @@ -1225,6 +1265,8 @@ func (c *ChainConfig) Rules(num *big.Int) Rules { IsPetersburg: c.IsPetersburg(num), IsIstanbul: c.IsIstanbul(num), IsBerlin: c.IsBerlin(num), + IsPrague: c.IsPrague(num), + IsOsaka: c.IsOsaka(num), IsCatalyst: c.IsCatalyst(num), // Quorum IsPrivacyEnhancementsEnabled: c.IsPrivacyEnhancementsEnabled(num), diff --git a/params/config_test.go b/params/config_test.go index 4e927cc71..33f1f015e 100644 --- a/params/config_test.go +++ b/params/config_test.go @@ -245,6 +245,40 @@ func TestCheckCompatible(t *testing.T) { head: 4, wantErr: nil, }, + { + stored: &ChainConfig{PragueBlock: big.NewInt(10)}, + new: &ChainConfig{PragueBlock: big.NewInt(20)}, + head: 4, + wantErr: nil, + }, + { + stored: &ChainConfig{PragueBlock: big.NewInt(10)}, + new: &ChainConfig{PragueBlock: big.NewInt(20)}, + head: 30, + wantErr: &ConfigCompatError{ + What: "Prague fork block", + StoredConfig: big.NewInt(10), + NewConfig: big.NewInt(20), + RewindTo: 9, + }, + }, + { + stored: &ChainConfig{OsakaBlock: big.NewInt(10)}, + new: &ChainConfig{OsakaBlock: big.NewInt(20)}, + head: 4, + wantErr: nil, + }, + { + stored: &ChainConfig{OsakaBlock: big.NewInt(10)}, + new: &ChainConfig{OsakaBlock: big.NewInt(20)}, + head: 30, + wantErr: &ConfigCompatError{ + What: "Osaka fork block", + StoredConfig: big.NewInt(10), + NewConfig: big.NewInt(20), + RewindTo: 9, + }, + }, { stored: &ChainConfig{MaxCodeSizeConfig: storedMaxCodeConfig0}, new: &ChainConfig{MaxCodeSizeConfig: nil}, @@ -324,6 +358,66 @@ func TestCheckCompatible(t *testing.T) { } } +func TestCheckConfigForkOrderPragueOsaka(t *testing.T) { + config := func(berlinBlock, pragueBlock, osakaBlock *big.Int) *ChainConfig { + cfg := *TestChainConfig + cfg.BerlinBlock = berlinBlock + cfg.PragueBlock = pragueBlock + cfg.OsakaBlock = osakaBlock + return &cfg + } + + tests := []struct { + name string + config *ChainConfig + wantErr string + }{ + { + name: "prague after berlin", + config: config(big.NewInt(10), big.NewInt(20), nil), + }, + { + name: "osaka after prague", + config: config(big.NewInt(10), big.NewInt(20), big.NewInt(30)), + }, + { + name: "prague requires berlin", + config: config(nil, big.NewInt(20), nil), + wantErr: "unsupported fork ordering: berlinBlock not enabled, but pragueBlock enabled at 20", + }, + { + name: "prague cannot precede berlin", + config: config(big.NewInt(20), big.NewInt(10), nil), + wantErr: "unsupported fork ordering: berlinBlock enabled at 20, but pragueBlock enabled at 10", + }, + { + name: "osaka requires prague", + config: config(big.NewInt(10), nil, big.NewInt(30)), + wantErr: "unsupported fork ordering: pragueBlock not enabled, but osakaBlock enabled at 30", + }, + { + name: "osaka cannot precede prague", + config: config(big.NewInt(10), big.NewInt(30), big.NewInt(20)), + wantErr: "unsupported fork ordering: pragueBlock enabled at 30, but osakaBlock enabled at 20", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.config.CheckConfigForkOrder() + if tt.wantErr == "" { + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + return + } + if err == nil || err.Error() != tt.wantErr { + t.Fatalf("error mismatch:\nerr: %v\nwant: %v", err, tt.wantErr) + } + }) + } +} + func TestCheckTransitionsData(t *testing.T) { type test struct { stored *ChainConfig @@ -523,6 +617,57 @@ func TestIsQIP714(t *testing.T) { } } +func TestIsPragueAndOsaka(t *testing.T) { + tests := []struct { + name string + config *ChainConfig + block int64 + isPrague bool + isOsaka bool + }{ + { + name: "prague requires berlin", + config: &ChainConfig{PragueBlock: big.NewInt(0)}, + block: 0, + isPrague: false, + isOsaka: false, + }, + { + name: "osaka requires prague", + config: &ChainConfig{BerlinBlock: big.NewInt(0), OsakaBlock: big.NewInt(0)}, + block: 0, + isPrague: false, + isOsaka: false, + }, + { + name: "prague active after berlin and prague blocks", + config: &ChainConfig{BerlinBlock: big.NewInt(0), PragueBlock: big.NewInt(10)}, + block: 10, + isPrague: true, + isOsaka: false, + }, + { + name: "osaka active after prague and osaka blocks", + config: &ChainConfig{BerlinBlock: big.NewInt(0), PragueBlock: big.NewInt(10), OsakaBlock: big.NewInt(20)}, + block: 20, + isPrague: true, + isOsaka: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + block := big.NewInt(tt.block) + if got := tt.config.IsPrague(block); got != tt.isPrague { + t.Fatalf("IsPrague mismatch: got %v, want %v", got, tt.isPrague) + } + if got := tt.config.IsOsaka(block); got != tt.isOsaka { + t.Fatalf("IsOsaka mismatch: got %v, want %v", got, tt.isOsaka) + } + }) + } +} + func TestIsPrivacyEnhancementsEnabled(t *testing.T) { type test struct { config *ChainConfig diff --git a/tests/fuzzers/bls12381/precompile_fuzzer.go b/tests/fuzzers/bls12381/precompile_fuzzer.go index 238531362..4fd0b91ee 100644 --- a/tests/fuzzers/bls12381/precompile_fuzzer.go +++ b/tests/fuzzers/bls12381/precompile_fuzzer.go @@ -73,7 +73,7 @@ func checkInput(id byte, inputLen int) bool { // other values are reserved for future use. func fuzz(id byte, data []byte) int { // Even on bad input, it should not crash, so we still test the gas calc - precompile := vm.PrecompiledContractsBLS[common.BytesToAddress([]byte{id})] + precompile := vm.PrecompiledContractsPrague[common.BytesToAddress([]byte{id})] gas := precompile.RequiredGas(data) if !checkInput(id, len(data)) { return 0