From a83e42aff05db12b478c884514349b136ea787b0 Mon Sep 17 00:00:00 2001 From: yihao Date: Sat, 12 Aug 2023 22:10:39 -0700 Subject: [PATCH] [Chain Utils] Add chain_utils module and implement get_inception_block. --- bot/crates/strategy/Cargo.toml | 1 + bot/crates/strategy/src/common/chain_utils.rs | 76 +++++++++++++++++++ bot/crates/strategy/src/common/mod.rs | 1 + bot/crates/strategy/src/lib.rs | 3 + 4 files changed, 81 insertions(+) create mode 100644 bot/crates/strategy/src/common/chain_utils.rs create mode 100644 bot/crates/strategy/src/common/mod.rs diff --git a/bot/crates/strategy/Cargo.toml b/bot/crates/strategy/Cargo.toml index e0c609a..e2c43b2 100644 --- a/bot/crates/strategy/Cargo.toml +++ b/bot/crates/strategy/Cargo.toml @@ -32,6 +32,7 @@ artemis-core = { path = "../artemis-core" } [dev-dependencies] fern = {version = "0.6.2", features = ["colored"]} +env_logger = "0.10.0" [features] debug = [] diff --git a/bot/crates/strategy/src/common/chain_utils.rs b/bot/crates/strategy/src/common/chain_utils.rs new file mode 100644 index 0000000..56b3776 --- /dev/null +++ b/bot/crates/strategy/src/common/chain_utils.rs @@ -0,0 +1,76 @@ +use ethers::{ + providers::{Middleware, ProviderError}, + types::{BlockNumber, Address, U64, NameOrAddress, BlockId} +}; +use log::{info, debug}; +use std::sync::Arc; + +pub async fn get_inception_block( + contract: Address, + provider: Arc) -> Result +{ + let mut last_block = + provider.get_block_number().await + .map_err(|err| ProviderError::CustomError(err.to_string()))?; + + // I am very confused about how to do the pattern matching here because provide_err is a reference + // to ProviderError. + // |err| match err.as_provider_error() { + // Some(provider_err) => ProviderError::from_err(provider_err), + // _ => ProviderError::CustomError(err.to_string()) + // }; + + let mut start_block = U64([1]); + let mut rpc_count = 0; + + while start_block < last_block { + let mid_block = start_block + (last_block - start_block) / 2; + let code = + provider.get_code( + NameOrAddress::Address(contract), + Some(BlockId::Number(BlockNumber::Number(mid_block)))) + .await; + rpc_count += 1; + debug!("Searching ({}) at block {:?} (start: {:?}, last: {:?}).", + rpc_count, mid_block, start_block, last_block); + match code { + Ok(_) => { + info!("Successfully find the code of contract {:?}, block {:?}.", contract, mid_block); + last_block = mid_block; + }, + Err(e) => { + info!("Failed to find the code of contract {:?}, block {:?}, err({:?}).", contract, mid_block, e); + start_block = mid_block + 1; + } + } + } + return Ok(BlockNumber::Number(start_block)); +} + +#[cfg(test)] +mod tests { + use std::error::Error; + use std::str::FromStr; + use ethers::providers::{Provider, Ws}; + use env_logger; + use super::*; + + // For some reason, the url below couldn't fetch code from the last 128 blocks. + // So that we cannot use the binary search to find the contract creation block. + // More details see https://ethereum.stackexchange.com/questions/40648/full-node-sync-only-preserve-the-last-128-history-states. + // In short, the current get_inception_block only works in the archive node. + + #[tokio::test] + async fn test_get_inception_block() -> Result<(), Box> + { + env_logger::init(); + + let contract = Address::from_str("0x115934131916C8b277DD010Ee02de363c09d037c")?; + let url: &str = + "wss://capable-crimson-vineyard.discover.quiknode.pro/b0f808fe30ebe9dd7b2a7122c563e20f1e9966da/"; + let provider = Arc::new(Provider::new(Ws::connect(url).await?)); + let block = get_inception_block(contract, provider).await?; + assert_eq!(block.as_number().unwrap().as_u64(), 12771526u64); + return Ok(()); + } +} \ No newline at end of file diff --git a/bot/crates/strategy/src/common/mod.rs b/bot/crates/strategy/src/common/mod.rs new file mode 100644 index 0000000..5b282f8 --- /dev/null +++ b/bot/crates/strategy/src/common/mod.rs @@ -0,0 +1 @@ +pub mod chain_utils; \ No newline at end of file diff --git a/bot/crates/strategy/src/lib.rs b/bot/crates/strategy/src/lib.rs index 7de6c42..287731c 100644 --- a/bot/crates/strategy/src/lib.rs +++ b/bot/crates/strategy/src/lib.rs @@ -12,5 +12,8 @@ mod tx_utils; /// Module contains core strategy implementation pub mod bot; +/// Modules contains common utilities +pub mod common; + /// Module contains the core type defenitions for sandwiching pub mod types;