Skip to content

Commit

Permalink
feat: use next free nonce in eth_sendTransaction (#11873)
Browse files Browse the repository at this point in the history
  • Loading branch information
caglaryucekaya authored Oct 19, 2024
1 parent cf4a445 commit 422ab17
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 3 deletions.
36 changes: 36 additions & 0 deletions crates/rpc/rpc-eth-api/src/helpers/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,42 @@ pub trait LoadState: EthApiTypes {
}
}

/// Returns the next available nonce without gaps for the given address
/// Next available nonce is either the on chain nonce of the account or the highest consecutive
/// nonce in the pool + 1
fn next_available_nonce(
&self,
address: Address,
) -> impl Future<Output = Result<u64, Self::Error>> + Send
where
Self: SpawnBlocking,
{
self.spawn_blocking_io(move |this| {
// first fetch the on chain nonce of the account
let on_chain_account_nonce = this
.latest_state()?
.account_nonce(address)
.map_err(Self::Error::from_eth_err)?
.unwrap_or_default();

let mut next_nonce = on_chain_account_nonce;
// Retrieve the highest consecutive transaction for the sender from the transaction pool
if let Some(highest_tx) = this
.pool()
.get_highest_consecutive_transaction_by_sender(address, on_chain_account_nonce)
{
// Return the nonce of the highest consecutive transaction + 1
next_nonce = highest_tx.nonce().checked_add(1).ok_or_else(|| {
Self::Error::from(EthApiError::InvalidTransaction(
RpcInvalidTransactionError::NonceMaxValue,
))
})?;
}

Ok(next_nonce)
})
}

/// Returns the number of transactions sent from an address at the given block identifier.
///
/// If this is [`BlockNumberOrTag::Pending`](reth_primitives::BlockNumberOrTag) then this will
Expand Down
5 changes: 2 additions & 3 deletions crates/rpc/rpc-eth-api/src/helpers/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,9 +365,8 @@ pub trait EthTransactions: LoadTransaction {

// set nonce if not already set before
if request.nonce.is_none() {
let nonce = self.transaction_count(from, Some(BlockId::pending())).await?;
// note: `.to()` can't panic because the nonce is constructed from a `u64`
request.nonce = Some(nonce.to());
let nonce = self.next_available_nonce(from).await?;
request.nonce = Some(nonce);
}

let chain_id = self.chain_id();
Expand Down

0 comments on commit 422ab17

Please sign in to comment.