[M] DOS in LibChainlinkOracle when not considering phaseId
`LibChainlinkOracle` is not fully compatible with Chainlink's data model due to the lack of support for `phaseId and aggregatorRoundId`. Chainlink's `roundID` is a composite number combining a `phaseID and an aggregatorRoundID`.\\nThe `phaseID` changes whenever there is an upgrade to the underlying aggregator, and this change causes a significant jump in the `roundID` values due to the bit-shifting operation described in the documentation.\\nref here: https://docs.chain.link/data-feeds/historical-data#solidity\\nThe Beanstalk `LibChainlinkOracle` misinterprets the progression of `roundID` as sequential, overlooking Chainlink's unique bundling of `phaseId` and `aggregatorRoundId`. With the advancement of `phaseID`, there's an exponential increase in `roundID` by 2^64, leading to a temporal suspension until a new interval commences. This will instigate a denial-of-service scenario. The `getEthUsdTwap and getEthUsdPrice` functions are particularly susceptible to this vulnerability, as they rely on accurate TWAP values for their computations, which effects for example any calls reliant on Oracle data.\\n```\\nfunction getRoundData(uint80 _roundId)\\n    public\\n    view\\n    virtual\\n    override\\n    returns (\\n      uint80 roundId,\\n      int256 answer,\\n      uint256 startedAt,\\n      uint256 updatedAt,\\n      uint80 answeredInRound\\n    )\\n  {\\n    (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId);\\n\\n    (\\n      uint80 roundId,\\n      int256 answer,\\n      uint256 startedAt,\\n      uint256 updatedAt,\\n      uint80 ansIn\\n    ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId);\\n\\n    return addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId);\\n  }\\n```\\n\\n```\\n function latestRoundData()\\n    public\\n    view\\n    virtual\\n    override\\n    returns (\\n      uint80 roundId,\\n      int256 answer,\\n      uint256 startedAt,\\n      uint256 updatedAt,\\n      uint80 answeredInRound\\n    )\\n  {\\n    Phase memory current = currentPhase; // cache storage reads\\n\\n    (\\n      uint80 roundId,\\n      int256 answer,\\n      uint256 startedAt,\\n      uint256 updatedAt,\\n      uint80 ansIn\\n    ) = current.aggregator.latestRoundData();\\n\\n    return addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, current.id);\\n  }\\n```\\n\\nhttps://etherscan.io/address/0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419#code\\nThe code segment extracted from the ETH/USD Chainlink aggregator above highlights the composite structure of `roundId`, integrating both `phaseId` and aggregatorRoundId. As highlighted, an increment in `phaseId` leads to a substantial leap in `roundId by 2^64`, thereby bypassing a number of "rounds." Consequently, any attempt to query currentRound - 1 post-upgrade encounters a non-existent round, triggering a revert. This condition could persist up to 24 hours based on configuration, impacting the timely execution of getEthUsdTwap and getEthUsdPrice.\\nThese functions, once operational again, might utilize altered TWAP values for computations, diverging from expected outcomes
Check return values of roundId. If the `roundID` is a nonzero value and is reverting then the oracle needs to try again with a lower `phaseId.`
If a `phaseID` increment occurs, it results in a jump in ``````roundID values, creating a gap in the sequence. When there are attempts to access round data for `roundIDs` within this gap, it will encounter inaccurate rounds, potentially causing the function to fail or return incorrect data, considering when the `phaseID` is incremented the `roundID increases by 2 ** 64.` This discrepancy can lead to a denial-of-servicein any calls to the oracle.
```\\nfunction getRoundData(uint80 _roundId)\\n    public\\n    view\\n    virtual\\n    override\\n    returns (\\n      uint80 roundId,\\n      int256 answer,\\n      uint256 startedAt,\\n      uint256 updatedAt,\\n      uint80 answeredInRound\\n    )\\n  {\\n    (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId);\\n\\n    (\\n      uint80 roundId,\\n      int256 answer,\\n      uint256 startedAt,\\n      uint256 updatedAt,\\n      uint80 ansIn\\n    ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId);\\n\\n    return addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId);\\n  }\\n```\\n