Skip to content

apollo_l1_gas_price,apollo_l1_gas_price_types: hold Chainlink query failures for the retry interval - #14992

Draft
asaf-sw wants to merge 1 commit into
asaf/l1-oracle-a9a-client-lifecyclefrom
asaf/l1-oracle-a9b-negative-caching
Draft

apollo_l1_gas_price,apollo_l1_gas_price_types: hold Chainlink query failures for the retry interval#14992
asaf-sw wants to merge 1 commit into
asaf/l1-oracle-a9a-client-lifecyclefrom
asaf/l1-oracle-a9b-negative-caching

Conversation

@asaf-sw

@asaf-sw asaf-sw commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Stacked on #14991. Part of the L1 price oracle replacement split of #14942.

What

Negative caching for the Chainlink client: a failed query's error is held in OracleState::last_error and served to callers with nothing better, and the next query is spawned once failure_retry_interval_seconds elapses instead of on every call.

Why hold a failure

Without it, every fetch_rate against a failing feed spawns a fresh query: two view calls per feed per attempt, on every proposal, for as long as the feed stays broken. A hostile or broken feed would otherwise cost blocking VM executions per block. Holding the failure bounds the retry cadence to one query per retry interval, which is also why the interval is its own config key rather than the sampling interval: a transient failure costs one retry interval, not the rest of the sampling interval.

The precedence rule

A held failure is served only when no valid read is held. Bugbot's first review of #14942 caught an availability regression in exactly this spot: the one call that observed a failing query finish was returned that failure directly, without consulting the rate the client already held. no_call_is_denied_a_rate_the_client_holds is the regression test, asserting every call through the failure's harvest is served the held rate; a_held_failure_does_not_mask_the_last_valid_rate pins the steady state after the failure is held.

A success clears last_error, so the client never reports a failure older than its newest read.

Landing state

Testing

4 new tests (82 total). A failing feed is queried once per retry interval, with the batcher call counter flat across ten calls inside the interval; the retry fires exactly at the interval and not one second earlier; a held failure does not mask the last valid rate, including on the very call that harvests the failure.

🤖 Generated with Claude Code

@reviewable-StarkWare

Copy link
Copy Markdown

This change is Reviewable

asaf-sw commented Aug 18, 2026

Copy link
Copy Markdown
Contributor Author

@asaf-sw
asaf-sw force-pushed the asaf/l1-oracle-a9a-client-lifecycle branch from 09068b0 to a47b43d Compare August 18, 2026 20:57
@asaf-sw
asaf-sw force-pushed the asaf/l1-oracle-a9b-negative-caching branch from c50e226 to c2af008 Compare August 18, 2026 20:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants