Skip to content

Commit 29b23f4

Browse files
core: implement EIP-3651, warm coinbase (#317)
* core: implement EIP-3651, warm coinbase (ethereum#25819) Implements EIP-3651, "Warm Coinbase", for Shanghai hardfork. Specification: https://eips.ethereum.org/EIPS/eip-3651. * improve test * update to shanghai * trigger ci * fix comments --------- Co-authored-by: Marius van der Wijden <[email protected]>
1 parent b1e5eea commit 29b23f4

File tree

5 files changed

+128
-7
lines changed

5 files changed

+128
-7
lines changed

core/blockchain_test.go

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3238,3 +3238,118 @@ func TestTransactionCountLimit(t *testing.T) {
32383238
t.Fatalf("error mismatch: have: %v, want: %v", err, consensus.ErrInvalidTxCount)
32393239
}
32403240
}
3241+
3242+
func TestEIP3651(t *testing.T) {
3243+
var (
3244+
addraa = common.HexToAddress("0x000000000000000000000000000000000000aaaa")
3245+
addrbb = common.HexToAddress("0x000000000000000000000000000000000000bbbb")
3246+
engine = ethash.NewFaker()
3247+
db = rawdb.NewMemoryDatabase()
3248+
3249+
// A sender who makes transactions, has some funds
3250+
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
3251+
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
3252+
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
3253+
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
3254+
funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether))
3255+
gspec = &Genesis{
3256+
Config: params.AllEthashProtocolChanges,
3257+
Alloc: GenesisAlloc{
3258+
addr1: {Balance: funds},
3259+
addr2: {Balance: funds},
3260+
// The address 0xAAAA sloads 0x00 and 0x01
3261+
addraa: {
3262+
Code: []byte{
3263+
byte(vm.PC),
3264+
byte(vm.PC),
3265+
byte(vm.SLOAD),
3266+
byte(vm.SLOAD),
3267+
},
3268+
Nonce: 0,
3269+
Balance: big.NewInt(0),
3270+
},
3271+
// The address 0xBBBB calls 0xAAAA
3272+
addrbb: {
3273+
Code: []byte{
3274+
byte(vm.PUSH1), 0, // out size
3275+
byte(vm.DUP1), // out offset
3276+
byte(vm.DUP1), // out insize
3277+
byte(vm.DUP1), // in offset
3278+
byte(vm.PUSH2), // address
3279+
byte(0xaa),
3280+
byte(0xaa),
3281+
byte(vm.GAS), // gas
3282+
byte(vm.DELEGATECALL),
3283+
},
3284+
Nonce: 0,
3285+
Balance: big.NewInt(0),
3286+
},
3287+
},
3288+
}
3289+
genesis = gspec.MustCommit(db)
3290+
)
3291+
3292+
gspec.Config.BerlinBlock = common.Big0
3293+
gspec.Config.LondonBlock = common.Big0
3294+
gspec.Config.ShanghaiBlock = common.Big0
3295+
signer := types.LatestSigner(gspec.Config)
3296+
3297+
blocks, _ := GenerateChain(gspec.Config, genesis, engine, db, 1, func(i int, b *BlockGen) {
3298+
b.SetCoinbase(addraa)
3299+
// One transaction to Coinbase
3300+
txdata := &types.DynamicFeeTx{
3301+
ChainID: gspec.Config.ChainID,
3302+
Nonce: 0,
3303+
To: &addrbb,
3304+
Gas: 500000,
3305+
GasFeeCap: newGwei(5),
3306+
GasTipCap: big.NewInt(2),
3307+
AccessList: nil,
3308+
Data: []byte{},
3309+
}
3310+
tx := types.NewTx(txdata)
3311+
tx, err := types.SignTx(tx, signer, key1)
3312+
if err != nil {
3313+
t.Fatalf("failed to sign tx: %v", err)
3314+
}
3315+
b.AddTx(tx)
3316+
})
3317+
chain, err := NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil)
3318+
if err != nil {
3319+
t.Fatalf("failed to create tester chain: %v", err)
3320+
}
3321+
if n, err := chain.InsertChain(blocks); err != nil {
3322+
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
3323+
}
3324+
3325+
block := chain.GetBlockByNumber(1)
3326+
3327+
// 1+2: Ensure EIP-1559 access lists are accounted for via gas usage.
3328+
innerGas := vm.GasQuickStep*2 + params.ColdSloadCostEIP2929*2
3329+
expectedGas := params.TxGas + 5*vm.GasFastestStep + vm.GasQuickStep + 100 + innerGas // 100 because 0xaaaa is in access list
3330+
if block.GasUsed() != expectedGas {
3331+
t.Fatalf("incorrect amount of gas spent: expected %d, got %d", expectedGas, block.GasUsed())
3332+
}
3333+
3334+
state, err := chain.State()
3335+
if err != nil {
3336+
t.Fatalf("failed to get new state: %v", err)
3337+
}
3338+
3339+
// 3: Ensure that miner received only the tx's tip.
3340+
actual := state.GetBalance(block.Coinbase())
3341+
expected := new(big.Int).Add(
3342+
new(big.Int).SetUint64(block.GasUsed()*block.Transactions()[0].GasTipCap().Uint64()),
3343+
ethash.ConstantinopleBlockReward,
3344+
)
3345+
if actual.Cmp(expected) != 0 {
3346+
t.Fatalf("miner balance incorrect: expected %d, got %d", expected, actual)
3347+
}
3348+
3349+
// 4: Ensure the tx sender paid for the gasUsed * (tip + block baseFee).
3350+
actual = new(big.Int).Sub(funds, state.GetBalance(addr1))
3351+
expected = new(big.Int).SetUint64(block.GasUsed() * (block.Transactions()[0].GasTipCap().Uint64() + block.BaseFee().Uint64()))
3352+
if actual.Cmp(expected) != 0 {
3353+
t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual)
3354+
}
3355+
}

core/state/statedb.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
"github.com/scroll-tech/go-ethereum/crypto"
3434
"github.com/scroll-tech/go-ethereum/log"
3535
"github.com/scroll-tech/go-ethereum/metrics"
36+
"github.com/scroll-tech/go-ethereum/params"
3637
"github.com/scroll-tech/go-ethereum/rlp"
3738
"github.com/scroll-tech/go-ethereum/trie"
3839
)
@@ -1018,15 +1019,16 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
10181019
}
10191020

10201021
// PrepareAccessList handles the preparatory steps for executing a state transition with
1021-
// regards to both EIP-2929 and EIP-2930:
1022+
// regards to EIP-2929, EIP-2930 and EIP-3651:
10221023
//
10231024
// - Add sender to access list (2929)
10241025
// - Add destination to access list (2929)
10251026
// - Add precompiles to access list (2929)
10261027
// - Add the contents of the optional tx access list (2930)
1028+
// - Add coinbase to access list (3651)
10271029
//
10281030
// This method should only be called if Berlin/2929+2930 is applicable at the current number.
1029-
func (s *StateDB) PrepareAccessList(sender common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList) {
1031+
func (s *StateDB) PrepareAccessList(rules params.Rules, sender, coinbase common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList) {
10301032
s.AddAddressToAccessList(sender)
10311033
if dst != nil {
10321034
s.AddAddressToAccessList(*dst)
@@ -1041,6 +1043,9 @@ func (s *StateDB) PrepareAccessList(sender common.Address, dst *common.Address,
10411043
s.AddSlotToAccessList(el.Address, key)
10421044
}
10431045
}
1046+
if rules.IsShanghai { // EIP-3651: warm coinbase
1047+
s.AddAddressToAccessList(coinbase)
1048+
}
10441049
}
10451050

10461051
// AddAddressToAccessList adds the given address to the access list

core/state_transition.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
338338

339339
// Set up the initial access list.
340340
if rules := st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber); rules.IsBerlin {
341-
st.state.PrepareAccessList(msg.From(), msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())
341+
st.state.PrepareAccessList(rules, msg.From(), st.evm.Context.Coinbase, msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())
342342
}
343343
var (
344344
ret []byte

core/vm/interface.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121

2222
"github.com/scroll-tech/go-ethereum/common"
2323
"github.com/scroll-tech/go-ethereum/core/types"
24+
"github.com/scroll-tech/go-ethereum/params"
2425
)
2526

2627
// StateDB is an EVM database for full state querying.
@@ -64,7 +65,7 @@ type StateDB interface {
6465
// is defined according to EIP161 (balance = nonce = code = 0).
6566
Empty(common.Address) bool
6667

67-
PrepareAccessList(sender common.Address, dest *common.Address, precompiles []common.Address, txAccesses types.AccessList)
68+
PrepareAccessList(rules params.Rules, sender, coinbase common.Address, dest *common.Address, precompiles []common.Address, txAccesses types.AccessList)
6869
AddressInAccessList(addr common.Address) bool
6970
SlotInAccessList(addr common.Address, slot common.Hash) (addressOk bool, slotOk bool)
7071
// AddAddressToAccessList adds the given address to the access list. This operation is safe to perform

core/vm/runtime/runtime.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
120120
sender = vm.AccountRef(cfg.Origin)
121121
)
122122
if rules := cfg.ChainConfig.Rules(vmenv.Context.BlockNumber); rules.IsBerlin {
123-
cfg.State.PrepareAccessList(cfg.Origin, &address, vm.ActivePrecompiles(rules), nil)
123+
cfg.State.PrepareAccessList(rules, cfg.Origin, cfg.Coinbase, &address, vm.ActivePrecompiles(rules), nil)
124124
}
125125
cfg.State.CreateAccount(address)
126126
// set the receiver's (the executing contract) code for execution.
@@ -152,7 +152,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {
152152
sender = vm.AccountRef(cfg.Origin)
153153
)
154154
if rules := cfg.ChainConfig.Rules(vmenv.Context.BlockNumber); rules.IsBerlin {
155-
cfg.State.PrepareAccessList(cfg.Origin, nil, vm.ActivePrecompiles(rules), nil)
155+
cfg.State.PrepareAccessList(rules, cfg.Origin, cfg.Coinbase, nil, vm.ActivePrecompiles(rules), nil)
156156
}
157157
// Call the code with the given configuration.
158158
code, address, leftOverGas, err := vmenv.Create(
@@ -178,7 +178,7 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er
178178
statedb := cfg.State
179179

180180
if rules := cfg.ChainConfig.Rules(vmenv.Context.BlockNumber); rules.IsBerlin {
181-
statedb.PrepareAccessList(cfg.Origin, &address, vm.ActivePrecompiles(rules), nil)
181+
statedb.PrepareAccessList(rules, cfg.Origin, cfg.Coinbase, &address, vm.ActivePrecompiles(rules), nil)
182182
}
183183
// Call the code with the given configuration.
184184
ret, leftOverGas, err := vmenv.Call(

0 commit comments

Comments
 (0)