Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FIP-0045 updates removing opt-in migration #455

Merged
merged 2 commits into from
Sep 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
183 changes: 92 additions & 91 deletions FIPS/fip-0045.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,9 @@ requires: FIP-0034
---

TODO:
- Re-spec ExtendClaimTerms as a token receiver hook value rather than explicit method
- Spec methods for sector migration on miner, market, and verifreg actors
- Spec change to SectorOnChainInfo to distinguish migrated sectors
- Figure out best migration plan for pending deals, pre-committed sectors
- Confirm policy for built-in market actor's default term maximum
- Spec token receiver hook payload schema for allocation requests
- Spec token receiver hook payload for extending allocations with new datacap
- Market method for fetching allocation/claim ids for deals (needed?)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the potential use case here?

- Spec hook/method for a different client extending the claim by spending DataCap (needed?).


## Simple Summary
Expand Down Expand Up @@ -83,7 +79,7 @@ and is much simpler than the Filecoin Plus premium proposal that also attempted
- *Claim*: a provider's assertion they are storing all or part of an allocation
- *Term*: period of time for which a DataCap allocation or claim is valid or active.

### Data cap allocations
### Verified Registry DataCap allocations

The Filecoin Plus verified registry actor is extended to record allocations of DataCap to specific
pieces of data to be stored by a provider. An allocation is independent of any deal with the
Expand Down Expand Up @@ -114,14 +110,18 @@ struct Allocation {
```

An allocation specifies a range of terms for which the provider may commit the data, between some
minimum and maximum. An allocation's maximum term must be at least as large as its minimum term.

minimum and maximum.
An allocation's maximum term must be at least as large as its minimum term.
Due to the implementation of term enforcement (details below), clients should leave a large buffer
between the minimum and maximum term to make the allocation practical for a provider.

Network policy limits the maximum value for an allocation's expiration,
so that an allocation cannot occupy non-useful DataCap indefinitely.

**Parameters**
- The minimum allowed value for `TermMinimum` is 6 months.
- The maximum allowed value for `TermMaximum` is 5 years (can be increased by a future FIP).
- `MinimumVerifiedAllocationTerm`: The minimum allowed value for `TermMinimum` is 6 months.
- `MaximumVerifiedAllocationTerm`: The maximum allowed value for `TermMaximum` is 5 years (can be increased by a future FIP).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `MaximumVerifiedAllocationTerm`: The maximum allowed value for `TermMaximum` is 5 years (can be increased by a future FIP).
- `MaximumVerifiedAllocationTerm`: The maximum allowed value for `TermMaximum` is 5 years (5 years is the current sector max lifetime, both may be increased by a future FIP).

- `MaximumVerifiedAllocationExpiration`: The maximum difference between `Expiration` and the epoch at which an allocation is created is 60 days.
Copy link

@misilva73 misilva73 Sep 9, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why 60 days? Is this the current expiration term for DataCap?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I chose 60 days as a reasonable balance between flexibility for providers scheduling deal-making, and the value being effective at reducing squatting. I'm very open to adjusting this value – please make a comment in the discussion thread if you would propose an alternative.

There's no current expiration, but it's worth introducing here because the changes make it practically a bit easier to squat on datacap (possible today, but more involved).

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have any specific value in mind. I was trying to understand the reasoning for the 60 days. It sounds reasonable to me as well.


Allocations are stored in the verified registry actor's state, grouped by client address.
Nesting by client promotes more efficient lookups at scale,
Expand All @@ -135,18 +135,19 @@ struct State {
Allocations: HAMT[Address]HAMT[AllocationID]Allocation

// Sequence number for allocation IDs.
// The value `0` is reserved for "no allocation"
NextAllocationId: AllocationID // uint64
}
```

#### Operations

#### Creation of allocations
An allocation is created by a verified client by transferring DataCap tokens (see below)
to the verified registry.
The `Allocation` metadata must be provided as transfer metadata.
The verified registry checks the same preconditions as the existing `UseBytes` method.
The size of the allocation must match the number of tokens received.

#### Removal of expired allocations
An allocation may be removed after its expiration epoch has passed (by anyone).

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we allowing expired allocations to be removed "by anyone"? What is the expected behavior here? Should clients remove them or are we supposed to have an automated process doing it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no reason to restrict it to the client address specifically, so this gives flexibility to users. E.g. if a client is a multisig or DAO or other complex entity, they don't need to go to the cost and trouble of multisigning this inconsequential message – one of the parties/delegates/employees can just do it.

There's no "should" or automation. Clients can clean up when the gas savings associated with a smaller collection justify it.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it. This makes sense.

When removed, the DataCap tokens are transferred back to the client.
The verified registry provides a new method to process removals, replacing `RestoreBytes`.
Expand All @@ -165,12 +166,12 @@ fn RemoveExpiredAllocations(params: RemoveExpiredAllocationsParams)

Allocations are also removed when claimed by a provider (see below).

The `RemoveVerifiedClientDataCap` method invokes a privileged method of the DataCap token actor
to burn DataCap tokens held on a client's balance.
#### Revocation of un-allocated data cap
The existing `RemoveVerifiedClientDataCap` method is changed to invoke a
privileged method of the DataCap token actor to burn DataCap tokens held on a client's balance.
Only the verified registry actor is permitted to invoke this method.

### Data cap claims

### Verified Registry DataCap claims
The verified registry actor is further extended to record each storage provider's commitment to a
DataCap allocation, called a claim. A claim represents a provider's obligation to store a piece of
data, and corresponding benefit of incentivized storage power.
Expand Down Expand Up @@ -208,7 +209,7 @@ struct State {
}
```

#### Operations
#### Creation of claims from allocations
An allocation is claimed when a storage miner actor proves the corresponding piece of data
is committed to a sector.
Upon converting an allocation to a claim, the verified registry actor burns the associated
Expand Down Expand Up @@ -245,7 +246,8 @@ struct SectorClaimResult {
fn ClaimAllocations(params: ClaimAllocationsParams) -> ClaimAllocationsResult
```

The record of a claim may be removed by the provider after the term maximum has elapsed.
#### Removal of expired claims
The record of a claim may be removed after the term maximum has elapsed.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Who can remove expired claims? Is this an automated process?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Iiuc, Anyone can remove the expired claims and it’s triggered by an onchain message.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to above, anyone can. In practise this will probably be some ancillary or operations account associated with a provider. There's no automation.


```
struct RemoveExpiredClaimsParams {
Expand All @@ -258,24 +260,14 @@ struct RemoveExpiredClaimsParams {
fn RemoveExpiredClaims(params: RemoveExpiredClaimsParams)
```


The maximum term for a claim may be increased by the client which originally made the allocation,
up to the network policy maximum.

A verified client can extend the term for a claim _beyond_ the initial maximum term by
spending new DataCap.
The term maximum can be extended up to the network policy maximum beyond the current epoch.
The client extending the claim need not be the one that made the original allocation.
This is similar to issuing a new allocation/claim for the same data,
but avoids overheads of re-sealing.

TODO: rework this to be a token receiver hook rather than explicit method
#### Extension of claim term by client
A client of a claim may increase its maximum term up to `MaximumVerifiedAllocationTerm`.

```
struct ClaimTerm {
Provider: Address // needed to find claim in state
ClaimID: ClaimID
TermMaximum: int64 // duration in epochs
TermMaximum: int64 // new duration in epochs from TermStart
}
struct ExtendClaimTermsParams{
Claims: []ClaimTerm
Expand All @@ -290,10 +282,21 @@ struct ExtendClaimTermsResult {
// Called by allocation client to extend the maximum term of their allocations,
// without consuming DataCap.
// The new TermMaximum must be no less than the current one,
// and no greater than the maximum initial term.
// and no greater than MaximumVerifiedAllocationTerm.
fn ExtendClaimTerms(params: ExtendClaimTermsParams) -> ExtendClaimTermsResult
```

#### Renewal of claim term by spending datacap
A verified client can extend the term for a claim _beyond_ the initial maximum term by
spending new DataCap.
The claim's term maximum can be extended up to `MaximumVerifiedAllocationTerm` beyond the current epoch.
The client extending the claim need not be the one that made the original allocation.
This is similar to issuing a new allocation/claim for the same data,
but avoids overheads of re-sealing.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This mechanism makes a lot of sense. There is no reason to re-seal the same data just because one needs to spend new DataCap.


TODO: spec token receiver hook for extending


### Data cap token
The `VerifiedClients` map of addreses to balances is removed from the verified registry state.
The balances of DataCap tokens held by verified clients are extracted to a DataCap token actor.
Expand Down Expand Up @@ -324,42 +327,45 @@ Parties will continue to interact with the built-in market actor and verified re
The built-in account and multisig actors are changed to implement a receiver hook method, as specified by FRC-0046.
This hook always succeeds, without inspecting the payload.

#### Operations
The `AddVerifiedClient` method is changed to invoke the DataCap token actor to
#### Changes to datacap operations
The verified registry's `AddVerifiedClient` method is changed to invoke the DataCap token actor to
mint new tokens to the client's balance.

The `UseBytes` method is removed.
The verified registry's `UseBytes` method is removed.
To create an allocation, a verified client transfers DataCap tokens to the verified registry actor.
The transfer must be accompanied by one or more `Allocation` records which specify
the allocation(s) to create.
The registry may reject the transfer if the allocations are invalid.

The `RestoreBytes` method is also removed.
The verified registry's `RestoreBytes` method is also removed.
Instead, the `RevokeAllocations` method on the verified registry actor transfers any released
DataCap tokens back to the client's balance for re-use.

### Simplified quality-adjusted power
A DataCap allocation/claim is valid for a range of commitment terms, between a client-specified
minimum and maximum, so long as the allocation is claimed before the allocation expires.

The actual term for a claim begins at the epoch the data is committed into a sector,
proven either with proof-of-replication or replica-update.
There is no distinct "deal start epoch".
A sector containing a DataCap claim is immediately eligible for a power multiplier of 10
for that fraction of the sector's capacity occupied by the incentivized data
The actual term for a claim ends the epoch that the sector containing the data expires,
or that data is replaced.

A sector's `DealWeight` and `VerifiedDealWeight` are calculated as simple sums of the sizes
of the deals, with no multiplication by duration.
The miner actor computes a sector’s power as `SectorSize + (9 * VerifedDealWeight)`.

A sector containing a DataCap claim is thus immediately eligible for a power multiplier of 10
for that fraction of the sector's capacity occupied by `VerifiedDealWeight`
(subject to the existing requirement to initially prove the sector in Window PoSt).

The actual term for a claim ends the epoch that the sector containing the data expires,
or that data is replaced.
The term cannot end during a sector's lifetime, except by explicit replacement of data.
If data is replaced, the sector immediately loses the power multiplier for that fraction
of the sector's capacity.
A claim term cannot end during a sector's lifetime, except by explicit replacement of data.
If data is replaced, the sector's verified deal weight is reduced and it immediately
loses the power multiplier for that fraction of the sector's capacity.
(Replacing non-zero data in a sector is not possible today).

Aligning the claim's term with the sector's expiration exactly in this way removes the
"spreading-out" of QA power over a sector's life in the current method of computation.
Providers gain 10x power for each byte of verified data exactly while that data is proven.
The miner actor computes a sector’s power as `SectorSize + (9 * VerifiedSize)`.

#### Pledge
A sector's pledge requirement is proportional to its share of power, but never decreases, just as today.
Expand All @@ -375,7 +381,28 @@ The pledge requirement for the old sector is not decreased,
but any subsequent penalty is calculated using its current (i.e. reduced) power.

### Storage miner actor
The built-in miner actor is trusted to enforce the verified and the continual storage of the data.
#### Differentiated sectors
A new field `SimpleQAPower: bool` is added to `SectorOnChainInfo`.
During the migration activating this proposal, `SimpleQAPower` is set for each sector:
- `true` if the sector has `VerifiedDealWeight = 0` and `DealWeight = 0`,
- `false` otherwise

All sectors committed after this proposal is activated take `SimpleQAPower = true`.
The value of `SimpleQAPower` never changes for an individual sector.

A sector with `SimpleQAPower = true` has its deal weights calculated as simple sums of deal size,
and QA power calculated according to the simple method described above, with no spreading out effect.

A sector with `SimpleQAPower = false` continues to use the existing QA-power calculation.
Such a sector cannot claim any allocations.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is likely to result in increased expirations, with "old" sectors being replaced by new sectors that can take allocations.

In addition, CC sectors can take advantage of this new way to package deals, while sectors with data have to wait for their deals to end.

Could we have a mechanism to turn sectors with SimpleQAPower = false into sectors with SimpleQAPower = true? For instance, if I have a 1-year sector with an old 1-year deal, there's no reason why I shouldn't be able to pack new deals into it, using the new logic and QAP calculation.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is impossible to change the data in a non-CC sector today anyway (there is no "re-snap"), so there are no sectors to which this would apply. It will be easier to implement re-snapping after this change, though, but by the time we do this will be an even smaller issue.

There are reasons not to do this. Perhaps for a narrow case of sectors where all the deals have already expired there would be fewer unwanted effects, but still this would cause a slight power loss for the SP, so is unlikely a major flow.

I agree that, for a capacity-constrained SP, a CC sector is more valuable than a sector with expired deals at the end of its life, due to the option of taking deals into it. But that's already the case today.

Such a sector may be extended, but, as today, this will result in its power being diluted
to "spread out" the verified reward over the sector's new commitment duration.

The `SimpleQAPower` field will become redundant and may be removed by a network upgrade once
all sectors with the value `false` have expired.

#### Term enforcement
The built-in miner actor enforces the term and the continual storage of the data.

The miner actor requires that the sector into which a claimed piece is committed must have a
**remaining lifespan that is sufficient to fulfil the minimum term**.
Expand All @@ -395,16 +422,9 @@ There is **no change to termination penalty** calculations.
If a sector is terminated early (continual faults, or manual termination),
the provider will pay a penalty related to the expected reward earned by the sector (up to some limit).

The verified registry can support re-commitment of the same data in a new sector
(even though the built-in storage market actor does not support resumption of a terminated deal).
If a claim’s maximum term has not been reached when a sector terminates,
the provider may commit the same piece into a new sector and regain the quality-adjusted power.
The new sector’s committed lifespan is still constrained to fit within the claim’s term.
The miner actor must ensure that the old sector is no longer alive.

#### Sector extension
A sector's scheduled commitment term cannot be extended beyond the maximum term of any
verified claim attributed to it.
claim attributed to it.
Thus, to extend a sector, a provider must simultaneously drop any verified claims with
terms that would be exceeded by the extended commitment.
Dropping a verified claim reduces the sector's power accordingly, as well as
Expand Down Expand Up @@ -480,7 +500,7 @@ The built-in market specifies an allocation's minimum term to be equal to the de
and maximum term to be some amount greater than the deal duration.

**Parameters**
- The built-in market calculates a term maximum of 1 year greater than a deal's specified duration.
- `MarketDefaultMaximumAllocationTerm`: The built-in market calculates a term maximum of 90 days greater than a deal's specified duration.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why 90 days?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not? This value was chosen as a compromise between flexibility for SP deal packing, and reasonably requesting the client's nominated term. The discussion thread for this is #313 (comment)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trying to understand the reasoning. I don't have any arguments against the 90 days.


```
let dealAllocation = Allocation {
Expand All @@ -489,12 +509,16 @@ let dealAllocation = Allocation {
Data: deal.PieceCID
Size: deal.PieceSize
TermMinimum: deal.EndEpoch - deal.StartEpoch
TermMaximum: deal.EndEpoch - deal.StartEpoch + EPOCHS_IN_YEAR
Expiration: deal.StartEpoch
TermMaximum: deal.EndEpoch - deal.StartEpoch + MarketDefaultMaximumAllocationTerm
Expiration: min(deal.StartEpoch, CURRENT_EPOCH + MaximumVerifiedAllocationExpiration)
AllowRanges: false
}
```

The market will accept verified deals with a `StartEpoch` beyond the maximum allowed allocation `Expiration`.
If such a deal is not activated before the allocation expires, it will not confer QA power.
However, the deal may still be activated and sector commitment should proceed (without QA power).

The market stores allocation IDs for not-yet-activated deals in a new mapping,
and the claim ID for activated deals in deal state.

Expand Down Expand Up @@ -526,43 +550,20 @@ The miner actor then invokes `ClaimAllocations` and, if successful,
computes quality adjusted power for the sector according to the piece size and QA power multiplier.

### Migration
#### Network upgrade
A network state migration is required to implement this proposal.

That migration must:
- Implement the new verified registry state schema for allocations and claims.
- Implement the new verified registry state schema for allocations and claims,
and set `NextAllocationId = 1`.
- Migrate the verified registry client balances map to DataCap token balances,
with appropriate unit conversion.
- Add a new field to SectorOnChainInfo identifying whether its quality-adjusted power is calculated
according to the old spread-out method, or the new direct method
- TODO: handle pending deals: either create allocations or keep not-yet-proven sectors in the old world.

#### Opt-in per-sector
The power for existing sectors is not changed by this proposal.

A provider may opt in to migrate a sector to the new QA power calculation method by invoking a new method.
Each active deal is converted to a claim as if an allocation had been created when the deal was made.
The claim's minimum term is the deal's duration, and maximum term is the greater of either
the sector's current expiration epoch, or 540 days beyond the current epoch
(since the provider could extend the sector to such lifetime prior to migrating).

Expired deals cannot be migrated, even though the old QA power calculation method has spread out
their power and reward over the sector's full lifetime.
This will generally result in an increase in power for a sector,
but may result in a decrease in case of expired deals.
This is why the migration is opt-in.

A new method on the storage miner actor:
- Fetches information about each not-yet-expired verified deal from the market
- Calls the verified registry to create a claim for each such deal.
- Re-calculates power according to the amount of space committed to active claims.
- Re-caclulates pledge requirement according to the new power and network conditions (but never decreases)

After migration, the client can extend the migrated claims' terms up to the network policy maximum.
After claims are extended, the provider can extend the sector commitment duration to match.
Note that a migrated sector cannot be extended unless the claim terms are extended,
lest it violate a claim's maximum term.

TODO: specify migration method and changes to SectorOnChainInfo
- Add a new field `SimpleQAPower` to each `SectorOnChainInfo`,
taking the value `DealWeight == 0 && VerifiedDealWeight == 0`
- Add the pending allocation mapping to market state, and claim ID field to deal states (all `0`)
- For each pending (not yet activated) deal with `Verified = true`, create an Allocation
- The maximum term for such allocations is 540 days, in order to support any possible sector duration
- The expiration for such allocations is set to `MaximumVerifiedAllocationExpiration` after the migration epoch,
which may be before the deal's start date.

## Design Rationale
The design rationale is mostly provided by the proposal's motivation.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,5 +83,5 @@ This improvement protocol helps achieve that objective for all members of the Fi
|[0041](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0041.md) | Forward Compatibility for PreCommit and ReplicaUpdate | FIP |@Kubuxu |Draft |
|[0042](https://github.com/filecoin-project/FIPs/blob/master/FRCs/frc-0042.md) | Calling Convention for Hashed Method Name | FRC |@Kubuxu, @anorth |Draft |
|[0044](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0044.md) | Standard Authentication Method for Actors | FIP |@arajasek, @anorth |Draft |
|[0045](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0045.md) | De-couple verified registry from markets | FIP |@anorth |Draft |
|[0045](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0045.md) | De-couple verified registry from markets | FIP |@anorth, @zenground0 |Draft |
|[0046](https://github.com/filecoin-project/FIPs/blob/master/FRCs/frc-0046.md) | Fungible token standard | FRC |@anorth, @jsuresh, @alexytsu |Draft |