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
No known key found for this signature in database
4 changed files with 32 additions and 37 deletions
processor/ethereum
erc20/src
router/src
src

View file

@ -2,6 +2,7 @@
#![doc = include_str!("../README.md")]
#![deny(missing_docs)]
use core::ops::RangeInclusive;
use std::collections::HashMap;
use alloy_core::primitives::{Address, U256};
@ -76,8 +77,8 @@ pub struct TopLevelTransfers {
pub struct Erc20;
impl Erc20 {
/// 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 {
let filter = Filter::new().from_block(from_block).to_block(to_block);
fn transfer_filter(blocks: RangeInclusive<u64>, erc20: Address, to: Address) -> Filter {
let filter = Filter::new().select(blocks);
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.
pub async fn top_level_transfers_unordered(
provider: &RootProvider<SimpleRequest>,
from_block: u64,
to_block: u64,
blocks: RangeInclusive<u64>,
erc20: Address,
to: Address,
) -> Result<TopLevelTransfers, RpcError<TransportErrorKind>> {
let mut logs = {
// 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
let mut transaction_logs = HashMap::new();

View file

@ -2,6 +2,7 @@
#![doc = include_str!("../README.md")]
#![deny(missing_docs)]
use core::ops::RangeInclusive;
use std::{
sync::Arc,
collections::{HashSet, HashMap},
@ -459,13 +460,13 @@ impl Router {
/// This is not guaranteed to return them in any order.
pub async fn in_instructions_unordered(
&self,
from_block: u64,
to_block: u64,
blocks: RangeInclusive<u64>,
allowed_erc20s: &HashSet<Address>,
) -> Result<Vec<InInstruction>, RpcError<TransportErrorKind>> {
// The InInstruction events for this block
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);
self.provider.get_logs(&filter).await?
};
@ -478,18 +479,15 @@ impl Router {
let erc20_transfer_logs = {
let mut transfers = FuturesUnordered::new();
for erc20 in allowed_erc20s {
transfers.push(async move {
(
erc20,
Erc20::top_level_transfers_unordered(
&self.provider,
from_block,
to_block,
*erc20,
self.address,
)
.await,
)
transfers.push({
// https://github.com/rust-lang/rust/issues/27186
let blocks: RangeInclusive<u64> = blocks.clone();
async move {
let transfers =
Erc20::top_level_transfers_unordered(&self.provider, blocks, *erc20, self.address)
.await;
(erc20, transfers)
}
});
}
@ -626,8 +624,7 @@ impl Router {
/// Fetch the executed actions for the specified range of blocks.
pub async fn executed(
&self,
from_block: u64,
to_block: u64,
blocks: RangeInclusive<u64>,
) -> Result<Vec<Executed>, RpcError<TransportErrorKind>> {
fn decode<E: SolEvent>(log: &Log) -> Result<E, RpcError<TransportErrorKind>> {
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?;
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.
pub async fn escapes(
&self,
from_block: u64,
to_block: u64,
blocks: RangeInclusive<u64>,
) -> 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 =
self.provider.get_logs(&filter.event_signature(EscapedEvent::SIGNATURE_HASH)).await?;
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
{
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[0], Executed::NextSeraiKeySet { nonce: 0, key: public_key.eth_repr() });
}
@ -191,7 +191,7 @@ impl Test {
{
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[0],
@ -236,7 +236,7 @@ impl Test {
{
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[0],
@ -283,15 +283,14 @@ impl Test {
if matches!(coin, Coin::Erc20(_)) {
// If we don't whitelist this token, we shouldn't be yielded an InInstruction
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());
}
let in_instructions = self
.router
.in_instructions_unordered(
block,
block,
block ..= block,
&if let Coin::Erc20(token) = coin { HashSet::from([token]) } else { HashSet::new() },
)
.await
@ -359,7 +358,7 @@ impl Test {
{
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[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();
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) }],
);
@ -730,7 +729,7 @@ async fn test_escape_hatch() {
assert!(receipt.status());
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.state.escaped_to.unwrap()).await, amount);
}

View file

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