Skip to content

Commit

Permalink
support london upgrade
Browse files Browse the repository at this point in the history
  • Loading branch information
calmbeing committed Jun 20, 2023
1 parent 5ccb1e9 commit c42d33b
Show file tree
Hide file tree
Showing 7 changed files with 219 additions and 79 deletions.
48 changes: 1 addition & 47 deletions consensus/misc/eip1559.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@ import (
"math/big"

"github.com/ledgerwatch/erigon-lib/chain"
"github.com/ledgerwatch/erigon-lib/common"

"github.com/ledgerwatch/erigon/common/math"
"github.com/ledgerwatch/erigon/core/types"
"github.com/ledgerwatch/erigon/params"
)
Expand All @@ -32,14 +30,6 @@ import (
// - gas limit check
// - basefee check
func VerifyEip1559Header(config *chain.Config, parent, header *types.Header) error {
// Verify that the gas limit remains within allowed bounds
parentGasLimit := parent.GasLimit
if !config.IsLondon(parent.Number.Uint64()) {
parentGasLimit = parent.GasLimit * params.ElasticityMultiplier
}
if err := VerifyGaslimit(parentGasLimit, header.GasLimit); err != nil {
return err
}
// Verify the header is not malformed
if header.BaseFee == nil {
return fmt.Errorf("header is missing baseFee")
Expand All @@ -55,43 +45,7 @@ func VerifyEip1559Header(config *chain.Config, parent, header *types.Header) err

// CalcBaseFee calculates the basefee of the header.
func CalcBaseFee(config *chain.Config, parent *types.Header) *big.Int {
// If the current block is the first EIP-1559 block, return the InitialBaseFee.
if !config.IsLondon(parent.Number.Uint64()) {
return new(big.Int).SetUint64(params.InitialBaseFee)
}

var (
parentGasTarget = parent.GasLimit / params.ElasticityMultiplier
parentGasTargetBig = new(big.Int).SetUint64(parentGasTarget)
baseFeeChangeDenominator = new(big.Int).SetUint64(getBaseFeeChangeDenominator(config.Bor, parent.Number.Uint64()))
)
// If the parent gasUsed is the same as the target, the baseFee remains unchanged.
if parent.GasUsed == parentGasTarget {
return new(big.Int).Set(parent.BaseFee)
}
if parent.GasUsed > parentGasTarget {
// If the parent block used more gas than its target, the baseFee should increase.
gasUsedDelta := new(big.Int).SetUint64(parent.GasUsed - parentGasTarget)
x := new(big.Int).Mul(parent.BaseFee, gasUsedDelta)
y := x.Div(x, parentGasTargetBig)
baseFeeDelta := math.BigMax(
x.Div(y, baseFeeChangeDenominator),
common.Big1,
)

return x.Add(parent.BaseFee, baseFeeDelta)
} else {
// Otherwise if the parent block used less gas than its target, the baseFee should decrease.
gasUsedDelta := new(big.Int).SetUint64(parentGasTarget - parent.GasUsed)
x := new(big.Int).Mul(parent.BaseFee, gasUsedDelta)
y := x.Div(x, parentGasTargetBig)
baseFeeDelta := x.Div(y, baseFeeChangeDenominator)

return math.BigMax(
x.Sub(parent.BaseFee, baseFeeDelta),
common.Big0,
)
}
return new(big.Int).SetUint64(params.InitialBaseFee)
}

func getBaseFeeChangeDenominator(borConfig *chain.BorConfig, number uint64) uint64 {
Expand Down
4 changes: 2 additions & 2 deletions consensus/misc/eip1559_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ func TestCalcBaseFee(t *testing.T) {
expectedBaseFee int64
}{
{params.InitialBaseFee, 20000000, 10000000, params.InitialBaseFee}, // usage == target
{params.InitialBaseFee, 20000000, 9000000, 987500000}, // usage below target
{params.InitialBaseFee, 20000000, 11000000, 1012500000}, // usage above target
{params.InitialBaseFee, 20000000, 9000000, params.InitialBaseFee}, // usage below target
{params.InitialBaseFee, 20000000, 11000000, params.InitialBaseFee}, // usage above target
}
for i, test := range tests {
parent := &types.Header{
Expand Down
57 changes: 38 additions & 19 deletions consensus/parlia/parlia.go
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,22 @@ func getVoteAttestationFromHeader(header *types.Header, chainConfig *chain.Confi
return &attestation, nil
}

// getParent returns the parent of a given block.
func (p *Parlia) getParent(chain consensus.ChainHeaderReader, header *types.Header, parents []*types.Header) (*types.Header, error) {
var parent *types.Header
number := header.Number.Uint64()
if len(parents) > 0 {
parent = parents[len(parents)-1]
} else {
parent = chain.GetHeader(header.ParentHash, number-1)
}

if parent == nil || parent.Number.Uint64() != number-1 || parent.Hash() != header.ParentHash {
return nil, consensus.ErrUnknownAncestor
}
return parent, nil
}

// verifyVoteAttestation checks whether the vote attestation in the header is valid.
func (p *Parlia) verifyVoteAttestation(chain consensus.ChainHeaderReader, header *types.Header, parents []*types.Header) error {
attestation, err := getVoteAttestationFromHeader(header, p.chainConfig, p.config)
Expand All @@ -419,16 +435,9 @@ func (p *Parlia) verifyVoteAttestation(chain consensus.ChainHeaderReader, header
return fmt.Errorf("invalid attestation, too large extra length: %d", len(attestation.Extra))
}

// Get parent block
number := header.Number.Uint64()
var parent *types.Header
if len(parents) > 0 {
parent = parents[len(parents)-1]
} else {
parent = chain.GetHeader(header.ParentHash, number-1)
}
if parent == nil || parent.Hash() != header.ParentHash {
return consensus.ErrUnknownAncestor
parent, err := p.getParent(chain, header, parents)
if err != nil {
return err
}

// The target block should be direct parent.
Expand Down Expand Up @@ -552,6 +561,22 @@ func (p *Parlia) verifyHeader(chain consensus.ChainHeaderReader, header *types.H
return consensus.ErrUnexpectedWithdrawals
}

parent, err := p.getParent(chain, header, parents)
if err != nil {
return err
}

// Verify the block's gas usage and (if applicable) verify the base fee.
if !chain.Config().IsLondon(header.Number.Uint64()) {
// Verify BaseFee not present before EIP-1559 fork.
if header.BaseFee != nil {
return fmt.Errorf("invalid baseFee before fork: have %d, expected 'nil'", header.BaseFee)
}
} else if err := misc.VerifyEip1559Header(chain.Config(), parent, header); err != nil {
// Verify the header's EIP-1559 attributes.
return err
}

// All basic checks passed, verify cascading fields
return p.verifyCascadingFields(chain, header, parents)
}
Expand All @@ -567,15 +592,9 @@ func (p *Parlia) verifyCascadingFields(chain consensus.ChainHeaderReader, header
return nil
}

var parent *types.Header
if len(parents) > 0 {
parent = parents[len(parents)-1]
} else {
parent = chain.GetHeader(header.ParentHash, number-1)
}

if parent == nil || parent.Number.Uint64() != number-1 || parent.Hash() != header.ParentHash {
return consensus.ErrUnknownAncestor
parent, err := p.getParent(chain, header, parents)
if err != nil {
return err
}

snap, err := p.snapshot(chain, number-1, header.ParentHash, parents, true /* verify */)
Expand Down
166 changes: 166 additions & 0 deletions core/blockchain_eip3529_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
package core

import (
"math/big"
"testing"

"github.com/ethereum/go-ethereum/core"
"github.com/ledgerwatch/erigon-lib/chain"
libcommon "github.com/ledgerwatch/erigon-lib/common"
"github.com/ledgerwatch/erigon-lib/kv/memdb"
"github.com/ledgerwatch/erigon/common"
"github.com/ledgerwatch/erigon/consensus"
"github.com/ledgerwatch/erigon/consensus/ethash"
"github.com/ledgerwatch/erigon/core/rawdb"
"github.com/ledgerwatch/erigon/core/types"
"github.com/ledgerwatch/erigon/core/vm"
"github.com/ledgerwatch/erigon/crypto"
"github.com/ledgerwatch/erigon/params"
)

func postLondonConfig() *chain.Config {
config := *params.TestChainConfig
config.LondonBlock = big.NewInt(0)
return &config
}

func preLondonConfig() *chain.Config {
config := *params.TestChainConfig
config.LondonBlock = nil
return &config
}

func TestSelfDestructGasPreEIP3529(t *testing.T) {
bytecode := []byte{
byte(vm.PC),
byte(vm.SELFDESTRUCT),
}

// Expected gas is (intrinsic + pc + cold load (due to legacy tx) + selfdestruct cost ) / 2
// The refund of 24000 gas (i.e. params.SelfdestructRefundGas) is not applied since refunds pre-EIP3529 are
// capped to half of the transaction's gas.
expectedGasUsed := (params.TxGas + vm.GasQuickStep + params.ColdAccountAccessCostEIP2929 + params.SelfdestructGasEIP150) / 2
testGasUsage(t, preLondonConfig(), ethash.NewFaker(), bytecode, nil, 60_000, expectedGasUsed)
}

func TestSstoreGasPreEIP3529(t *testing.T) {
bytecode := []byte{
byte(vm.PUSH1), 0x3, // value
byte(vm.PUSH1), 0x3, // location
byte(vm.SSTORE), // Set slot[3] = 3
}
// // Expected gas is intrinsic + 2*pushGas + cold load (due to legacy tx) + SstoreGas
expectedGasUsed := params.TxGas + 2*vm.GasFastestStep + params.ColdSloadCostEIP2929 + params.SstoreSetGasEIP2200
testGasUsage(t, preLondonConfig(), ethash.NewFaker(), bytecode, nil, 60_000, expectedGasUsed)
}

func TestSelfDestructGasPostEIP3529(t *testing.T) {
bytecode := []byte{
byte(vm.PC),
byte(vm.SELFDESTRUCT),
}
// Expected gas is intrinsic + pc + cold load (due to legacy tx) + SelfDestructGas
expectedGasUsed := params.TxGas + vm.GasQuickStep + params.ColdAccountAccessCostEIP2929 + params.SelfdestructGasEIP150
testGasUsage(t, postLondonConfig(), ethash.NewFaker(), bytecode, nil, 60_000, expectedGasUsed)
}

func TestSstoreGasPostEIP3529(t *testing.T) {
bytecode := []byte{
byte(vm.PUSH1), 0x3, // value
byte(vm.PUSH1), 0x3, // location
byte(vm.SSTORE), // Set slot[3] = 3
}
// Expected gas is intrinsic + 2*pushGas + cold load (due to legacy tx) + SstoreGas
expectedGasUsed := params.TxGas + 2*vm.GasFastestStep + params.ColdSloadCostEIP2929 + params.SstoreSetGasEIP2200
testGasUsage(t, postLondonConfig(), ethash.NewFaker(), bytecode, nil, 60_000, expectedGasUsed)
}

func TestSstoreModifyGasPostEIP3529(t *testing.T) {
bytecode := []byte{
byte(vm.PUSH1), 0x3, // value
byte(vm.PUSH1), 0x1, // location
byte(vm.SSTORE), // Set slot[1] = 3
}
// initialize contract storage
initialStorage := make(map[libcommon.Hash]libcommon.Hash)
// Populate two slots
initialStorage[libcommon.HexToHash("01")] = libcommon.HexToHash("01")
initialStorage[libcommon.HexToHash("02")] = libcommon.HexToHash("02")
// Expected gas is intrinsic + 2*pushGas + cold load (due to legacy tx) + SstoreReset (a->b such that a!=0)
expectedGasUsed := params.TxGas + 2*vm.GasFastestStep + params.ColdSloadCostEIP2929 + (params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929)
testGasUsage(t, postLondonConfig(), ethash.NewFaker(), bytecode, initialStorage, 60_000, expectedGasUsed)
}

func TestSstoreClearGasPostEIP3529(t *testing.T) {
bytecode := []byte{
byte(vm.PUSH1), 0x0, // value
byte(vm.PUSH1), 0x1, // location
byte(vm.SSTORE), // Set slot[1] = 0
}
// initialize contract storage
initialStorage := make(map[libcommon.Hash]libcommon.Hash)
// Populate two slots
initialStorage[libcommon.HexToHash("01")] = libcommon.HexToHash("01")
initialStorage[libcommon.HexToHash("02")] = libcommon.HexToHash("02")

// Expected gas is intrinsic + 2*pushGas + cold load (due to legacy tx) + SstoreReset (a->b such that a!=0) - sstoreClearGasRefund
expectedGasUsage := params.TxGas + 2*vm.GasFastestStep + params.ColdSloadCostEIP2929 + (params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929) - params.SstoreClearsScheduleRefundEIP3529
testGasUsage(t, postLondonConfig(), ethash.NewFaker(), bytecode, initialStorage, 60_000, expectedGasUsage)
}

// Test the gas used by running a transaction sent to a smart contract with given bytecode and storage.
func testGasUsage(t *testing.T, config *chain.Config, engine consensus.Engine, bytecode []byte, initialStorage map[libcommon.Hash]libcommon.Hash, initialGas, expectedGasUsed uint64) {
var (
aa = libcommon.HexToAddress("0x000000000000000000000000000000000000aaaa")

// Generate a canonical chain to act as the main dataset
db = memdb.NewTestDB(t)

// A sender who makes transactions, has some funds
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
address = crypto.PubkeyToAddress(key.PublicKey)
balanceBefore = big.NewInt(1000000000000000)
gspec = &types.Genesis{Config: params.TestChainConfig, Alloc: core.GenesisAlloc{
address: {Balance: balanceBefore},
aa: {
Code: bytecode,
Storage: initialStorage,
Nonce: 0,
Balance: big.NewInt(0),
},
}}
genesis = gspec.MustCommit(db)
)

blocks, _ := GenerateChain(gspec.Config, genesis, engine, db, 1, func(i int, b *BlockGen) {
b.SetCoinbase(common.Address{1})

// One transaction to 0xAAAA
signer := types.LatestSigner(gspec.Config)
tx, _ := types.SignNewTx(key, signer, &types.LegacyTx{
Nonce: 0,
To: &aa,
Gas: initialGas,
GasPrice: newGwei(5),
})
b.AddTx(tx)
})

// Import the canonical chain
diskdb := rawdb.NewMemoryDatabase()
gspec.MustCommit(diskdb)

chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil)
if err != nil {
t.Fatalf("failed to create tester chain: %v", err)
}
if n, err := chain.InsertChain(blocks); err != nil {
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
}

block := chain.GetBlockByNumber(1)

if block.GasUsed() != expectedGasUsed {
t.Fatalf("incorrect amount of gas spent: expected %d, got %d", expectedGasUsed, block.GasUsed())
}
}
10 changes: 5 additions & 5 deletions core/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -427,11 +427,11 @@ func (st *StateTransition) TransitionDb(refunds bool, gasBailout bool) (*Executi
} else {
st.state.AddBalance(st.evm.Context().Coinbase, amount)
}
if !msg.IsFree() && rules.IsLondon && rules.IsEip1559FeeCollector {
burntContractAddress := *st.evm.ChainConfig().Eip1559FeeCollector
burnAmount := new(uint256.Int).Mul(new(uint256.Int).SetUint64(st.gasUsed()), st.evm.Context().BaseFee)
st.state.AddBalance(burntContractAddress, burnAmount)
}
// if !msg.IsFree() && rules.IsLondon && rules.IsEip1559FeeCollector {
// burntContractAddress := *st.evm.ChainConfig().Eip1559FeeCollector
// burnAmount := new(uint256.Int).Mul(new(uint256.Int).SetUint64(st.gasUsed()), st.evm.Context().BaseFee)
// st.state.AddBalance(burntContractAddress, burnAmount)
// }
if st.isBor {
// Deprecating transfer log and will be removed in future fork. PLEASE DO NOT USE this transfer log going forward. Parameters won't get updated as expected going forward with EIP1559
// add transfer log
Expand Down
5 changes: 3 additions & 2 deletions core/types/block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func TestBlockEncoding(t *testing.T) {
}

func TestEIP1559BlockEncoding(t *testing.T) {
blockEnc := common.FromHex("f9030bf901fea083cafc574e1f51ba9dc0568fc617a08ea2429fb384059c972f13b19fa1c8dd55a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017a05fe50b260da6308036625b850b5d6ced6d0a9f814c0688bc91ffb7b7a3a54b67a0bc37d79753ad738a6dac4921e57392f145d8887476de3f783dfa7edae9283e52b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd8825208845506eb0780a0bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff49888a13a5a8c8f2bb1c4843b9aca00f90106f85f800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba09bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094fa08a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b1b8a302f8a0018080843b9aca008301e24194095e7baea6a6c7c4c2dfeb977efac326af552d878080f838f7940000000000000000000000000000000000000001e1a0000000000000000000000000000000000000000000000000000000000000000080a0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7d22f548e8ecb3f51f41cb31b0a06de6a5cbae13c0c856e33acf021b51819636cfc009d39eafb9f606d546e305a8c0")
blockEnc := common.FromHex("f90303f901faa083cafc574e1f51ba9dc0568fc617a08ea2429fb384059c972f13b19fa1c8dd55a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017a05fe50b260da6308036625b850b5d6ced6d0a9f814c0688bc91ffb7b7a3a54b67a0bc37d79753ad738a6dac4921e57392f145d8887476de3f783dfa7edae9283e52b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd8825208845506eb0780a0bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff49888a13a5a8c8f2bb1c480f90102f85f800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba09bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094fa08a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b1b89f02f89c018080808301e24194095e7baea6a6c7c4c2dfeb977efac326af552d878080f838f7940000000000000000000000000000000000000001e1a0000000000000000000000000000000000000000000000000000000000000000080a0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7d22f548e8ecb3f51f41cb31b0a06de6a5cbae13c0c856e33acf021b51819636cfc009d39eafb9f606d546e305a8c0")
var block Block
if err := rlp.DecodeBytes(blockEnc, &block); err != nil {
t.Fatal("decode error: ", err)
Expand All @@ -95,7 +95,7 @@ func TestEIP1559BlockEncoding(t *testing.T) {
check("Coinbase", block.Coinbase(), libcommon.HexToAddress("8888f1f195afa192cfee860698584c030f4c9db1"))
check("MixDigest", block.MixDigest(), libcommon.HexToHash("bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff498"))
check("Root", block.Root(), libcommon.HexToHash("ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017"))
check("Hash", block.Hash(), libcommon.HexToHash("c7252048cd273fe0dac09650027d07f0e3da4ee0675ebbb26627cea92729c372"))
check("Hash", block.Hash(), libcommon.HexToHash("0xae9d971d16de73f69f940f1bd4ce5961158781176e73abea92a2b8781403885e"))
check("Nonce", block.NonceU64(), uint64(0xa13a5a8c8f2bb1c4))
check("Time", block.Time(), uint64(1426516743))
check("Size", block.Size(), common.StorageSize(len(blockEnc)))
Expand Down Expand Up @@ -132,6 +132,7 @@ func TestEIP1559BlockEncoding(t *testing.T) {

check("len(Transactions)", len(block.Transactions()), 2)
check("Transactions[0].Hash", block.Transactions()[0].Hash(), tx1.Hash())
check("Transactions[1].inner", block.Transactions()[1].Type(), tx2.Type())
check("Transactions[1].Hash", block.Transactions()[1].Hash(), tx2.Hash())
check("Transactions[1].Type", block.Transactions()[1].Type(), tx2.Type())
ourBlockEnc, err := rlp.EncodeToBytes(&block)
Expand Down
8 changes: 4 additions & 4 deletions params/protocol_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,10 @@ const (
// Introduced in Tangerine Whistle (Eip 150)
CreateBySelfdestructGas uint64 = 25000

BaseFeeChangeDenominator = 8 // Bounds the amount the base fee can change between blocks.
BaseFeeChangeDenominatorPostDelhi = 16 // Bounds the amount the base fee can change between blocks post delhi hard fork for polygon networks.
ElasticityMultiplier = 2 // Bounds the maximum gas limit an EIP-1559 block may have.
InitialBaseFee = 1000000000 // Initial base fee for EIP-1559 blocks.
BaseFeeChangeDenominator = 8 // Bounds the amount the base fee can change between blocks.
BaseFeeChangeDenominatorPostDelhi = 16 // Bounds the amount the base fee can change between blocks post delhi hard fork for polygon networks.
ElasticityMultiplier = 2 // Bounds the maximum gas limit an EIP-1559 block may have.
InitialBaseFee = 0 // Initial base fee for EIP-1559 blocks.

MaxCodeSize = 24576 // Maximum bytecode to permit for a contract
MaxInitCodeSize = 2 * MaxCodeSize // Maximum initcode to permit in a creation transaction and create instructions
Expand Down

0 comments on commit c42d33b

Please sign in to comment.