Skip to content

Commit 0d0ea46

Browse files
committed
core: implement EIP-3651, warm coinbase (ethereum#25819)
1 parent b0ec104 commit 0d0ea46

File tree

5 files changed

+130
-13
lines changed

5 files changed

+130
-13
lines changed

core/blockchain_test.go

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1609,3 +1609,115 @@ func TestTransientStorageReset(t *testing.T) {
16091609
t.Fatalf("Unexpected dirty storage slot")
16101610
}
16111611
}
1612+
1613+
func TestEIP3651(t *testing.T) {
1614+
var (
1615+
ConstantinopleBlockReward = big.NewInt(3e+18) // Block reward in wei for successfully mining a block upward from Constantinople
1616+
1617+
aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa")
1618+
bb = common.HexToAddress("0x000000000000000000000000000000000000bbbb")
1619+
engine = ethash.NewFaker()
1620+
1621+
// A sender who makes transactions, has some funds
1622+
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
1623+
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
1624+
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
1625+
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
1626+
funds = big.NewInt(8000000000000000)
1627+
gspec = &Genesis{
1628+
Config: params.TestChainConfig,
1629+
Alloc: GenesisAlloc{
1630+
addr1: {Balance: funds},
1631+
addr2: {Balance: funds},
1632+
// The address 0xAAAA sloads 0x00 and 0x01
1633+
aa: {
1634+
Code: []byte{
1635+
byte(vm.PC),
1636+
byte(vm.PC),
1637+
byte(vm.SLOAD),
1638+
byte(vm.SLOAD),
1639+
},
1640+
Nonce: 0,
1641+
Balance: big.NewInt(0),
1642+
},
1643+
// The address 0xBBBB calls 0xAAAA
1644+
bb: {
1645+
Code: []byte{
1646+
byte(vm.PUSH1), 0, // out size
1647+
byte(vm.DUP1), // out offset
1648+
byte(vm.DUP1), // out insize
1649+
byte(vm.DUP1), // in offset
1650+
byte(vm.PUSH2), // address
1651+
byte(0xaa),
1652+
byte(0xaa),
1653+
byte(vm.GAS), // gas
1654+
byte(vm.DELEGATECALL),
1655+
},
1656+
Nonce: 0,
1657+
Balance: big.NewInt(0),
1658+
},
1659+
},
1660+
}
1661+
)
1662+
1663+
gspec.Config.Eip1559Block = common.Big0
1664+
signer := types.LatestSigner(gspec.Config)
1665+
1666+
_, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) {
1667+
b.SetCoinbase(aa)
1668+
// One transaction to Coinbase
1669+
txdata := &types.DynamicFeeTx{
1670+
ChainID: gspec.Config.ChainId,
1671+
Nonce: 0,
1672+
To: &bb,
1673+
Gas: 500000,
1674+
GasFeeCap: big.NewInt(12500000000),
1675+
GasTipCap: big.NewInt(0),
1676+
AccessList: nil,
1677+
Data: []byte{},
1678+
}
1679+
tx := types.NewTx(txdata)
1680+
tx, _ = types.SignTx(tx, signer, key1)
1681+
1682+
b.AddTx(tx)
1683+
})
1684+
1685+
diskdb := rawdb.NewMemoryDatabase()
1686+
gspec.MustCommit(diskdb)
1687+
1688+
chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{})
1689+
if err != nil {
1690+
t.Fatalf("failed to create tester chain: %v", err)
1691+
}
1692+
if n, err := chain.InsertChain(blocks); err != nil {
1693+
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
1694+
}
1695+
1696+
block := chain.GetBlockByNumber(1)
1697+
1698+
// 1+2: Ensure EIP-1559 access lists are accounted for via gas usage.
1699+
innerGas := vm.GasQuickStep*2 + params.ColdSloadCostEIP2929*2
1700+
expectedGas := params.TxGas + 5*vm.GasFastestStep + vm.GasQuickStep + 100 + innerGas // 100 because 0xaaaa is in access list
1701+
if block.GasUsed() != expectedGas {
1702+
t.Fatalf("incorrect amount of gas spent: expected %d, got %d", expectedGas, block.GasUsed())
1703+
}
1704+
1705+
state, _ := chain.State()
1706+
1707+
// 3: Ensure that miner received only the tx's tip.
1708+
actual := state.GetBalance(block.Coinbase())
1709+
expected := new(big.Int).Add(
1710+
new(big.Int).SetUint64(block.GasUsed()*block.Transactions()[0].GasTipCap().Uint64()),
1711+
ConstantinopleBlockReward,
1712+
)
1713+
if actual.Cmp(expected) != 0 {
1714+
t.Fatalf("miner balance incorrect: expected %d, got %d", expected, actual)
1715+
}
1716+
1717+
// 4: Ensure the tx sender paid for the gasUsed * (tip + block baseFee).
1718+
actual = new(big.Int).Sub(funds, state.GetBalance(addr1))
1719+
expected = new(big.Int).SetUint64(block.GasUsed() * (block.Transactions()[0].GasTipCap().Uint64() + block.BaseFee().Uint64()))
1720+
if actual.Cmp(expected) != 0 {
1721+
t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual)
1722+
}
1723+
}

core/state/statedb.go

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -765,26 +765,31 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (root common.Hash, err error)
765765
// - Add the contents of the optional tx access list (2930)
766766
//
767767
// Potential EIPs:
768-
// - Reset transient storage(1153)
769-
func (s *StateDB) Prepare(rules params.Rules, sender common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList) {
768+
// - Reset access list (Berlin)
769+
// - Add coinbase to access list (EIP-3651)
770+
// - Reset transient storage (EIP-1153)
771+
func (s *StateDB) Prepare(rules params.Rules, sender, coinbase common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList) {
770772
if rules.IsEIP1559 {
771773
// Clear out any leftover from previous executions
772-
s.accessList = newAccessList()
774+
al := newAccessList()
775+
s.accessList = al
773776

774-
s.AddAddressToAccessList(sender)
777+
al.AddAddress(sender)
775778
if dst != nil {
776-
s.AddAddressToAccessList(*dst)
779+
al.AddAddress(*dst)
777780
// If it's a create-tx, the destination will be added inside evm.create
778781
}
779782
for _, addr := range precompiles {
780-
s.AddAddressToAccessList(addr)
783+
al.AddAddress(addr)
781784
}
782785
for _, el := range list {
783-
s.AddAddressToAccessList(el.Address)
786+
al.AddAddress(el.Address)
784787
for _, key := range el.StorageKeys {
785-
s.AddSlotToAccessList(el.Address, key)
788+
al.AddSlot(el.Address, key)
786789
}
787790
}
791+
// EIP-3651: warm coinbase
792+
al.AddAddress(coinbase)
788793
}
789794
// Reset transient storage at the beginning of transaction execution
790795
s.transientStorage = newTransientStorage()

core/state_transition.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ func (st *StateTransition) TransitionDb(owner common.Address) (ret []byte, usedG
332332
// Execute the preparatory steps for state transition which includes:
333333
// - prepare accessList(post-berlin)
334334
// - reset transient storage(eip 1153)
335-
st.state.Prepare(rules, msg.From(), msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())
335+
st.state.Prepare(rules, msg.From(), st.evm.Context.Coinbase, msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())
336336

337337
var (
338338
evm = st.evm

core/vm/interface.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ type StateDB interface {
6969
// AddSlotToAccessList adds the given (address,slot) to the access list. This operation is safe to perform
7070
// even if the feature/fork is not active yet
7171
AddSlotToAccessList(addr common.Address, slot common.Hash)
72-
Prepare(rules params.Rules, sender common.Address, dest *common.Address, precompiles []common.Address, txAccesses types.AccessList)
72+
Prepare(rules params.Rules, sender, coinbase common.Address, dest *common.Address, precompiles []common.Address, txAccesses types.AccessList)
7373

7474
RevertToSnapshot(int)
7575
Snapshot() int

core/vm/runtime/runtime.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
125125
// Execute the preparatory steps for state transition which includes:
126126
// - prepare accessList(post-berlin)
127127
// - reset transient storage(eip 1153)
128-
cfg.State.Prepare(rules, cfg.Origin, &address, vm.ActivePrecompiles(rules), nil)
128+
cfg.State.Prepare(rules, cfg.Origin, cfg.Coinbase, &address, vm.ActivePrecompiles(rules), nil)
129129

130130
cfg.State.CreateAccount(address)
131131
// set the receiver's (the executing contract) code for execution.
@@ -160,7 +160,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {
160160
// Execute the preparatory steps for state transition which includes:
161161
// - prepare accessList(post-berlin)
162162
// - reset transient storage(eip 1153)
163-
cfg.State.Prepare(rules, cfg.Origin, nil, vm.ActivePrecompiles(rules), nil)
163+
cfg.State.Prepare(rules, cfg.Origin, cfg.Coinbase, nil, vm.ActivePrecompiles(rules), nil)
164164

165165
// Call the code with the given configuration.
166166
code, address, leftOverGas, err := vmenv.Create(
@@ -189,7 +189,7 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er
189189
// Execute the preparatory steps for state transition which includes:
190190
// - prepare accessList(post-berlin)
191191
// - reset transient storage(eip 1153)
192-
statedb.Prepare(rules, cfg.Origin, &address, vm.ActivePrecompiles(rules), nil)
192+
statedb.Prepare(rules, cfg.Origin, cfg.Coinbase, &address, vm.ActivePrecompiles(rules), nil)
193193

194194
// Call the code with the given configuration.
195195
ret, leftOverGas, err := vmenv.Call(

0 commit comments

Comments
 (0)