diff --git a/CHANGELOG.md b/CHANGELOG.md index 75a97f2..3872559 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,29 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.1.1] - 2025-11-04 + +### Fixed + +- Added randomized exponential backoff when fetching the latest block fails, preventing tight RPC retry loops and improving recovery. + +## [0.1.0] - 2025-10-09 + +### Added + +- Documented Gas Network scoring in `EVALUATION.md` and linked the reference from the README. +- Added a canonical signing round-trip test to enforce the v1 payload schema. + +### Changed + +- Breaking: Adopted the latest signing spec — agent payloads now include `schema_version`, hash canonical JSON, encode `price` as a wei-denominated decimal string via `PriceUnit`, and drop the legacy `kind` / `FeeUnit` fields. +- Updated publishing and oracle conversion to emit wei strings from agents and safely parse them when building `OraclePayloadV2` records. +- Refreshed tooling: Docker builds now use `cargo-chef`, CI caching switches to `Swatinem/rust-cache`, and dependencies bump (`tracing-subscriber` 0.3.20, `slab` 0.4.11) with `alloy` serde support enabled. + +### Removed + +- Dropped the Homebrew installer target from `cargo-dist` configuration. + ## [0.0.9] - 2025-01-22 ### Added diff --git a/Cargo.lock b/Cargo.lock index bf002de..05aaebf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1528,7 +1528,7 @@ dependencies = [ [[package]] name = "gas-agent" -version = "0.1.0" +version = "0.1.1" dependencies = [ "alloy", "anyhow", diff --git a/Cargo.toml b/Cargo.toml index 3df87ab..f8dc0e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "gas-agent" -version = "0.1.0" +version = "0.1.1" edition = "2021" description = "Blocknative Gas Agent - Generate real-time gas price estimates for the Gas Network" homepage = "https://gas.network" diff --git a/src/agent.rs b/src/agent.rs index 6127459..458e6cd 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -7,6 +7,7 @@ use crate::rpc::{get_latest_block, get_rpc_client, Block, BlockHeader, RpcClient use crate::types::{AgentKind, AgentPayload, PriceUnit, Settlement, SystemNetworkKey}; use anyhow::{Context, Result}; use chrono::Utc; +use rand::Rng; use reqwest::Url; use std::sync::Arc; use std::time::Duration; @@ -14,6 +15,8 @@ use tokio::sync::RwLock; use tracing::{debug, error, info, warn}; const MAX_NUM_BLOCK_DISTRIBUTIONS: usize = 50; +const ERROR_RETRY_BASE_BACKOFF_MS: u64 = 250; +const ERROR_RETRY_MAX_BACKOFF_MS: u64 = 5_000; pub async fn start_agents(chain_config: ChainConfig, config: &Config) -> Result<()> { let agents = GasAgent::new(chain_config, config).await?; @@ -253,10 +256,15 @@ impl GasAgent { tokio::time::sleep(wait).await; let mut get_new_block = true; + // Track exponential backoff across consecutive RPC failures + let mut backoff_ms: u64 = ERROR_RETRY_BASE_BACKOFF_MS; + let max_backoff_ms: u64 = ERROR_RETRY_MAX_BACKOFF_MS; while get_new_block { match get_latest_block(&self.rpc_client).await { Ok(block) => { + // Reset backoff state after a successful RPC response + backoff_ms = ERROR_RETRY_BASE_BACKOFF_MS; debug!( "Block for System: {}, Network: {}, Height {}", &self.chain_config.system, &self.chain_config.network, block.number @@ -286,7 +294,16 @@ impl GasAgent { } } Err(e) => { - error!(error = %e, "Failed to get latest block"); + let cap = backoff_ms.min(max_backoff_ms); + let floor = ERROR_RETRY_BASE_BACKOFF_MS.min(cap); + let sleep_ms: u64 = rand::rng().random_range(floor..=cap); + error!( + error = ?e, + retry_ms = sleep_ms, + "Failed to get latest block; retrying" + ); + tokio::time::sleep(Duration::from_millis(sleep_ms)).await; + backoff_ms = backoff_ms.saturating_mul(2).min(max_backoff_ms); } } }