Skip to content

Commit 142d206

Browse files
committed
all: implement EIP-2718 + EIP-2930
1 parent 1a55e20 commit 142d206

27 files changed

+931
-242
lines changed

accounts/abi/bind/backends/simulated.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -705,14 +705,15 @@ type callMsg struct {
705705
ethereum.CallMsg
706706
}
707707

708-
func (m callMsg) From() common.Address { return m.CallMsg.From }
709-
func (m callMsg) Nonce() uint64 { return 0 }
710-
func (m callMsg) CheckNonce() bool { return false }
711-
func (m callMsg) To() *common.Address { return m.CallMsg.To }
712-
func (m callMsg) GasPrice() *big.Int { return m.CallMsg.GasPrice }
713-
func (m callMsg) Gas() uint64 { return m.CallMsg.Gas }
714-
func (m callMsg) Value() *big.Int { return m.CallMsg.Value }
715-
func (m callMsg) Data() []byte { return m.CallMsg.Data }
708+
func (m callMsg) From() common.Address { return m.CallMsg.From }
709+
func (m callMsg) Nonce() uint64 { return 0 }
710+
func (m callMsg) CheckNonce() bool { return false }
711+
func (m callMsg) To() *common.Address { return m.CallMsg.To }
712+
func (m callMsg) GasPrice() *big.Int { return m.CallMsg.GasPrice }
713+
func (m callMsg) Gas() uint64 { return m.CallMsg.Gas }
714+
func (m callMsg) Value() *big.Int { return m.CallMsg.Value }
715+
func (m callMsg) Data() []byte { return m.CallMsg.Data }
716+
func (m callMsg) AccessList() *types.AccessList { return m.CallMsg.AccessList }
716717

717718
// filterBackend implements filters.Backend to support filtering for logs without
718719
// taking bloom-bits acceleration structures into account.

core/bench_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) {
8585
return func(i int, gen *BlockGen) {
8686
toaddr := common.Address{}
8787
data := make([]byte, nbytes)
88-
gas, _ := IntrinsicGas(data, false, false, false)
88+
gas, _ := IntrinsicGas(data, nil, false, false, false, false)
8989
tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data), types.HomesteadSigner{}, benchRootKey)
9090
gen.AddTx(tx)
9191
}

core/blockchain_test.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3029,3 +3029,73 @@ func TestInitThenFailCreateContract(t *testing.T) {
30293029
}
30303030
}
30313031
}
3032+
3033+
func TestEIP2718Transition(t *testing.T) {
3034+
var (
3035+
aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa")
3036+
3037+
// Generate a canonical chain to act as the main dataset
3038+
engine = ethash.NewFaker()
3039+
db = rawdb.NewMemoryDatabase()
3040+
3041+
// A sender who makes transactions, has some funds
3042+
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
3043+
address = crypto.PubkeyToAddress(key.PublicKey)
3044+
funds = big.NewInt(1000000000)
3045+
gspec = &Genesis{
3046+
Config: params.YoloV2ChainConfig,
3047+
Alloc: GenesisAlloc{
3048+
address: {Balance: funds},
3049+
// The address 0xAAAAA selfdestructs if called
3050+
aa: {
3051+
// Code needs to just selfdestruct
3052+
Code: []byte{
3053+
byte(vm.PC),
3054+
byte(vm.PC),
3055+
byte(vm.SLOAD),
3056+
byte(vm.SLOAD),
3057+
},
3058+
Nonce: 0,
3059+
Balance: big.NewInt(0),
3060+
},
3061+
},
3062+
}
3063+
genesis = gspec.MustCommit(db)
3064+
)
3065+
3066+
blocks, _ := GenerateChain(gspec.Config, genesis, engine, db, 1, func(i int, b *BlockGen) {
3067+
b.SetCoinbase(common.Address{1})
3068+
3069+
// One transaction to AAAA
3070+
accesses := types.AccessList{types.AccessTuple{
3071+
Address: &aa,
3072+
StorageKeys: []*common.Hash{
3073+
{0},
3074+
},
3075+
}}
3076+
3077+
tx := types.NewAccessListTransaction(gspec.Config.ChainID, 0, aa, big.NewInt(0), 30000, big.NewInt(1), nil, &accesses)
3078+
tx, _ = types.SignTx(tx, types.NewEIP2718Signer(gspec.Config.ChainID), key)
3079+
3080+
b.AddTx(tx)
3081+
})
3082+
// Import the canonical chain
3083+
diskdb := rawdb.NewMemoryDatabase()
3084+
gspec.MustCommit(diskdb)
3085+
3086+
chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil)
3087+
if err != nil {
3088+
t.Fatalf("failed to create tester chain: %v", err)
3089+
}
3090+
if n, err := chain.InsertChain(blocks); err != nil {
3091+
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
3092+
}
3093+
3094+
block := chain.GetBlockByNumber(1)
3095+
3096+
expected := params.TxGas + params.TxAccessListAddress + params.TxAccessListStorageKey + vm.GasQuickStep*2 + vm.WarmStorageReadCostEIP2929 + vm.ColdSloadCostEIP2929
3097+
if block.GasUsed() != expected {
3098+
t.Fatalf("incorrect amount of gas spent: expected %d, got %d", expected, block.GasUsed())
3099+
3100+
}
3101+
}

core/error.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,6 @@ var (
6363
// ErrIntrinsicGas is returned if the transaction is specified to use less gas
6464
// than required to start the invocation.
6565
ErrIntrinsicGas = errors.New("intrinsic gas too low")
66+
67+
ErrTxTypeInvalid = errors.New("invalid tx type")
6668
)

core/state_processor.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
8686
// for the transaction, gas used and an error if the transaction failed,
8787
// indicating the block was invalid.
8888
func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, error) {
89+
if !config.IsYoloV2(header.Number) && tx.Type() != types.LegacyTxId {
90+
return nil, ErrTxTypeInvalid
91+
}
92+
8993
msg, err := tx.AsMessage(types.MakeSigner(config, header.Number))
9094
if err != nil {
9195
return nil, err
@@ -105,6 +109,14 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
105109
for _, addr := range vmenv.ActivePrecompiles() {
106110
statedb.AddAddressToAccessList(addr)
107111
}
112+
if msg.AccessList() != nil {
113+
for _, el := range *msg.AccessList() {
114+
statedb.AddAddressToAccessList(*el.Address)
115+
for _, key := range el.StorageKeys {
116+
statedb.AddSlotToAccessList(*el.Address, *key)
117+
}
118+
}
119+
}
108120
}
109121

110122
// Apply the transaction to the current state (included in the env)
@@ -123,7 +135,12 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
123135

124136
// Create a new receipt for the transaction, storing the intermediate root and gas used by the tx
125137
// based on the eip phase, we're passing whether the root touch-delete accounts.
126-
receipt := types.NewReceipt(root, result.Failed(), *usedGas)
138+
var receipt *types.Receipt
139+
if config.IsYoloV2(header.Number) {
140+
receipt = types.NewEIP2718Receipt(tx.Type(), root, result.Failed(), *usedGas)
141+
} else {
142+
receipt = types.NewReceipt(root, result.Failed(), *usedGas)
143+
}
127144
receipt.TxHash = tx.Hash()
128145
receipt.GasUsed = result.UsedGas
129146
// if the transaction created a contract, store the creation address in the receipt.

core/state_transition.go

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"math/big"
2222

2323
"github.com/ethereum/go-ethereum/common"
24+
"github.com/ethereum/go-ethereum/core/types"
2425
"github.com/ethereum/go-ethereum/core/vm"
2526
"github.com/ethereum/go-ethereum/params"
2627
)
@@ -50,6 +51,7 @@ type StateTransition struct {
5051
initialGas uint64
5152
value *big.Int
5253
data []byte
54+
accessList *types.AccessList
5355
state vm.StateDB
5456
evm *vm.EVM
5557
}
@@ -66,6 +68,7 @@ type Message interface {
6668
Nonce() uint64
6769
CheckNonce() bool
6870
Data() []byte
71+
AccessList() *types.AccessList
6972
}
7073

7174
// ExecutionResult includes all output after executing given evm
@@ -104,10 +107,10 @@ func (result *ExecutionResult) Revert() []byte {
104107
}
105108

106109
// IntrinsicGas computes the 'intrinsic gas' for a message with the given data.
107-
func IntrinsicGas(data []byte, contractCreation, isHomestead bool, isEIP2028 bool) (uint64, error) {
110+
func IntrinsicGas(data []byte, accessList *types.AccessList, isContractCreation bool, isHomestead, isEIP2028, isEIP2718 bool) (uint64, error) {
108111
// Set the starting gas for the raw transaction
109112
var gas uint64
110-
if contractCreation && isHomestead {
113+
if isContractCreation && isHomestead {
111114
gas = params.TxGasContractCreation
112115
} else {
113116
gas = params.TxGas
@@ -137,19 +140,26 @@ func IntrinsicGas(data []byte, contractCreation, isHomestead bool, isEIP2028 boo
137140
}
138141
gas += z * params.TxDataZeroGas
139142
}
143+
144+
if isEIP2718 && accessList != nil {
145+
gas += uint64(accessList.Addresses()) * params.TxAccessListAddress
146+
gas += uint64(accessList.StorageKeys()) * params.TxAccessListStorageKey
147+
}
148+
140149
return gas, nil
141150
}
142151

143152
// NewStateTransition initialises and returns a new state transition object.
144153
func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition {
145154
return &StateTransition{
146-
gp: gp,
147-
evm: evm,
148-
msg: msg,
149-
gasPrice: msg.GasPrice(),
150-
value: msg.Value(),
151-
data: msg.Data(),
152-
state: evm.StateDB,
155+
gp: gp,
156+
evm: evm,
157+
msg: msg,
158+
gasPrice: msg.GasPrice(),
159+
value: msg.Value(),
160+
data: msg.Data(),
161+
state: evm.StateDB,
162+
accessList: msg.AccessList(),
153163
}
154164
}
155165

@@ -232,10 +242,11 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
232242
sender := vm.AccountRef(msg.From())
233243
homestead := st.evm.ChainConfig().IsHomestead(st.evm.BlockNumber)
234244
istanbul := st.evm.ChainConfig().IsIstanbul(st.evm.BlockNumber)
245+
yoloV2 := st.evm.ChainConfig().IsYoloV2(st.evm.BlockNumber)
235246
contractCreation := msg.To() == nil
236247

237248
// Check clauses 4-5, subtract intrinsic gas if everything is correct
238-
gas, err := IntrinsicGas(st.data, contractCreation, homestead, istanbul)
249+
gas, err := IntrinsicGas(st.data, st.accessList, contractCreation, homestead, istanbul, yoloV2)
239250
if err != nil {
240251
return nil, err
241252
}

core/tx_pool.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ type TxPool struct {
224224
mu sync.RWMutex
225225

226226
istanbul bool // Fork indicator whether we are in the istanbul stage.
227+
yoloV2 bool // Fork indicator whether we are in the YoloV2 stage.
227228

228229
currentState *state.StateDB // Current state in the blockchain head
229230
pendingNonces *txNoncer // Pending state tracking virtual nonces
@@ -550,7 +551,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
550551
return ErrInsufficientFunds
551552
}
552553
// Ensure the transaction has more gas than the basic tx fee.
553-
intrGas, err := IntrinsicGas(tx.Data(), tx.To() == nil, true, pool.istanbul)
554+
intrGas, err := IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, pool.istanbul, pool.yoloV2)
554555
if err != nil {
555556
return err
556557
}
@@ -1180,6 +1181,7 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) {
11801181
// Update all fork indicator by next pending block number.
11811182
next := new(big.Int).Add(newHead.Number, big.NewInt(1))
11821183
pool.istanbul = pool.chainconfig.IsIstanbul(next)
1184+
pool.yoloV2 = pool.chainconfig.IsYoloV2(next)
11831185
}
11841186

11851187
// promoteExecutables moves transactions that have become processable from the

0 commit comments

Comments
 (0)