mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-28 07:36:44 +00:00
core: implement EIP-3651, warm coinbase (#317)
* core: implement EIP-3651, warm coinbase (#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 <m.vanderwijden@live.de>
This commit is contained in:
parent
b1e5eea84d
commit
29b23f4f5b
5 changed files with 128 additions and 7 deletions
|
|
@ -3238,3 +3238,118 @@ func TestTransactionCountLimit(t *testing.T) {
|
|||
t.Fatalf("error mismatch: have: %v, want: %v", err, consensus.ErrInvalidTxCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEIP3651(t *testing.T) {
|
||||
var (
|
||||
addraa = common.HexToAddress("0x000000000000000000000000000000000000aaaa")
|
||||
addrbb = common.HexToAddress("0x000000000000000000000000000000000000bbbb")
|
||||
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
|
||||
addraa: {
|
||||
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
|
||||
addrbb: {
|
||||
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),
|
||||
},
|
||||
},
|
||||
}
|
||||
genesis = gspec.MustCommit(db)
|
||||
)
|
||||
|
||||
gspec.Config.BerlinBlock = common.Big0
|
||||
gspec.Config.LondonBlock = common.Big0
|
||||
gspec.Config.ShanghaiBlock = common.Big0
|
||||
signer := types.LatestSigner(gspec.Config)
|
||||
|
||||
blocks, _ := GenerateChain(gspec.Config, genesis, engine, db, 1, func(i int, b *BlockGen) {
|
||||
b.SetCoinbase(addraa)
|
||||
// One transaction to Coinbase
|
||||
txdata := &types.DynamicFeeTx{
|
||||
ChainID: gspec.Config.ChainID,
|
||||
Nonce: 0,
|
||||
To: &addrbb,
|
||||
Gas: 500000,
|
||||
GasFeeCap: newGwei(5),
|
||||
GasTipCap: big.NewInt(2),
|
||||
AccessList: nil,
|
||||
Data: []byte{},
|
||||
}
|
||||
tx := types.NewTx(txdata)
|
||||
tx, err := types.SignTx(tx, signer, key1)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to sign tx: %v", err)
|
||||
}
|
||||
b.AddTx(tx)
|
||||
})
|
||||
chain, err := NewBlockChain(db, 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.
|
||||
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, err := chain.State()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get new state: %v", err)
|
||||
}
|
||||
|
||||
// 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()),
|
||||
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].GasTipCap().Uint64() + block.BaseFee().Uint64()))
|
||||
if actual.Cmp(expected) != 0 {
|
||||
t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import (
|
|||
"github.com/scroll-tech/go-ethereum/crypto"
|
||||
"github.com/scroll-tech/go-ethereum/log"
|
||||
"github.com/scroll-tech/go-ethereum/metrics"
|
||||
"github.com/scroll-tech/go-ethereum/params"
|
||||
"github.com/scroll-tech/go-ethereum/rlp"
|
||||
"github.com/scroll-tech/go-ethereum/trie"
|
||||
)
|
||||
|
|
@ -1018,15 +1019,16 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
|
|||
}
|
||||
|
||||
// PrepareAccessList handles the preparatory steps for executing a state transition with
|
||||
// regards to both EIP-2929 and EIP-2930:
|
||||
// regards to EIP-2929, EIP-2930 and EIP-3651:
|
||||
//
|
||||
// - Add sender to access list (2929)
|
||||
// - Add destination to access list (2929)
|
||||
// - Add precompiles to access list (2929)
|
||||
// - Add the contents of the optional tx access list (2930)
|
||||
// - Add coinbase to access list (3651)
|
||||
//
|
||||
// This method should only be called if Berlin/2929+2930 is applicable at the current number.
|
||||
func (s *StateDB) PrepareAccessList(sender common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList) {
|
||||
func (s *StateDB) PrepareAccessList(rules params.Rules, sender, coinbase common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList) {
|
||||
s.AddAddressToAccessList(sender)
|
||||
if dst != nil {
|
||||
s.AddAddressToAccessList(*dst)
|
||||
|
|
@ -1041,6 +1043,9 @@ func (s *StateDB) PrepareAccessList(sender common.Address, dst *common.Address,
|
|||
s.AddSlotToAccessList(el.Address, key)
|
||||
}
|
||||
}
|
||||
if rules.IsShanghai { // EIP-3651: warm coinbase
|
||||
s.AddAddressToAccessList(coinbase)
|
||||
}
|
||||
}
|
||||
|
||||
// AddAddressToAccessList adds the given address to the access list
|
||||
|
|
|
|||
|
|
@ -338,7 +338,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
|||
|
||||
// Set up the initial access list.
|
||||
if rules := st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber); rules.IsBerlin {
|
||||
st.state.PrepareAccessList(msg.From(), msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())
|
||||
st.state.PrepareAccessList(rules, msg.From(), st.evm.Context.Coinbase, msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())
|
||||
}
|
||||
var (
|
||||
ret []byte
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import (
|
|||
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
"github.com/scroll-tech/go-ethereum/core/types"
|
||||
"github.com/scroll-tech/go-ethereum/params"
|
||||
)
|
||||
|
||||
// StateDB is an EVM database for full state querying.
|
||||
|
|
@ -64,7 +65,7 @@ type StateDB interface {
|
|||
// is defined according to EIP161 (balance = nonce = code = 0).
|
||||
Empty(common.Address) bool
|
||||
|
||||
PrepareAccessList(sender common.Address, dest *common.Address, precompiles []common.Address, txAccesses types.AccessList)
|
||||
PrepareAccessList(rules params.Rules, sender, coinbase common.Address, dest *common.Address, precompiles []common.Address, txAccesses types.AccessList)
|
||||
AddressInAccessList(addr common.Address) bool
|
||||
SlotInAccessList(addr common.Address, slot common.Hash) (addressOk bool, slotOk bool)
|
||||
// AddAddressToAccessList adds the given address to the access list. This operation is safe to perform
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
|
|||
sender = vm.AccountRef(cfg.Origin)
|
||||
)
|
||||
if rules := cfg.ChainConfig.Rules(vmenv.Context.BlockNumber); rules.IsBerlin {
|
||||
cfg.State.PrepareAccessList(cfg.Origin, &address, vm.ActivePrecompiles(rules), nil)
|
||||
cfg.State.PrepareAccessList(rules, cfg.Origin, cfg.Coinbase, &address, vm.ActivePrecompiles(rules), nil)
|
||||
}
|
||||
cfg.State.CreateAccount(address)
|
||||
// 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) {
|
|||
sender = vm.AccountRef(cfg.Origin)
|
||||
)
|
||||
if rules := cfg.ChainConfig.Rules(vmenv.Context.BlockNumber); rules.IsBerlin {
|
||||
cfg.State.PrepareAccessList(cfg.Origin, nil, vm.ActivePrecompiles(rules), nil)
|
||||
cfg.State.PrepareAccessList(rules, cfg.Origin, cfg.Coinbase, nil, vm.ActivePrecompiles(rules), nil)
|
||||
}
|
||||
// Call the code with the given configuration.
|
||||
code, address, leftOverGas, err := vmenv.Create(
|
||||
|
|
@ -178,7 +178,7 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er
|
|||
statedb := cfg.State
|
||||
|
||||
if rules := cfg.ChainConfig.Rules(vmenv.Context.BlockNumber); rules.IsBerlin {
|
||||
statedb.PrepareAccessList(cfg.Origin, &address, vm.ActivePrecompiles(rules), nil)
|
||||
statedb.PrepareAccessList(rules, cfg.Origin, cfg.Coinbase, &address, vm.ActivePrecompiles(rules), nil)
|
||||
}
|
||||
// Call the code with the given configuration.
|
||||
ret, leftOverGas, err := vmenv.Call(
|
||||
|
|
|
|||
Loading…
Reference in a new issue