Skip to content

Commit 365588a

Browse files
MariusVanDerWijdenshekhirin
authored andcommitted
core: implement EIP-3651, warm coinbase (ethereum#25819)
Implements EIP-3651, "Warm Coinbase", for Shanghai hardfork. Specification: https://eips.ethereum.org/EIPS/eip-3651.
1 parent b169320 commit 365588a

File tree

6 files changed

+128
-14
lines changed

6 files changed

+128
-14
lines changed

core/blockchain_test.go

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4187,3 +4187,111 @@ func TestTransientStorageReset(t *testing.T) {
41874187
t.Fatalf("Unexpected dirty storage slot")
41884188
}
41894189
}
4190+
4191+
func TestEIP3651(t *testing.T) {
4192+
var (
4193+
aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa")
4194+
bb = common.HexToAddress("0x000000000000000000000000000000000000bbbb")
4195+
engine = ethash.NewFaker()
4196+
4197+
// A sender who makes transactions, has some funds
4198+
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
4199+
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
4200+
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
4201+
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
4202+
funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether))
4203+
gspec = &Genesis{
4204+
Config: params.AllEthashProtocolChanges,
4205+
Alloc: GenesisAlloc{
4206+
addr1: {Balance: funds},
4207+
addr2: {Balance: funds},
4208+
// The address 0xAAAA sloads 0x00 and 0x01
4209+
aa: {
4210+
Code: []byte{
4211+
byte(vm.PC),
4212+
byte(vm.PC),
4213+
byte(vm.SLOAD),
4214+
byte(vm.SLOAD),
4215+
},
4216+
Nonce: 0,
4217+
Balance: big.NewInt(0),
4218+
},
4219+
// The address 0xBBBB calls 0xAAAA
4220+
bb: {
4221+
Code: []byte{
4222+
byte(vm.PUSH1), 0, // out size
4223+
byte(vm.DUP1), // out offset
4224+
byte(vm.DUP1), // out insize
4225+
byte(vm.DUP1), // in offset
4226+
byte(vm.PUSH2), // address
4227+
byte(0xaa),
4228+
byte(0xaa),
4229+
byte(vm.GAS), // gas
4230+
byte(vm.DELEGATECALL),
4231+
},
4232+
Nonce: 0,
4233+
Balance: big.NewInt(0),
4234+
},
4235+
},
4236+
}
4237+
)
4238+
4239+
gspec.Config.BerlinBlock = common.Big0
4240+
gspec.Config.LondonBlock = common.Big0
4241+
gspec.Config.ShanghaiBlock = common.Big0
4242+
signer := types.LatestSigner(gspec.Config)
4243+
4244+
_, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) {
4245+
b.SetCoinbase(aa)
4246+
// One transaction to Coinbase
4247+
txdata := &types.DynamicFeeTx{
4248+
ChainID: gspec.Config.ChainID,
4249+
Nonce: 0,
4250+
To: &bb,
4251+
Gas: 500000,
4252+
GasFeeCap: newGwei(5),
4253+
GasTipCap: big.NewInt(2),
4254+
AccessList: nil,
4255+
Data: []byte{},
4256+
}
4257+
tx := types.NewTx(txdata)
4258+
tx, _ = types.SignTx(tx, signer, key1)
4259+
4260+
b.AddTx(tx)
4261+
})
4262+
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{Tracer: logger.NewMarkdownLogger(&logger.Config{}, os.Stderr)}, nil, nil)
4263+
if err != nil {
4264+
t.Fatalf("failed to create tester chain: %v", err)
4265+
}
4266+
if n, err := chain.InsertChain(blocks); err != nil {
4267+
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
4268+
}
4269+
4270+
block := chain.GetBlockByNumber(1)
4271+
4272+
// 1+2: Ensure EIP-1559 access lists are accounted for via gas usage.
4273+
innerGas := vm.GasQuickStep*2 + params.ColdSloadCostEIP2929*2
4274+
expectedGas := params.TxGas + 5*vm.GasFastestStep + vm.GasQuickStep + 100 + innerGas // 100 because 0xaaaa is in access list
4275+
if block.GasUsed() != expectedGas {
4276+
t.Fatalf("incorrect amount of gas spent: expected %d, got %d", expectedGas, block.GasUsed())
4277+
}
4278+
4279+
state, _ := chain.State()
4280+
4281+
// 3: Ensure that miner received only the tx's tip.
4282+
actual := state.GetBalance(block.Coinbase())
4283+
expected := new(big.Int).Add(
4284+
new(big.Int).SetUint64(block.GasUsed()*block.Transactions()[0].GasTipCap().Uint64()),
4285+
ethash.ConstantinopleBlockReward,
4286+
)
4287+
if actual.Cmp(expected) != 0 {
4288+
t.Fatalf("miner balance incorrect: expected %d, got %d", expected, actual)
4289+
}
4290+
4291+
// 4: Ensure the tx sender paid for the gasUsed * (tip + block baseFee).
4292+
actual = new(big.Int).Sub(funds, state.GetBalance(addr1))
4293+
expected = new(big.Int).SetUint64(block.GasUsed() * (block.Transactions()[0].GasTipCap().Uint64() + block.BaseFee().Uint64()))
4294+
if actual.Cmp(expected) != 0 {
4295+
t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual)
4296+
}
4297+
}

