From d6dfcbd2d71ee1be09ac30dce6bf66cbc4e1d280 Mon Sep 17 00:00:00 2001 From: Bryan Stitt Date: Thu, 22 Dec 2022 11:49:34 -0800 Subject: [PATCH] add wait_for_sync helper --- Dockerfile | 5 +- web3_proxy/src/bin/wait_for_sync.rs | 135 ++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+), 3 deletions(-) create mode 100644 web3_proxy/src/bin/wait_for_sync.rs diff --git a/Dockerfile b/Dockerfile index 7eb2d8bb..02bfdfa0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,12 +8,11 @@ COPY . . RUN --mount=type=cache,target=/usr/local/cargo/registry \ --mount=type=cache,target=/usr/src/web3_proxy/target \ cargo test &&\ - cargo install --locked --path ./web3_proxy + cargo install --locked --root /opt/bin --path ./web3_proxy FROM debian:bullseye-slim -COPY --from=builder /usr/local/cargo/bin/web3_proxy /usr/local/bin/web3_proxy -COPY --from=builder /usr/local/cargo/bin/web3_proxy_cli /usr/local/bin/web3_proxy_cli +COPY --from=builder /opt/bin/* /usr/local/bin/ ENTRYPOINT ["web3_proxy"] # TODO: lower log level when done with prototyping diff --git a/web3_proxy/src/bin/wait_for_sync.rs b/web3_proxy/src/bin/wait_for_sync.rs new file mode 100644 index 00000000..a214d67b --- /dev/null +++ b/web3_proxy/src/bin/wait_for_sync.rs @@ -0,0 +1,135 @@ +// TODO: websockets instead of http + +use anyhow::Context; +use argh::FromArgs; +use chrono::Utc; +use ethers::types::{Block, TxHash}; +use log::info; +use log::warn; +use reqwest::Client; +use serde::Deserialize; +use serde_json::json; +use tokio::time::sleep; +use tokio::time::Duration; + +#[derive(Debug, FromArgs)] +/// Command line interface for admins to interact with web3_proxy +pub struct CliConfig { + /// the RPC to check + #[argh(option, default = "\"http://localhost:8545\".to_string()")] + pub check_url: String, + + /// the RPC to compare to + #[argh(option, default = "\"https://eth.llamarpc.com\".to_string()")] + pub compare_url: String, +} + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + // if RUST_LOG isn't set, configure a default + if std::env::var("RUST_LOG").is_err() { + std::env::set_var("RUST_LOG", "wait_for_sync=debug"); + } + + env_logger::init(); + + // this probably won't matter for us in docker, but better safe than sorry + fdlimit::raise_fd_limit(); + + let cli_config: CliConfig = argh::from_env(); + + let json_request = json!({ + "id": "1", + "jsonrpc": "2.0", + "method": "eth_getBlockByNumber", + "params": [ + "latest", + false, + ], + }); + + let client = reqwest::Client::new(); + + // TODO: make sure the chain ids match + // TODO: automatic compare_url based on the chain id + + loop { + match main_loop(&cli_config, &client, &json_request).await { + Ok(()) => break, + Err(err) => { + warn!("{:?}", err); + sleep(Duration::from_secs(10)).await; + } + } + } + + Ok(()) +} + +#[derive(Deserialize)] +struct JsonRpcBlockResult { + result: Block, +} + +async fn main_loop( + cli_config: &CliConfig, + client: &Client, + json_request: &serde_json::Value, +) -> anyhow::Result<()> { + let check_result = client + .post(&cli_config.check_url) + .json(json_request) + .send() + .await + .context("querying check block")? + .json::() + .await + .context("parsing check block")?; + + let compare_result = client + .post(&cli_config.compare_url) + .json(json_request) + .send() + .await + .context("querying compare block")? + .json::() + .await + .context("parsing compare block")?; + + let check_block = check_result.result; + let compare_block = compare_result.result; + + let check_number = check_block.number.context("no check block number")?; + let compare_number = compare_block.number.context("no compare block number")?; + + if check_number < compare_number { + let diff_number = compare_number - check_number; + + let diff_time = compare_block.timestamp - check_block.timestamp; + + return Err(anyhow::anyhow!( + "behind by {} blocks ({} < {}). behind by {} seconds", + diff_number, + check_number, + compare_number, + diff_time, + )); + } + + // TODO: check more. like that the hashes are on the same chain + + let check_time = check_block.time().context("parsing check time")?; + + let now = Utc::now(); + + let ago = now.signed_duration_since(check_time); + + info!( + "Synced on block {} @ {} ({} seconds old)", + check_number, + check_time.to_rfc3339(), + ago.num_seconds() + ); + + Ok(()) +}