cfx_rpc_eth_types/
call.rs

1use crate::{BlockId, BlockOverrides, TransactionRequest};
2use cfx_bytes::Bytes;
3
4/// Bundle of transactions
5#[derive(Clone, Debug, Default, PartialEq, Eq)]
6#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
8pub struct Bundle {
9    /// All transactions to execute
10    pub transactions: Vec<TransactionRequest>,
11    /// Block overrides to apply
12    #[cfg_attr(
13        feature = "serde",
14        serde(default, skip_serializing_if = "Option::is_none")
15    )]
16    pub block_override: Option<BlockOverrides>,
17}
18
19impl From<Vec<TransactionRequest>> for Bundle {
20    /// Converts a `TransactionRequest` into a `Bundle`.
21    fn from(tx_request: Vec<TransactionRequest>) -> Self {
22        Self {
23            transactions: tx_request,
24            block_override: None,
25        }
26    }
27}
28
29/// State context for callMany
30#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
31#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
32#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
33pub struct StateContext {
34    /// Block Number
35    #[cfg_attr(
36        feature = "serde",
37        serde(skip_serializing_if = "Option::is_none")
38    )]
39    pub block_number: Option<BlockId>,
40    /// Inclusive number of tx to replay in block. -1 means replay all
41    #[cfg_attr(
42        feature = "serde",
43        serde(skip_serializing_if = "Option::is_none")
44    )]
45    #[doc(alias = "tx_index")]
46    pub transaction_index: Option<TransactionIndex>,
47}
48
49/// CallResponse for eth_callMany
50#[derive(Clone, Debug, Default, PartialEq, Eq)]
51#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
52#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
53pub struct EthCallResponse {
54    /// eth_call output (if no error)
55    #[cfg_attr(
56        feature = "serde",
57        serde(skip_serializing_if = "Option::is_none")
58    )]
59    pub value: Option<Bytes>,
60    /// eth_call output (if error)
61    #[cfg_attr(
62        feature = "serde",
63        serde(skip_serializing_if = "Option::is_none")
64    )]
65    pub error: Option<String>,
66}
67
68impl EthCallResponse {
69    /// Returns the value if present, otherwise returns the error.
70    pub fn ensure_ok(self) -> Result<Bytes, String> {
71        match self.value {
72            Some(output) => Ok(output),
73            None => {
74                Err(self.error.unwrap_or_else(|| "Unknown error".to_string()))
75            }
76        }
77    }
78}
79
80/// Represents a transaction index where -1 means all transactions
81#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
82pub enum TransactionIndex {
83    /// -1 means all transactions
84    #[default]
85    All,
86    /// Transaction index
87    Index(usize),
88}
89
90impl TransactionIndex {
91    /// Returns true if this is the all variant
92    pub const fn is_all(&self) -> bool { matches!(self, Self::All) }
93
94    /// Returns true if this is the index variant
95    pub const fn is_index(&self) -> bool { matches!(self, Self::Index(_)) }
96
97    /// Returns the index if this is the index variant
98    pub const fn index(&self) -> Option<usize> {
99        match self {
100            Self::All => None,
101            Self::Index(idx) => Some(*idx),
102        }
103    }
104}
105
106impl From<usize> for TransactionIndex {
107    fn from(index: usize) -> Self { Self::Index(index) }
108}
109
110#[cfg(feature = "serde")]
111impl serde::Serialize for TransactionIndex {
112    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
113    where S: serde::Serializer {
114        match self {
115            Self::All => serializer.serialize_i8(-1),
116            Self::Index(idx) => idx.serialize(serializer),
117        }
118    }
119}
120
121#[cfg(feature = "serde")]
122impl<'de> serde::Deserialize<'de> for TransactionIndex {
123    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
124    where D: serde::Deserializer<'de> {
125        match isize::deserialize(deserializer)? {
126            -1 => Ok(Self::All),
127            idx if idx < -1 => Err(serde::de::Error::custom(format!(
128                "Invalid transaction index, expected -1 or positive integer, got {}",
129                idx
130            ))),
131            idx => Ok(Self::Index(idx as usize)),
132        }
133    }
134}