Skip to content

solana-autopilot: ask native price sources by stage like the EVM autopilot - #5112

Merged
squadgazzz merged 3 commits into
mainfrom
solana-autopilot/be-430-parallel-driver-probes
Oct 19, 2026
Merged

squadgazzz merged 3 commits into
mainfrom
solana-autopilot/be-430-parallel-driver-probes

Conversation

@squadgazzz

@squadgazzz squadgazzz commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Description

A native price lookup asks its sources the way the EVM autopilot does: by configured stage, a stage at once, until a token has results-required prices, and the best of them wins.

The sources were asked one after another, so a lookup cost the sum of every driver's probe (a /quote selling 0.01 wSOL into the token), and a slow driver held every quote on that token once #5068 forwards orderbook lookups to the autopilot under a 5s budget.

Stages come from config in the EVM [native-price-estimation] shape, estimators = [[{ type = "CoinGecko" }], [{ type = "Driver", name, url }]], with CoinGecko's url and key in [native-prices.coin-gecko]. A lookup starts as many stages as could reach results-required (default 2, as on EVM), drops the sources still in flight once every asked token has that many prices, and asks later stages only for the tokens still short.

Config and image ship together: cowprotocol/infrastructure#7288.

Changes

  • [native-prices] estimators lists stages, and results-required stops a lookup early
  • fetch_into_cache polls a stage on FuturesUnordered and drops it once every token has enough prices

How to test

New unit tests.

Related issues

BE-430

@linear-code

linear-code Bot commented Oct 16, 2026

Copy link
Copy Markdown

BE-430

@squadgazzz squadgazzz changed the title solana-autopilot: ask the driver price probes together solana-autopilot: ask native price sources by stage like the EVM autopilot Oct 16, 2026
@squadgazzz
squadgazzz marked this pull request as ready for review October 16, 2026 13:10
@squadgazzz
squadgazzz requested a review from a team as a code owner October 16, 2026 13:10
@claude

claude Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Claude finished @squadgazzz's task in 3m 44s —— View job


PR Review: staged native price sources

I traced the new staged fetch_into_cache loop against the EVM-style semantics described in the PR, checked the config plumbing, and read through the new tests.

Verdict: This looks solid and well-tested. I did not find a correctness bug worth a change request, so there are no inline comments. Summary of what I checked below.

Logic (prices.rs::fetch_into_cache)

  • Termination / no infinite loop: ✅ The outer loop is bounded by next_stage < stages.len(), and the inner stage-launcher always advances next_stage at least once per outer iteration (missing ≥ 1 since asked is non-empty and each asked token is !enough, so answers.len() = 0 < missing on entry). Progress is guaranteed even when results_required exceeds the number of sources — it degrades to "ask everyone, cache the best found".
  • No underflow: ✅ self.results_required - priced(&found, token) is safe because asked only retains tokens where priced < results_required.
  • Best-price accumulation: ✅ or_insert((price, 0)) then *best = (*best).min(price); *count += 1 correctly yields count = number of sources that priced the token and the min price, including the first insert.
  • Early-drop cancellation: ✅ Breaking the drain loop on asked.iter().all(enough) drops the in-flight FuturesUnordered, which cancels the pending reqwest requests — matching the comment and the a_lookup_stops_at_the_required_prices test.
  • Failure accounting: ✅ The fail-closed check (failures > 0 && failures == total sources) only fires when every configured source was actually asked and failed; a lookup that stops early can't reach it. Negative caching still only happens when failures == 0, preserving the "a failed source might know it, so retry next cut" behavior from main.
  • Partial pricing: ✅ A token reached by only one source (count < results_required) is still cached with its found price in the final loop, so single-source tokens aren't dropped.

Config (config.rs) & example.toml

  • estimators: Vec<Vec<...>> + results_required: NonZero<usize> (default 2) mirror the EVM [native-price-estimation] shape. NonZero rules out a zero that would make enough trivially true. new() filters empty stages and treats all-empty as Denominated. Example TOML, doc comments, and the loads_the_example_config test are all consistent.

Behavior note (not a defect — already implied by the PR)

With the shipped example (two single-source stages, results-required = 2), every token now always queries both CoinGecko and the driver on every (re)fetch — nothing is ever dropped, since 2 prices require 2 sources. This is the intended "ask together, best wins" design; operators wanting strict fallback would set results-required = 1. Flagging only so it's a conscious choice for driver load.

⚠️ I was unable to run cargo test -p autopilot-svm / clippy — cargo is blocked in this review sandbox. The new tests read correctly (timing assertions, atom-math, stop-early counts all check out by inspection), but please rely on CI for the actual pass.
· solana-autopilot/be-430-parallel-driver-probes

@squadgazzz
squadgazzz requested a review from tilacog October 16, 2026 14:01
@squadgazzz squadgazzz added the hotfix Labels PRs that should be applied into production right away label Oct 19, 2026
@squadgazzz squadgazzz removed the hotfix Labels PRs that should be applied into production right away label Oct 19, 2026
@squadgazzz
squadgazzz added this pull request to the merge queue Oct 19, 2026
Merged via the queue into main with commit bb723f5 Oct 19, 2026
25 checks passed
@squadgazzz
squadgazzz deleted the solana-autopilot/be-430-parallel-driver-probes branch October 19, 2026 14:05
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 19, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants