Skip to content

Commit

Permalink
Implement header.ExtraPrefix serialization in upgrade/ packages (#846)
Browse files Browse the repository at this point in the history
  • Loading branch information
StephenButtolph authored Feb 28, 2025
1 parent 7effabd commit e98ccb3
Show file tree
Hide file tree
Showing 10 changed files with 286 additions and 163 deletions.
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

0 comments on commit e98ccb3

Please sign in to comment.