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
The way oracle provider switch works is the following:\\n`Oracle.update()` is called to set a new provider. This is only allowed if there is no other provider switch pending.\\nThere is a brief transition period, when both the previous provider and a new provider are active. This is to ensure that all the requests made to the previous oracle are commited before switching to a new provider. This is handled by the `Oracle._handleLatest()` function, in particular the switch to a new provider occurs only when `Oracle.latestStale()` returns true. The lines of interest to us are:\\n```\\n        uint256 latestTimestamp = global.latest == 0 ? 0 : oracles[global.latest].provider.latest().timestamp;\\n        if (uint256(oracles[global.latest].timestamp) > latestTimestamp) return false;\\n```\\n\\n`latestTimestamp` - is the timestamp of last commited price for the previous provider `oracles[global.latest].timestamp` is the timestamp of the last requested price for the previous provider The switch doesn't occur, until last commited price is equal to or after the last request timestamp for the previous provider. 3. The functions to `commit` the price are in PythOracle: `commitRequested` and `commit`. 3.1. `commitRequested` requires publish timestamp of the pyth price to be within MIN_VALID_TIME_AFTER_VERSION..MAX_VALID_TIME_AFTER_VERSION from request time. It is possible that pyth price with signature in this time period is not available for different reasons (pyth price feed is down, keeper was down during this period and didn't collect price and signature):\\n```\\n        uint256 versionToCommit = versionList[versionIndex];\\n        PythStructs.Price memory pythPrice = _validateAndGetPrice(versionToCommit, updateData);\\n```\\n\\n`versionList` is an array of oracle request timestamps. And `_validateAndGetPrice()` filters the price within the interval specified (if it is not in the interval, it will revert):\\n```\\n        return pyth.parsePriceFeedUpdates{value: pyth.getUpdateFee(updateDataList)}(\\n            updateDataList,\\n            idList,\\n            SafeCast.toUint64(oracleVersion + MIN_VALID_TIME_AFTER_VERSION),\\n            SafeCast.toUint64(oracleVersion + MAX_VALID_TIME_AFTER_VERSION)\\n        )[0].price;\\n```\\n\\n3.2. `commit` can not be done with timestamp older than the first oracle request timestamp: if any oracle request is still active, it will simply redirect to commitRequested:\\n```\\n        if (versionList.length > nextVersionIndexToCommit && oracleVersion >= versionList[nextVersionIndexToCommit]) {\\n            commitRequested(nextVersionIndexToCommit, updateData);\\n            return;\\n        }\\n```\\n\\nAll new oracle requests are directed to a new provider, this means that previous provider can not receive any new requests (which allows to finalize it):\\n```\\n    function request(address account) external onlyAuthorized {\\n        (OracleVersion memory latestVersion, uint256 currentTimestamp) = oracles[global.current].provider.status();\\n\\n        oracles[global.current].provider.request(account);\\n        oracles[global.current].timestamp = uint96(currentTimestamp);\\n        _updateLatest(latestVersion);\\n    }\\n```\\n\\nSo the following scenario is possible: timestamp=69: oracle price is commited for timestamp=50 timestamp=70: user requests to open position (Oracle.request() is made) timestamp=80: owner calls `Oracle.update()` timestamp=81: pyth price signing service goes offline (or keeper goes offline) ... timestamp=120: signing service goes online again. timestamp=121: another user requests to open position (Oracle.request() is made, directed to new provider) timestamp=200: new provider's price is commited (commitRequested is called with timestamp=121)\\nAt this time, `Oracle.latest()` will return price at timestamp=50. It will ignore new provider's latest commit, because previous provider last request (timestamp=70) is still not commited. Any new price requests and commits to a new provider will be ignored, but the previous provider can not be commited due to absence of prices in the valid time range. It is also not possible to change oracle for the market, because there is no such function. It is also impossible to cancel provider update and impossible to change the provider back to previous one, as all of these will revert.\\nIt is still possible for the owner to manually whitelist some address to call `request()` for the previous provider. However, this situation provides even worse result. While the latest version for the previous provider will now be later than the last request, so it will let the oracle switch to new provider, however `oracle.status()` will briefly return invalid oracle version, because it will return oracle version at the timestamp = last request before the provider switch, which will be invalid (the new request will be after that timestamp):\\nThis can be abused by some user who can backrun the previous provider oracle commit (or commit himself) and use the invalid oracle returned by `status()` (oracle version with price = 0). Market doesn't expect the oracle status to return invalid price (it is expected to be always valid), so it will use this invalid price as if it's a normal price = 0, which will totally break the market:\\nSo if the oracle provider switch becomes stuck, there is no way out and the market will become stale, not allowing any user to withdraw the funds.
There are multiple possible ways to fix this. For example, allow to finalize previous provider if the latest `commit` from the new provider is newer than the latest `commit` from the previous provider by `GRACE_PERIOD` seconds. Or allow PythOracle to `commit` directly (instead of via commitRequested) if the `commit` oracleVersion is newer than the last request by `GRACE_PERIOD` seconds.
Issue 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\\nSwitching oracle provider can make the oracle stuck and stop updating new prices. This will mean the market will become stale and will revert on all requests from user, disallowing to withdraw funds, bricking the contract entirely.
```\\n        uint256 latestTimestamp = global.latest == 0 ? 0 : oracles[global.latest].provider.latest().timestamp;\\n        if (uint256(oracles[global.latest].timestamp) > latestTimestamp) return false;\\n```\\n