Skip to content

Commit ecaa36b

Browse files
committed
Handle pending transactions in RPC
1 parent 4a63ad1 commit ecaa36b

File tree

3 files changed

+56
-12
lines changed

3 files changed

+56
-12
lines changed

crates/module-system/module-implementations/sov-evm/src/helpers.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,19 @@ pub(crate) fn from_recovered_with_block_context(
6767
alloy_rpc_types::Transaction::from_transaction(tx.convert(), tx_info)
6868
}
6969

70+
pub(crate) fn from_recovered_pending(
71+
tx: Recovered<TransactionSigned>,
72+
) -> alloy_rpc_types::Transaction {
73+
let tx_info = TransactionInfo {
74+
block_hash: None,
75+
block_number: None,
76+
index: None,
77+
hash: None,
78+
base_fee: None,
79+
};
80+
alloy_rpc_types::Transaction::from_transaction(tx.convert(), tx_info)
81+
}
82+
7083
#[cfg(test)]
7184
mod tests {
7285
use alloy_primitives::{Address, U256};

crates/module-system/module-implementations/sov-evm/src/rpc/handlers.rs

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::error::into_rpc_error;
22
use crate::rpc::error::ensure_success;
33
use alloy_consensus::ReceiptEnvelope;
4+
use alloy_consensus::Transaction as TransactionTrait;
45
use alloy_eips::BlockId;
56
use alloy_primitives::{Address, U64};
67
use alloy_primitives::{Bytes, B256, U256};
@@ -153,16 +154,32 @@ where
153154
block_id: Option<BlockId>,
154155
state: &mut ApiStateAccessor<S>,
155156
) -> RpcResult<U64> {
156-
let mut state = self.resolve_state_for_block_id(block_id, state)?;
157-
158-
let ethereum_address: EthereumAddress = address.into();
159-
let credential_id = ethereum_address.as_credential_id();
160-
161-
let nonce = self
162-
.uniqueness_module
163-
.next_nonce(&credential_id, state.deref_mut())
164-
.unwrap_or_default();
165-
157+
let block_id = block_id.unwrap_or_else(BlockId::latest);
158+
let is_pending = block_id.is_latest() || block_id.is_pending();
159+
160+
let nonce = {
161+
let mut resolved_state = self.resolve_state_for_block_id(Some(block_id), state)?;
162+
let ethereum_address: EthereumAddress = address.into();
163+
let credential_id = ethereum_address.as_credential_id();
164+
self.uniqueness_module
165+
.next_nonce(&credential_id, resolved_state.deref_mut())
166+
.unwrap_or_default()
167+
};
168+
169+
let pending_nonce = if is_pending {
170+
let pending_txs: Vec<_> = self.pending_transactions.collect_infallible(state);
171+
pending_txs
172+
.iter()
173+
.filter(|pending| pending.transaction.signer == address)
174+
.map(|pending| pending.transaction.signed_transaction.nonce())
175+
.max()
176+
.map(|nonce| nonce.saturating_add(1))
177+
.unwrap_or(0)
178+
} else {
179+
0
180+
};
181+
182+
let nonce = nonce.max(pending_nonce);
166183
trace!(%address, nonce, method = "eth_getTransactionCount", "EVM module JSON-RPC request");
167184
Ok(U64::from(nonce))
168185
}
@@ -217,7 +234,9 @@ where
217234
hash: B256,
218235
state: &mut ApiStateAccessor<S>,
219236
) -> RpcResult<Option<Transaction>> {
220-
let transaction = self.get_transaction(hash, state);
237+
let transaction = self
238+
.get_transaction(hash, state)
239+
.or_else(|| self.get_pending_transaction(hash, state));
221240
trace!(
222241
%hash,
223242
?transaction,

crates/module-system/module-implementations/sov-evm/src/rpc/mod.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::error::into_rpc_error;
55
use crate::evm::executor;
66
use crate::evm::primitive_types::{Receipt, TransactionSigned, TxSignedAndRecovered};
77
use crate::executor::get_cfg_env;
8-
use crate::helpers::{from_recovered_with_block_context, prepare_call_env};
8+
use crate::helpers::{from_recovered_pending, from_recovered_with_block_context, prepare_call_env};
99
pub use crate::primitive_types::MaybeSealedBlock;
1010
use crate::{verify_contract_creation_allowlist, Evm, SealedBlock};
1111
use alloy_consensus::{transaction::Recovered, Transaction as TransactionTrait, TxReceipt};
@@ -151,6 +151,18 @@ where
151151
Some(tx)
152152
}
153153

154+
fn get_pending_transaction(
155+
&self,
156+
hash: B256,
157+
state: &mut ApiStateAccessor<S>,
158+
) -> Option<Transaction> {
159+
let pending_transactions: Vec<_> = self.pending_transactions.collect_infallible(state);
160+
let pending = pending_transactions
161+
.iter()
162+
.find(|pending| *pending.transaction.signed_transaction.hash() == hash)?;
163+
Some(from_recovered_pending(pending.transaction.clone().into()))
164+
}
165+
154166
fn get_receipt_by_hash(
155167
&self,
156168
hash: B256,

0 commit comments

Comments
 (0)