Skip to content

fix: cache payment-side token prices and add oracle HTTP timeouts#529

Merged
dev-jodee merged 7 commits into
solana-foundation:mainfrom
raushan728:fix/oracle-timeouts-batch-payment-mints
Jun 11, 2026
Merged

fix: cache payment-side token prices and add oracle HTTP timeouts#529
dev-jodee merged 7 commits into
solana-foundation:mainfrom
raushan728:fix/oracle-timeouts-batch-payment-mints

Conversation

@raushan728

@raushan728 raushan728 commented May 22, 2026

Copy link
Copy Markdown
Contributor

Added 5s connect and 10s read timeouts to the Jupiter oracle reqwest client via named Duration constants so retry logic can actually fire on hanging requests. Hanging server helper and HangingOracle extracted to oracle_mock.rs.

Refactored calculate_payment_lamport_totals to batch fetch prices via CacheUtil::get_or_fetch_token_prices and decimals once per unique mint instead of per transfer matching calculate_spl_transfers_value_in_lamports. Extracted repeated lamport math into calculate_token_value_in_lamports_from_price and updated calculate_token_value_in_lamports to use it.

Closes #519

@greptile-apps

greptile-apps Bot commented May 22, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR addresses two issues from #519: it adds 5 s connect and 10 s read timeouts to the RetryingPriceOracle reqwest client via named constants, and it refactors calculate_payment_lamport_totals to batch-fetch prices and decimals once per unique mint rather than once per transfer, matching the existing calculate_spl_transfers_value_in_lamports pattern.

  • Oracle timeouts: ORACLE_CONNECT_TIMEOUT / ORACLE_REQUEST_TIMEOUT constants are wired into Client::builder() inside RetryingPriceOracle::new; a new spawn_hanging_server / HangingOracle integration test in oracle_mock.rs verifies the timeout fires within 15 s.
  • Batch price fetching: calculate_payment_lamport_totals now collects payment_mints in a HashSet, calls CacheUtil::get_or_fetch_token_prices once for all mints, fetches decimals once per mint, then processes valid_transfers in a second pass; shared lamport math is extracted to calculate_token_value_in_lamports_from_price.
  • Test plumbing: oracle_mock.rs is registered as a #[cfg(test)] module and get_price_oracle is now conditionally imported from it in cache.rs, so test builds inject TestOracleProxy (backed by a thread_local! TEST_ORACLE) without touching the production path.

Confidence Score: 5/5

Safe to merge; production logic is correct and the refactoring is consistent with the existing batch-fetch pattern in calculate_spl_transfers_value_in_lamports.

The production changes are straightforward: named timeout constants wired into the reqwest client, and a two-pass batching refactor that mirrors the already-proven pattern in calculate_spl_transfers_value_in_lamports. The only findings are in test code — a silently discarded initialize() result that would surface as a confusing test failure rather than a silent pass, and a hanging-server helper that is fragile if max_retries were ever raised. Neither affects production behaviour.

No production files require special attention; the minor issues are confined to test helpers in token.rs and oracle_mock.rs.

Important Files Changed

Filename Overview
crates/lib/src/token/token.rs Refactors calculate_payment_lamport_totals to batch price/decimals fetches per unique mint; extracts shared lamport math into calculate_token_value_in_lamports_from_price. One test uses let _ = …initialize() which silently discards an error result.
crates/lib/src/oracle/oracle.rs Adds named ORACLE_CONNECT_TIMEOUT (5 s) and ORACLE_REQUEST_TIMEOUT (10 s) constants and wires them into the reqwest Client built inside RetryingPriceOracle::new; adds timeout integration test using HangingOracle.
crates/lib/src/tests/oracle_mock.rs New test-only module: TestOracleProxy with thread-local injection, HangingOracle for timeout testing, and spawn_hanging_server helper. The server thread accepts one connection then sleeps 30 s; safe with max_retries=1 but fragile if retry count grows.
crates/lib/src/cache.rs Splits get_price_oracle import under #[cfg(not(test))] / #[cfg(test)] so oracle_mock::get_price_oracle is used in test builds; no logic changes to cache behaviour.
crates/lib/src/tests/mod.rs Registers the new oracle_mock module under #[cfg(test)].

Sequence Diagram

