1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
use cfx_rpc_utils::error::errors::{
    EthApiError, RpcInvalidTransactionError, RpcPoolError,
};
use cfx_types::{H256, U256};
use primitives::transaction::TransactionError;

#[derive(Debug, Clone, thiserror::Error, PartialEq, Eq)]
pub enum TransactionPoolError {
    ///
    #[error("{0:?}")]
    TransactionError(TransactionError),
    /// gas limit exceeded maximum value
    #[error("transaction gas {have} exceeds the maximum value {max:?}")]
    GasLimitExceeded { max: U256, have: U256 },

    #[error("transaction gas price {have} less than the minimum value {min}")]
    GasPriceLessThanMinimum { min: U256, have: U256 },

    #[error("{0}")]
    RlpDecodeError(String),

    #[error("Transaction {hash:?} is discarded due to in too distant future")]
    NonceTooDistant { hash: H256, nonce: U256 },

    #[error("Transaction {hash:?} is discarded due to a too stale nonce")]
    NonceTooStale { hash: H256, nonce: U256 },

    #[error("Transaction {hash:?} is discarded due to out of balance, needs {need:?} but account balance is {have:?}")]
    OutOfBalance { need: U256, have: U256, hash: H256 },

    #[error("txpool is full")]
    TxPoolFull,

    #[error("Tx with same nonce already inserted. To replace it, you need to specify a gas price > {expected:?}")]
    HigherGasPriceNeeded { expected: U256 },

    #[error("db error: {0}")]
    StateDbError(String),
}

impl From<cfx_statedb::Error> for TransactionPoolError {
    fn from(value: cfx_statedb::Error) -> Self {
        TransactionPoolError::StateDbError(format!(
            "Failed to read account_cache from storage: {}",
            value
        ))
    }
}

impl From<TransactionPoolError> for EthApiError {
    fn from(err: TransactionPoolError) -> Self {
        match err {
            TransactionPoolError::TransactionError(tx_err) => match tx_err {
                TransactionError::AlreadyImported => Self::PoolError(RpcPoolError::ReplaceUnderpriced),
                TransactionError::ChainIdMismatch { .. } => Self::InvalidTransaction(RpcInvalidTransactionError::InvalidChainId),
                TransactionError::EpochHeightOutOfBound { .. } => Self::InvalidBlockRange,
                TransactionError::NotEnoughBaseGas { .. } => Self::InvalidTransaction(RpcInvalidTransactionError::GasTooLow),
                TransactionError::Stale => Self::InvalidTransaction(RpcInvalidTransactionError::NonceTooLow),
                TransactionError::TooCheapToReplace => Self::PoolError(RpcPoolError::ReplaceUnderpriced),
                TransactionError::LimitReached => Self::PoolError(RpcPoolError::TxPoolOverflow),
                TransactionError::InsufficientGasPrice { .. } => Self::PoolError(RpcPoolError::Underpriced),
                TransactionError::InsufficientGas { .. } => Self::InvalidTransaction(RpcInvalidTransactionError::GasTooLow),
                TransactionError::InsufficientBalance { .. } => Self::InvalidTransaction(RpcInvalidTransactionError::InsufficientFundsForTransfer),
                TransactionError::GasLimitExceeded { .. } => Self::InvalidTransaction(RpcInvalidTransactionError::GasTooHigh),
                TransactionError::InvalidGasLimit(_) => Self::InvalidTransaction(RpcInvalidTransactionError::GasUintOverflow),
                TransactionError::InvalidSignature(_) => Self::InvalidTransactionSignature,
                TransactionError::TooBig => Self::InvalidTransaction(RpcInvalidTransactionError::MaxInitCodeSizeExceeded),
                TransactionError::InvalidRlp(_) => Self::FailedToDecodeSignedTransaction,
                TransactionError::ZeroGasPrice => Self::PoolError(RpcPoolError::Underpriced),
                TransactionError::FutureTransactionType => Self::InvalidTransaction(RpcInvalidTransactionError::TxTypeNotSupported),
                TransactionError::InvalidReceiver => Self::Other("Invalid receiver".to_string()),
                TransactionError::TooLargeNonce => Self::InvalidTransaction(RpcInvalidTransactionError::NonceMaxValue),
            },
            TransactionPoolError::GasLimitExceeded { .. } => Self::PoolError(RpcPoolError::ExceedsGasLimit),
            TransactionPoolError::GasPriceLessThanMinimum { .. } => Self::PoolError(RpcPoolError::Underpriced),
            TransactionPoolError::RlpDecodeError(_) => Self::FailedToDecodeSignedTransaction,
            TransactionPoolError::NonceTooDistant { .. } => Self::InvalidTransaction(RpcInvalidTransactionError::NonceTooHigh),
            TransactionPoolError::NonceTooStale { .. } => Self::InvalidTransaction(RpcInvalidTransactionError::NonceTooLow),
            TransactionPoolError::OutOfBalance { .. } => Self::InvalidTransaction(RpcInvalidTransactionError::InsufficientFundsForTransfer),
            TransactionPoolError::TxPoolFull => Self::PoolError(RpcPoolError::TxPoolOverflow),
            TransactionPoolError::HigherGasPriceNeeded {..} => Self::PoolError(RpcPoolError::ReplaceUnderpriced),
            TransactionPoolError::StateDbError(_) => Self::InternalEthError,
        }
    }
}