Vulnerability: ChainlinkAggregator: binary search for roundId does not work correctly and Oracle can even end up temporarily DOSed
Severity: medium

Description:
When a phase switchover occurs, it can be necessary that phases need to be searched for a `roundId` with a timestamp as close as possible but bigger than `targetTimestamp`.\\nFinding the `roundId` with the closest possible timestamp is necessary according to the sponsor to minimize the delay of position changes:\\n\\nThe binary search algorithm is not able to find this best `roundId` which thereby causes unintended position changes.\\nAlso it can occur that the `ChainlinkAggregator` library is unable to find a valid `roundId` at all (as opposed to only not finding the "best").\\nThis would cause the Oracle to be temporarily DOSed until there are more valid rounds.\\nLet's say in a phase there's only one valid round (roundId=1) and the timestamp for this round is greater than `targetTimestamp`\\nWe would expect the `roundId` that the binary search finds to be `roundId=1`.\\nThe binary search loop is executed with `minRoundId=1` and `maxRoundId=1001`.\\nAll the above conditions can easily occur in reality, they represent the basic scenario under which this algorithm executes.\\n`minRoundId` and `maxRoundId` change like this in the iterations of the loop:\\n```\\nminRoundId=1\\nmaxRoundId=1001\\n\\n-> \\n\\nminRoundId=1\\nmaxRoundId=501\\n\\n-> \\n\\nminRoundId=1\\nmaxRoundId=251\\n\\n-> \\n\\nminRoundId=1\\nmaxRoundId=126\\n\\n-> \\n\\nminRoundId=1\\nmaxRoundId=63\\n\\n-> \\n\\nminRoundId=1\\nmaxRoundId=32\\n\\n-> \\n\\nminRoundId=1\\nmaxRoundId=16\\n\\n-> \\n\\nminRoundId=1\\nmaxRoundId=8\\n\\n-> \\n\\nminRoundId=1\\nmaxRoundId=4\\n\\n-> \\n\\nminRoundId=1\\nmaxRoundId=2\\n\\nNow the loop terminates because\\nminRoundId + 1 !< maxRoundId\\n```\\n\\nSince we assumed that `roundId=2` is invalid, the function returns `0` (maxTimestamp=type(uint256).max):\\nIn the case that `latestRound.roundId` is equal to the `roundId=1` (i.e. same phase and same round id which could not be found) there would be no other valid rounds that the `ChainlinkAggregator` can find which causes a temporary DOS.

Impact:
As explained above this would result in sub-optimal and unintended position changes in the best case. In the worst-case the Oracle can be temporarily DOSed, unable to find a valid `roundId`.\\nThis means that users cannot interact with the perennial protocol because the Oracle cannot be synced. So they cannot close losing trades which is a loss of funds.

Recommended mitigation:
I recommend to add a check if `minRoundId` is a valid solution for the binary search. If it is, `minRoundId` should be used to return the result instead of maxRoundId:\\n```\\n         // If the found timestamp is not greater than target timestamp or no max was found, then the desired round does\\n         // not exist in this phase\\n// Remove the line below\\n        if (maxTimestamp <= targetTimestamp || maxTimestamp == type(uint256).max) return 0;\\n// Add the line below\\n        if ((minTimestamp <= targetTimestamp || minTimestamp == type(uint256).max) && (maxTimestamp <= targetTimestamp || maxTimestamp == type(uint256).max)) return 0;\\n \\n// Add the line below\\n        if (minTimestamp > targetTimestamp) {\\n// Add the line below\\n            return _aggregatorRoundIdToProxyRoundId(phaseId, uint80(minRoundId));\\n// Add the line below\\n        }\\n         return _aggregatorRoundIdToProxyRoundId(phaseId, uint80(maxRoundId));\\n     }\\n```\\n\\nAfter applying the changes, the binary search only returns `0` if both `minRoundId` and `maxRoundId` are not a valid result.\\nIf this line is passed we know that either of both is valid and we can use `minRoundId` if it is the better result.