sequenceDiagram
    participant Caller
    participant TokenUtil
    participant CacheUtil
    participant Oracle as RetryingPriceOracle
    participant RPC

    Caller->>TokenUtil: calculate_payment_lamport_totals(config, tx, rpc, owner)
    Note over TokenUtil: First pass — collect payment_mints & valid_transfers
    TokenUtil->>TokenUtil: resolve accounts, filter inflow/outflow
    TokenUtil->>TokenUtil: collect unique mints into payment_mints HashSet

    TokenUtil->>CacheUtil: get_or_fetch_token_prices(rpc, config, mint_addresses)
    CacheUtil->>Oracle: get_token_prices(mint_addresses) [batched, once]
    Oracle-->>CacheUtil: "HashMap<mint, TokenPrice>"
    CacheUtil-->>TokenUtil: "HashMap<mint, TokenPrice>"

    alt "max_price_staleness_slots > 0"
        TokenUtil->>RPC: get_slot()
        RPC-->>TokenUtil: current_slot
    end
    TokenUtil->>TokenUtil: check_price_staleness for each price

    loop per unique mint
        TokenUtil->>RPC: get_mint_decimals(mint)
        RPC-->>TokenUtil: decimals
    end

    Note over TokenUtil: Second pass — compute lamports per transfer
    loop per valid_transfer
        TokenUtil->>TokenUtil: calculate_token_value_in_lamports_from_price(amount, price, decimals)
        TokenUtil->>TokenUtil: totals.checked_add_assign(inflow, outflow)
    end
    TokenUtil-->>Caller: PaymentLamportTotals
Loading

Reviews (6): Last reviewed commit: "fix: make TestOracleProxy fallback consi..." | Re-trigger Greptile

Comment thread crates/lib/src/oracle/oracle.rs Outdated
Comment thread crates/lib/src/oracle/oracle.rs
@raushan728 raushan728 force-pushed the fix/oracle-timeouts-batch-payment-mints branch from b7a3d8e to 761da69 Compare May 22, 2026 11:57
@github-actions

Copy link
Copy Markdown

This PR has been inactive for 7 days and has been marked as stale. It will be closed in 5 days if there is no further activity.

@github-actions github-actions Bot added the stale label May 30, 2026
@raushan728

Copy link
Copy Markdown
Contributor Author

Ping! Just keeping this PR active.

@github-actions github-actions Bot removed the stale label Jun 2, 2026
Comment thread crates/lib/src/oracle/oracle.rs Outdated
Comment thread crates/lib/src/token/token.rs Outdated
Comment thread crates/lib/src/token/token.rs Outdated
Comment thread crates/lib/src/token/token.rs Outdated
Comment thread crates/lib/src/token/token.rs Outdated
Comment thread crates/lib/src/oracle/oracle.rs Outdated
@raushan728 raushan728 force-pushed the fix/oracle-timeouts-batch-payment-mints branch from 761da69 to 7bd02af Compare June 5, 2026 10:01
@raushan728 raushan728 force-pushed the fix/oracle-timeouts-batch-payment-mints branch from 7bd02af to 1364b7f Compare June 5, 2026 10:50
@raushan728 raushan728 requested a review from dev-jodee June 5, 2026 11:03

@dev-jodee dev-jodee left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some other changes to do, also can you not rebase / force push your changes and just commit on top of whats already there? Makes it easier to review just the diff from last reviewed commit. Thanks !

Comment thread crates/lib/src/oracle/oracle.rs Outdated
Comment thread crates/lib/src/oracle/oracle.rs Outdated
Comment thread crates/lib/src/oracle/oracle.rs
Comment thread crates/lib/src/token/token.rs
Comment thread crates/lib/src/token/token.rs Outdated
@raushan728

Copy link
Copy Markdown
Contributor Author

Some other changes to do, also can you not rebase / force push your changes and just commit on top of whats already there? Makes it easier to review just the diff from last reviewed commit. Thanks !

I thought rebasing was the normal flow for keeping a PR up to date, so that's why I did it. Anyway, noted for future Kora contributions.

@raushan728 raushan728 requested a review from dev-jodee June 6, 2026 06:14
@github-actions

Copy link
Copy Markdown

✅ Fork external live tests passed.

fork-external-live-pass:b85c8cd8823908e1edb4f46d28fac90b6459432f
run: https://github.com/solana-foundation/kora/actions/runs/27353281065

@dev-jodee dev-jodee merged commit d471051 into solana-foundation:main Jun 11, 2026
16 of 17 checks passed
@raushan728 raushan728 deleted the fix/oracle-timeouts-batch-payment-mints branch June 12, 2026 12:40
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.

Cache payment-side token prices/decimals and add oracle timeouts

2 participants