forked from cerc-io/plugeth
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.
This commit is contained in:
parent
e185a8c818
commit
f32feeb260
@ -154,6 +154,8 @@ func Transaction(ctx *cli.Context) error {
|
|||||||
}
|
}
|
||||||
// Validate <256bit fields
|
// Validate <256bit fields
|
||||||
switch {
|
switch {
|
||||||
|
case tx.Nonce()+1 < tx.Nonce():
|
||||||
|
r.Error = errors.New("nonce exceeds 2^64-1")
|
||||||
case tx.Value().BitLen() > 256:
|
case tx.Value().BitLen() > 256:
|
||||||
r.Error = errors.New("value exceeds 256 bits")
|
r.Error = errors.New("value exceeds 256 bits")
|
||||||
case tx.GasPrice().BitLen() > 256:
|
case tx.GasPrice().BitLen() > 256:
|
||||||
|
@ -51,6 +51,10 @@ var (
|
|||||||
// next one expected based on the local chain.
|
// next one expected based on the local chain.
|
||||||
ErrNonceTooHigh = errors.New("nonce too high")
|
ErrNonceTooHigh = errors.New("nonce too high")
|
||||||
|
|
||||||
|
// ErrNonceMax is returned if the nonce of a transaction sender account has
|
||||||
|
// maximum allowed value and would become invalid if incremented.
|
||||||
|
ErrNonceMax = errors.New("nonce has max value")
|
||||||
|
|
||||||
// ErrGasLimitReached is returned by the gas pool if the amount of gas required
|
// ErrGasLimitReached is returned by the gas pool if the amount of gas required
|
||||||
// by a transaction is higher than what's left in the block.
|
// by a transaction is higher than what's left in the block.
|
||||||
ErrGasLimitReached = errors.New("gas limit reached")
|
ErrGasLimitReached = errors.New("gas limit reached")
|
||||||
|
@ -17,10 +17,12 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
"github.com/ethereum/go-ethereum/consensus"
|
"github.com/ethereum/go-ethereum/consensus"
|
||||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||||
"github.com/ethereum/go-ethereum/consensus/misc"
|
"github.com/ethereum/go-ethereum/consensus/misc"
|
||||||
@ -54,11 +56,12 @@ func TestStateProcessorErrors(t *testing.T) {
|
|||||||
LondonBlock: big.NewInt(0),
|
LondonBlock: big.NewInt(0),
|
||||||
Ethash: new(params.EthashConfig),
|
Ethash: new(params.EthashConfig),
|
||||||
}
|
}
|
||||||
signer = types.LatestSigner(config)
|
signer = types.LatestSigner(config)
|
||||||
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
|
key2, _ = crypto.HexToECDSA("0202020202020202020202020202020202020202020202020202002020202020")
|
||||||
)
|
)
|
||||||
var makeTx = func(nonce uint64, to common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *types.Transaction {
|
var makeTx = func(key *ecdsa.PrivateKey, nonce uint64, to common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *types.Transaction {
|
||||||
tx, _ := types.SignTx(types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, data), signer, testKey)
|
tx, _ := types.SignTx(types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, data), signer, key)
|
||||||
return tx
|
return tx
|
||||||
}
|
}
|
||||||
var mkDynamicTx = func(nonce uint64, to common.Address, gasLimit uint64, gasTipCap, gasFeeCap *big.Int) *types.Transaction {
|
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) {
|
|||||||
Gas: gasLimit,
|
Gas: gasLimit,
|
||||||
To: &to,
|
To: &to,
|
||||||
Value: big.NewInt(0),
|
Value: big.NewInt(0),
|
||||||
}), signer, testKey)
|
}), signer, key1)
|
||||||
return tx
|
return tx
|
||||||
}
|
}
|
||||||
{ // Tests against a 'recent' chain definition
|
{ // Tests against a 'recent' chain definition
|
||||||
@ -82,6 +85,10 @@ func TestStateProcessorErrors(t *testing.T) {
|
|||||||
Balance: big.NewInt(1000000000000000000), // 1 ether
|
Balance: big.NewInt(1000000000000000000), // 1 ether
|
||||||
Nonce: 0,
|
Nonce: 0,
|
||||||
},
|
},
|
||||||
|
common.HexToAddress("0xfd0810DD14796680f72adf1a371963d0745BCc64"): GenesisAccount{
|
||||||
|
Balance: big.NewInt(1000000000000000000), // 1 ether
|
||||||
|
Nonce: math.MaxUint64,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
genesis = gspec.MustCommit(db)
|
genesis = gspec.MustCommit(db)
|
||||||
@ -97,32 +104,38 @@ func TestStateProcessorErrors(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{ // ErrNonceTooLow
|
{ // ErrNonceTooLow
|
||||||
txs: []*types.Transaction{
|
txs: []*types.Transaction{
|
||||||
makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil),
|
makeTx(key1, 0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil),
|
||||||
makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil),
|
makeTx(key1, 0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil),
|
||||||
},
|
},
|
||||||
want: "could not apply tx 1 [0x0026256b3939ed97e2c4a6f3fce8ecf83bdcfa6d507c47838c308a1fb0436f62]: nonce too low: address 0x71562b71999873DB5b286dF957af199Ec94617F7, tx: 0 state: 1",
|
want: "could not apply tx 1 [0x0026256b3939ed97e2c4a6f3fce8ecf83bdcfa6d507c47838c308a1fb0436f62]: nonce too low: address 0x71562b71999873DB5b286dF957af199Ec94617F7, tx: 0 state: 1",
|
||||||
},
|
},
|
||||||
{ // ErrNonceTooHigh
|
{ // ErrNonceTooHigh
|
||||||
txs: []*types.Transaction{
|
txs: []*types.Transaction{
|
||||||
makeTx(100, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil),
|
makeTx(key1, 100, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil),
|
||||||
},
|
},
|
||||||
want: "could not apply tx 0 [0xdebad714ca7f363bd0d8121c4518ad48fa469ca81b0a081be3d10c17460f751b]: nonce too high: address 0x71562b71999873DB5b286dF957af199Ec94617F7, tx: 100 state: 0",
|
want: "could not apply tx 0 [0xdebad714ca7f363bd0d8121c4518ad48fa469ca81b0a081be3d10c17460f751b]: nonce too high: address 0x71562b71999873DB5b286dF957af199Ec94617F7, tx: 100 state: 0",
|
||||||
},
|
},
|
||||||
|
{ // ErrNonceMax
|
||||||
|
txs: []*types.Transaction{
|
||||||
|
makeTx(key2, math.MaxUint64, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil),
|
||||||
|
},
|
||||||
|
want: "could not apply tx 0 [0x84ea18d60eb2bb3b040e3add0eb72f757727122cc257dd858c67cb6591a85986]: nonce has max value: address 0xfd0810DD14796680f72adf1a371963d0745BCc64, nonce: 18446744073709551615",
|
||||||
|
},
|
||||||
{ // ErrGasLimitReached
|
{ // ErrGasLimitReached
|
||||||
txs: []*types.Transaction{
|
txs: []*types.Transaction{
|
||||||
makeTx(0, common.Address{}, big.NewInt(0), 21000000, big.NewInt(875000000), nil),
|
makeTx(key1, 0, common.Address{}, big.NewInt(0), 21000000, big.NewInt(875000000), nil),
|
||||||
},
|
},
|
||||||
want: "could not apply tx 0 [0xbd49d8dadfd47fb846986695f7d4da3f7b2c48c8da82dbc211a26eb124883de9]: gas limit reached",
|
want: "could not apply tx 0 [0xbd49d8dadfd47fb846986695f7d4da3f7b2c48c8da82dbc211a26eb124883de9]: gas limit reached",
|
||||||
},
|
},
|
||||||
{ // ErrInsufficientFundsForTransfer
|
{ // ErrInsufficientFundsForTransfer
|
||||||
txs: []*types.Transaction{
|
txs: []*types.Transaction{
|
||||||
makeTx(0, common.Address{}, big.NewInt(1000000000000000000), params.TxGas, big.NewInt(875000000), nil),
|
makeTx(key1, 0, common.Address{}, big.NewInt(1000000000000000000), params.TxGas, big.NewInt(875000000), nil),
|
||||||
},
|
},
|
||||||
want: "could not apply tx 0 [0x98c796b470f7fcab40aaef5c965a602b0238e1034cce6fb73823042dd0638d74]: insufficient funds for gas * price + value: address 0x71562b71999873DB5b286dF957af199Ec94617F7 have 1000000000000000000 want 1000018375000000000",
|
want: "could not apply tx 0 [0x98c796b470f7fcab40aaef5c965a602b0238e1034cce6fb73823042dd0638d74]: insufficient funds for gas * price + value: address 0x71562b71999873DB5b286dF957af199Ec94617F7 have 1000000000000000000 want 1000018375000000000",
|
||||||
},
|
},
|
||||||
{ // ErrInsufficientFunds
|
{ // ErrInsufficientFunds
|
||||||
txs: []*types.Transaction{
|
txs: []*types.Transaction{
|
||||||
makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(900000000000000000), nil),
|
makeTx(key1, 0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(900000000000000000), nil),
|
||||||
},
|
},
|
||||||
want: "could not apply tx 0 [0x4a69690c4b0cd85e64d0d9ea06302455b01e10a83db964d60281739752003440]: insufficient funds for gas * price + value: address 0x71562b71999873DB5b286dF957af199Ec94617F7 have 1000000000000000000 want 18900000000000000000000",
|
want: "could not apply tx 0 [0x4a69690c4b0cd85e64d0d9ea06302455b01e10a83db964d60281739752003440]: insufficient funds for gas * price + value: address 0x71562b71999873DB5b286dF957af199Ec94617F7 have 1000000000000000000 want 18900000000000000000000",
|
||||||
},
|
},
|
||||||
@ -132,13 +145,13 @@ func TestStateProcessorErrors(t *testing.T) {
|
|||||||
// multiplication len(data) +gas_per_byte overflows uint64. Not testable at the moment
|
// multiplication len(data) +gas_per_byte overflows uint64. Not testable at the moment
|
||||||
{ // ErrIntrinsicGas
|
{ // ErrIntrinsicGas
|
||||||
txs: []*types.Transaction{
|
txs: []*types.Transaction{
|
||||||
makeTx(0, common.Address{}, big.NewInt(0), params.TxGas-1000, big.NewInt(875000000), nil),
|
makeTx(key1, 0, common.Address{}, big.NewInt(0), params.TxGas-1000, big.NewInt(875000000), nil),
|
||||||
},
|
},
|
||||||
want: "could not apply tx 0 [0xcf3b049a0b516cb4f9274b3e2a264359e2ba53b2fb64b7bda2c634d5c9d01fca]: intrinsic gas too low: have 20000, want 21000",
|
want: "could not apply tx 0 [0xcf3b049a0b516cb4f9274b3e2a264359e2ba53b2fb64b7bda2c634d5c9d01fca]: intrinsic gas too low: have 20000, want 21000",
|
||||||
},
|
},
|
||||||
{ // ErrGasLimitReached
|
{ // ErrGasLimitReached
|
||||||
txs: []*types.Transaction{
|
txs: []*types.Transaction{
|
||||||
makeTx(0, common.Address{}, big.NewInt(0), params.TxGas*1000, big.NewInt(875000000), nil),
|
makeTx(key1, 0, common.Address{}, big.NewInt(0), params.TxGas*1000, big.NewInt(875000000), nil),
|
||||||
},
|
},
|
||||||
want: "could not apply tx 0 [0xbd49d8dadfd47fb846986695f7d4da3f7b2c48c8da82dbc211a26eb124883de9]: gas limit reached",
|
want: "could not apply tx 0 [0xbd49d8dadfd47fb846986695f7d4da3f7b2c48c8da82dbc211a26eb124883de9]: gas limit reached",
|
||||||
},
|
},
|
||||||
|
@ -222,6 +222,9 @@ func (st *StateTransition) preCheck() error {
|
|||||||
} else if stNonce > msgNonce {
|
} else if stNonce > msgNonce {
|
||||||
return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooLow,
|
return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooLow,
|
||||||
st.msg.From().Hex(), msgNonce, stNonce)
|
st.msg.From().Hex(), msgNonce, stNonce)
|
||||||
|
} else if stNonce+1 < stNonce {
|
||||||
|
return fmt.Errorf("%w: address %v, nonce: %d", ErrNonceMax,
|
||||||
|
st.msg.From().Hex(), stNonce)
|
||||||
}
|
}
|
||||||
// Make sure the sender is an EOA
|
// Make sure the sender is an EOA
|
||||||
if codeHash := st.state.GetCodeHash(st.msg.From()); codeHash != emptyCodeHash && codeHash != (common.Hash{}) {
|
if codeHash := st.state.GetCodeHash(st.msg.From()); codeHash != emptyCodeHash && codeHash != (common.Hash{}) {
|
||||||
|
@ -35,6 +35,7 @@ var (
|
|||||||
ErrReturnDataOutOfBounds = errors.New("return data out of bounds")
|
ErrReturnDataOutOfBounds = errors.New("return data out of bounds")
|
||||||
ErrGasUintOverflow = errors.New("gas uint64 overflow")
|
ErrGasUintOverflow = errors.New("gas uint64 overflow")
|
||||||
ErrInvalidCode = errors.New("invalid code: must not begin with 0xef")
|
ErrInvalidCode = errors.New("invalid code: must not begin with 0xef")
|
||||||
|
ErrNonceUintOverflow = errors.New("nonce uint64 overflow")
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrStackUnderflow wraps an evm error when the items on the stack less
|
// ErrStackUnderflow wraps an evm error when the items on the stack less
|
||||||
|
@ -424,6 +424,9 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
|||||||
return nil, common.Address{}, gas, ErrInsufficientBalance
|
return nil, common.Address{}, gas, ErrInsufficientBalance
|
||||||
}
|
}
|
||||||
nonce := evm.StateDB.GetNonce(caller.Address())
|
nonce := evm.StateDB.GetNonce(caller.Address())
|
||||||
|
if nonce+1 < nonce {
|
||||||
|
return nil, common.Address{}, gas, ErrNonceUintOverflow
|
||||||
|
}
|
||||||
evm.StateDB.SetNonce(caller.Address(), nonce+1)
|
evm.StateDB.SetNonce(caller.Address(), nonce+1)
|
||||||
// We add this to the access list _before_ taking a snapshot. Even if the creation fails,
|
// We add this to the access list _before_ taking a snapshot. Even if the creation fails,
|
||||||
// the access-list change should not be rolled back
|
// the access-list change should not be rolled back
|
||||||
|
Loading…
Reference in New Issue
Block a user