all: implement EIP-1559 (#22837)
This is the initial implementation of EIP-1559 in packages core/types and core. Mining, RPC, etc. will be added in subsequent commits. Co-authored-by: Marius van der Wijden <m.vanderwijden@live.de> Co-authored-by: lightclient@protonmail.com <lightclient@protonmail.com> Co-authored-by: Felix Lange <fjl@twurst.com>
This commit is contained in:
committed by
GitHub
parent
14bc6e5130
commit
94451c2788
@ -73,6 +73,10 @@ func newCanonical(engine consensus.Engine, n int, full bool) (ethdb.Database, *B
|
||||
return db, blockchain, err
|
||||
}
|
||||
|
||||
func newGwei(n int64) *big.Int {
|
||||
return new(big.Int).Mul(big.NewInt(n), big.NewInt(params.GWei))
|
||||
}
|
||||
|
||||
// Test fork of length N starting from block i
|
||||
func testFork(t *testing.T, blockchain *BlockChain, i, n int, full bool, comparator func(td1, td2 *big.Int)) {
|
||||
// Copy old chain up to #i into a new db
|
||||
@ -3109,3 +3113,156 @@ func TestEIP2718Transition(t *testing.T) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// TestEIP1559Transition tests the following:
|
||||
//
|
||||
// 1. A tranaction whose feeCap is greater than the baseFee is valid.
|
||||
// 2. Gas accounting for access lists on EIP-1559 transactions is correct.
|
||||
// 3. Only the transaction's tip will be received by the coinbase.
|
||||
// 4. The transaction sender pays for both the tip and baseFee.
|
||||
// 5. The coinbase receives only the partially realized tip when
|
||||
// feeCap - tip < baseFee.
|
||||
// 6. Legacy transaction behave as expected (e.g. gasPrice = feeCap = tip).
|
||||
func TestEIP1559Transition(t *testing.T) {
|
||||
var (
|
||||
aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa")
|
||||
|
||||
// Generate a canonical chain to act as the main dataset
|
||||
engine = ethash.NewFaker()
|
||||
db = rawdb.NewMemoryDatabase()
|
||||
|
||||
// A sender who makes transactions, has some funds
|
||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
|
||||
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
|
||||
funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether))
|
||||
gspec = &Genesis{
|
||||
Config: params.AllEthashProtocolChanges,
|
||||
Alloc: GenesisAlloc{
|
||||
addr1: {Balance: funds},
|
||||
addr2: {Balance: funds},
|
||||
// The address 0xAAAA sloads 0x00 and 0x01
|
||||
aa: {
|
||||
Code: []byte{
|
||||
byte(vm.PC),
|
||||
byte(vm.PC),
|
||||
byte(vm.SLOAD),
|
||||
byte(vm.SLOAD),
|
||||
},
|
||||
Nonce: 0,
|
||||
Balance: big.NewInt(0),
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
gspec.Config.BerlinBlock = common.Big0
|
||||
gspec.Config.LondonBlock = common.Big0
|
||||
genesis := gspec.MustCommit(db)
|
||||
signer := types.LatestSigner(gspec.Config)
|
||||
|
||||
blocks, _ := GenerateChain(gspec.Config, genesis, engine, db, 1, func(i int, b *BlockGen) {
|
||||
b.SetCoinbase(common.Address{1})
|
||||
|
||||
// One transaction to 0xAAAA
|
||||
accesses := types.AccessList{types.AccessTuple{
|
||||
Address: aa,
|
||||
StorageKeys: []common.Hash{{0}},
|
||||
}}
|
||||
|
||||
txdata := &types.DynamicFeeTx{
|
||||
ChainID: gspec.Config.ChainID,
|
||||
Nonce: 0,
|
||||
To: &aa,
|
||||
Gas: 30000,
|
||||
FeeCap: newGwei(5),
|
||||
Tip: big.NewInt(2),
|
||||
AccessList: accesses,
|
||||
Data: []byte{},
|
||||
}
|
||||
tx := types.NewTx(txdata)
|
||||
tx, _ = types.SignTx(tx, signer, key1)
|
||||
|
||||
b.AddTx(tx)
|
||||
})
|
||||
|
||||
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)
|
||||
|
||||
// 1+2: Ensure EIP-1559 access lists are accounted for via gas usage.
|
||||
expectedGas := params.TxGas + params.TxAccessListAddressGas + params.TxAccessListStorageKeyGas +
|
||||
vm.GasQuickStep*2 + params.WarmStorageReadCostEIP2929 + params.ColdSloadCostEIP2929
|
||||
if block.GasUsed() != expectedGas {
|
||||
t.Fatalf("incorrect amount of gas spent: expected %d, got %d", expectedGas, block.GasUsed())
|
||||
}
|
||||
|
||||
state, _ := chain.State()
|
||||
|
||||
// 3: Ensure that miner received only the tx's tip.
|
||||
actual := state.GetBalance(block.Coinbase())
|
||||
expected := new(big.Int).Add(
|
||||
new(big.Int).SetUint64(block.GasUsed()*block.Transactions()[0].Tip().Uint64()),
|
||||
ethash.ConstantinopleBlockReward,
|
||||
)
|
||||
if actual.Cmp(expected) != 0 {
|
||||
t.Fatalf("miner balance incorrect: expected %d, got %d", expected, actual)
|
||||
}
|
||||
|
||||
// 4: Ensure the tx sender paid for the gasUsed * (tip + block baseFee).
|
||||
actual = new(big.Int).Sub(funds, state.GetBalance(addr1))
|
||||
expected = new(big.Int).SetUint64(block.GasUsed() * (block.Transactions()[0].Tip().Uint64() + block.BaseFee().Uint64()))
|
||||
if actual.Cmp(expected) != 0 {
|
||||
t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual)
|
||||
}
|
||||
|
||||
blocks, _ = GenerateChain(gspec.Config, block, engine, db, 1, func(i int, b *BlockGen) {
|
||||
b.SetCoinbase(common.Address{2})
|
||||
|
||||
txdata := &types.LegacyTx{
|
||||
Nonce: 0,
|
||||
To: &aa,
|
||||
Gas: 30000,
|
||||
GasPrice: newGwei(5),
|
||||
}
|
||||
tx := types.NewTx(txdata)
|
||||
tx, _ = types.SignTx(tx, signer, key2)
|
||||
|
||||
b.AddTx(tx)
|
||||
})
|
||||
|
||||
if n, err := chain.InsertChain(blocks); err != nil {
|
||||
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
|
||||
}
|
||||
|
||||
block = chain.GetBlockByNumber(2)
|
||||
state, _ = chain.State()
|
||||
effectiveTip := block.Transactions()[0].Tip().Uint64() - block.BaseFee().Uint64()
|
||||
|
||||
// 6+5: Ensure that miner received only the tx's effective tip.
|
||||
actual = state.GetBalance(block.Coinbase())
|
||||
expected = new(big.Int).Add(
|
||||
new(big.Int).SetUint64(block.GasUsed()*effectiveTip),
|
||||
ethash.ConstantinopleBlockReward,
|
||||
)
|
||||
if actual.Cmp(expected) != 0 {
|
||||
t.Fatalf("miner balance incorrect: expected %d, got %d", expected, actual)
|
||||
}
|
||||
|
||||
// 4: Ensure the tx sender paid for the gasUsed * (effectiveTip + block baseFee).
|
||||
actual = new(big.Int).Sub(funds, state.GetBalance(addr2))
|
||||
expected = new(big.Int).SetUint64(block.GasUsed() * (effectiveTip + block.BaseFee().Uint64()))
|
||||
if actual.Cmp(expected) != 0 {
|
||||
t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user