Alexander Wade
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # Actor Spec: StorageMarket [Back to Master Tracking Doc](https://hackmd.io/LOZjAsz-THelSD5lWqSVlw) ## Contents [TOC] ## At a Glance The StorageMarket actor manages the relationship between Miners and their Clients. This relationship revolves around DealProposals, in which a Miner agrees to store a specific piece of the Client's data for a period of time and at a specified price. The StorageMarket actor: * Manages Miner and Client collateral held on behalf of their deals. * Allows a Miner to publish signed DealProposals, at which point the Miner becomes responsible for the Client's data (as well as the terms of the deal). * A Client signs a DealProposal to signal their agreement to its terms * A Miner's publication of these signed DealProposals signals the Miner's agreement to its terms * Tracks important information about published DealProposals for use at various points during the Miner's Storage Mining Cycle. **Actor Type:** - Singleton - Address: 5 **Exported Methods:** 1. Constructor 2. AddBalance 3. WithdrawBalance 4. PublishStorageDeals 5. VerifyDealsForActivation 6. ActivateDeals 7. OnMinerSectorsTerminate 8. ComputeDataCommitment 9. CronTick ## State ```go= type State struct { Proposals cid.Cid States cid.Cid PendingProposals cid.Cid EscrowTable cid.Cid LockedTable cid.Cid NextID abi.DealID DealOpsByEpoch cid.Cid LastCron abi.ChainEpoch TotalClientLockedCollateral abi.TokenAmount TotalProviderLockedCollateral abi.TokenAmount TotalClientStorageFee abi.TokenAmount } ``` **`Proposals`**: Tracks published DealProposals by unique DealID. * Notes: * Cid type: AMT, `array[DealID]DealProposal` * Maps a deal's unique DealID to its `DealProposal` * See DealProposal below **`States`**: Tracks important epochs for active deals that have been included in a Sector. * Notes: * Cid type: AMT, `array[DealID]DealState` * Maps a deal's unique DealID to its `DealState` * See DealState below **`PendingProposals`**: Tracks proposals that have not reached their start epoch. Prevents Miners from publishing the same `DealProposal` twice. * Notes: * Cid type, HAMT, `map[DealCid]DealProposal` * Maps a `DealProposal` Cid to its `DealProposal` * See DealProposal below **`EscrowTable`**: Tracks funds held in escrow. Includes locked funds (see below). * Notes: * Cid type: BalanceTable, `map[Address]TokenAmount` * Maps an actor's ID address to the token amount held in this table **`LockedTable`**: Tracks funds held in escrow that are also locked. * Notes: * Cid type: BalanceTable, `map[Address]TokenAmount` * Maps an actor's ID address to the token amount held in this table **`NextID`**: Tracks the next DealID that will be assigned to a published storage deal * Invariants: * `NextID >= 0` **`DealOpsByEpoch`**: Tracks deals that need updates at specific epochs. The `CronTick` method performs these updates and may re-insert the deal if future updates are required. * Notes: * Cid type: SetMultimap, `map[ChainEpoch]Set` * Maps a StartEpoch to a set of DealProposals that start at that epoch * Deals are initially inserted into `DealOpsByEpoch` in `PublishStorageDeals`. **`LastCron`**: The last epoch in which `CronTick` was called. Subsequent `CronTick`s perform updates from `LastCron + 1` to `rt.CurrEpoch`. * Invariants: * `LastCron >= -1` **`TotalClientLockedCollateral`**: Sum of all ClientCollateral locked in published deals. Unlocked when corresponding deals are terminated. * Invariants: * `TotalClientLockedCollateral >= 0` **`TotalProviderLockedCollateral`**: Sum of all ProviderCollateral locked in published deals. Unlocked when corresponding deals are terminated. * Invariants: * `TotalProviderLockedCollateral >= 0` **`TotalClientStorageFee`**: Sum of all storage fees locked in published deals. Unlocked over time as payments are made. * Invariants: * `TotalClientStorageFee >= 0` #### DealProposal A `DealProposal` contains information about a Storage Deal between a Miner (`Provider`) and their Client. ```go= type DealProposal struct { PieceCID cid.Cid PieceSize abi.PaddedPieceSize VerifiedDeal bool Client addr.Address Provider addr.Address Label string StartEpoch abi.ChainEpoch EndEpoch abi.ChainEpoch StoragePricePerEpoch abi.TokenAmount ProviderCollateral abi.TokenAmount ClientCollateral abi.TokenAmount } ``` **`PieceCID`**: The root Cid of the "piece" of data to be stored by the Miner on behalf of the Client. * Invariants: * `PieceCID.Defined() == true` **`PieceSize`**: The number of bytes that will be stored, padded to a power of two with extra zeroes. * Invariants: * Should pass `PieceSize.Validate()` (`abi/piece.go`) **`VerifiedDeal`**: Whether the deal is a Verified Deal (see VerifiedRegistry spec) * Notes: * If `true`, the `Client` must be a Verified Client. StorageMarket must successfully invoke VerifiedRegistry.UseBytes, consuming a portion of Client's `DataCap` **`Client`**: The address of the client providing the Piece data and paying the Miner for storage. * Notes: * Uses ID address protocol **`Provider`**: The Miner storing the data for `Client`. * Notes: * Uses ID address protocol * Requirements: * Must have a Miner actor CodeCID * NOTE: This is not currently enforced. **`Label`**: Arbitrary string that can help identify the deal. **`StartEpoch`**: The epoch in which the `Provider` becomes responsible for storing the data. **`EndEpoch`**: The epoch in which the `Provider` is no longer responsible for storing the data. * Invariants: * `EndEpoch > StartEpoch` **`StoragePricePerEpoch`**: The token amount paid by `Client` for each epoch the deal is active. * Notes: * Total payment is calculated for each epoch from `StartEpoch` to `EndEpoch` * Requirements: * `StoragePricePerEpoch >= 0` **`ProviderCollateral`**: The token amount put up by the deal's `Provider`. This amount is taken from the Provider's existing entry in `st.EscrowTable`, and added to the Provider's entry in `st.LockedTable`. * Notes: * See `OnMinerSectorsTerminate` for details on refund/slashing * Requirements: * `ProviderCollateral >= 0` **`ClientCollateral`**: The token amount put up by the deal's `Client`. This amount is taken from the Client's existing entry in `st.EscrowTable`, and added to the Client's entry in `st.LockedTable` * Notes: * See `OnMinerSectorsTerminate` for details on refund/slashing * Requirements: * `ClientCollateral >= 0` #### DealState A deal's `DealState` tracks important epochs for deals that have been included in a Sector. ```go= type DealState struct { SectorStartEpoch abi.ChainEpoch LastUpdatedEpoch abi.ChainEpoch SlashEpoch abi.ChainEpoch } ``` **`SectorStartEpoch`**: Once a deal is activated (`ActivateDeals`), the deal's `SectorStartEpoch` records the `StartEpoch` in which the Miner ProveCommitted the Sector. * Invariants: * `SectorStartEpoch >= 0` **`LastUpdatedEpoch`**: Tracks the last epoch in which a deal's `DealState` was updated. * Invariants: * `LastUpdatedEpoch >= -1` **`SlashEpoch`**: Tracks the epoch in which a deal was slashed. * Invariants: * `SlashEpoch >= -1` ## Exported Methods #### 1. Constructor ```go= func (a Actor) Constructor(rt Runtime, _ *adt.EmptyValue) *adt.EmptyValue ``` Initializes the StorageMarket actor's state. All values are `nil`, except `LastCron`, which is set to `ChainEpoch(-1)`. #### 2. AddBalance ```go= func (a Actor) AddBalance(rt Runtime, providerOrClientAddress *addr.Address) *adt.EmptyValue ``` Adds `ValueReceived()` to the `EscrowTable` entry corresponding to `providerOrClientAddress` * `providerOrClientAddress` must resolve to an ID address * Resolved address must have a CodeCID * If CodeCID is of a Miner actor, Caller must be one of the Miner's control addresses * Caller must be a Signable-type actor * `ValueReceived()` must be greater than zero Additionally, an empty entry is created in the `LockedTable` if one does not exist. ##### Failure conditions * Caller provides zero `ValueReceived()` * Caller is not a Signable-type actor * `providerOrClientAddress` fails to resolve * `providerOrClientAddress` does not have an associated CodeCID * `providerOrClientAddress` resolves to a Miner actor, and Caller is not one of the Miner's control addresses * `providerOrClientAddress` does not resolve to a Miner actor, and Caller is not a Signable-type actor #### 3. WithdrawBalance ```go= func (a Actor) WithdrawBalance(rt Runtime, params *WithdrawBalanceParams) *adt.EmptyValue ``` Allows an actor to withdraw available balance held in escrow. * If the actor in question is a Miner, balance withdrawn is sent to the Miner's Owner address. ##### Parameters ```go= type WithdrawBalanceParams struct { ProviderOrClientAddress addr.Address Amount abi.TokenAmount } ``` **`ProviderOrClientAddress`**: Must resolve to a Signable-type actor, or a Miner actor. * Notes: * All address protocols allowed * Requirements: * If `ProviderOrClientAddress` resolves to a Miner actor, Caller must be one of the Miner's control addresses **`Amount`**: The amount to withdraw from escrow. * Notes: * If less than `Amount` is available, this method will send the entire available balance. * Requirements: * `Amount >= 0` ##### Failure conditions * `params.Amount < 0` * `providerOrClientAddress` does not have an associated CodeCID * `providerOrClientAddress` resolves to a Miner actor, and Caller is not one of the Miner's control addresses * `providerOrClientAddress` is not a Miner actor, and is not Caller #### 4. PublishStorageDeals ```go= func (a Actor) PublishStorageDeals(rt Runtime, params *PublishStorageDealsParams) *PublishStorageDealsReturn ``` Used by a Miner to publish a new set of Storage Deals, each signed by the deal's Client. * These deals have not yet been included in a Sector. * Each passed-in deal is given a unique DealID before being placed in `State`: * `st.PendingProposals`: Maps the Cid of the deal's `Proposal` to the `Proposal` itself * `st.Proposals`: Maps the unique DealID to the deal's `Proposal` * `st.DealOpsByEpoch`: Maps the Proposal's `StartEpoch` to the unique DealID * This is used by `CronTick` * Each deal corresponds to collateral amounts that both the Miner and Client must provide. * Collateral should already exist for both parties in their respective `st.EscrowTable` entries. * The Client provides a base `ClientCollateral`, as well as the total storage fee calculated from various deal parameters. ##### Parameters `PublishStorageDealsParams` contains a slice of signed `DealProposals`. ```go= type PublishStorageDealsParams struct { Deals []ClientDealProposal } ``` **`Deals`**: See `ClientDealProposal` below * Requirements: * `len(Deals) != 0` ###### ClientDealProposal ```go= type ClientDealProposal struct { Proposal DealProposal ClientSignature acrypto.Signature } ``` **`Proposal`**: The DealProposal agreed to between the Miner and Client * Requirements: * Must not be `nil` **`ClientSignature`**: A signature over `Proposal` by `Proposal.Client` * Requirements: * Must not be `nil` * Must be a valid signature as per `rt.Syscalls().VerifySignature` ##### Return A slice of DealIDs corresponding to the newly-published Storage Deals. ```go= type PublishStorageDealsReturn struct { IDs []abi.DealID } ``` ##### Failure conditions * Caller is not a Signable actor * `len(params.Deals) == 0` * Deal's Provider address: * Is not able to be resolved * Does not have a Miner actor CodeCID * NOTE: This is not currently enforced * Caller is not the Worker address associated with deal's Provider * VerifiedRegistry.UseBytes fails for any `deal.Client` and `deal.PieceSize` * For any `ClientDealProposal`: * `validateDeal` fails: * Signature verification fails * `len(proposal.Label) > DealMaxLabelSize` (256) * `proposal.PieceSize.Validate()` fails * `proposal.PieceCID.Defined() == false` * `proposal.PieceCID.Prefix() != PieceCIDPrefix` * `proposal.EndEpoch <= proposal.StartEpoch` * `rt.CurrEpoch() > proposal.StartEpoch` * Invalid proposal duration * Invalid proposal price * Invalid `proposal.ProviderCollateral` * Invalid `proposal.ClientCollateral` * `deal.Provider` is different than any other deal's Provider * `deal.Client` address is not able to be resolved * Specified collateral is not available in Client or Provider's escrow balance * Proposal already exists in `st.PendingProposals` #### 5. VerifyDealsForActivation ```go= func (A Actor) VerifyDealsForActivation(rt Runtime, params *VerifyDealsForActivationParams) *VerifyDealsForActivationReturn ``` Allows a Miner to verify that a set of Storage Deals is valid for a Sector. This method is called by a Miner after publishing a set of Storage Deals via `PublishStorageDeals`. After accepting Client data from published deals, the Miner PreCommits a Sector containing those deals via `Miner.PreCommitSector`. * As part of this, the Miner declares an expiration epoch for the containing Sector. The start epoch of the Sector is defined as `rt.CurrEpoch()` (when `Miner.PreCommitSector` is invoked). * `Miner.PreCommitSector` must record the total DealWeight of the Sector. In order to calculate this, `VerifyDealsForActivation` is invoked. This method iterates over a slice of provided DealIDs, validates that the deal in question is unique and may be activated, then calculates each deal's respective weight. The sum of these weights is returned, split into weight corresponding to verified deals and weight corresponding to regular deals. ##### Parameters ```go= type VerifyDealsForActivationParams struct { DealIDs []abi.DealID SectorExpiry abi.ChainEpoch SectorStart abi.ChainEpoch } ``` **`DealIDs`**: A slice of DealIDs included in a Sector the Miner is PreCommitting. * Requirements: * Each `DealID` must correspond to an entry in `st.Proposals` * Caller must be the `Provider` of each referenced deal * Each `DealID` must be unique within the slice **`SectorExpiry`**: The expiration epoch for the containing Sector declared by the Miner. * Requirements: * Each deal's `EndEpoch` must be less than or equal to `SectorExpiry` **`SectorStart`**: The start epoch for the containing Sector. Set to `rt.CurrEpoch()`. * Requirements: * Each deal's `StartEpoch` must come after `SectorStart` ##### Return ```go= type VerifyDealsForActivationReturn struct { DealWeight abi.DealWeight VerifiedDealWeight abi.DealWeight DealSpace uint64 } ``` **`DealWeight`**: The sum of DealWeights calculated for each passed-in `DealID` not corresponding to a Verified Deal. * Notes: * Measured in byte-epochs * Calculated as `proposal.Duration() * proposal.PieceSize` * Invariants: * `DealWeight >= 0` **`VerifiedDealWeight`**: The sum of DealWeights calculated for each passed-in `DealID` corresponding to a Verified Deal. * Notes: * Measured in byte-epochs * Calculated as `proposal.Duration() * proposal.PieceSize` * Invariants: * `VerifiedDealWeight >= 0` **`DealSpace`**: The sum of the `PieceSize` of each passed-in deal. * Notes: * Measured in bytes * Invariants: * `DealSpace >= 0` ##### Failure conditions * Caller is not a Miner actor * `params.DealIDs` contains a duplicate entry * A referenced `DealID` is not found in `st.Proposals` * A referenced deal cannot be activated (`validateDealCanActivate`): * Caller is not the deal's `Provider` * Deal's `StartEpoch` has already elapsed (`CurrEpoch > proposal.StartEpoch`) * Deal's `EndEpoch` exceeds the Sector's expiration (`proposal.EndEpoch > params.SectorExpiry`) #### 6. ActivateDeals ```go= func (a Actor) ActivateDeals(rt Runtime, params *ActivateDealsParams) *adt.EmptyValue ``` After PreCommitting a Sector with its contained deals, a Miner attempts to ProveCommit the Sector via `Miner.ProveCommitSector`, which submits a proof of replication to the StoragePower actor (`SubmitPoRepForBulkVerify`). If this proof is valid, the StoragePower actor calls `Miner.ConfirmSectorProofsValid` at the end of the same epoch. For each valid Sector proof, `Miner.ConfirmSectorProofsValid` activates the deals stored in that Sector via `ActivateDeals`. This method: * Validates that each DealProposal may be activated * Checks that each DealProposal: * Exists in `st.Proposals` * Exists in `st.PendingProposals` * Does not exist in `st.States` * This would imply that the deal has already been included in a Sector * Inserts each DealProposal into `st.States` by its `DealID`. Each deal now has a corresponding DealState. The `DealState.SectorStartEpoch` of each deal is set to `rt.CurrEpoch()`, while the other two fields are set to `epochUndefined` (`ChainEpoch(-1)`). ##### Parameters ```go= type ActivateDealsParams struct { DealIDs []abi.DealID SectorExpiry abi.ChainEpoch } ``` **`DealIDs`**: A slice of `DealIDs` being activated. * Notes: * Each `DealID` is stored within the same Sector. * Requirements: * Each `DealID` must correspond to an entry in `st.Proposals` * Caller must be the `Provider` of each referenced deal * No deal's `StartEpoch` should have already elapsed * No deal should exist within `st.States` * Each deal must exist within `st.PendingProposals` **`SectorExpiry`**: The expiration epoch of the containing Sector. * Requirements: * Each deal's `EndEpoch` must be less than or equal to `SectorExpiry` ##### Failure conditions * Caller is not a Miner actor * A referenced deal cannot be activated (`validateDealCanActivate`): * Caller is not the deal's `Provider` * Deal's `StartEpoch` has already elapsed (`CurrEpoch > proposal.StartEpoch`) * Deal's `EndEpoch` exceeds the Sector's expiration (`proposal.EndEpoch > params.SectorExpiry`) * A referenced deal exists within `st.States` * A referenced deal was not found within `st.Proposals` * A referenced deal was not found within `st.PendingProposals` #### 7. OnMinerSectorsTerminate ```go= func (a Actor) OnMinerSectorsTerminate(rt Runtime, params *OnMinerSectorsTerminateParams) *adt.EmptyValue ``` A Miner may invoke this method from one of the following exported methods: * Miner.TerminateSectors * Miner.ReportConsensusFault * Miner.OnDeferredCronEvent This method simply iterates over the provided `DealIDs` and sets the deal's `DealState.SlashEpoch` to `params.Epoch`. The actual slashing occurs the next time this deal is processed in `CronTick`. * Special cases: * If the deal has already expired (`deal.EndEpoch <= params.Epoch`), `SlashEpoch` is not set. * If the deal's `SlashEpoch` has already been set (`DealState.SlashEpoch != epochUndefined`), nothing happens. ##### Parameters ```go= type OnMinerSectorsTerminateParams struct { Epoch abi.ChainEpoch DealIDs []abi.DealID } ``` **`Epoch`**: The epoch in which the containing Sector was terminated. **`DealIDs`**: A slice of `DealIDs` whose containing sector has been terminated. ##### Failure conditions * Caller is not a Miner actor * For any given passed-in `DealID`, Caller is not that deal's Provider (panic) * Deal does not exist in `st.States` * Note: This implies the deal was never activated and so should not be included in a Sector #### 8. ComputeDataCommitment ```go= func (a Actor) ComputeDataCommitment(rt Runtime, params *ComputeDataCommitmentParams) *cbg.CborCid ``` After PreCommitting a Sector with its contained deals, a Miner attempts to ProveCommit the Sector via `Miner.ProveCommitSector`, which submits a proof of replication to the StoragePower actor (`SubmitPoRepForBulkVerify`). As part of this process, the Miner invokes `ComputeDataCommitment` to calculate the Unsealed Sector CID for the Sector in question. The resulting UnsealedCID (also referred to as "CommD," or "data commitment") is passed in along with other values to `SubmitPoRepForBulkVerify`. This method returns the result of the syscall `rt.Syscalls().ComputeUnsealedSectorCID`. ##### Parameters ```go= type ComputeDataCommitmentParams struct { DealIDs []abi.DealID SectorType abi.RegisteredSealProof } ``` **`DealIDs`**: A slice of `DealIDs` that will all be stored in the same Sector. * Requirements: * Each deal must exist within `st.Proposals` **`SectorType`**: The seal proof type used by the Miner for this Sector. Should be equivalent to the Miner's `MinerInfo.SealProofType`. ##### Failure conditions * Caller is not a Miner actor * A referenced `DealID` is not found within `st.Proposals` #### 9. CronTick ```go= func (a Actor) CronTick(rt Runtime, _ *adt.EmptyValue) *adt.EmptyValue ``` `CronTick` is a special method invoked by the Cron actor at the end of each tipset. The primary purpose of `CronTick` is to handle updates to deals that need to occur at specific epochs. These updates are tracked by `st.DealOpsByEpoch`, which maps an epoch to a list of deals that need updates at that epoch. `CronTick` iterates over each deal for a given epoch. Typically, `CronTick` is only concerned with a single epoch, `rt.CurrEpoch()`. However, in the rare case that an epoch does not invoke the Cron actor, `CronTick` iterates over each of the deals for each epoch since it was last invoked (`st.LastCron + 1` to `rt.CurrEpoch()`). Deals are initially inserted in `st.DealOpsByEpoch` in `PublishStorageDeals`, where they are inserted by `DealProposal.StartEpoch`. This means that during the deal's start epoch, `CronTick` will process an update for that deal for the first time. The operations performed on each deal depend in large part on the deal's respective `DealState` entry (in `st.States`), which is created on a deal's activation via `ActivateDeals`: * `SectorStartEpoch`: Set to `rt.CurrEpoch()`. Never updated. * `LastUpdatedEpoch`: Set to `epochUndefined` (-1). Updated each time the deal is processed in `CronTick`. * `SlashEpoch`: Set to `epochUndefined` (-1). Updated if a deal's containing Sector is terminated via `OnMinerSectorsTerminate`. The first time `CronTick` processes a specific deal, it will perform ONE of the following actions: * **Init Timeout**: If a deal was published via `PublishStorageDeals` but never activated via `ActivateDeals`, `CronTick` considers it "timed out," as its `StartEpoch` has elapsed without it appearing in a proven Sector. * Identification: * `DealID` exists in `st.Proposals` and `st.PendingProposals`, but NOT within `st.States` * Actions taken: * `deal.ClientCollateral` and `deal.ClientStorageFee` are unlocked and returned to `deal.Client` * A penalty is calculated and slashed from `deal.ProviderCollateral`. Any amount remaining is unlocked and returned to `deal.Provider`. * If the deal in question is a Verified Deal (see VerifiedRegistry actor), the bytes consumed by the deal are restored. * The deal is deleted from `st.Proposals` * Notes: * If a deal is in Init Timeout, no other updates will be performed. * **Init Update**: If this is the first time a deal has been processed by `CronTick`, `CronTick` performs an Init Update. * Identification: * `DealID` exists in `st.Proposals`, `st.PendingProposals`, and `st.States` * `DealState.LastUpdatedEpoch == epochUndefined` * Actions taken: * Deal's entry is deleted from `st.PendingProposals` `CronTick` performs these updates for ALL deals, EXCEPT those caught by Init Timeout: * **Client-Provider Payment**: Clients pay Providers for storage incrementally. Payment is due each time a deal is processed by `CronTick`, and is calculated from `deal.StoragePricePerEpoch` times the number of epochs elapsed since the last time the deal was processed. If the deal has already ended (`rt.CurrEpoch > deal.EndEpoch`), payment is not due for epochs between `EndEpoch` and `CurrEpoch`. * Special case: If `deal.Provider` was slashed for this deal, `deal.Client` will only be charged up to `state.SlashEpoch` at max. * Actions taken: * Payment amount is transferred from the Client's `LockedTable` to the Provider's `EscrowTable`. * **Handle Slashed Deal**: If a deal's containing Sector was terminated, the Provider must be slashed. * Identification: * `DealState.SlashEpoch != epochUndefined` * Actions taken: * `deal.ClientCollateral` is unlocked and returned to `deal.Client` * Any remaining storage fees are unlocked and returned to `deal.Client` * `deal.ProviderCollateral` is slashed by removing the amount from the Provider's `EscrowTable` balance and sending it to the BurntFunds actor * The deal is deleted from `st.Proposals` and `st.States` * **Handle Expired Deal**: If a deal's `EndEpoch` has elapsed (and the deal was not slashed), the deal has been completed. * Identification: * `rt.CurrEpoch() >= deal.EndEpoch`, AND `DealState.SlashEpoch == epochUndefined` * Actions taken: * `deal.ClientCollateral` and `deal.ProviderCollateral` are unlocked and returned to `deal.Client` and `deal.Provider` * The deal is deleted from `st.Proposals` and `st.States` * **Handle Ongoing Deal**: A deal that has not been slashed and has not expired must be processed again in a future epoch. * Identification: * `rt.CurrEpoch() < deal.EndEpoch`, AND `DealState.SlashEpoch == epochUndefined` * Actions taken: * `DealState.LastUpdatedEpoch` is set to `rt.CurrEpoch()` * The deal is re-inserted in `st.DealOpsByState` at the epoch `rt.CurrEpoch() + DealUpdatesInterval` (100) * NOTE: If this epoch is beyond the deal's EndEpoch, the EndEpoch is used instead. No matter the case, once an epoch's deals have been iterated over and processed, that epoch's entries are deleted from `st.DealOpsByEpoch`. ##### Failure conditions * Caller is not the Cron actor * For any deal/`DealID` referenced by `StartEpoch` in `st.DealOpsByEpoch`: * Deal does not exist in `st.Proposals` * `DealState` does not exist in `st.States`, AND: * `deal.StartEpoch > rt.CurrEpoch()` (panic) * `processDealInitTimeout` fails to unlock or slash balances * `DealState.LastUpdatedEpoch == epochUndefined` AND deal does not exist in `st.PendingProposals` * `updatePendingDealState` fails: * `DealState.LastUpdatedEpoch > rt.CurrEpoch()` (panic) * `DealState.SlashEpoch > rt.CurrEpoch()` (panic) * `DealState.SlashEpoch > deal.EndEpoch` (panic) * Payment from `deal.Client` to `deal.Provider` fails (`st.transferBalance`) * If `DealState.SlashEpoch` is set, AND: * Client collateral and remaining storage fee fail to be unlocked * Provider collateral fails to be slashed * If `rt.CurrEpoch() >= deal.EndEpoch`, AND: * `DealState.SectorStartEpoch == epochUndefined` (panic) * Provider and Client collateral fail to be unlocked

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully