Skip to content

Commit

Permalink
core: implement EIP-3651, warm coinbase (ethereum#25819)
Browse files Browse the repository at this point in the history
  • Loading branch information
gzliudan committed Nov 20, 2024
1 parent 8e72c6d commit 08e9592
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 13 deletions.
112 changes: 112 additions & 0 deletions core/blockchain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1609,3 +1609,115 @@ func TestTransientStorageReset(t *testing.T) {
t.Fatalf("Unexpected dirty storage slot")
}
}

func TestEIP3651(t *testing.T) {
var (
ConstantinopleBlockReward = big.NewInt(3e+18) // Block reward in wei for successfully mining a block upward from Constantinople

aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa")
bb = common.HexToAddress("0x000000000000000000000000000000000000bbbb")
engine = ethash.NewFaker()

// 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 = big.NewInt(8000000000000000)
gspec = &Genesis{
Config: params.TestChainConfig,
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),
},
// The address 0xBBBB calls 0xAAAA
bb: {
Code: []byte{
byte(vm.PUSH1), 0, // out size
byte(vm.DUP1), // out offset
byte(vm.DUP1), // out insize
byte(vm.DUP1), // in offset
byte(vm.PUSH2), // address
byte(0xaa),
byte(0xaa),
byte(vm.GAS), // gas
byte(vm.DELEGATECALL),
},
Nonce: 0,
Balance: big.NewInt(0),
},
},
}
)

gspec.Config.Eip1559Block = common.Big0
signer := types.LatestSigner(gspec.Config)

_, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) {
b.SetCoinbase(aa)
// One transaction to Coinbase
txdata := &types.DynamicFeeTx{
ChainID: gspec.Config.ChainId,
Nonce: 0,
To: &bb,
Gas: 500000,
GasFeeCap: big.NewInt(12500000000),
GasTipCap: big.NewInt(0),
AccessList: nil,
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{})
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.
innerGas := vm.GasQuickStep*2 + params.ColdSloadCostEIP2929*2
expectedGas := params.TxGas + 5*vm.GasFastestStep + vm.GasQuickStep + 100 + innerGas // 100 because 0xaaaa is in access list
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].GasTipCap().Uint64()),
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].GasTipCap().Uint64() + block.BaseFee().Uint64()))
if actual.Cmp(expected) != 0 {
t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual)
}
}
21 changes: 13 additions & 8 deletions core/state/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -765,26 +765,31 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (root common.Hash, err error)
// - Add the contents of the optional tx access list (2930)
//
// Potential EIPs:
// - Reset transient storage(1153)
func (s *StateDB) Prepare(rules params.Rules, sender common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList) {
// - Reset access list (Berlin)
// - Add coinbase to access list (EIP-3651)
// - Reset transient storage (EIP-1153)
func (s *StateDB) Prepare(rules params.Rules, sender, coinbase common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList) {
if rules.IsEIP1559 {
// Clear out any leftover from previous executions
s.accessList = newAccessList()
al := newAccessList()
s.accessList = al

s.AddAddressToAccessList(sender)
al.AddAddress(sender)
if dst != nil {
s.AddAddressToAccessList(*dst)
al.AddAddress(*dst)
// If it's a create-tx, the destination will be added inside evm.create
}
for _, addr := range precompiles {
s.AddAddressToAccessList(addr)
al.AddAddress(addr)
}
for _, el := range list {
s.AddAddressToAccessList(el.Address)
al.AddAddress(el.Address)
for _, key := range el.StorageKeys {
s.AddSlotToAccessList(el.Address, key)
al.AddSlot(el.Address, key)
}
}
// EIP-3651: warm coinbase
al.AddAddress(coinbase)
}
// Reset transient storage at the beginning of transaction execution
s.transientStorage = newTransientStorage()
Expand Down
2 changes: 1 addition & 1 deletion core/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ func (st *StateTransition) TransitionDb(owner common.Address) (ret []byte, usedG
// Execute the preparatory steps for state transition which includes:
// - prepare accessList(post-berlin)
// - reset transient storage(eip 1153)
st.state.Prepare(rules, msg.From(), msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())
st.state.Prepare(rules, msg.From(), st.evm.Context.Coinbase, msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())

var (
evm = st.evm
Expand Down
2 changes: 1 addition & 1 deletion core/vm/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ type StateDB interface {
// AddSlotToAccessList adds the given (address,slot) to the access list. This operation is safe to perform
// even if the feature/fork is not active yet
AddSlotToAccessList(addr common.Address, slot common.Hash)
Prepare(rules params.Rules, sender common.Address, dest *common.Address, precompiles []common.Address, txAccesses types.AccessList)
Prepare(rules params.Rules, sender, coinbase common.Address, dest *common.Address, precompiles []common.Address, txAccesses types.AccessList)

RevertToSnapshot(int)
Snapshot() int
Expand Down
6 changes: 3 additions & 3 deletions core/vm/runtime/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
// Execute the preparatory steps for state transition which includes:
// - prepare accessList(post-berlin)
// - reset transient storage(eip 1153)
cfg.State.Prepare(rules, cfg.Origin, &address, vm.ActivePrecompiles(rules), nil)
cfg.State.Prepare(rules, cfg.Origin, cfg.Coinbase, &address, vm.ActivePrecompiles(rules), nil)

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

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

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

0 comments on commit 08e9592

Please sign in to comment.