From e26da1ec347ef93895523c73082db552c1a256f3 Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Thu, 29 Aug 2024 21:58:56 -0400 Subject: [PATCH] Have the Eventuality task drop outputs which aren't ours and aren't worth it to aggregate We could drop these entirely, yet there's some degree of utility to be able to add coins to Serai in this manner. --- processor/scanner/src/eventuality/mod.rs | 28 ++++++++++++++++++++++-- processor/scanner/src/scan/mod.rs | 5 ++++- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/processor/scanner/src/eventuality/mod.rs b/processor/scanner/src/eventuality/mod.rs index 7db188de..9068769b 100644 --- a/processor/scanner/src/eventuality/mod.rs +++ b/processor/scanner/src/eventuality/mod.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::{HashSet, HashMap}; use group::GroupEncoding; @@ -288,7 +288,6 @@ impl> ContinuallyRan for EventualityTas let mut non_external_outputs = block.scan_for_outputs(key.key); non_external_outputs.retain(|output| output.kind() != OutputType::External); // Drop any outputs less than the dust limit - // TODO: Either further filter to outputs we made or also check cost_to_aggregate non_external_outputs.retain(|output| { let balance = output.balance(); balance.amount.0 >= self.feed.dust(balance.coin).0 @@ -315,6 +314,31 @@ impl> ContinuallyRan for EventualityTas .retain(|output| completed_eventualities.contains_key(&output.transaction_id())); } + // Finally, for non-External outputs we didn't make, we check they're worth more than the + // cost to aggregate them to avoid some profitable spam attacks by malicious miners + { + // Fetch and cache the costs to aggregate as this call may be expensive + let coins = + non_external_outputs.iter().map(|output| output.balance().coin).collect::>(); + let mut costs_to_aggregate = HashMap::new(); + for coin in coins { + costs_to_aggregate.insert( + coin, + self.feed.cost_to_aggregate(coin, &block).await.map_err(|e| { + format!("EventualityTask couldn't fetch cost to aggregate {coin:?} at {b}: {e:?}") + })?, + ); + } + + // Only retain out outputs/outputs sufficiently worthwhile + non_external_outputs.retain(|output| { + completed_eventualities.contains_key(&output.transaction_id()) || { + let balance = output.balance(); + balance.amount.0 >= (2 * costs_to_aggregate[&balance.coin].0) + } + }); + } + // Now, we iterate over all Forwarded outputs and queue their InInstructions for output in non_external_outputs.iter().filter(|output| output.kind() == OutputType::Forwarded) diff --git a/processor/scanner/src/scan/mod.rs b/processor/scanner/src/scan/mod.rs index f76adb00..405861ba 100644 --- a/processor/scanner/src/scan/mod.rs +++ b/processor/scanner/src/scan/mod.rs @@ -226,7 +226,10 @@ impl ContinuallyRan for ScanTask { costs_to_aggregate.entry(balance.coin) { e.insert(self.feed.cost_to_aggregate(balance.coin, &block).await.map_err(|e| { - format!("couldn't fetch cost to aggregate {:?} at {b}: {e:?}", balance.coin) + format!( + "ScanTask couldn't fetch cost to aggregate {:?} at {b}: {e:?}", + balance.coin + ) })?); } let cost_to_aggregate = costs_to_aggregate[&balance.coin];