From c835231830979279594e789707cf0a04d3239c59 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Fri, 11 Oct 2024 12:13:11 -0600 Subject: [PATCH] gracefully fallback when etherscan api response changes --- Cargo.lock | 1 - hotshot-state-prover/Cargo.toml | 1 - hotshot-state-prover/src/service.rs | 64 +++++++++++++++++++++-------- marketplace-builder/Cargo.toml | 3 ++ 4 files changed, 50 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fea8a7dda6..b5e51e9203 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4447,7 +4447,6 @@ dependencies = [ "reqwest 0.12.8", "sequencer-utils", "serde", - "serde_json", "surf-disco", "tide-disco", "time 0.3.36", diff --git a/hotshot-state-prover/Cargo.toml b/hotshot-state-prover/Cargo.toml index b0e908e982..1d74d2549c 100644 --- a/hotshot-state-prover/Cargo.toml +++ b/hotshot-state-prover/Cargo.toml @@ -34,7 +34,6 @@ jf-utils = { workspace = true } reqwest = { workspace = true } sequencer-utils = { path = "../utils" } serde = { workspace = true } -serde_json = { workspace = true } surf-disco = { workspace = true } tide-disco = { workspace = true } time = { workspace = true } diff --git a/hotshot-state-prover/src/service.rs b/hotshot-state-prover/src/service.rs index 8684e35048..3faebe3c61 100644 --- a/hotshot-state-prover/src/service.rs +++ b/hotshot-state-prover/src/service.rs @@ -303,6 +303,30 @@ pub async fn read_contract_state( Ok((state.into(), st_state.into())) } +/// Relevant fields in the etherscan price oracle feed, +/// used for parsing their JSON responses. +/// See +#[allow(dead_code)] +#[derive(Deserialize, Debug, Clone)] +struct EtherscanPriceOracleResponse { + status: String, + message: String, + result: EtherscanPriceOracleResult, +} +/// The `result` field in `EtherscanPriceOracleResponse` +#[allow(dead_code)] +#[derive(Deserialize, Debug, Clone)] +struct EtherscanPriceOracleResult { + #[serde(rename = "suggestBaseFee")] + base_fee: String, + #[serde(rename = "SafeGasPrice")] + safe_max_fee: String, + #[serde(rename = "ProposeGasPrice")] + propose_max_fee: String, + #[serde(rename = "FastGasPrice")] + fast_max_fee: String, +} + /// submit the latest finalized state along with a proof to the L1 LightClient contract pub async fn submit_state_and_proof( proof: Proof, @@ -318,29 +342,35 @@ pub async fn submit_state_and_proof( let new_state: ParsedLightClientState = public_input.into(); let mut tx = contract.new_finalized_state(new_state.into(), proof.into()); + + // TODO: (alex) centralize this to a dedicated ethtxmanager with gas control // frugal gas price: set to SafeGasPrice based on live price oracle // safe to be included with low priority position in a block. // ignore this if etherscan fail to return if let Ok(res) = reqwest::get("https://api.etherscan.io/api?module=gastracker&action=gasoracle").await { - let gas_info = res.json::().await?; - let safe_gas: U256 = parse_units( - gas_info["result"]["SafeGasPrice"] - .as_str() - .expect("fail to parse SafeGasPrice"), - "gwei", - ) - .unwrap() // safe unwrap, etherscan will return right value - .into(); - - if let TypedTransaction::Eip1559(inner) = &mut tx.tx { - inner.max_fee_per_gas = Some(safe_gas); - tracing::info!( - "Gas oracle info: {}, setting maxFeePerGas to: {}", - gas_info, - safe_gas, - ); + // parse etherscan response, + // if etherscan API changes, we log the warning and fallback to default (by falling through) + if let Ok(res) = res.json::().await { + if let TypedTransaction::Eip1559(inner) = &mut tx.tx { + // both safe unwraps below assuming correct etherscan stream + let safe_max_fee: U256 = parse_units(res.result.safe_max_fee.clone(), "gwei") + .unwrap() + .into(); + let base_fee: U256 = parse_units(res.result.base_fee.clone(), "gwei") + .unwrap() + .into(); + inner.max_fee_per_gas = Some(safe_max_fee); + inner.max_priority_fee_per_gas = Some(safe_max_fee - base_fee); + tracing::info!( + "Gas oracle info: {:?}, setting maxFeePerGas to: {}", + res.result, + safe_max_fee, + ); + } + } else { + tracing::warn!("!! Etherscan Price Oracle API changed !!") } } diff --git a/marketplace-builder/Cargo.toml b/marketplace-builder/Cargo.toml index ef4268bea7..9fd7f193c6 100644 --- a/marketplace-builder/Cargo.toml +++ b/marketplace-builder/Cargo.toml @@ -45,4 +45,7 @@ url = { workspace = true } vbs = { workspace = true } [dev-dependencies] +hotshot-query-service = { workspace = true } sequencer = { path = "../sequencer", features = ["testing"] } +sequencer-utils = { path = "../utils", features = ["testing"] } +tempfile = { workspace = true }