core/state/statedb.go

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1067,26 +1067,32 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
10671067
// - Add the contents of the optional tx access list (2930)
10681068
//
10691069
// Potential EIPs:
1070-
// - Reset transient storage(1153)
1071-
func (s *StateDB) Prepare(rules params.Rules, sender common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList) {
1070+
// - Reset access list (Berlin)
1071+
// - Add coinbase to access list (EIP-3651)
1072+
// - Reset transient storage (EIP-1153)
1073+
func (s *StateDB) Prepare(rules params.Rules, sender, coinbase common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList) {
10721074
if rules.IsBerlin {
10731075
// Clear out any leftover from previous executions
1074-
s.accessList = newAccessList()
1076+
al := newAccessList()
1077+
s.accessList = al
10751078

1076-
s.AddAddressToAccessList(sender)
1079+
al.AddAddress(sender)
10771080
if dst != nil {
1078-
s.AddAddressToAccessList(*dst)
1081+
al.AddAddress(*dst)
10791082
// If it's a create-tx, the destination will be added inside evm.create
10801083
}
10811084
for _, addr := range precompiles {
1082-
s.AddAddressToAccessList(addr)
1085+
al.AddAddress(addr)
10831086
}
10841087
for _, el := range list {
1085-
s.AddAddressToAccessList(el.Address)
1088+
al.AddAddress(el.Address)
10861089
for _, key := range el.StorageKeys {
1087-
s.AddSlotToAccessList(el.Address, key)
1090+
al.AddSlot(el.Address, key)
10881091
}
10891092
}
1093+
if rules.IsShanghai { // EIP-3651: warm coinbase
1094+
al.AddAddress(coinbase)
1095+
}
10901096
}
10911097
// Reset transient storage at the beginning of transaction execution
10921098
s.transientStorage = newTransientStorage()

core/state_transition.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
322322
// Execute the preparatory steps for state transition which includes:
323323
// - prepare accessList(post-berlin)
324324
// - reset transient storage(eip 1153)
325-
st.state.Prepare(rules, msg.From(), msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())
325+
st.state.Prepare(rules, msg.From(), st.evm.Context.Coinbase, msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())
326326

327327
var (
328328
ret []byte

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
@@ -122,7 +122,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
122122
// Execute the preparatory steps for state transition which includes:
123123
// - prepare accessList(post-berlin)
124124
// - reset transient storage(eip 1153)
125-
cfg.State.Prepare(rules, cfg.Origin, &address, vm.ActivePrecompiles(rules), nil)
125+
cfg.State.Prepare(rules, cfg.Origin, cfg.Coinbase, &address, vm.ActivePrecompiles(rules), nil)
126126

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

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

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

tests/state_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ func runBenchmark(b *testing.B, t *StateTest) {
241241
b.ResetTimer()
242242
for n := 0; n < b.N; n++ {
243243
snapshot := statedb.Snapshot()
244-
statedb.Prepare(rules, msg.From(), msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())
244+
statedb.Prepare(rules, msg.From(), context.Coinbase, msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())
245245
b.StartTimer()
246246
start := time.Now()
247247

0 commit comments

Comments
 (0)