use crate::cache::StateSource;
use alloy::primitives::Address;
use core::fmt::{self, Display, Formatter};
use signet_bundle::TxRequirement;
use std::collections::BTreeMap;
use tracing::{trace, trace_span};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum SimItemValidity {
Never,
Future,
Now,
}
impl SimItemValidity {
pub const fn is_valid_now(&self) -> bool {
matches!(self, SimItemValidity::Now)
}
pub const fn is_never_valid(&self) -> bool {
matches!(self, SimItemValidity::Never)
}
pub const fn is_future_valid(&self) -> bool {
matches!(self, SimItemValidity::Future)
}
}
impl Display for SimItemValidity {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::Never => f.write_str("never"),
Self::Future => f.write_str("future"),
Self::Now => f.write_str("now"),
}
}
}
pub async fn check_bundle_tx_list<S>(
items: impl Iterator<Item = TxRequirement>,
source: &S,
) -> Result<SimItemValidity, S::Error>
where
S: StateSource,
{
let mut nonce_cache: BTreeMap<Address, u64> = BTreeMap::new();
let mut items = items.peekable();
if let Some(first) = items.peek() {
let info = source.account_details(&first.signer).await?;
if first.balance > info.balance {
trace!(
required = %first.balance,
available = %info.balance,
signer = %first.signer,
"insufficient balance",
);
return Ok(SimItemValidity::Future);
}
nonce_cache.insert(first.signer, info.nonce);
}
for requirement in items {
let state_nonce = match nonce_cache.get(&requirement.signer) {
Some(cached_nonce) => *cached_nonce,
None => {
let nonce = source.nonce(&requirement.signer).await?;
nonce_cache.insert(requirement.signer, nonce);
nonce
}
};
let _guard = trace_span!(
"check_bundle_tx",
signer = %requirement.signer,
item_nonce = requirement.nonce,
expected_nonce = state_nonce,
)
.entered();
if requirement.nonce < state_nonce {
trace!("nonce too low");
return Ok(SimItemValidity::Never);
}
if requirement.nonce > state_nonce {
trace!("nonce too high");
return Ok(SimItemValidity::Future);
}
nonce_cache.entry(requirement.signer).and_modify(|n| *n += 1);
}
Ok(SimItemValidity::Now)
}