core/vm: implement EIP-2681: Limit account nonce to 2^64-1 (#23853)

This commit is contained in:
Daniel Liu 2024-08-20 10:01:09 +08:00 committed by Daniel Liu
parent 7aeb9bd8f9
commit 6f1d1b6688
4 changed files with 20 additions and 9 deletions

View file

@ -37,6 +37,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")
ErrNotXDPoS = errors.New("XDPoS not found in config") ErrNotXDPoS = errors.New("XDPoS not found in config")
ErrNotFoundM1 = errors.New("list M1 not found ") ErrNotFoundM1 = errors.New("list M1 not found ")

View file

@ -197,16 +197,19 @@ func (st *StateTransition) buyGas() error {
} }
func (st *StateTransition) preCheck() error { func (st *StateTransition) preCheck() error {
msg := st.msg
sender := st.from()
// Make sure this transaction's nonce is correct // Make sure this transaction's nonce is correct
if msg.CheckNonce() { if st.msg.CheckNonce() {
nonce := st.state.GetNonce(sender.Address()) // Make sure this transaction's nonce is correct.
if nonce < msg.Nonce() { stNonce := st.state.GetNonce(st.from().Address())
return ErrNonceTooHigh if msgNonce := st.msg.Nonce(); stNonce < msgNonce {
} else if nonce > msg.Nonce() { return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooHigh,
return ErrNonceTooLow st.msg.From().Hex(), msgNonce, stNonce)
} else if stNonce > msgNonce {
return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooLow,
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)
} }
} }
return st.buyGas() return st.buyGas()

View file

@ -34,6 +34,7 @@ var (
ErrWriteProtection = errors.New("write protection") ErrWriteProtection = errors.New("write protection")
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")
ErrNonceUintOverflow = errors.New("nonce uint64 overflow")
// errStopToken is an internal token indicating interpreter loop termination, // errStopToken is an internal token indicating interpreter loop termination,
// never returned to outside callers. // never returned to outside callers.

View file

@ -443,6 +443,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