use crate::{
collision_manager::Collisions,
error::CollisionReason,
storage::Storage,
};
use fuel_core_types::services::txpool::PoolTransaction;
use num_rational::Ratio;
pub trait CollisionsExt<S> {
fn check_collision_requirements(
&self,
tx: &PoolTransaction,
has_dependencies: bool,
storage: &S,
) -> Result<(), CollisionReason>;
}
impl<S> CollisionsExt<S> for Collisions<S::StorageIndex>
where
S: Storage,
{
fn check_collision_requirements(
&self,
tx: &PoolTransaction,
has_dependencies: bool,
storage: &S,
) -> Result<(), CollisionReason> {
if has_dependencies && self.len() > 1 {
return Err(CollisionReason::MultipleCollisions);
}
for (collision, reason) in self.iter() {
if !is_better_than_collision(tx, collision, storage)? {
tracing::info!(
"Transaction {} collided with {} because of {:?}",
tx.id(),
storage
.get(collision)
.map(|d| d.transaction.id().to_string())
.unwrap_or(String::from("Error")),
reason
);
if let Some(reason) = reason.first() {
return Err(reason.clone());
} else {
return Err(CollisionReason::Unknown);
}
}
}
Ok(())
}
}
fn is_better_than_collision<S>(
tx: &PoolTransaction,
collision: &S::StorageIndex,
storage: &S,
) -> Result<bool, CollisionReason>
where
S: Storage,
{
let new_tx_ratio = Ratio::new(tx.tip(), tx.max_gas());
let colliding_tx = storage.get(collision).ok_or(CollisionReason::Unknown)?;
let colliding_tx_ratio = Ratio::new(
colliding_tx.dependents_cumulative_tip,
colliding_tx.dependents_cumulative_gas,
);
Ok(new_tx_ratio > colliding_tx_ratio)
}