Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: discorver factories async #229

Closed
molaco opened this issue Nov 4, 2024 · 1 comment
Closed

Feat: discorver factories async #229

molaco opened this issue Nov 4, 2024 · 1 comment
Labels
enhancement New feature or request

Comments

@molaco
Copy link
Contributor

molaco commented Nov 4, 2024

Describe the feature you would like

Because discover factories was very slow and there was a async TODO I wrote some simple code that makes it 10x faster. I hope its useful.

Additional context

use alloy_eips::{BlockId, BlockNumberOrTag};
use alloy_provider::{
    network::primitives::BlockTransactions, network::Ethereum, Provider, ProviderBuilder,
    RootProvider,
};
use alloy_rpc_types::eth::Filter;
use alloy_sol_types::{sol, SolCall, SolEvent, SolValue};
use alloy_transport_http::Http;

// use indicatif::ProgressBar;
use reqwest::Client;

use revm::{
    primitives::{address, Address, Bytes, TxKind, B256, U256},
    Evm,
};
use revm_database::{AlloyDB, CacheDB, StateBuilder};
use revm_database_interface::WrapDatabaseAsync;
use revm_inspector::{inspector_handle_register, inspectors::TracerEip3155};
use revm_wiring::EthereumWiring;

use std::time::Instant;
use std::{collections::HashMap, sync::Arc};
use tokio::task;
use tokio_stream::{self as stream, StreamExt};


#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Set up the HTTP transport which is consumed by the RPC client.
    let rpc_url = "".parse()?;

    // create ethers client and wrap it in Arc<M>
    let client = ProviderBuilder::new().on_http(rpc_url);

    // Params
    let chain_id: u64 = 1;
    let block_number = 10889447;
    // let block_number = 21106431;

    // Fetch the transaction-rich block
    let block = match client
        .get_block_by_number(BlockNumberOrTag::Number(block_number), true)
        .await
    {
        Ok(Some(block)) => block,
        Ok(None) => anyhow::bail!("Block not found"),
        Err(error) => anyhow::bail!("Error: {:?}", error),
    };
    println!("Fetched block number: {}", block.header.number);
    let previous_block_number = block_number - 1;

    // Discover UniswapV2 factories
    sol! {
        /// Interface of the UniswapV2Factory contract
        #[derive(Debug, PartialEq, Eq)]
        #[sol(rpc)]
        contract IUniswapV2Factory {
            event PairCreated(address indexed token0, address indexed token1, address pair, uint256 index);
            function getPair(address tokenA, address tokenB) external view returns (address pair);
            function allPairs(uint256 index) external view returns (address pair);
            function allPairsLength() external view returns (uint256 length);
        }
    }

    let pair_created_signature = IUniswapV2Factory::PairCreated::SIGNATURE_HASH;

    let block_filter = Filter::new().event_signature(pair_created_signature);

    let mut from_block = 0;
    let block_step = 50000;

    let mut block_num_vec: Vec<(u64, u64)> = Vec::new();
    let mut identified_factories: HashMap<Address, u64> = HashMap::new();

    let total_start = Instant::now();

    while from_block < block_number {
        // Get pair created event logs within the block range
        let mut target_block = from_block + block_step - 1;
        if target_block > block_number {
            target_block = block_number;
        }

        block_num_vec.push((from_block, target_block));

        from_block += block_step;
    }

    let stream_start = Instant::now();

    let mut stream = futures::stream::iter(&block_num_vec).map(|&(from_block, target_block)| {
        let block_filter = block_filter.clone();
        let client = client.clone();
        task::spawn(async move {
            process_block_logs_batch(&from_block, &target_block, client, &block_filter).await
        })
    });

    let results_start = Instant::now();
    let results_duration = results_start.elapsed();

    let results = stream.collect::<Vec<_>>().await;

    for result in results {
        match result.await {
            Ok(Ok(local_identified_factories)) => {
                for (addrs, count) in local_identified_factories {
                    *identified_factories.entry(addrs).or_insert(0) += count;
                }
            }
            Ok(Err(err)) => {
                // The task ran successfully, but there was an error in the Result.
                eprintln!("Error occurred: {:?}", err);
            }
            Err(join_err) => {
                // The task itself failed (possibly panicked).
                eprintln!("Task join error: {:?}", join_err);
            }
        }
    }

    // Print the found factories
    for (key, value) in &identified_factories {
        println!("{}: {}", key, value);
    }

    let stream_duration = stream_start.elapsed();
    let total_duration = total_start.elapsed();
    println!("Stream processing took: {:?}", stream_duration);
    println!("Results collection took: {:?}", results_duration);
    println!("Total collection took: {:?}", total_duration);

    Ok(())
}

async fn process_block_logs_batch(
    from_block: &u64,
    target_block: &u64,
    client: RootProvider<Http<Client>>,
    block_filter: &Filter,
) -> anyhow::Result<HashMap<Address, u64>> {
    let block_filter = block_filter.clone();
    let mut local_identified_factories: HashMap<Address, u64> = HashMap::new();

    let logs = client
        .get_logs(&block_filter.from_block(*from_block).to_block(*target_block))
        .await?;

    for log in logs {
        // tracing::trace!("found matching event at factory {}", log.address());

        if let Some(amms_length) = local_identified_factories.get_mut(&log.address()) {
            *amms_length += 1;
        } else {
            local_identified_factories.insert(log.address(), 0);
        }
    }

    Ok(local_identified_factories)
}
@molaco molaco added the enhancement New feature or request label Nov 4, 2024
@molaco
Copy link
Contributor Author

molaco commented Nov 4, 2024

#230

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants