Take advantage of RangeInclusive for specifying filters' blocks

This commit is contained in:
Luke Parker
2025-01-24 07:44:47 -05:00
parent 604a4b2442
commit 29bb5e21ab
4 changed files with 32 additions and 37 deletions

View File

@@ -2,6 +2,7 @@
#![doc = include_str!("../README.md")] #![doc = include_str!("../README.md")]
#![deny(missing_docs)] #![deny(missing_docs)]
use core::ops::RangeInclusive;
use std::collections::HashMap; use std::collections::HashMap;
use alloy_core::primitives::{Address, U256}; use alloy_core::primitives::{Address, U256};
@@ -76,8 +77,8 @@ pub struct TopLevelTransfers {
pub struct Erc20; pub struct Erc20;
impl Erc20 { impl Erc20 {
/// The filter for transfer logs of the specified ERC20, to the specified recipient. /// The filter for transfer logs of the specified ERC20, to the specified recipient.
fn transfer_filter(from_block: u64, to_block: u64, erc20: Address, to: Address) -> Filter { fn transfer_filter(blocks: RangeInclusive<u64>, erc20: Address, to: Address) -> Filter {
let filter = Filter::new().from_block(from_block).to_block(to_block); let filter = Filter::new().select(blocks);
filter.address(erc20).event_signature(Transfer::SIGNATURE_HASH).topic2(to.into_word()) filter.address(erc20).event_signature(Transfer::SIGNATURE_HASH).topic2(to.into_word())
} }
@@ -180,14 +181,13 @@ impl Erc20 {
/// The `transfers` in the result are unordered. The `logs` are sorted by index. /// The `transfers` in the result are unordered. The `logs` are sorted by index.
pub async fn top_level_transfers_unordered( pub async fn top_level_transfers_unordered(
provider: &RootProvider<SimpleRequest>, provider: &RootProvider<SimpleRequest>,
from_block: u64, blocks: RangeInclusive<u64>,
to_block: u64,
erc20: Address, erc20: Address,
to: Address, to: Address,
) -> Result<TopLevelTransfers, RpcError<TransportErrorKind>> { ) -> Result<TopLevelTransfers, RpcError<TransportErrorKind>> {
let mut logs = { let mut logs = {
// Get all transfers within these blocks // Get all transfers within these blocks
let logs = provider.get_logs(&Self::transfer_filter(from_block, to_block, erc20, to)).await?; let logs = provider.get_logs(&Self::transfer_filter(blocks, erc20, to)).await?;
// The logs, indexed by their transactions // The logs, indexed by their transactions
let mut transaction_logs = HashMap::new(); let mut transaction_logs = HashMap::new();

View File

@@ -2,6 +2,7 @@
#![doc = include_str!("../README.md")] #![doc = include_str!("../README.md")]
#![deny(missing_docs)] #![deny(missing_docs)]
use core::ops::RangeInclusive;
use std::{ use std::{
sync::Arc, sync::Arc,
collections::{HashSet, HashMap}, collections::{HashSet, HashMap},
@@ -459,13 +460,13 @@ impl Router {
/// This is not guaranteed to return them in any order. /// This is not guaranteed to return them in any order.
pub async fn in_instructions_unordered( pub async fn in_instructions_unordered(
&self, &self,
from_block: u64, blocks: RangeInclusive<u64>,
to_block: u64,
allowed_erc20s: &HashSet<Address>, allowed_erc20s: &HashSet<Address>,
) -> Result<Vec<InInstruction>, RpcError<TransportErrorKind>> { ) -> Result<Vec<InInstruction>, RpcError<TransportErrorKind>> {
// The InInstruction events for this block // The InInstruction events for this block
let in_instruction_logs = { let in_instruction_logs = {
let filter = Filter::new().from_block(from_block).to_block(to_block).address(self.address); // https://github.com/rust-lang/rust/issues/27186
let filter = Filter::new().select(blocks.clone()).address(self.address);
let filter = filter.event_signature(InInstructionEvent::SIGNATURE_HASH); let filter = filter.event_signature(InInstructionEvent::SIGNATURE_HASH);
self.provider.get_logs(&filter).await? self.provider.get_logs(&filter).await?
}; };
@@ -478,18 +479,15 @@ impl Router {
let erc20_transfer_logs = { let erc20_transfer_logs = {
let mut transfers = FuturesUnordered::new(); let mut transfers = FuturesUnordered::new();
for erc20 in allowed_erc20s { for erc20 in allowed_erc20s {
transfers.push(async move { transfers.push({
( // https://github.com/rust-lang/rust/issues/27186
erc20, let blocks: RangeInclusive<u64> = blocks.clone();
Erc20::top_level_transfers_unordered( async move {
&self.provider, let transfers =
from_block, Erc20::top_level_transfers_unordered(&self.provider, blocks, *erc20, self.address)
to_block, .await;
*erc20, (erc20, transfers)
self.address, }
)
.await,
)
}); });
} }
@@ -626,8 +624,7 @@ impl Router {
/// Fetch the executed actions for the specified range of blocks. /// Fetch the executed actions for the specified range of blocks.
pub async fn executed( pub async fn executed(
&self, &self,
from_block: u64, blocks: RangeInclusive<u64>,
to_block: u64,
) -> Result<Vec<Executed>, RpcError<TransportErrorKind>> { ) -> Result<Vec<Executed>, RpcError<TransportErrorKind>> {
fn decode<E: SolEvent>(log: &Log) -> Result<E, RpcError<TransportErrorKind>> { fn decode<E: SolEvent>(log: &Log) -> Result<E, RpcError<TransportErrorKind>> {
Ok( Ok(
@@ -643,7 +640,7 @@ impl Router {
) )
} }
let filter = Filter::new().from_block(from_block).to_block(to_block).address(self.address); let filter = Filter::new().select(blocks).address(self.address);
let mut logs = self.provider.get_logs(&filter).await?; let mut logs = self.provider.get_logs(&filter).await?;
logs.sort_by_key(|log| (log.block_number, log.log_index)); logs.sort_by_key(|log| (log.block_number, log.log_index));
@@ -707,10 +704,9 @@ impl Router {
/// Fetch the `Escape`s from the smart contract through the escape hatch. /// Fetch the `Escape`s from the smart contract through the escape hatch.
pub async fn escapes( pub async fn escapes(
&self, &self,
from_block: u64, blocks: RangeInclusive<u64>,
to_block: u64,
) -> Result<Vec<Escape>, RpcError<TransportErrorKind>> { ) -> Result<Vec<Escape>, RpcError<TransportErrorKind>> {
let filter = Filter::new().from_block(from_block).to_block(to_block).address(self.address); let filter = Filter::new().select(blocks).address(self.address);
let mut logs = let mut logs =
self.provider.get_logs(&filter.event_signature(EscapedEvent::SIGNATURE_HASH)).await?; self.provider.get_logs(&filter.event_signature(EscapedEvent::SIGNATURE_HASH)).await?;
logs.sort_by_key(|log| (log.block_number, log.log_index)); logs.sort_by_key(|log| (log.block_number, log.log_index));

View File

@@ -144,7 +144,7 @@ impl Test {
// Confirm nonce 0 was used as such // Confirm nonce 0 was used as such
{ {
let block = receipt.block_number.unwrap(); let block = receipt.block_number.unwrap();
let executed = router.executed(block, block).await.unwrap(); let executed = router.executed(block ..= block).await.unwrap();
assert_eq!(executed.len(), 1); assert_eq!(executed.len(), 1);
assert_eq!(executed[0], Executed::NextSeraiKeySet { nonce: 0, key: public_key.eth_repr() }); assert_eq!(executed[0], Executed::NextSeraiKeySet { nonce: 0, key: public_key.eth_repr() });
} }
@@ -191,7 +191,7 @@ impl Test {
{ {
let block = receipt.block_number.unwrap(); let block = receipt.block_number.unwrap();
let executed = self.router.executed(block, block).await.unwrap(); let executed = self.router.executed(block ..= block).await.unwrap();
assert_eq!(executed.len(), 1); assert_eq!(executed.len(), 1);
assert_eq!( assert_eq!(
executed[0], executed[0],
@@ -236,7 +236,7 @@ impl Test {
{ {
let block = receipt.block_number.unwrap(); let block = receipt.block_number.unwrap();
let executed = self.router.executed(block, block).await.unwrap(); let executed = self.router.executed(block ..= block).await.unwrap();
assert_eq!(executed.len(), 1); assert_eq!(executed.len(), 1);
assert_eq!( assert_eq!(
executed[0], executed[0],
@@ -283,15 +283,14 @@ impl Test {
if matches!(coin, Coin::Erc20(_)) { if matches!(coin, Coin::Erc20(_)) {
// If we don't whitelist this token, we shouldn't be yielded an InInstruction // If we don't whitelist this token, we shouldn't be yielded an InInstruction
let in_instructions = let in_instructions =
self.router.in_instructions_unordered(block, block, &HashSet::new()).await.unwrap(); self.router.in_instructions_unordered(block ..= block, &HashSet::new()).await.unwrap();
assert!(in_instructions.is_empty()); assert!(in_instructions.is_empty());
} }
let in_instructions = self let in_instructions = self
.router .router
.in_instructions_unordered( .in_instructions_unordered(
block, block ..= block,
block,
&if let Coin::Erc20(token) = coin { HashSet::from([token]) } else { HashSet::new() }, &if let Coin::Erc20(token) = coin { HashSet::from([token]) } else { HashSet::new() },
) )
.await .await
@@ -359,7 +358,7 @@ impl Test {
{ {
let block = receipt.block_number.unwrap(); let block = receipt.block_number.unwrap();
let executed = self.router.executed(block, block).await.unwrap(); let executed = self.router.executed(block ..= block).await.unwrap();
assert_eq!(executed.len(), 1); assert_eq!(executed.len(), 1);
assert_eq!(executed[0], Executed::EscapeHatch { nonce: self.state.next_nonce, escape_to }); assert_eq!(executed[0], Executed::EscapeHatch { nonce: self.state.next_nonce, escape_to });
} }
@@ -707,7 +706,7 @@ async fn test_escape_hatch() {
let block = receipt.block_number.unwrap(); let block = receipt.block_number.unwrap();
assert_eq!( assert_eq!(
test.router.escapes(block, block).await.unwrap(), test.router.escapes(block ..= block).await.unwrap(),
vec![Escape { coin: Coin::Ether, amount: U256::from(1) }], vec![Escape { coin: Coin::Ether, amount: U256::from(1) }],
); );
@@ -730,7 +729,7 @@ async fn test_escape_hatch() {
assert!(receipt.status()); assert!(receipt.status());
let block = receipt.block_number.unwrap(); let block = receipt.block_number.unwrap();
assert_eq!(test.router.escapes(block, block).await.unwrap(), vec![Escape { coin, amount }],); assert_eq!(test.router.escapes(block ..= block).await.unwrap(), vec![Escape { coin, amount }],);
assert_eq!(erc20.balance_of(&test, test.router.address()).await, U256::from(0)); assert_eq!(erc20.balance_of(&test, test.router.address()).await, U256::from(0));
assert_eq!(erc20.balance_of(&test, test.state.escaped_to.unwrap()).await, amount); assert_eq!(erc20.balance_of(&test, test.state.escaped_to.unwrap()).await, amount);
} }

View File

@@ -160,10 +160,10 @@ impl<D: Db> ScannerFeed for Rpc<D> {
block: Header, block: Header,
) -> Result<(Vec<EthereumInInstruction>, Vec<Executed>), RpcError<TransportErrorKind>> { ) -> Result<(Vec<EthereumInInstruction>, Vec<Executed>), RpcError<TransportErrorKind>> {
let instructions = router let instructions = router
.in_instructions_unordered(block.number, block.number, &HashSet::from(TOKENS)) .in_instructions_unordered(block.number ..= block.number, &HashSet::from(TOKENS))
.await?; .await?;
let executed = router.executed(block.number, block.number).await?; let executed = router.executed(block.number ..= block.number).await?;
Ok((instructions, executed)) Ok((instructions, executed))
} }