Skip to content

Commit f32feeb

Browse files
authored
core/vm: implement EIP-2681: Limit account nonce to 2^64-1 (#23853)
This retroactively implements requirements or EIP-2681 for the account nonce upper limit.
1 parent e185a8c commit f32feeb

File tree

6 files changed

+39
-13
lines changed

6 files changed

+39
-13
lines changed

cmd/evm/internal/t8ntool/transaction.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ func Transaction(ctx *cli.Context) error {
154154
}
155155
// Validate <256bit fields
156156
switch {
157+
case tx.Nonce()+1 < tx.Nonce():
158+
r.Error = errors.New("nonce exceeds 2^64-1")
157159
case tx.Value().BitLen() > 256:
158160
r.Error = errors.New("value exceeds 256 bits")
159161
case tx.GasPrice().BitLen() > 256:

core/error.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ var (
5151
// next one expected based on the local chain.
5252
ErrNonceTooHigh = errors.New("nonce too high")
5353

54+
// ErrNonceMax is returned if the nonce of a transaction sender account has
55+
// maximum allowed value and would become invalid if incremented.
56+
ErrNonceMax = errors.New("nonce has max value")
57+
5458
// ErrGasLimitReached is returned by the gas pool if the amount of gas required
5559
// by a transaction is higher than what's left in the block.
5660
ErrGasLimitReached = errors.New("gas limit reached")

core/state_processor_test.go

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@
1717
package core
1818

1919
import (
20+
"crypto/ecdsa"
2021
"math/big"
2122
"testing"
2223

2324
"github.com/ethereum/go-ethereum/common"
25+
"github.com/ethereum/go-ethereum/common/math"
2426
"github.com/ethereum/go-ethereum/consensus"
2527
"github.com/ethereum/go-ethereum/consensus/ethash"
2628
"github.com/ethereum/go-ethereum/consensus/misc"
@@ -54,11 +56,12 @@ func TestStateProcessorErrors(t *testing.T) {
5456
LondonBlock: big.NewInt(0),
5557
Ethash: new(params.EthashConfig),
5658
}
57-
signer = types.LatestSigner(config)
58-
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
59+
signer = types.LatestSigner(config)
60+
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
61+
key2, _ = crypto.HexToECDSA("0202020202020202020202020202020202020202020202020202002020202020")
5962
)
60-
var makeTx = func(nonce uint64, to common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *types.Transaction {
61-
tx, _ := types.SignTx(types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, data), signer, testKey)
63+
var makeTx = func(key *ecdsa.PrivateKey, nonce uint64, to common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *types.Transaction {
64+
tx, _ := types.SignTx(types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, data), signer, key)
6265
return tx
6366
}
6467
var mkDynamicTx = func(nonce uint64, to common.Address, gasLimit uint64, gasTipCap, gasFeeCap *big.Int) *types.Transaction {
@@ -69,7 +72,7 @@ func TestStateProcessorErrors(t *testing.T) {
6972
Gas: gasLimit,
7073
To: &to,
7174
Value: big.NewInt(0),
72-
}), signer, testKey)
75+
}), signer, key1)
7376
return tx
7477
}
7578
{ // Tests against a 'recent' chain definition
@@ -82,6 +85,10 @@ func TestStateProcessorErrors(t *testing.T) {
8285
Balance: big.NewInt(1000000000000000000), // 1 ether
8386
Nonce: 0,
8487
},
88+
common.HexToAddress("0xfd0810DD14796680f72adf1a371963d0745BCc64"): GenesisAccount{
89+
Balance: big.NewInt(1000000000000000000), // 1 ether
90+
Nonce: math.MaxUint64,
91+
},
8592
},
8693
}
8794
genesis = gspec.MustCommit(db)
@@ -97,32 +104,38 @@ func TestStateProcessorErrors(t *testing.T) {
97104
}{
98105
{ // ErrNonceTooLow
99106
txs: []*types.Transaction{
100-
makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil),
101-
makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil),
107+
makeTx(key1, 0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil),
108+
makeTx(key1, 0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil),
102109
},
103110
want: "could not apply tx 1 [0x0026256b3939ed97e2c4a6f3fce8ecf83bdcfa6d507c47838c308a1fb0436f62]: nonce too low: address 0x71562b71999873DB5b286dF957af199Ec94617F7, tx: 0 state: 1",
104111
},
105112
{ // ErrNonceTooHigh
106113
txs: []*types.Transaction{
107-
makeTx(100, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil),
114+
makeTx(key1, 100, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil),
108115
},
109116
want: "could not apply tx 0 [0xdebad714ca7f363bd0d8121c4518ad48fa469ca81b0a081be3d10c17460f751b]: nonce too high: address 0x71562b71999873DB5b286dF957af199Ec94617F7, tx: 100 state: 0",
110117
},
118+
{ // ErrNonceMax
119+
txs: []*types.Transaction{
120+
makeTx(key2, math.MaxUint64, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil),
121+
},
122+
want: "could not apply tx 0 [0x84ea18d60eb2bb3b040e3add0eb72f757727122cc257dd858c67cb6591a85986]: nonce has max value: address 0xfd0810DD14796680f72adf1a371963d0745BCc64, nonce: 18446744073709551615",
123+
},
111124
{ // ErrGasLimitReached
112125
txs: []*types.Transaction{
113-
makeTx(0, common.Address{}, big.NewInt(0), 21000000, big.NewInt(875000000), nil),
126+
makeTx(key1, 0, common.Address{}, big.NewInt(0), 21000000, big.NewInt(875000000), nil),
114127
},
115128
want: "could not apply tx 0 [0xbd49d8dadfd47fb846986695f7d4da3f7b2c48c8da82dbc211a26eb124883de9]: gas limit reached",
116129
},
117130
{ // ErrInsufficientFundsForTransfer
118131
txs: []*types.Transaction{
119-
makeTx(0, common.Address{}, big.NewInt(1000000000000000000), params.TxGas, big.NewInt(875000000), nil),
132+
makeTx(key1, 0, common.Address{}, big.NewInt(1000000000000000000), params.TxGas, big.NewInt(875000000), nil),
120133
},
121134
want: "could not apply tx 0 [0x98c796b470f7fcab40aaef5c965a602b0238e1034cce6fb73823042dd0638d74]: insufficient funds for gas * price + value: address 0x71562b71999873DB5b286dF957af199Ec94617F7 have 1000000000000000000 want 1000018375000000000",
122135
},
123136
{ // ErrInsufficientFunds
124137
txs: []*types.Transaction{
125-
makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(900000000000000000), nil),
138+
makeTx(key1, 0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(900000000000000000), nil),
126139
},
127140
want: "could not apply tx 0 [0x4a69690c4b0cd85e64d0d9ea06302455b01e10a83db964d60281739752003440]: insufficient funds for gas * price + value: address 0x71562b71999873DB5b286dF957af199Ec94617F7 have 1000000000000000000 want 18900000000000000000000",
128141
},
@@ -132,13 +145,13 @@ func TestStateProcessorErrors(t *testing.T) {
132145
// multiplication len(data) +gas_per_byte overflows uint64. Not testable at the moment
133146
{ // ErrIntrinsicGas
134147
txs: []*types.Transaction{
135-
makeTx(0, common.Address{}, big.NewInt(0), params.TxGas-1000, big.NewInt(875000000), nil),
148+
makeTx(key1, 0, common.Address{}, big.NewInt(0), params.TxGas-1000, big.NewInt(875000000), nil),
136149
},
137150
want: "could not apply tx 0 [0xcf3b049a0b516cb4f9274b3e2a264359e2ba53b2fb64b7bda2c634d5c9d01fca]: intrinsic gas too low: have 20000, want 21000",
138151
},
139152
{ // ErrGasLimitReached
140153
txs: []*types.Transaction{
141-
makeTx(0, common.Address{}, big.NewInt(0), params.TxGas*1000, big.NewInt(875000000), nil),
154+
makeTx(key1, 0, common.Address{}, big.NewInt(0), params.TxGas*1000, big.NewInt(875000000), nil),
142155
},
143156
want: "could not apply tx 0 [0xbd49d8dadfd47fb846986695f7d4da3f7b2c48c8da82dbc211a26eb124883de9]: gas limit reached",
144157
},

core/state_transition.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,9 @@ func (st *StateTransition) preCheck() error {
222222
} else if stNonce > msgNonce {
223223
return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooLow,
224224
st.msg.From().Hex(), msgNonce, stNonce)
225+
} else if stNonce+1 < stNonce {
226+
return fmt.Errorf("%w: address %v, nonce: %d", ErrNonceMax,
227+
st.msg.From().Hex(), stNonce)
225228
}
226229
// Make sure the sender is an EOA
227230
if codeHash := st.state.GetCodeHash(st.msg.From()); codeHash != emptyCodeHash && codeHash != (common.Hash{}) {

core/vm/errors.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ var (
3535
ErrReturnDataOutOfBounds = errors.New("return data out of bounds")
3636
ErrGasUintOverflow = errors.New("gas uint64 overflow")
3737
ErrInvalidCode = errors.New("invalid code: must not begin with 0xef")
38+
ErrNonceUintOverflow = errors.New("nonce uint64 overflow")
3839
)
3940

4041
// ErrStackUnderflow wraps an evm error when the items on the stack less

core/vm/evm.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,9 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
424424
return nil, common.Address{}, gas, ErrInsufficientBalance
425425
}
426426
nonce := evm.StateDB.GetNonce(caller.Address())
427+
if nonce+1 < nonce {
428+
return nil, common.Address{}, gas, ErrNonceUintOverflow
429+
}
427430
evm.StateDB.SetNonce(caller.Address(), nonce+1)
428431
// We add this to the access list _before_ taking a snapshot. Even if the creation fails,
429432
// the access-list change should not be rolled back

0 commit comments

Comments
 (0)