mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-01-27 16:18:08 -05:00
fix(rpc): add fee/value and balance to insufficient funds RPC error (#10872)
This commit is contained in:
29
Cargo.lock
generated
29
Cargo.lock
generated
@@ -820,9 +820,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.88"
|
||||
version = "1.0.89"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e1496f8fb1fbf272686b8d37f523dab3e4a7443300055e74cdaa449f3114356"
|
||||
checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6"
|
||||
|
||||
[[package]]
|
||||
name = "aquamarine"
|
||||
@@ -1606,9 +1606,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.1.18"
|
||||
version = "1.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b62ac837cdb5cb22e10a256099b4fc502b1dfe560cb282963a974d7abd80e476"
|
||||
checksum = "2d74707dde2ba56f86ae90effb3b43ddd369504387e718014de010cec7959800"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
"libc",
|
||||
@@ -3683,9 +3683,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.60"
|
||||
version = "0.1.61"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141"
|
||||
checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
@@ -4005,9 +4005,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "intrusive-collections"
|
||||
version = "0.9.6"
|
||||
version = "0.9.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b694dc9f70c3bda874626d2aed13b780f137aab435f4e9814121955cf706122e"
|
||||
checksum = "189d0897e4cbe8c75efedf3502c18c887b05046e59d28404d4d8e46cbc4d1e86"
|
||||
dependencies = [
|
||||
"memoffset",
|
||||
]
|
||||
@@ -5592,9 +5592,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pretty_assertions"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66"
|
||||
checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d"
|
||||
dependencies = [
|
||||
"diff",
|
||||
"yansi",
|
||||
@@ -8966,9 +8966,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revm-inspectors"
|
||||
version = "0.7.1"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02b2198350ddee1744cc99812fb39175daf6960af26c1dcfb26ec853c1937d9e"
|
||||
checksum = "125a280fca309d863831a833e53e0366f2cef215321ba345353cbef421e5a374"
|
||||
dependencies = [
|
||||
"alloy-primitives",
|
||||
"alloy-rpc-types-eth",
|
||||
@@ -8978,7 +8978,6 @@ dependencies = [
|
||||
"boa_engine",
|
||||
"boa_gc",
|
||||
"colorchoice",
|
||||
"intrusive-collections",
|
||||
"revm",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
@@ -11471,9 +11470,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "yansi"
|
||||
version = "0.5.1"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
|
||||
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
|
||||
|
||||
[[package]]
|
||||
name = "yoke"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
use alloy_primitives::{Address, Bytes};
|
||||
use alloy_primitives::{Address, Bytes, U256};
|
||||
use alloy_sol_types::decode_revert_reason;
|
||||
use reth_errors::RethError;
|
||||
use reth_primitives::{revm_primitives::InvalidHeader, BlockId};
|
||||
@@ -304,9 +304,14 @@ pub enum RpcInvalidTransactionError {
|
||||
/// thrown if creation transaction provides the init code bigger than init code size limit.
|
||||
#[error("max initcode size exceeded")]
|
||||
MaxInitCodeSizeExceeded,
|
||||
/// Represents the inability to cover max cost + value (account balance too low).
|
||||
#[error("insufficient funds for gas * price + value")]
|
||||
InsufficientFunds,
|
||||
/// Represents the inability to cover max fee + value (account balance too low).
|
||||
#[error("insufficient funds for gas * price + value: have {balance} want {cost}")]
|
||||
InsufficientFunds {
|
||||
/// Transaction cost.
|
||||
cost: U256,
|
||||
/// Current balance of transaction sender.
|
||||
balance: U256,
|
||||
},
|
||||
/// Thrown when calculating gas usage
|
||||
#[error("gas uint64 overflow")]
|
||||
GasUintOverflow,
|
||||
@@ -476,7 +481,9 @@ impl From<revm::primitives::InvalidTransaction> for RpcInvalidTransactionError {
|
||||
InvalidTransaction::CallerGasLimitMoreThanBlock |
|
||||
InvalidTransaction::CallGasCostMoreThanGasLimit => Self::GasTooHigh,
|
||||
InvalidTransaction::RejectCallerWithCode => Self::SenderNoEOA,
|
||||
InvalidTransaction::LackOfFundForMaxFee { .. } => Self::InsufficientFunds,
|
||||
InvalidTransaction::LackOfFundForMaxFee { fee, balance } => {
|
||||
Self::InsufficientFunds { cost: *fee, balance: *balance }
|
||||
}
|
||||
InvalidTransaction::OverflowPaymentInTransaction => Self::GasUintOverflow,
|
||||
InvalidTransaction::NonceOverflowInTransaction => Self::NonceMaxValue,
|
||||
InvalidTransaction::CreateInitCodeSizeLimit => Self::MaxInitCodeSizeExceeded,
|
||||
@@ -518,7 +525,9 @@ impl From<reth_primitives::InvalidTransactionError> for RpcInvalidTransactionErr
|
||||
// This conversion is used to convert any transaction errors that could occur inside the
|
||||
// txpool (e.g. `eth_sendRawTransaction`) to their corresponding RPC
|
||||
match err {
|
||||
InvalidTransactionError::InsufficientFunds { .. } => Self::InsufficientFunds,
|
||||
InvalidTransactionError::InsufficientFunds(res) => {
|
||||
Self::InsufficientFunds { cost: res.expected, balance: res.got }
|
||||
}
|
||||
InvalidTransactionError::NonceNotConsistent { tx, state } => {
|
||||
Self::NonceTooLow { tx, state }
|
||||
}
|
||||
@@ -678,8 +687,8 @@ impl From<InvalidPoolTransactionError> for RpcPoolError {
|
||||
InvalidPoolTransactionError::Other(err) => Self::PoolTransactionError(err),
|
||||
InvalidPoolTransactionError::Eip4844(err) => Self::Eip4844(err),
|
||||
InvalidPoolTransactionError::Eip7702(err) => Self::Eip7702(err),
|
||||
InvalidPoolTransactionError::Overdraft => {
|
||||
Self::Invalid(RpcInvalidTransactionError::InsufficientFunds)
|
||||
InvalidPoolTransactionError::Overdraft { cost, balance } => {
|
||||
Self::Invalid(RpcInvalidTransactionError::InsufficientFunds { cost, balance })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,16 +47,19 @@ where
|
||||
DB: Database,
|
||||
EthApiError: From<<DB as Database>::Error>,
|
||||
{
|
||||
Ok(db
|
||||
// Get the caller account.
|
||||
.basic(env.caller)?
|
||||
// Get the caller balance.
|
||||
.map(|acc| acc.balance)
|
||||
.unwrap_or_default()
|
||||
// Subtract transferred value from the caller balance.
|
||||
// Get the caller account.
|
||||
let caller = db.basic(env.caller)?;
|
||||
// Get the caller balance.
|
||||
let balance = caller.map(|acc| acc.balance).unwrap_or_default();
|
||||
// Get transaction value.
|
||||
let value = env.value;
|
||||
// Subtract transferred value from the caller balance. Return error if the caller has
|
||||
// insufficient funds.
|
||||
let balance = balance
|
||||
.checked_sub(env.value)
|
||||
// Return error if the caller has insufficient funds.
|
||||
.ok_or_else(|| RpcInvalidTransactionError::InsufficientFunds)?
|
||||
.ok_or_else(|| RpcInvalidTransactionError::InsufficientFunds { cost: value, balance })?;
|
||||
|
||||
Ok(balance
|
||||
// Calculate the amount of gas the caller can afford with the specified gas price.
|
||||
.checked_div(env.gas_price)
|
||||
// This will be 0 if gas price is 0. It is fine, because we check it before.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! Transaction pool errors
|
||||
|
||||
use alloy_primitives::{Address, TxHash};
|
||||
use alloy_primitives::{Address, TxHash, U256};
|
||||
use reth_primitives::{BlobTransactionValidationError, InvalidTransactionError};
|
||||
|
||||
/// Transaction pool result type.
|
||||
@@ -203,8 +203,13 @@ pub enum InvalidPoolTransactionError {
|
||||
#[error("transaction underpriced")]
|
||||
Underpriced,
|
||||
/// Thrown if the transaction's would require an account to be overdrawn
|
||||
#[error("transaction overdraws from account")]
|
||||
Overdraft,
|
||||
#[error("transaction overdraws from account, balance: {balance}, cost: {cost}")]
|
||||
Overdraft {
|
||||
/// Cost transaction is allowed to consume. See `reth_transaction_pool::PoolTransaction`.
|
||||
cost: U256,
|
||||
/// Balance of account.
|
||||
balance: U256,
|
||||
},
|
||||
/// EIP-4844 related errors
|
||||
#[error(transparent)]
|
||||
Eip4844(#[from] Eip4844PoolTransactionError),
|
||||
@@ -274,7 +279,7 @@ impl InvalidPoolTransactionError {
|
||||
false
|
||||
}
|
||||
Self::IntrinsicGasTooLow => true,
|
||||
Self::Overdraft => false,
|
||||
Self::Overdraft { .. } => false,
|
||||
Self::Other(err) => err.is_bad_transaction(),
|
||||
Self::Eip4844(eip4844_err) => {
|
||||
match eip4844_err {
|
||||
|
||||
@@ -553,7 +553,10 @@ impl<T: TransactionOrdering> TxPool<T> {
|
||||
)),
|
||||
InsertErr::Overdraft { transaction } => Err(PoolError::new(
|
||||
*transaction.hash(),
|
||||
PoolErrorKind::InvalidTransaction(InvalidPoolTransactionError::Overdraft),
|
||||
PoolErrorKind::InvalidTransaction(InvalidPoolTransactionError::Overdraft {
|
||||
cost: transaction.cost(),
|
||||
balance: on_chain_balance,
|
||||
}),
|
||||
)),
|
||||
InsertErr::TxTypeConflict { transaction } => Err(PoolError::new(
|
||||
*transaction.hash(),
|
||||
|
||||
Reference in New Issue
Block a user