Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement EIP-3651(warm coinbase) #677

Open
wants to merge 1 commit into
base: dev-upgrade
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading