This commit is contained in:
Daniel Liu 2026-05-10 21:54:47 -07:00 committed by GitHub
commit 52f7daec78
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 103 additions and 2 deletions

View file

@ -545,7 +545,7 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
// Check clause 6
value, overflow := uint256.FromBig(msg.Value)
if overflow {
return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From.Hex())
return nil, types.ErrUint256Overflow
}
if !value.IsZero() && !st.evm.Context.CanTransfer(st.state, msg.From, value) {
return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From.Hex())

View file

@ -97,9 +97,19 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types
}
// Transactions can't be negative. This may never happen using RLP decoded
// transactions but may occur for transactions created using the RPC.
if tx.Value().Sign() < 0 {
val := tx.Value()
if val.Sign() < 0 {
return ErrNegativeValue
}
if val.BitLen() > 256 {
return types.ErrUint256Overflow
}
// For legacy transactions, ensure gasPrice does not exceed 256 bits
if tx.Type() == types.LegacyTxType {
if tx.GasPrice().BitLen() > 256 {
return types.ErrUint256Overflow
}
}
// Ensure the transaction doesn't exceed the current block limit gas
if head.GasLimit < tx.Gas() {
return ErrGasLimit

View file

@ -96,6 +96,44 @@ func TestValidateTransactionEIP2681(t *testing.T) {
}
}
func TestValidateTransactionValueOverflow(t *testing.T) {
key, err := crypto.GenerateKey()
if err != nil {
t.Fatal(err)
}
head := &types.Header{
Number: big.NewInt(1),
GasLimit: 5000000,
Time: 1,
Difficulty: big.NewInt(1),
}
signer := types.LatestSigner(params.TestChainConfig)
opts := &ValidationOptions{
Config: params.TestChainConfig,
Accept: 0xFF,
MaxSize: 32 * 1024,
MaxBlobCount: 6,
MinTip: big.NewInt(0),
}
to := common.HexToAddress("0x0000000000000000000000000000000000000001")
overflowValue := new(big.Int).Lsh(big.NewInt(1), 256)
tx := types.NewTx(&types.LegacyTx{
Nonce: 0,
To: &to,
Value: overflowValue,
Gas: 21000,
GasPrice: big.NewInt(1),
})
tx, err = types.SignTx(tx, types.HomesteadSigner{}, key)
if err != nil {
t.Fatal(err)
}
err = ValidateTransaction(tx, head, signer, opts)
if !errors.Is(err, types.ErrUint256Overflow) {
t.Fatalf("expected %v, got %v", types.ErrUint256Overflow, err)
}
}
// createTestTransaction creates a basic transaction for testing
func createTestTransaction(key *ecdsa.PrivateKey, nonce uint64) *types.Transaction {
to := common.HexToAddress("0x0000000000000000000000000000000000000001")

View file

@ -3989,6 +3989,11 @@ type configTimeBackend struct {
time uint64
}
type overflowRejectingBackend struct {
*backendMock
lastTx *types.Transaction
}
func (b configTimeBackend) ChainConfig() *params.ChainConfig {
return b.genesis.Config
}
@ -4019,6 +4024,14 @@ func (b *testBackend) RPCTxSyncMaxTimeout() time.Duration {
func (b *backendMock) RPCTxSyncDefaultTimeout() time.Duration { return 2 * time.Second }
func (b *backendMock) RPCTxSyncMaxTimeout() time.Duration { return 5 * time.Minute }
func (b *overflowRejectingBackend) SendTx(ctx context.Context, tx *types.Transaction) error {
b.lastTx = tx
if tx.Value().BitLen() > 256 {
return types.ErrUint256Overflow
}
return nil
}
func makeSignedRaw(t *testing.T, api *TransactionAPI, from, to common.Address, value *big.Int) (hexutil.Bytes, *types.Transaction) {
t.Helper()
@ -4110,6 +4123,43 @@ func TestSendRawTransactionSync_Timeout(t *testing.T) {
}
}
func TestSendRawTransactionRejectsValueOverflow(t *testing.T) {
t.Parallel()
key, err := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
require.NoError(t, err)
backend := &overflowRejectingBackend{backendMock: newBackendMock()}
api := NewTransactionAPI(backend, nil)
to := common.Address{0x42}
overflowValue := new(big.Int).Lsh(big.NewInt(1), 256)
tx, err := types.SignNewTx(key, types.LatestSigner(backend.ChainConfig()), &types.LegacyTx{
Nonce: 0,
GasPrice: big.NewInt(2),
Gas: 21000,
To: &to,
Value: overflowValue,
})
require.NoError(t, err)
raw, err := tx.MarshalBinary()
require.NoError(t, err)
_, err = api.SendRawTransaction(context.Background(), raw)
require.ErrorIs(t, err, types.ErrUint256Overflow)
require.NotNil(t, backend.lastTx)
require.Equal(t, overflowValue, backend.lastTx.Value())
}
func TestTxValidationErrorUint256Overflow(t *testing.T) {
t.Parallel()
err := txValidationError(types.ErrUint256Overflow)
require.Equal(t, errCodeInvalidParams, err.ErrorCode())
require.ErrorContains(t, err, types.ErrUint256Overflow.Error())
}
func TestGetStorageValues(t *testing.T) {
t.Parallel()

View file

@ -24,6 +24,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
)
@ -131,6 +132,8 @@ func txValidationError(err error) *invalidTxError {
return &invalidTxError{Message: err.Error(), Code: errCodeInvalidParams}
case errors.Is(err, core.ErrTipVeryHigh):
return &invalidTxError{Message: err.Error(), Code: errCodeInvalidParams}
case errors.Is(err, types.ErrUint256Overflow):
return &invalidTxError{Message: err.Error(), Code: errCodeInvalidParams}
case errors.Is(err, core.ErrTipAboveFeeCap):
return &invalidTxError{Message: err.Error(), Code: errCodeInvalidParams}
case errors.Is(err, core.ErrFeeCapTooLow):