# During oracle provider switch, if it is impossible to commit the last request of previous provider, then the oracle will get stuck (no price updates) without any possibility to fix it

Perennial oracle provider switch can deadlock when the previous provider's last request can never be committed, freezing price updates and bricking the market.

- Payout: Contest reward
- Severity: medium
- Program: Perennial
- Credited: panprog
- Disclosed: 2023-07-17
- Write-up quality: 7/10
- Original: https://github.com/sherlock-audit/2023-07-perennial-judging/issues/46
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-07-perennial%3AM-3
- Tags: domain:web3 impact:dos impact:funds-loss kind:contest platform:sherlock sev:medium tech:solidity technique:source-review vuln:business-logic vuln:dos vuln:oracle-manipulation

**Target:** Oracle provider switch logic in Oracle.sol / PythOracle
**Root cause:** Oracle._handleLatest only switches to the new provider once the previous provider's last requested timestamp is committed, but PythOracle.commitRequested requires a Pyth price within a bounded window of the request time; if that price/signature is unavailable, the last request can never be committed and the switch never completes.
**Steps:**
1. At t=70 user calls `Oracle.request()` on provider A (timestamp 70 recorded).
2. Owner calls `Oracle.update()` at t=80 to switch to provider B.
3. Pyth signing service/keepers offline t=81..120, so no valid price for timestamp 70 within MIN/MAX_VALID_TIME_AFTER_VERSION.
4. At t=121 new request goes to provider B; at t=200 `commitRequested` commits B's price.
5. `Oracle.latest()` still returns provider A's price at t=50 because `oracles[global.latest].timestamp (70) > latestTimestamp (50)`, so switch never occurs.
6. `commitRequested` for A reverts (no valid Pyth price in window); no cancel/switch-back function exists; market reverts on all user actions.
**How found:** Code reading of Oracle._handleLatest switch condition combined with PythOracle.commitRequested's bounded timestamp validation; reasoned that the last request timestamp could fall outside any available Pyth price window, making the final commit impossible.
**Exploitation:** Not attacker-triggered directly; requires natural unavailability of Pyth signatures/keepers during the transition window. Owner workaround (whitelisting an address to call request() on old provider) causes `status()` to briefly return an invalid oracle version (price 0), which a user can backrun to make Market.sol consume price=0 and break the market.
**Escalation:** Owner whitelisting a caller to push a new request on the old provider lets the switch proceed but exposes an invalid zero-price oracle version that a backrunner can exploit against Market.sol.
**Insight:** When a state machine gates a transition on 'last item committed', check whether the commit path has time-bounded validation that can make that last item permanently uncommittable; also check whether any cancel/rollback path exists.
