Skip to content

api: fix empty request_id in trace spans (#790), .env.example token fallback (#811), coinbase prod-URL test coverage (#706), single source of truth for price scale (#709) - #857

Merged
abayomicornelius merged 1 commit into
SO4-Markets:mainfrom
thefadah:so4-790-811-706-709
Aug 28, 2026

Conversation

@thefadah

Copy link
Copy Markdown
Contributor

#790 — trace spans always had an empty request_id

On a Router, .layer(a).layer(b) makes the last layer outermost — it sees the request first. So SetRequestIdLayer (added after trace_layer) ran after it, and trace_layer's make_span_with read request.extensions().get::<RequestId>() while it was still None → every span got request_id = "", defeating the request-id-in-logs feature from #657. middleware_integration.rs::test_request_id_and_completion_logs didn't catch it because it only checks the response header (produced by PropagateRequestIdLayer, which works regardless).

Fix: SetRequestIdLayer is now added last (outermost), so it populates the extension before trace_layer reads it:

.layer(PropagateRequestIdLayer::x_request_id())
.layer(trace_layer)
.layer(SetRequestIdLayer::x_request_id(MakeRequestUuid))
.layer(from_fn_with_state(state, track_metrics))

trace_span_carries_the_request_id_not_an_empty_string drives a request with an explicit x-request-id through the real router with a capturing subscriber and asserts that id appears in the span's structured output (and that "request_id":"" does not).

#811.env.example produced a zero-token oracle

PRICE_FEED_CONFIG=[] is a present value that parses to zero configured tokens — it never triggers the include_str!("../../config/tokens.json") fallback, which only fires when the var is entirely unset. Following the example verbatim gave a service that starts cleanly but never fetches a price (GET /prices always 503). The line is now left unset with a comment spelling out the difference and a populated override example.

#706 — coinbase's production request-building branch had zero coverage

fetch_spot_price_with_url picks use_query from a substring check of base_url. The real COINBASE_EXCHANGE_RATES_URL (.../v2/exchange-rates?currency=) always takes use_query = true (the reqwest .query() path). Every existing wiremock test builds base_url as "{uri}/" — neither substring — so all of them exercise the use_query = false format!-concatenation branch that production never runs. Added fetch_spot_price_production_url_shape_uses_query_param_branch: a wiremock test in the real URL shape with a query_param("currency", "BTC") matcher, asserting the currency arrives as a query parameter.

#709 — the "30-decimal scale" invariant was four ungoverned magic numbers

binance.rs and pyth.rs each hardcoded 30 / 10^30 independently (two FLOAT_PRECISION copies, let scale_digits = 30usize, -30..=0, 30 + exponent) with no shared source. Introduced crate::SCALE_DIGITS: u32 = 30 and a derived crate::FLOAT_PRECISION = 10i128.pow(SCALE_DIGITS). binance::FLOAT_PRECISION / pyth::FLOAT_PRECISION are now pub use re-exports (callers unchanged), and every scale/exponent bound is derived from SCALE_DIGITS.

Incidental

oracle/src/price_loop.rs: a pre-existing broken lib unit test (build_cached_price gained a 5th param pyth_batch_failed: bool but fixed_source_builds_signed_cached_price still passed 4 args) made cargo test / cargo clippy --all-targets fail to compile on main. One-arg fix included.

Verification

cargo check -p oracle --lib --tests and cargo clippy -p oracle --lib --tests are clean locally.

Closes #790
Closes #811
Closes #706
Closes #709

…ple token fallback (SO4-Markets#811); coinbase prod-URL test coverage (SO4-Markets#706); single source of truth for price scale (SO4-Markets#709)

- SO4-Markets#790: on a Router, the last .layer() added is outermost / runs first, so
  SetRequestIdLayer (added after trace_layer) ran too late — trace_layer's
  make_span_with read the RequestId extension before it was set and every
  span got request_id = "". Swapped the two so SetRequestIdLayer is
  outermost. Test asserts the span carries the real id.

- SO4-Markets#811: .env.example set PRICE_FEED_CONFIG=[] — a present, empty value that
  configures zero tokens (GET /prices always 503s), never the include_str!
  fallback which only fires when the var is unset. Left it unset with a
  comment explaining the difference and a populated override example.

- SO4-Markets#706: every coinbase HTTP test built base_url as "{uri}/", exercising only
  the use_query=false branch; production's ".../exchange-rates?currency="
  shape always takes use_query=true (the reqwest .query() path), which had
  zero coverage. Added a wiremock test in that shape with a query_param
  matcher.

- SO4-Markets#709: the "prices are scaled to 30 decimals" invariant was four
  disconnected literals across binance.rs and pyth.rs (two FLOAT_PRECISION
  copies, two bare 30s). Introduced crate::SCALE_DIGITS (and a derived
  crate::FLOAT_PRECISION); binance/pyth now re-export FLOAT_PRECISION and
  derive their scale/exponent bounds from SCALE_DIGITS.

Also fixes a pre-existing broken lib unit test in price_loop.rs
(build_cached_price gained a 5th arg) so cargo test / clippy --all-targets
compile again.

Verified locally: cargo check --lib --tests and cargo clippy --lib --tests
are clean.
@drips-wave

drips-wave Bot commented Aug 28, 2026

Copy link
Copy Markdown

@thefadah Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment