-
Notifications
You must be signed in to change notification settings - Fork 149
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
2dd2fb5
commit 3d2037f
Showing
6 changed files
with
237 additions
and
67 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
// (c) 2025, Ava Labs, Inc. All rights reserved. | ||
// See the file LICENSE for licensing terms. | ||
|
||
package header | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
|
||
"github.com/ava-labs/avalanchego/utils/math" | ||
"github.com/ava-labs/coreth/core/types" | ||
"github.com/ava-labs/coreth/params" | ||
"github.com/ava-labs/coreth/plugin/evm/upgrade/ap1" | ||
"github.com/ava-labs/coreth/plugin/evm/upgrade/cortina" | ||
) | ||
|
||
var errInvalidGasLimit = errors.New("invalid gas limit") | ||
|
||
// GasLimit takes the previous header and the timestamp of its child block and | ||
// calculates the gas limit for the child block. | ||
func GasLimit( | ||
config *params.ChainConfig, | ||
parent *types.Header, | ||
timestamp uint64, | ||
) uint64 { | ||
switch { | ||
case config.IsCortina(timestamp): | ||
return cortina.GasLimit | ||
case config.IsApricotPhase1(timestamp): | ||
return ap1.GasLimit | ||
default: | ||
// The gas limit prior Apricot Phase 1 started at the genesis value and | ||
// migrated towards the [ap1.GasLimit] following the `core.CalcGasLimit` | ||
// updates. However, since all chains have activated Apricot Phase 1, | ||
// this code is not used in production. To avoid a dependency on the | ||
// `core` package, this code is modified to just return the parent gas | ||
// limit; which was valid to do prior to Apricot Phase 1. | ||
return parent.GasLimit | ||
} | ||
} | ||
|
||
// VerifyGasLimit verifies that the gas limit for the header is valid. | ||
func VerifyGasLimit( | ||
config *params.ChainConfig, | ||
parent *types.Header, | ||
header *types.Header, | ||
) error { | ||
switch { | ||
case config.IsCortina(header.Time): | ||
if header.GasLimit != cortina.GasLimit { | ||
return fmt.Errorf("%w: expected to be %d in Cortina, but found %d", | ||
errInvalidGasLimit, | ||
cortina.GasLimit, | ||
header.GasLimit, | ||
) | ||
} | ||
case config.IsApricotPhase1(header.Time): | ||
if header.GasLimit != ap1.GasLimit { | ||
return fmt.Errorf("%w: expected to be %d in ApricotPhase1, but found %d", | ||
errInvalidGasLimit, | ||
ap1.GasLimit, | ||
header.GasLimit, | ||
) | ||
} | ||
default: | ||
if header.GasLimit < params.MinGasLimit || header.GasLimit > params.MaxGasLimit { | ||
return fmt.Errorf("%w: %d not in range [%d, %d]", | ||
errInvalidGasLimit, | ||
header.GasLimit, | ||
params.MinGasLimit, | ||
params.MaxGasLimit, | ||
) | ||
} | ||
|
||
// Verify that the gas limit remains within allowed bounds | ||
diff := math.AbsDiff(parent.GasLimit, header.GasLimit) | ||
limit := parent.GasLimit / params.GasLimitBoundDivisor | ||
if diff >= limit { | ||
return fmt.Errorf("%w: have %d, want %d += %d", | ||
errInvalidGasLimit, | ||
header.GasLimit, | ||
parent.GasLimit, | ||
limit, | ||
) | ||
} | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
// (c) 2025, Ava Labs, Inc. All rights reserved. | ||
// See the file LICENSE for licensing terms. | ||
|
||
package header | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/ava-labs/coreth/core/types" | ||
"github.com/ava-labs/coreth/params" | ||
"github.com/ava-labs/coreth/plugin/evm/upgrade/ap1" | ||
"github.com/ava-labs/coreth/plugin/evm/upgrade/cortina" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestGasLimit(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
upgrades params.NetworkUpgrades | ||
parent *types.Header | ||
timestamp uint64 | ||
want uint64 | ||
}{ | ||
{ | ||
name: "cortina", | ||
upgrades: params.TestCortinaChainConfig.NetworkUpgrades, | ||
want: cortina.GasLimit, | ||
}, | ||
{ | ||
name: "ap1", | ||
upgrades: params.TestApricotPhase1Config.NetworkUpgrades, | ||
want: ap1.GasLimit, | ||
}, | ||
{ | ||
name: "launch", | ||
upgrades: params.TestLaunchConfig.NetworkUpgrades, | ||
parent: &types.Header{ | ||
GasLimit: 1, | ||
}, | ||
want: 1, // Same as parent | ||
}, | ||
} | ||
for _, test := range tests { | ||
t.Run(test.name, func(t *testing.T) { | ||
config := ¶ms.ChainConfig{ | ||
NetworkUpgrades: test.upgrades, | ||
} | ||
got := GasLimit(config, test.parent, test.timestamp) | ||
require.Equal(t, test.want, got) | ||
}) | ||
} | ||
} | ||
|
||
func TestVerifyGasLimit(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
upgrades params.NetworkUpgrades | ||
parent *types.Header | ||
header *types.Header | ||
want error | ||
}{ | ||
{ | ||
name: "cortina_valid", | ||
upgrades: params.TestCortinaChainConfig.NetworkUpgrades, | ||
header: &types.Header{ | ||
GasLimit: cortina.GasLimit, | ||
}, | ||
}, | ||
{ | ||
name: "cortina_invalid", | ||
upgrades: params.TestCortinaChainConfig.NetworkUpgrades, | ||
header: &types.Header{ | ||
GasLimit: cortina.GasLimit + 1, | ||
}, | ||
want: errInvalidGasLimit, | ||
}, | ||
{ | ||
name: "ap1_valid", | ||
upgrades: params.TestApricotPhase1Config.NetworkUpgrades, | ||
header: &types.Header{ | ||
GasLimit: ap1.GasLimit, | ||
}, | ||
}, | ||
{ | ||
name: "ap1_invalid", | ||
upgrades: params.TestApricotPhase1Config.NetworkUpgrades, | ||
header: &types.Header{ | ||
GasLimit: ap1.GasLimit + 1, | ||
}, | ||
want: errInvalidGasLimit, | ||
}, | ||
{ | ||
name: "launch_valid", | ||
upgrades: params.TestLaunchConfig.NetworkUpgrades, | ||
parent: &types.Header{ | ||
GasLimit: 50_000, | ||
}, | ||
header: &types.Header{ | ||
GasLimit: 50_001, // Gas limit is allowed to change by 1/1024 | ||
}, | ||
}, | ||
{ | ||
name: "launch_too_low", | ||
upgrades: params.TestLaunchConfig.NetworkUpgrades, | ||
parent: &types.Header{ | ||
GasLimit: params.MinGasLimit, | ||
}, | ||
header: &types.Header{ | ||
GasLimit: params.MinGasLimit - 1, | ||
}, | ||
want: errInvalidGasLimit, | ||
}, | ||
{ | ||
name: "launch_too_high", | ||
upgrades: params.TestLaunchConfig.NetworkUpgrades, | ||
parent: &types.Header{ | ||
GasLimit: params.MaxGasLimit, | ||
}, | ||
header: &types.Header{ | ||
GasLimit: params.MaxGasLimit + 1, | ||
}, | ||
want: errInvalidGasLimit, | ||
}, | ||
{ | ||
name: "change_too_large", | ||
upgrades: params.TestLaunchConfig.NetworkUpgrades, | ||
parent: &types.Header{ | ||
GasLimit: params.MinGasLimit, | ||
}, | ||
header: &types.Header{ | ||
GasLimit: params.MaxGasLimit, | ||
}, | ||
want: errInvalidGasLimit, | ||
}, | ||
} | ||
for _, test := range tests { | ||
t.Run(test.name, func(t *testing.T) { | ||
config := ¶ms.ChainConfig{ | ||
NetworkUpgrades: test.upgrades, | ||
} | ||
err := VerifyGasLimit(config, test.parent, test.header) | ||
require.ErrorIs(t, err, test.want) | ||
}) | ||
} | ||
} |