Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement header.ExtraPrefix serialization in upgrades package #846

Merged
merged 3 commits into from
Feb 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions core/txpool/blobpool/blobpool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ func (bc *testBlockChain) CurrentBlock() *types.Header {
GasLimit: gasLimit,
GasUsed: 0,
BaseFee: mid,
Extra: make([]byte, header.FeeWindowSize),
Extra: make([]byte, ap3.WindowSize),
}
baseFee, err := header.BaseFee(
bc.config, parent, blockTime,
Expand Down Expand Up @@ -159,7 +159,7 @@ func (bc *testBlockChain) CurrentBlock() *types.Header {
GasLimit: gasLimit,
BaseFee: baseFee,
ExcessBlobGas: &excessBlobGas,
Extra: make([]byte, header.FeeWindowSize),
Extra: make([]byte, ap3.WindowSize),
}
}

Expand Down
26 changes: 13 additions & 13 deletions plugin/evm/header/base_fee_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,15 @@ func TestBaseFee(t *testing.T) {
parent: &types.Header{
Number: big.NewInt(1),
},
wantErr: errDynamicFeeWindowInsufficientLength,
wantErr: ap3.ErrWindowInsufficientLength,
},
{
name: "ap3_invalid_timestamp",
upgrades: params.TestApricotPhase3Config.NetworkUpgrades,
parent: &types.Header{
Number: big.NewInt(1),
Time: 1,
Extra: feeWindowBytes(ap3.Window{}),
Extra: (&ap3.Window{}).Bytes(),
},
timestamp: 0,
wantErr: errInvalidTimestamp,
Expand All @@ -78,7 +78,7 @@ func TestBaseFee(t *testing.T) {
Number: big.NewInt(1),
GasUsed: ap3.TargetGas - ap3.IntrinsicBlockGas,
Time: 1,
Extra: feeWindowBytes(ap3.Window{}),
Extra: (&ap3.Window{}).Bytes(),
BaseFee: big.NewInt(ap3.MinBaseFee + 1),
},
timestamp: 1,
Expand All @@ -89,7 +89,7 @@ func TestBaseFee(t *testing.T) {
upgrades: params.TestApricotPhase3Config.NetworkUpgrades,
parent: &types.Header{
Number: big.NewInt(1),
Extra: feeWindowBytes(ap3.Window{}),
Extra: (&ap3.Window{}).Bytes(),
BaseFee: big.NewInt(ap3.MaxBaseFee),
},
timestamp: 1,
Expand All @@ -112,7 +112,7 @@ func TestBaseFee(t *testing.T) {
upgrades: params.TestApricotPhase3Config.NetworkUpgrades,
parent: &types.Header{
Number: big.NewInt(1),
Extra: feeWindowBytes(ap3.Window{}),
Extra: (&ap3.Window{}).Bytes(),
BaseFee: big.NewInt(ap3.MaxBaseFee),
},
timestamp: 2 * ap3.WindowLen,
Expand All @@ -137,7 +137,7 @@ func TestBaseFee(t *testing.T) {
parent: &types.Header{
Number: big.NewInt(1),
GasUsed: 2 * ap3.TargetGas,
Extra: feeWindowBytes(ap3.Window{}),
Extra: (&ap3.Window{}).Bytes(),
BaseFee: big.NewInt(ap3.MinBaseFee),
},
timestamp: 1,
Expand All @@ -161,7 +161,7 @@ func TestBaseFee(t *testing.T) {
parent: &types.Header{
Number: big.NewInt(1),
GasUsed: 1,
Extra: feeWindowBytes(ap3.Window{}),
Extra: (&ap3.Window{}).Bytes(),
BaseFee: big.NewInt(1),
},
timestamp: 2 * ap3.WindowLen,
Expand All @@ -180,7 +180,7 @@ func TestBaseFee(t *testing.T) {
upgrades: params.TestApricotPhase4Config.NetworkUpgrades,
parent: &types.Header{
Number: big.NewInt(1),
Extra: feeWindowBytes(ap3.Window{}),
Extra: (&ap3.Window{}).Bytes(),
BaseFee: big.NewInt(ap4.MaxBaseFee),
BlockGasCost: big.NewInt(ap4.MinBlockGasCost),
},
Expand All @@ -205,7 +205,7 @@ func TestBaseFee(t *testing.T) {
parent: &types.Header{
Number: big.NewInt(1),
GasUsed: ap3.TargetGas,
Extra: feeWindowBytes(ap3.Window{}),
Extra: (&ap3.Window{}).Bytes(),
BaseFee: big.NewInt(ap4.MinBaseFee),
ExtDataGasUsed: big.NewInt(ap3.TargetGas),
BlockGasCost: big.NewInt(ap4.MinBlockGasCost),
Expand Down Expand Up @@ -238,7 +238,7 @@ func TestBaseFee(t *testing.T) {
upgrades: params.TestApricotPhase5Config.NetworkUpgrades,
parent: &types.Header{
Number: big.NewInt(1),
Extra: feeWindowBytes(ap3.Window{}),
Extra: (&ap3.Window{}).Bytes(),
BaseFee: big.NewInt(ap4.MaxBaseFee),
},
timestamp: 1,
Expand All @@ -262,7 +262,7 @@ func TestBaseFee(t *testing.T) {
parent: &types.Header{
Number: big.NewInt(1),
GasUsed: ap5.TargetGas,
Extra: feeWindowBytes(ap3.Window{}),
Extra: (&ap3.Window{}).Bytes(),
BaseFee: big.NewInt(ap4.MinBaseFee),
ExtDataGasUsed: big.NewInt(ap5.TargetGas),
},
Expand Down Expand Up @@ -295,7 +295,7 @@ func TestBaseFee(t *testing.T) {
parent: &types.Header{
Number: big.NewInt(1),
GasUsed: ap5.TargetGas,
Extra: feeWindowBytes(ap3.Window{}),
Extra: (&ap3.Window{}).Bytes(),
BaseFee: big.NewInt(etna.MinBaseFee),
ExtDataGasUsed: big.NewInt(ap5.TargetGas),
},
Expand Down Expand Up @@ -346,7 +346,7 @@ func TestEstimateNextBaseFee(t *testing.T) {
upgrades: params.TestApricotPhase3Config.NetworkUpgrades,
parent: &types.Header{
Number: big.NewInt(1),
Extra: feeWindowBytes(ap3.Window{}),
Extra: (&ap3.Window{}).Bytes(),
BaseFee: big.NewInt(ap3.MaxBaseFee),
},
timestamp: 1,
Expand Down
37 changes: 2 additions & 35 deletions plugin/evm/header/dynamic_fee_windower.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@
package header

import (
"encoding/binary"
"errors"
"fmt"
"math/big"

"github.com/ava-labs/avalanchego/utils/wrappers"
"github.com/ava-labs/coreth/core/types"
"github.com/ava-labs/coreth/params"
"github.com/ava-labs/coreth/plugin/evm/upgrade/ap3"
Expand All @@ -20,10 +18,6 @@ import (
"github.com/ethereum/go-ethereum/common/math"
)

// FeeWindowSize is the number of bytes that are used to encode the dynamic fee
// window in the header's Extra field after the Apricot Phase 3 upgrade.
const FeeWindowSize = wrappers.LongLen * ap3.WindowLen

var (
maxUint256Plus1 = new(big.Int).Lsh(common.Big1, 256)
maxUint256 = new(big.Int).Sub(maxUint256Plus1, common.Big1)
Expand All @@ -41,8 +35,7 @@ var (
ap3BaseFeeChangeDenominator = big.NewInt(ap3.BaseFeeChangeDenominator)
ap5BaseFeeChangeDenominator = big.NewInt(ap5.BaseFeeChangeDenominator)

errInvalidTimestamp = errors.New("invalid timestamp")
errDynamicFeeWindowInsufficientLength = errors.New("insufficient length for dynamic fee window")
errInvalidTimestamp = errors.New("invalid timestamp")
)

// baseFeeFromWindow should only be called if `timestamp` >= `config.ApricotPhase3Timestamp`
Expand Down Expand Up @@ -165,7 +158,7 @@ func feeWindow(
return ap3.Window{}, nil
}

dynamicFeeWindow, err := parseFeeWindow(parent.Extra)
dynamicFeeWindow, err := ap3.ParseWindow(parent.Extra)
if err != nil {
return ap3.Window{}, err
}
Expand Down Expand Up @@ -236,29 +229,3 @@ func selectBigWithinBounds(lowerBound, value, upperBound *big.Int) *big.Int {
return value
}
}

func parseFeeWindow(bytes []byte) (ap3.Window, error) {
if len(bytes) < FeeWindowSize {
return ap3.Window{}, fmt.Errorf("%w: expected at least %d bytes but got %d bytes",
errDynamicFeeWindowInsufficientLength,
FeeWindowSize,
len(bytes),
)
}

var window ap3.Window
for i := range window {
offset := i * wrappers.LongLen
window[i] = binary.BigEndian.Uint64(bytes[offset:])
}
return window, nil
}

func feeWindowBytes(w ap3.Window) []byte {
bytes := make([]byte, FeeWindowSize)
for i, v := range w {
offset := i * wrappers.LongLen
binary.BigEndian.PutUint64(bytes[offset:], v)
}
return bytes
}
73 changes: 0 additions & 73 deletions plugin/evm/header/dynamic_fee_windower_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ package header
import (
"math/big"
"testing"

"github.com/ava-labs/coreth/plugin/evm/upgrade/ap3"
"github.com/stretchr/testify/require"
)

func TestSelectBigWithinBounds(t *testing.T) {
Expand Down Expand Up @@ -58,73 +55,3 @@ func TestSelectBigWithinBounds(t *testing.T) {
})
}
}

func TestParseDynamicFeeWindow(t *testing.T) {
tests := []struct {
name string
bytes []byte
window ap3.Window
parseErr error
}{
{
name: "insufficient_length",
bytes: make([]byte, FeeWindowSize-1),
parseErr: errDynamicFeeWindowInsufficientLength,
},
{
name: "zero_window",
bytes: make([]byte, FeeWindowSize),
window: ap3.Window{},
},
{
name: "truncate_bytes",
bytes: []byte{
FeeWindowSize: 1,
},
window: ap3.Window{},
},
{
name: "endianess",
bytes: []byte{
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
},
window: ap3.Window{
0x0102030405060708,
0x1112131415161718,
0x2122232425262728,
0x3132333435363738,
0x4142434445464748,
0x5152535455565758,
0x6162636465666768,
0x7172737475767778,
0x8182838485868788,
0x9192939495969798,
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
require := require.New(t)

window, err := parseFeeWindow(test.bytes)
require.Equal(test.window, window)
require.ErrorIs(err, test.parseErr)
if test.parseErr != nil {
return
}

expectedBytes := test.bytes[:FeeWindowSize]
bytes := feeWindowBytes(window)
require.Equal(expectedBytes, bytes)
})
}
}
15 changes: 8 additions & 7 deletions plugin/evm/header/extra.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/ava-labs/coreth/core/types"
"github.com/ava-labs/coreth/params"
"github.com/ava-labs/coreth/plugin/evm/upgrade/ap3"
)

var errInvalidExtraLength = errors.New("invalid header.Extra length")
Expand All @@ -26,7 +27,7 @@ func ExtraPrefix(
if err != nil {
return nil, fmt.Errorf("failed to calculate fee window: %w", err)
}
return feeWindowBytes(window), nil
return window.Bytes(), nil
default:
// Prior to AP3 there was no expected extra prefix.
return nil, nil
Expand All @@ -39,20 +40,20 @@ func VerifyExtra(rules params.AvalancheRules, extra []byte) error {
extraLen := len(extra)
switch {
case rules.IsDurango:
if extraLen < FeeWindowSize {
if extraLen < ap3.WindowSize {
return fmt.Errorf(
"%w: expected >= %d but got %d",
errInvalidExtraLength,
FeeWindowSize,
ap3.WindowSize,
extraLen,
)
}
case rules.IsApricotPhase3:
if extraLen != FeeWindowSize {
if extraLen != ap3.WindowSize {
return fmt.Errorf(
"%w: expected %d but got %d",
errInvalidExtraLength,
FeeWindowSize,
ap3.WindowSize,
extraLen,
)
}
Expand Down Expand Up @@ -84,8 +85,8 @@ func PredicateBytesFromExtra(_ params.AvalancheRules, extra []byte) []byte {
// to this size.
// After Durango, the VM pre-verifies the extra data past the dynamic fee
// rollup window is valid.
if len(extra) <= FeeWindowSize {
if len(extra) <= ap3.WindowSize {
return nil
}
return extra[FeeWindowSize:]
return extra[ap3.WindowSize:]
}
Loading
Loading