Skip to content

Commit 60cbf64

Browse files
colinlyguoThegaram
andauthored
feat: add EIP-7702 (#1112)
* feat: add EIP-7702 * fix goimport * add unit tests * add api test * sync txpool update * update generated code * make code readable * fix goimport * fix TestAsyncChecker unit test * add AuthorizationList in fuzz tests for completeness sake * add EuclidV2 test, EIP-7702 transaction in TestT8n * clean up logs * bump version * fix TestAsyncChecker * Revert "fix TestAsyncChecker" This reverts commit 314478303d4a504a3948bd6595568916ba7d82f0. * accept eip-7702 txns only after enabling eip-7702 * revert IntrinsicGas param name from setCodeAuthorizations to authList * fix a bug * align upstream implementation in Encoding Receipts * fix one test case * fix tracer * return precode copy * support setcode tx in EstimateGas and add unit tests * add TestValidateAuthorizations * poseidon hash fix * migrate a fix before the fix pr is merged * support setcode type transactions in TransactionData * chore: auto version bump [bot] * add a nonce-gapped-auth-does-not-block-pending-tx unit test * make the auth invalid * Apply suggestions from code review * change usedAndLeftSlots and knownConflicts to util functions * add comments about different return of applyAuthorization * remove gencodec:required in transaction signatures * fix goimport * update StructLogger and AccessListTracer * fix a bug * fix flaky test --------- Co-authored-by: colinlyguo <[email protected]> Co-authored-by: Péter Garamvölgyi <[email protected]>
1 parent 6843832 commit 60cbf64

File tree

96 files changed

+2722
-290
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

96 files changed

+2722
-290
lines changed

Makefile

+5
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ test: all
4343
$(GORUN) build/ci.go test ./consensus ./core ./eth ./miner ./node ./trie ./rollup/...
4444
# RIP-7212 (secp256r1) precompiled contract test
4545
cd ${PWD}/core/vm; go test -v -run=^TestPrecompiledP256 -bench=^BenchmarkPrecompiledP256
46+
# EIP-7702 test
47+
cd ${PWD}/core/vm/runtime; go test -v -run=^TestDelegatedAccountAccessCost
48+
cd ${PWD}/core/types; go test -v -run=^TestParseDelegation
49+
cd ${PWD}/internal/ethapi; go test -v -run=^TestEstimateGas
50+
cd ${PWD}/cmd/evm; go test -v -run=^TestT8n
4651

4752
lint: ## Run linters.
4853
$(GORUN) build/ci.go lint

accounts/abi/bind/backends/simulated.go

+16-15
Original file line numberDiff line numberDiff line change
@@ -639,7 +639,7 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
639639
// about the transaction and calling mechanisms.
640640
vmEnv := vm.NewEVM(evmContext, txContext, stateDB, b.config, vm.Config{NoBaseFee: true})
641641
gasPool := new(core.GasPool).AddGas(math.MaxUint64)
642-
signer := types.MakeSigner(b.blockchain.Config(), head.Number)
642+
signer := types.MakeSigner(b.blockchain.Config(), head.Number, head.Time)
643643
l1DataFee, err := fees.EstimateL1DataFeeForMessage(msg, head.BaseFee, b.blockchain.Config(), signer, stateDB, head.Number)
644644
if err != nil {
645645
return nil, err
@@ -660,7 +660,7 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
660660
panic("could not fetch parent")
661661
}
662662
// Check transaction validity
663-
signer := types.MakeSigner(b.blockchain.Config(), block.Number())
663+
signer := types.MakeSigner(b.blockchain.Config(), block.Number(), block.Time())
664664
sender, err := types.Sender(signer, tx)
665665
if err != nil {
666666
panic(fmt.Errorf("invalid transaction: %v", err))
@@ -809,19 +809,20 @@ type callMsg struct {
809809
ethereum.CallMsg
810810
}
811811

812-
func (m callMsg) From() common.Address { return m.CallMsg.From }
813-
func (m callMsg) Nonce() uint64 { return 0 }
814-
func (m callMsg) IsFake() bool { return true }
815-
func (m callMsg) To() *common.Address { return m.CallMsg.To }
816-
func (m callMsg) GasPrice() *big.Int { return m.CallMsg.GasPrice }
817-
func (m callMsg) GasFeeCap() *big.Int { return m.CallMsg.GasFeeCap }
818-
func (m callMsg) GasTipCap() *big.Int { return m.CallMsg.GasTipCap }
819-
func (m callMsg) Gas() uint64 { return m.CallMsg.Gas }
820-
func (m callMsg) Value() *big.Int { return m.CallMsg.Value }
821-
func (m callMsg) Data() []byte { return m.CallMsg.Data }
822-
func (m callMsg) AccessList() types.AccessList { return m.CallMsg.AccessList }
823-
func (m callMsg) IsL1MessageTx() bool { return false }
824-
func (m callMsg) TxSize() common.StorageSize { return 0 }
812+
func (m callMsg) From() common.Address { return m.CallMsg.From }
813+
func (m callMsg) Nonce() uint64 { return 0 }
814+
func (m callMsg) IsFake() bool { return true }
815+
func (m callMsg) To() *common.Address { return m.CallMsg.To }
816+
func (m callMsg) GasPrice() *big.Int { return m.CallMsg.GasPrice }
817+
func (m callMsg) GasFeeCap() *big.Int { return m.CallMsg.GasFeeCap }
818+
func (m callMsg) GasTipCap() *big.Int { return m.CallMsg.GasTipCap }
819+
func (m callMsg) Gas() uint64 { return m.CallMsg.Gas }
820+
func (m callMsg) Value() *big.Int { return m.CallMsg.Value }
821+
func (m callMsg) Data() []byte { return m.CallMsg.Data }
822+
func (m callMsg) AccessList() types.AccessList { return m.CallMsg.AccessList }
823+
func (m callMsg) IsL1MessageTx() bool { return false }
824+
func (m callMsg) TxSize() common.StorageSize { return 0 }
825+
func (m callMsg) SetCodeAuthorizations() []types.SetCodeAuthorization { return nil }
825826

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

accounts/external/backend.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ func (api *ExternalSigner) SignTx(account accounts.Account, tx *types.Transactio
218218
switch tx.Type() {
219219
case types.LegacyTxType, types.AccessListTxType:
220220
args.GasPrice = (*hexutil.Big)(tx.GasPrice())
221-
case types.DynamicFeeTxType:
221+
case types.DynamicFeeTxType, types.SetCodeTxType:
222222
args.MaxFeePerGas = (*hexutil.Big)(tx.GasFeeCap())
223223
args.MaxPriorityFeePerGas = (*hexutil.Big)(tx.GasTipCap())
224224
default:

cmd/evm/internal/t8ntool/execution.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
117117
}
118118
var (
119119
statedb = MakePreState(rawdb.NewMemoryDatabase(), pre.Pre)
120-
signer = types.MakeSigner(chainConfig, new(big.Int).SetUint64(pre.Env.Number))
120+
signer = types.MakeSigner(chainConfig, new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp)
121121
gaspool = new(core.GasPool)
122122
blockHash = common.Hash{0x13, 0x37}
123123
rejectedTxs []*rejectedTx

cmd/evm/internal/t8ntool/transaction.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ func Transaction(ctx *cli.Context) error {
113113
return NewError(ErrorIO, errors.New("only rlp supported"))
114114
}
115115
}
116-
signer := types.MakeSigner(chainConfig, new(big.Int))
116+
signer := types.MakeSigner(chainConfig, new(big.Int), 0)
117117
// We now have the transactions in 'body', which is supposed to be an
118118
// rlp list of transactions
119119
it, err := rlp.NewListIterator([]byte(body))
@@ -140,7 +140,7 @@ func Transaction(ctx *cli.Context) error {
140140
r.Address = sender
141141
}
142142
// Check intrinsic gas
143-
if gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil,
143+
if gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil,
144144
chainConfig.IsHomestead(new(big.Int)), chainConfig.IsIstanbul(new(big.Int)), chainConfig.IsShanghai(new(big.Int))); err != nil {
145145
r.Error = err
146146
results = append(results, r)

cmd/evm/internal/t8ntool/transition.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ func Transition(ctx *cli.Context) error {
241241
}
242242
}
243243
// We may have to sign the transactions.
244-
signer := types.MakeSigner(chainConfig, big.NewInt(int64(prestate.Env.Number)))
244+
signer := types.MakeSigner(chainConfig, big.NewInt(int64(prestate.Env.Number)), prestate.Env.Timestamp)
245245

246246
if txs, err = signUnsignedTransactions(txsWithKeys, signer); err != nil {
247247
return NewError(ErrorJson, fmt.Errorf("failed signing transactions: %v", err))

cmd/evm/t8n_test.go

+16-8
Original file line numberDiff line numberDiff line change
@@ -124,14 +124,14 @@ func TestT8n(t *testing.T) {
124124
output: t8nOutput{alloc: true, result: true},
125125
expOut: "exp.json",
126126
},
127-
{ // missing blockhash test
128-
base: "./testdata/4",
129-
input: t8nInput{
130-
"alloc.json", "txs.json", "env.json", "Berlin", "",
131-
},
132-
output: t8nOutput{alloc: true, result: true},
133-
expExitCode: 4,
134-
},
127+
//{ // missing blockhash test
128+
// base: "./testdata/4",
129+
// input: t8nInput{
130+
// "alloc.json", "txs.json", "env.json", "Berlin", "",
131+
// },
132+
// output: t8nOutput{alloc: true, result: true},
133+
// expExitCode: 4,
134+
//},
135135
{ // Uncle test
136136
base: "./testdata/5",
137137
input: t8nInput{
@@ -204,6 +204,14 @@ func TestT8n(t *testing.T) {
204204
output: t8nOutput{result: true},
205205
expOut: "exp.json",
206206
},
207+
{ // EuclidV2 test, EIP-7702 transaction
208+
base: "./testdata/33",
209+
input: t8nInput{
210+
"alloc.json", "txs.json", "env.json", "EuclidV2", "",
211+
},
212+
output: t8nOutput{alloc: true, result: true},
213+
expOut: "exp.json",
214+
},
207215
} {
208216

209217
args := []string{"t8n"}

cmd/evm/testdata/33/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This test sets some EIP-7702 delegations and calls them.

cmd/evm/testdata/33/alloc.json

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"0x8a0a19589531694250d570040a0c4b74576919b8": {
3+
"nonce": "0x00",
4+
"balance": "0x0de0b6b3a7640000",
5+
"code": "0x600060006000600060007310000000000000000000000000000000000000015af1600155600060006000600060007310000000000000000000000000000000000000025af16002553d600060003e600051600355",
6+
"storage": {
7+
"0x01": "0x0100",
8+
"0x02": "0x0100",
9+
"0x03": "0x0100"
10+
}
11+
},
12+
"0x000000000000000000000000000000000000aaaa": {
13+
"nonce": "0x00",
14+
"balance": "0x4563918244f40000",
15+
"code": "0x58808080600173703c4b2bd70c169f5717101caee543299fc946c75af100",
16+
"storage": {}
17+
},
18+
"0x000000000000000000000000000000000000bbbb": {
19+
"nonce": "0x00",
20+
"balance": "0x29a2241af62c0000",
21+
"code": "0x6042805500",
22+
"storage": {}
23+
},
24+
"0x71562b71999873DB5b286dF957af199Ec94617F7": {
25+
"nonce": "0x00",
26+
"balance": "0x6124fee993bc0000",
27+
"code": "0x",
28+
"storage": {}
29+
}
30+
}

cmd/evm/testdata/33/env.json

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"currentCoinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
3+
"currentGasLimit": "71794957647893862",
4+
"currentNumber": "1",
5+
"currentTimestamp": "1000",
6+
"currentRandom": "0",
7+
"currentDifficulty": "0",
8+
"blockHashes": {},
9+
"ommers": [],
10+
"currentBaseFee": "7",
11+
"parentUncleHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
12+
"withdrawals": [],
13+
"parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000"
14+
}

cmd/evm/testdata/33/exp.json

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
{
2+
"alloc": {
3+
"0x000000000000000000000000000000000000aaaa": {
4+
"code": "0x58808080600173703c4b2bd70c169f5717101caee543299fc946c75af100",
5+
"balance": "0x4563918244f40000"
6+
},
7+
"0x000000000000000000000000000000000000bbbb": {
8+
"code": "0x6042805500",
9+
"balance": "0x29a2241af62c0000"
10+
},
11+
"0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba": {
12+
"balance": "0x2bf52"
13+
},
14+
"0x703c4b2bd70c169f5717101caee543299fc946c7": {
15+
"code": "0xef0100000000000000000000000000000000000000bbbb",
16+
"storage": {
17+
"0x0000000000000000000000000000000000000000000000000000000000000042": "0x0000000000000000000000000000000000000000000000000000000000000042"
18+
},
19+
"balance": "0x1",
20+
"nonce": "0x1"
21+
},
22+
"0x71562b71999873db5b286df957af199ec94617f7": {
23+
"code": "0xef0100000000000000000000000000000000000000aaaa",
24+
"balance": "0x6124fee993afa30e",
25+
"nonce": "0x2"
26+
},
27+
"0x8a0a19589531694250d570040a0c4b74576919b8": {
28+
"code": "0x600060006000600060007310000000000000000000000000000000000000015af1600155600060006000600060007310000000000000000000000000000000000000025af16002553d600060003e600051600355",
29+
"storage": {
30+
"0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000100",
31+
"0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000000000000000000000000000000000000000000100",
32+
"0x0000000000000000000000000000000000000000000000000000000000000003": "0x0000000000000000000000000000000000000000000000000000000000000100"
33+
},
34+
"balance": "0xde0b6b3a7640000"
35+
}
36+
},
37+
"result": {
38+
"stateRoot": "0x9fdcacd4510e93c4488e537dc51578b5c6d505771db64a2610036eeb4be7b26f",
39+
"txRoot": "0x5d13a0b074e80388dc754da92b22922313a63417b3e25a10f324935e09697a53",
40+
"receiptsRoot": "0x504c5d86c34391f70d210e6c482615b391db4bdb9f43479366399d9c5599850a",
41+
"logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
42+
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","receipts": [{
43+
"type": "0x4",
44+
"root": "0x",
45+
"status": "0x1",
46+
"cumulativeGasUsed": "0x15fa9",
47+
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","logs": null,"transactionHash": "0x0417aab7c1d8a3989190c3167c132876ce9b8afd99262c5a0f9d06802de3d7ef",
48+
"contractAddress": "0x0000000000000000000000000000000000000000",
49+
"gasUsed": "0x15fa9",
50+
"blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
51+
"transactionIndex": "0x0"
52+
}
53+
],
54+
"currentDifficulty": "0x0",
55+
"gasUsed": "0x15fa9"
56+
}
57+
}

cmd/evm/testdata/33/txs.json

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
[
2+
{
3+
"type": "0x4",
4+
"chainId": "0x1",
5+
"nonce": "0x0",
6+
"to": "0x71562b71999873db5b286df957af199ec94617f7",
7+
"gas": "0x7a120",
8+
"gasPrice": null,
9+
"maxPriorityFeePerGas": "0x2",
10+
"maxFeePerGas": "0x12a05f200",
11+
"value": "0x0",
12+
"input": "0x",
13+
"accessList": [],
14+
"authorizationList": [
15+
{
16+
"chainId": "0x1",
17+
"address": "0x000000000000000000000000000000000000aaaa",
18+
"nonce": "0x1",
19+
"yParity": "0x1",
20+
"r": "0xf7e3e597fc097e71ed6c26b14b25e5395bc8510d58b9136af439e12715f2d721",
21+
"s": "0x6cf7c3d7939bfdb784373effc0ebb0bd7549691a513f395e3cdabf8602724987"
22+
},
23+
{
24+
"chainId": "0x0",
25+
"address": "0x000000000000000000000000000000000000bbbb",
26+
"nonce": "0x0",
27+
"yParity": "0x1",
28+
"r": "0x5011890f198f0356a887b0779bde5afa1ed04e6acb1e3f37f8f18c7b6f521b98",
29+
"s": "0x56c3fa3456b103f3ef4a0acb4b647b9cab9ec4bc68fbcdf1e10b49fb2bcbcf61"
30+
}
31+
],
32+
"secretKey": "0xb71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291",
33+
"v": "0x0",
34+
"r": "0x0",
35+
"s": "0x0"
36+
}
37+
]

common/hexutil/json.go

+45
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,16 @@ import (
2323
"math/big"
2424
"reflect"
2525
"strconv"
26+
27+
"github.com/holiman/uint256"
2628
)
2729

2830
var (
2931
bytesT = reflect.TypeOf(Bytes(nil))
3032
bigT = reflect.TypeOf((*Big)(nil))
3133
uintT = reflect.TypeOf(Uint(0))
3234
uint64T = reflect.TypeOf(Uint64(0))
35+
u256T = reflect.TypeOf((*uint256.Int)(nil))
3336
)
3437

3538
// Bytes marshals/unmarshals as a JSON string with 0x prefix.
@@ -225,6 +228,48 @@ func (b *Big) UnmarshalGraphQL(input interface{}) error {
225228
return err
226229
}
227230

231+
// U256 marshals/unmarshals as a JSON string with 0x prefix.
232+
// The zero value marshals as "0x0".
233+
type U256 uint256.Int
234+
235+
// MarshalText implements encoding.TextMarshaler
236+
func (b U256) MarshalText() ([]byte, error) {
237+
u256 := (*uint256.Int)(&b)
238+
return []byte(u256.Hex()), nil
239+
}
240+
241+
// UnmarshalJSON implements json.Unmarshaler.
242+
func (b *U256) UnmarshalJSON(input []byte) error {
243+
// The uint256.Int.UnmarshalJSON method accepts "dec", "0xhex"; we must be
244+
// more strict, hence we check string and invoke SetFromHex directly.
245+
if !isString(input) {
246+
return errNonString(u256T)
247+
}
248+
// The hex decoder needs to accept empty string ("") as '0', which uint256.Int
249+
// would reject.
250+
if len(input) == 2 {
251+
(*uint256.Int)(b).Clear()
252+
return nil
253+
}
254+
err := (*uint256.Int)(b).SetFromHex(string(input[1 : len(input)-1]))
255+
if err != nil {
256+
return &json.UnmarshalTypeError{Value: err.Error(), Type: u256T}
257+
}
258+
return nil
259+
}
260+
261+
// UnmarshalText implements encoding.TextUnmarshaler
262+
func (b *U256) UnmarshalText(input []byte) error {
263+
// The uint256.Int.UnmarshalText method accepts "dec", "0xhex"; we must be
264+
// more strict, hence we check string and invoke SetFromHex directly.
265+
return (*uint256.Int)(b).SetFromHex(string(input))
266+
}
267+
268+
// String returns the hex encoding of b.
269+
func (b *U256) String() string {
270+
return (*uint256.Int)(b).Hex()
271+
}
272+
228273
// Uint64 marshals/unmarshals as a JSON string with 0x prefix.
229274
// The zero value marshals as "0x0".
230275
type Uint64 uint64

core/bench_test.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ 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, nil, false, false, false, false)
89-
signer := types.MakeSigner(gen.config, big.NewInt(int64(i)))
88+
gas, _ := IntrinsicGas(data, nil, nil, false, false, false, false)
89+
signer := types.MakeSigner(gen.config, big.NewInt(int64(i)), 0 /* block time */)
9090
gasPrice := big.NewInt(0)
9191
if gen.header.BaseFee != nil {
9292
gasPrice = gen.header.BaseFee
@@ -130,7 +130,7 @@ func genTxRing(naccounts int) func(int, *BlockGen) {
130130
if gen.header.BaseFee != nil {
131131
gasPrice = gen.header.BaseFee
132132
}
133-
signer := types.MakeSigner(gen.config, big.NewInt(int64(i)))
133+
signer := types.MakeSigner(gen.config, big.NewInt(int64(i)), 0 /* block time */)
134134
for {
135135
gas -= params.TxGas
136136
if gas < params.TxGas {

core/blockchain.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1507,7 +1507,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er
15071507
}
15081508

15091509
// Start a parallel signature recovery (signer will fluke on fork transition, minimal perf loss)
1510-
senderCacher.recoverFromBlocks(types.MakeSigner(bc.chainConfig, chain[0].Number()), chain)
1510+
senderCacher.recoverFromBlocks(types.MakeSigner(bc.chainConfig, chain[0].Number(), chain[0].Time()), chain)
15111511

15121512
var (
15131513
stats = insertStats{startTime: mclock.Now()}

0 commit comments

Comments
 (0)