Skip to content

Commit 220454e

Browse files
authored
fix(all): critical fixes to the libevm branch (#1551)
- add missing fee config block for `params.ChainConfig` `Description` method and add test - add missing fee config block for `params.ChainConfig` `Verify` method and add test - add test for `params.SetEthUpgrades` - add comment on the usage of `params.SetEthUpgrades` in genesis
1 parent 4f496a0 commit 220454e

File tree

6 files changed

+288
-2
lines changed

6 files changed

+288
-2
lines changed

core/genesis.go

+7
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,13 @@ func SetupGenesisBlock(
184184
customrawdb.WriteChainConfig(db, stored, newcfg)
185185
return newcfg, stored, nil
186186
}
187+
188+
// Notes on the following line:
189+
// - this is needed in coreth to handle the case where existing nodes do not
190+
// have the Berlin or London forks initialized by block number on disk.
191+
// See https://github.com/ava-labs/coreth/pull/667/files
192+
// - this is not needed in subnet-evm but it does not impact it either
193+
params.SetEthUpgrades(storedcfg, params.GetExtra(storedcfg).NetworkUpgrades)
187194
// Check config compatibility and write the config. Compatibility errors
188195
// are returned to the caller unless we're already at block zero.
189196
// we use last accepted block for cfg compatibility check. Note this allows

core/genesis_extra_test.go

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// (c) 2025 Ava Labs, Inc. All rights reserved.
2+
// See the file LICENSE for licensing terms.
3+
4+
package core
5+
6+
import (
7+
"math/big"
8+
"testing"
9+
"time"
10+
11+
"github.com/ava-labs/libevm/common"
12+
"github.com/ava-labs/libevm/core/rawdb"
13+
"github.com/ava-labs/libevm/core/types"
14+
"github.com/ava-labs/libevm/triedb"
15+
"github.com/ava-labs/subnet-evm/commontype"
16+
"github.com/ava-labs/subnet-evm/params"
17+
"github.com/ava-labs/subnet-evm/params/extras"
18+
"github.com/ava-labs/subnet-evm/utils"
19+
"github.com/stretchr/testify/require"
20+
)
21+
22+
func TestGenesisEthUpgrades(t *testing.T) {
23+
db := rawdb.NewMemoryDatabase()
24+
preEthUpgrades := params.WithExtra(
25+
&params.ChainConfig{
26+
ChainID: big.NewInt(43114), // Specifically refers to mainnet for this UT
27+
HomesteadBlock: big.NewInt(0),
28+
// For this test to be a proper regression test, DAOForkBlock and
29+
// DAOForkSupport should be set to match the values in
30+
// [params.SetEthUpgrades]. Otherwise, in case of a regression, the test
31+
// would pass as there would be a mismatch at genesis, which is
32+
// incorrectly considered a success.
33+
DAOForkBlock: big.NewInt(0),
34+
DAOForkSupport: true,
35+
EIP150Block: big.NewInt(0),
36+
EIP155Block: big.NewInt(0),
37+
EIP158Block: big.NewInt(0),
38+
ByzantiumBlock: big.NewInt(0),
39+
ConstantinopleBlock: big.NewInt(0),
40+
PetersburgBlock: big.NewInt(0),
41+
IstanbulBlock: big.NewInt(0),
42+
MuirGlacierBlock: big.NewInt(0),
43+
},
44+
&extras.ChainConfig{
45+
FeeConfig: commontype.FeeConfig{
46+
MinBaseFee: big.NewInt(1),
47+
},
48+
NetworkUpgrades: extras.NetworkUpgrades{
49+
SubnetEVMTimestamp: utils.NewUint64(0),
50+
},
51+
},
52+
)
53+
tdb := triedb.NewDatabase(db, triedb.HashDefaults)
54+
config := *preEthUpgrades
55+
// Set this up once, just to get the genesis hash
56+
_, genHash, err := SetupGenesisBlock(db, tdb, &Genesis{Config: &config}, common.Hash{}, false)
57+
require.NoError(t, err)
58+
// Write the configuration back to the db as it would be in prior versions
59+
rawdb.WriteChainConfig(db, genHash, preEthUpgrades)
60+
// Make some other block
61+
block := types.NewBlock(
62+
&types.Header{
63+
Number: big.NewInt(1640340), // Berlin activation on mainnet
64+
Difficulty: big.NewInt(1),
65+
ParentHash: genHash,
66+
Time: uint64(time.Now().Unix()),
67+
},
68+
nil, nil, nil, nil,
69+
)
70+
rawdb.WriteBlock(db, block)
71+
// We should still be able to re-initialize
72+
config = *preEthUpgrades
73+
avalancheUpgrades := extras.NetworkUpgrades{}
74+
params.SetEthUpgrades(&config, avalancheUpgrades) // New versions will set additional fields eg, LondonBlock
75+
_, _, err = SetupGenesisBlock(db, tdb, &Genesis{Config: &config}, block.Hash(), false)
76+
require.NoError(t, err)
77+
}

params/extras/config.go

+13
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,15 @@ func (c *ChainConfig) Description() string {
176176
}
177177
banner += fmt.Sprintf("Upgrade Config: %s", string(upgradeConfigBytes))
178178
banner += "\n"
179+
180+
feeBytes, err := json.Marshal(c.FeeConfig)
181+
if err != nil {
182+
feeBytes = []byte("cannot marshal FeeConfig")
183+
}
184+
banner += fmt.Sprintf("Fee Config: %s\n", string(feeBytes))
185+
186+
banner += fmt.Sprintf("Allow Fee Recipients: %v\n", c.AllowFeeRecipients)
187+
179188
return banner
180189
}
181190

@@ -318,6 +327,10 @@ func checkForks(forks []fork, blockFork bool) error {
318327

319328
// Verify verifies chain config.
320329
func (c *ChainConfig) Verify() error {
330+
if err := c.FeeConfig.Verify(); err != nil {
331+
return fmt.Errorf("invalid fee config: %w", err)
332+
}
333+
321334
// Verify the precompile upgrades are internally consistent given the existing chainConfig.
322335
if err := c.verifyPrecompileUpgrades(); err != nil {
323336
return fmt.Errorf("invalid precompile upgrades: %w", err)

params/extras/config_test.go

+185
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
// (c) 2025 Ava Labs, Inc. All rights reserved.
2+
// See the file LICENSE for licensing terms.
3+
4+
package extras
5+
6+
import (
7+
"math/big"
8+
"testing"
9+
"time"
10+
11+
"github.com/ava-labs/avalanchego/snow"
12+
"github.com/ava-labs/avalanchego/upgrade"
13+
"github.com/ava-labs/libevm/common"
14+
"github.com/ava-labs/subnet-evm/commontype"
15+
"github.com/ava-labs/subnet-evm/precompile/contracts/txallowlist"
16+
"github.com/stretchr/testify/assert"
17+
"github.com/stretchr/testify/require"
18+
)
19+
20+
func pointer[T any](v T) *T { return &v }
21+
22+
func TestChainConfigDescription(t *testing.T) {
23+
t.Parallel()
24+
25+
tests := map[string]struct {
26+
config *ChainConfig
27+
wantRegex string
28+
}{
29+
"nil": {},
30+
"empty": {
31+
config: &ChainConfig{},
32+
wantRegex: `Avalanche Upgrades \(timestamp based\)\:
33+
- SubnetEVM Timestamp: ( )+@nil( )+\(https:\/\/github\.com\/ava-labs\/avalanchego\/releases\/tag\/v1\.10\.0\)
34+
( - .+Timestamp: .+\n)+
35+
Upgrade Config: {}
36+
Fee Config: {}
37+
Allow Fee Recipients: false
38+
$`,
39+
},
40+
"set": {
41+
config: &ChainConfig{
42+
NetworkUpgrades: NetworkUpgrades{
43+
SubnetEVMTimestamp: pointer(uint64(1)),
44+
DurangoTimestamp: pointer(uint64(2)),
45+
EtnaTimestamp: pointer(uint64(3)),
46+
FortunaTimestamp: pointer(uint64(4)),
47+
},
48+
FeeConfig: commontype.FeeConfig{
49+
GasLimit: big.NewInt(5),
50+
TargetBlockRate: 6,
51+
MinBaseFee: big.NewInt(7),
52+
TargetGas: big.NewInt(8),
53+
BaseFeeChangeDenominator: big.NewInt(9),
54+
MinBlockGasCost: big.NewInt(10),
55+
MaxBlockGasCost: big.NewInt(11),
56+
BlockGasCostStep: big.NewInt(12),
57+
},
58+
AllowFeeRecipients: true,
59+
UpgradeConfig: UpgradeConfig{
60+
NetworkUpgradeOverrides: &NetworkUpgrades{
61+
SubnetEVMTimestamp: pointer(uint64(13)),
62+
},
63+
StateUpgrades: []StateUpgrade{
64+
{
65+
BlockTimestamp: pointer(uint64(14)),
66+
StateUpgradeAccounts: map[common.Address]StateUpgradeAccount{
67+
common.Address{15}: {
68+
Code: []byte{16},
69+
},
70+
},
71+
},
72+
},
73+
},
74+
},
75+
wantRegex: `Avalanche Upgrades \(timestamp based\)\:
76+
- SubnetEVM Timestamp: ( )+@1( )+\(https:\/\/github\.com\/ava-labs\/avalanchego\/releases\/tag\/v1\.10\.0\)
77+
( - .+Timestamp: .+\n)+
78+
Upgrade Config: {"networkUpgradeOverrides":{"subnetEVMTimestamp":13},"stateUpgrades":\[{"blockTimestamp":14,"accounts":{"0x0f00000000000000000000000000000000000000":{"code":"0x10"}}}\]}
79+
Fee Config: {"gasLimit":5,"targetBlockRate":6,"minBaseFee":7,"targetGas":8,"baseFeeChangeDenominator":9,"minBlockGasCost":10,"maxBlockGasCost":11,"blockGasCostStep":12}
80+
Allow Fee Recipients: true
81+
$`,
82+
},
83+
}
84+
85+
for name, test := range tests {
86+
t.Run(name, func(t *testing.T) {
87+
got := test.config.Description()
88+
assert.Regexp(t, test.wantRegex, got, "config description mismatch")
89+
})
90+
}
91+
}
92+
93+
func TestChainConfigVerify(t *testing.T) {
94+
t.Parallel()
95+
96+
validFeeConfig := commontype.FeeConfig{
97+
GasLimit: big.NewInt(1),
98+
TargetBlockRate: 1,
99+
MinBaseFee: big.NewInt(1),
100+
TargetGas: big.NewInt(1),
101+
BaseFeeChangeDenominator: big.NewInt(1),
102+
MinBlockGasCost: big.NewInt(1),
103+
MaxBlockGasCost: big.NewInt(1),
104+
BlockGasCostStep: big.NewInt(1),
105+
}
106+
107+
tests := map[string]struct {
108+
config ChainConfig
109+
errRegex string
110+
}{
111+
"invalid_feeconfig": {
112+
config: ChainConfig{
113+
FeeConfig: commontype.FeeConfig{
114+
GasLimit: nil,
115+
},
116+
},
117+
errRegex: "^invalid fee config: ",
118+
},
119+
"invalid_precompile_upgrades": {
120+
// Also see precompile_config_test.go TestVerifyWithChainConfig* tests
121+
config: ChainConfig{
122+
FeeConfig: validFeeConfig,
123+
UpgradeConfig: UpgradeConfig{
124+
PrecompileUpgrades: []PrecompileUpgrade{
125+
// same precompile cannot be configured twice for the same timestamp
126+
{Config: txallowlist.NewDisableConfig(pointer(uint64(1)))},
127+
{Config: txallowlist.NewDisableConfig(pointer(uint64(1)))},
128+
},
129+
},
130+
},
131+
errRegex: "^invalid precompile upgrades: ",
132+
},
133+
"invalid_state_upgrades": {
134+
config: ChainConfig{
135+
FeeConfig: validFeeConfig,
136+
UpgradeConfig: UpgradeConfig{
137+
StateUpgrades: []StateUpgrade{
138+
{BlockTimestamp: nil},
139+
},
140+
},
141+
},
142+
errRegex: "^invalid state upgrades: ",
143+
},
144+
"invalid_network_upgrades": {
145+
config: ChainConfig{
146+
FeeConfig: validFeeConfig,
147+
NetworkUpgrades: NetworkUpgrades{
148+
SubnetEVMTimestamp: nil,
149+
},
150+
AvalancheContext: AvalancheContext{SnowCtx: &snow.Context{}},
151+
},
152+
errRegex: "^invalid network upgrades: ",
153+
},
154+
"valid": {
155+
config: ChainConfig{
156+
FeeConfig: validFeeConfig,
157+
NetworkUpgrades: NetworkUpgrades{
158+
SubnetEVMTimestamp: pointer(uint64(1)),
159+
DurangoTimestamp: pointer(uint64(2)),
160+
EtnaTimestamp: pointer(uint64(3)),
161+
FortunaTimestamp: pointer(uint64(4)),
162+
},
163+
AvalancheContext: AvalancheContext{SnowCtx: &snow.Context{
164+
NetworkUpgrades: upgrade.Config{
165+
DurangoTime: time.Unix(2, 0),
166+
EtnaTime: time.Unix(3, 0),
167+
FortunaTime: time.Unix(4, 0),
168+
},
169+
}},
170+
},
171+
},
172+
}
173+
174+
for name, test := range tests {
175+
t.Run(name, func(t *testing.T) {
176+
err := test.config.Verify()
177+
if test.errRegex == "" {
178+
assert.NoError(t, err)
179+
} else {
180+
require.Error(t, err)
181+
assert.Regexp(t, test.errRegex, err.Error())
182+
}
183+
})
184+
}
185+
}

params/extras/precompile_config_test.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,9 @@ func TestVerifyPrecompiles(t *testing.T) {
246246

247247
func TestVerifyRequiresSortedTimestamps(t *testing.T) {
248248
admins := []common.Address{{1}}
249-
config := &ChainConfig{}
249+
config := &ChainConfig{
250+
FeeConfig: DefaultFeeConfig,
251+
}
250252
config.PrecompileUpgrades = []PrecompileUpgrade{
251253
{
252254
Config: txallowlist.NewConfig(utils.NewUint64(2), admins, nil, nil),

params/extras/precompile_upgrade_test.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ import (
1616

1717
func TestVerifyUpgradeConfig(t *testing.T) {
1818
admins := []common.Address{{1}}
19-
chainConfig := &ChainConfig{}
19+
chainConfig := &ChainConfig{
20+
FeeConfig: DefaultFeeConfig,
21+
}
2022
chainConfig.GenesisPrecompiles = Precompiles{
2123
txallowlist.ConfigKey: txallowlist.NewConfig(utils.NewUint64(1), admins, nil, nil),
2224
}

0 commit comments

Comments
 (0)