Motivation
The StorageDurationMultiplier FIP proposes increasing the maximum sector commitment length from 1.5 to 5 years. The naive way to achieve this goal is to increase the MaxSectorDuration
parameter from 1.5 to 5 years. This parameter tweak seems very simple, but it has an unaccounted externality of causing mitigation of possible PoRep bug to be much more difficult.
What follows is an implementation proposal allowing for a significant reduction in the effort required for future mitigation, while causing only a slight increase in complexity.
Proposal
The core of the proposal is to separate the period of validity of a proof from the period of commitment for a sector. This leaves the 1.5-year sector extension process in place to maintain proof validity, but allows SPs to commit to longer periods.
The existing sector Expiration
property would be renamed to CommitmentExpiration
with a duration range from MinSectorLifetime
to MaxSectorLifetime
.
A new sector property is introduced called ProofExpiration
. The initial value of ProofExpiration
always falls into the range of (CurrentEpoch + MaxProofDuration - ProofRefereshWindow, CurrentEpoch + MaximumProofDuration]
or CommitmentExpiration
whichever is smaller.
MaxProofDuration
: maximum period from last commitment or refresh for which a PoRep is valid, set to 1.5y to match current behaviourProofRefreshWindow
: a window of time before ProofExpiration when the proof can be extended, set to 0.5y
The proof refresh window creates a trade-off: the larger the window, the more refreshes can happen in a singular batch, but more frequently each proof must be refreshed.
For example with MaxProofDuration
of 1.5y and ProofRefreshWindow
of 0.5y, each extension will be at least 1y and at most 1.5y. SPs will have to refresh sectors every MaxProofDuration - ProofRefereshWindow
epochs.
The proof expiration is not freely chosen by the SP, but takes a value that is derived and quantised from the sector’s activation epoch. It is calculated as:
Current Epoch | Current Proof Expiration | New Proof Expiration | New Proof Duration |
0 - Sector Activation | NaN | 1.5y | 1.5y |
1.0000y - Refresh | 1.5y | 2.5y | 1.5y |
1.4999y - Refresh | 1.5y | 2.5y | 1y |
1.6y - Refresh does nothing | 2.5y | 2.5y | 0.9y |
2.0000y - Refresh | 2.5y | 3.5y | 1.5y |
2.4999y - Refresh | 2.5y | 3.5y | 1y |
At initial commitment, it should calculate MaxProofDuration
, then the refresh has to be made every year. We can play with longer durations or shorter refresh windows, but shorter refresh window doesn’t buy us much.
Storage Provider can at any point call RefreshProofEpiration(SectorSelector)
requesting a refreshed proof expiration. This call only results in an actual refresh of the ProofExpiration
if called within ProofRefereshWindow
of the ProofExpiration
.
This call will refresh the ProofExpiration
of each of the requested sectors to fall into (CurrentEpoch + MaxProofDuration - ProofRefereshWindow, CurrentEpoch + MaximumProofDuration]
according to the above formula or CommitmentExpiration
whichever is smaller.
In case of a PoRep bug, the RefreshProofExpiration
method would be disallowed for sectors created with insecure PoRep.
Other policies are possible too, such as requiring re-sealing or some other computation. The mechanism can support other policies developed in response to a concrete security flaw.
It also has the following benefits:
- The bug response upgrade does not need to iterate over all sectors within one epoch. The mechanism to iterate over all sectors exists in form of an expiration schedule.
- Sectors’ ProofExpirations are spread out uniformly (according to onboarding) and are not possible to manipulate on a short timescale, which could be an issue otherwise leading to non-even distribution and terminations of sectors.
- Storage Providers must take action to avoid early sector termination when a Bug Response Policy is implemented, instead of the network having to create a new mechanism to enforce the Bug Response Policy.
Limitations of this mechanism include:
- The response period must be specified now but can be modified at cost of some additional complexity in future.
- Relative to the naive approach of just increasing the maximum sector duration, this mechanism requires more SP operational costs and on-chain activity. But only a little less than the amount required today to extend sectors. (Less because we won’t recompute pledge, etc).
- Relative to the naive approach, this mechanism introduces operational risk to SPs, who will pay a termination fee for failing to refresh expiring proofs. Since the sector duration multiplier proposal greatly increases rewards for long commitments, this operational cost might be considered just part of the risk taken in pursuit of those rewards. On the other hand, SPs are given a generous window of time to refresh their sectors.
Implementation
It should be possible to avoid changing the sector state as there are only three valid ProofExpiration
values for a given active sector:
SectorActivation + ΔE * ceil((CurrentEpoch - SectorActivation + 1) / ΔE) - ΔE + ProofRefereshWindow
(1)SectorActivation + ΔE * ceil((CurrentEpoch - SectorActivation + 1) / ΔE) + ProofRefereshWindow
(2)CommitmentExpiration
if it is smaller than either of the above (3)
Currently, sectors are scheduled for expiration in the ExpirationSet
at the epoch of Expiration
(calledCommitmentExpiration
in this document). All future extensions and new sectors should be scheduled at the ProofExpiration
epoch.
To check when a given sector is scheduled for expiration, the ExpirationSet
would have to be checked at most two points out of the candidate ProofExpiration
values.
On the other hand, when refreshing the sector’s expiration two operations have to be performed:
- removal of old expiration: always at (1), if not present at epoch (1), then the sector cannot be refreshed
- scheduling of new expiration: at (2) or (3), whichever is smaller
Accelerated Expiration Set
If in case of a significant PoRep bug, proofs had to be updated sooner than the 1.5y timeline, it should be possible to accelerate the ExpirationSet
.
Today the epoch number within the expiration set has the same definition as the chain epoch. A mapping function could be introduced to the ExpirationSet
, such that the schedule is accelerated.
For example, if the mapping function , is changed to where is the upgrade epoch and is the acceleration factor, and expirations are processed within the range at epoch . If for example is used, the expiration set will be integrated at twice the normal rate, resulting in maximum proof expiration of 0.75y. If a new expiration is to be scheduled, it should also use the updated function.