lidofinance / core

Lido DAO smart contracts
https://lido.fi
GNU General Public License v3.0
382 stars 193 forks source link

Hash consensus: allow updating a future initial epoch #662

Closed skozin closed 1 year ago

skozin commented 1 year ago

Allows updating the initial epoch of a HashConsensus instance while the current initial epoch is still in the future. This simplifies the protocol upgrade process by allowing to pre-deploy the consensus contract before the exact time of the protocol upgrade is known.

arwer13 commented 1 year ago

Thank you!

We also have another problem: error InitialEpochIsYetToArrive() at AccountingOracle.initialize. Because BaseOracle._initialize calls _setConsensusContract which checks refSlot < lastProcessingRefSlot where refSlot is taken from IConsensusContract(addr).getCurrentFrame() which calls _computeFrameIndex which requires epoch >= config.initialEpoch what is false at the moment of AccountingOracle initialization.

arwer13 commented 1 year ago

I also not sure if it is a good idea to check on AccountingOracle migration strictly initialEpoch == legacyProcessedEpoch + epochsPerFram. There might be multiple scenarios when its wrong. For example (the day counts are approx):

  1. Aragon Voting started at hardfork-4days. EVMScript has updateInitialEpoch(hardfork +1d)
  2. For any reason at hardfork-1d LidoOracle committee didn't report
  3. Voting passed, it's time to enact because the hardfork is comming
  4. Enactment reverts due to the check initialEpoch == legacyProcessedEpoch + epochsPerFram

UPD: or we know we want the AccountingOracle be operable at frame after the next after hardfork. But in the case we might want to parametrize the check

skozin commented 1 year ago

@arwer13 See the latest commit with the fix for the revert you've mentioned.

As for the initial epoch check, the assumed process of deployment is the following:

  1. HashConsensus, AccountingOracle impl, and accounting oracle's proxy are deployed before the upgrade voting is started. The initial epoch of HashConsensus is far in the future, thus the consensus is guaranteed to be inoperable.
  2. The upgrade vote is started.
  3. The upgrade vote is passed.
  4. As part of the upgrade vote execution, the migrator contract performs the following:
    • Calculates the new oracle's initial epoch as the last legacy oracle's epoch plus the frame size. The new oracle's initial epoch might be in the past if more time than the frame length passed since the last legacy oracle's report.
    • Updates the initial epoch of HashConsensus to the calculated value by calling updateInitialEpoch.
    • Disables the legacy oracle by upgrading it to the compat impl.
    • Initializes accounting oracle's proxy, passing the HashConsensus address.

Thus, if the initial epoch is calculated correctly in the migrator contract, the check should pass regardless of the vote timing.