# Actor Spec: StoragePower [Back to Master Tracking Doc](https://hackmd.io/LOZjAsz-THelSD5lWqSVlw) ## Contents [TOC] ## At a Glance The StoragePower actor has a few roles: * Entry point into Filecoin for Miners * Keeps track of created Miner instances, as well as miners with power above consensus threshold * Manages active Miner instances and associated StoragePower accounting * Tracks deferred cron events for each Miner, and ensures these events are executed at specific epochs (through `OnEpochTickEnd`) * Aggregates Proofs of Replication (PoReps) for Miners, and submits them for bulk verification once per epoch * Updates network KPI via Reward actor. **Actor Type:** - Singleton - Address: 4 **Exported Methods:** 1. Constructor 2. CreateMiner 3. UpdateClaimedPower 4. EnrollCronEvent 5. OnEpochTickEnd 6. UpdatePledgeTotal 7. SubmitPoRepForBulkVerify 8. CurrentTotalPower ## Terms * **RawBytePower**: A Miner's power in terms of the number of bytes in the Miner's committed sectors. * **QualityAdjPower**: A Miner's RawBytePower adjusted for the number of deals stored in the Miner's committed sectors. * **ConsensusMinerMinPower**: The minimum QualityAdjPower a Miner must have in order to qualify for leader election. ## State ```go= type State struct { TotalRawBytePower abi.StoragePower TotalBytesCommitted abi.StoragePower TotalQualityAdjPower abi.StoragePower TotalQABytesCommitted abi.StoragePower TotalPledgeCollateral abi.TokenAmount ThisEpochRawBytePower abi.StoragePower ThisEpochQualityAdjPower abi.StoragePower ThisEpochPledgeCollateral abi.TokenAmount ThisEpochQAPowerSmoothed smoothing.FilterEstimate MinerCount int64 MinerAboveMinPowerCount int64 CronEventQueue cid.Cid FirstCronEpoch abi.ChainEpoch Claims cid.Cid ProofValidationBatch *cid.Cid } ``` **`TotalRawBytePower`**: The sum of all RawBytePower from all Miners meeting minimum power (ConsensusMinerMinPower) * Invariants: * `TotalRawBytePower >= 0` **`TotalBytesCommitted`**: The sum of all RawBytePower from all Miners, including those that do not meet minimum power (ConsensusMinerMinPower) * Invariants: * `TotalBytesCommitted >= TotalRawBytePower` **`TotalQualityAdjPower`**: The sum of all QualityAdjPower from all Miners meeting minimum power (ConsensusMinerMinPower) * Invariants: * `TotalQualityAdjPower >= TotalRawBytePower` **`TotalQABytesCommitted`**: The sum of all QualityAdjPower from all Miners, including those that do not meet minimum power (ConsensusMinerMinPower) * Invariants: * `TotalQABytesCommitted >= TotalQualityAdjPower` **`TotalPledgeCollateral`**: Current total amount of pledge collateral held across all Miners * Invariants: * `TotalPledgeCollateral >= 0` **`ThisEpochRawBytePower`**: Total RawBytePower of consensus-eligible Miners. Set each cron tick and remains constant until the next cron tick. * Invariants: * `ThisEpochRawBytePower >= 0` **`ThisEpochQualityAdjPower`**: Total QualityAdjPower of consensus-eligible Miners. Set each cron tick and remains constant until the next cron tick. * Invariants: * `ThisEpochQualityAdjPower >= 0` **`ThisEpochPledgeCollateral`**: Total pledge collateral held across all Miners. Set each cron tick and remains constant until the next cron tick. * Invariants: * `ThisEpochPledgeCollateral >= 0` **`ThisEpochQAPowerSmoothed`**: TODO **`MinerCount`**: The number of Miner actors created via `CreateMiner`, minus the number deleted via `OnConsensusFault` * Notes: * Does not factor in ConsensusMinerMinPower * Invariants: * `MinerCount >= MinerAboveMinPowerCount` **`MinerAboveMinPowerCount`**: The number of Miner Claims with a QualityAdjPower above ConsensusMinerMinPower. * Notes: * Miners that meet this threshold are eligible for leader election. * Invariants: * `MinerAboveMinPowerCount >= 0` **`CronEventQueue`**: A collection of CronEvents that are sent to specific Miners at specific epochs. * Notes: * Cid type: HAMT, `map[ChainEpoch]AMT[CronEvent]` * Maps a ChainEpoch to an array of CronEvents to process at that epoch. * See `CronEvent` below **`FirstCronEpoch`**: The epoch at which cron tick processing will start. * Invariants: * `FirstCronEpoch >= 0` **`Claims`**: A collection of Claims denoting the StoragePower each Miner has accrued. * Notes: * Cid type: HAMT, `map[Address]Claim` * Maps a Miner's address to its Power Claim * Uses the Miner's ID address * See `Claim` below **`ProofValidationBatch`**: A collection of PoReps for each Miner that will be processed on the next invocation of `OnEpochTickEnd`. * Notes: * Cid type, HAMT, `map[Address]AMT[SealVerifyInfo]` * Maps a Miner's address to an array of SealVerifyInfo that will be provided to `rt.Syscalls().BatchVerifySeals` * Uses the Miner's ID address * See `SealVerifyInfo` below #### CronEvent ```go= type CronEvent struct { MinerAddr addr.Address CallbackPayload []byte } ``` **`MinerAddr`**: The address of the Miner whose `OnDeferredCronEvent` method will be invoked. * Notes: * Uses ID addresses **`CallbackPayload`**: The parameters with which `OnDeferredCronEvent` will be invoked. #### Claim A Claim tracks power accrued by a Miner across all active Sectors. ```go= type Claim struct { SealProofType abi.RegisteredSealProof RawBytePower abi.StoragePower QualityAdjPower abi.StoragePower } ``` **`SealProofType`**: The type of proof being used by the Miner **`RawBytePower`**: Sum of RawBytePower for a Miner's Sectors * Invariants: * `RawBytePower >= 0` **`QualityAdjPower`**: Sum of QualityAdjPower for a Miner's Sectors * Invariants: * `QualityAdjPower >= 0` #### SealVerifyInfo ```go= type SealVerifyInfo struct { SealProof RegisteredSealProof SectorID DealIDs []DealID Randomness SealRandomness InteractiveRandomness InteractiveSealRandomness Proof []byte SealedCID cid.Cid UnsealedCID cid.Cid } ``` **`SealProof`**: The proof type used by a Miner for sealing Sectors. **`SectorID`**: The ID of the sector being proven. Combines the Miner's actor ID and the SectorNumber. **`DealIDs`**: A slice of DealIDs stored in the sector given by `SectorID` **`Randomness`**: Randomness included before PreCommit. Used to validate proof of replication. **`InteractiveRandomness`**: Randomness included after PreCommit. Used to validate proof of replication. **`Proof`**: A Proof of Replication that validates the sealing process has been performed correctly. **`SealedCID`**: The root hash of the Sealed Sector **`UnsealedCID`**: The root hash of the Unsealed Sector ## Exported Methods #### 1. Constructor ```go= func (a Actor) Constructor(rt Runtime, _ *adt.EmptyValue) *adt.EmptyValue ``` Initializes StoragePower actor state. #### 2. CreateMiner ```go= func (a Actor) CreateMiner(rt Runtime, params *CreateMinerParams) *CreateMinerReturn ``` Creates a new Miner actor via the Init actor. * The new Miner's ID address is inserted into `st.Claims`, and `st.MinerCount` is incremented. ##### Parameters ```go= type CreateMinerParams struct { Owner addr.Address Worker addr.Address SealProofType abi.RegisteredSealProof Peer abi.PeerID Multiaddrs []abi.Multiaddrs } ``` **`Owner`**: The new Miner's Owner address * Requirements: * See Miner actor Constructor for requirements. **`Worker`**: The new Miner's Worker address * Requirements: * See Miner actor Constructor for requirements. **`SealProofType`**: The proof type used for the Miner's sector commit proofs * Requirements: * See Miner actor Constructor for requirements. **`Peer`**: The Libp2p identity used to connect with this Miner * Requirements: * See Miner actor Constructor for requirements. **`Multiaddrs`**: Slice of Libp2p multi-addresses used to establish connections with this miner * Requirements: * See Miner actor Constructor for requirements. ##### Return ```go= type CreateMinerReturn struct { IDAddress addr.Address RobustAddress addr.Address } ``` **`IDAddress`**: The new Miner's ID address **`RobustAddress`**: The new Miner's ACTOR address ##### Failure conditions * Caller is not a Signable actor * Init actor constructor or Miner actor constructor fails * Init actor returns bad value, causing CBOR unmarshaling to fail #### 3. UpdateClaimedPower ```go= func (a Actor) UpdateClaimedPower(rt Runtime, params *UpdateClaimedPowerParams) *adt.EmptyValue ``` Invoked by a Miner whenever their claimed power changes, which may result from any of the following exported methods: * Miner.SubmitWindowedPoSt * Miner.ExtendSectorExpiration * Miner.TerminateSectors * Miner.DeclareFaults * Miner.OnDeferredCronEvent (proving period) * Miner.ConfirmSectorProofsValid This method: * Updates the calling Miner's Claim to reflect the change in power * Updates StoragePower state to reflect the change in overall power: * `st.TotalBytesCommitted` and `st.TotalQABytesCommitted` are adjusted directly * `st.MinerAboveMinPowerCount` is increased by 1 if the change to Miner power puts them above `ConsensusMinMinerPower` * `st.MinerAboveMinPowerCount` is decreased by 1 if the change to Miner power puts them below `ConsensusMinMinerPower` * `st.RawBytePower` and `st.TotalQualityAdjPower` are adjusted depending on the Miner's power in relation to `ConsensusMinMinerPower` ##### Parameters UpdateClaimedPowerParams contains the amount a Miner's power has changed. Both amounts may be positive or negative, signalling an increase or decrease in Miner's power, respectively. ```go= type UpdateClaimedPowerParams struct { RawByteDelta abi.StoragePower QualityAdjustedDelta abi.StoragePower } ``` **`RawByteDelta`**: The change to the Miner's RawBytePower **`QualityAdjustedDelta`**: The change to the Miner's QualityAdjPower ##### Failure conditions * Caller is not a Miner actor * Miner's Claim not found in `st.Claims` * Change to Miner's Claim results in a negative value for either field (panic) #### 4. EnrollCronEvent ```go= func (a Actor) EnrollCronEvent(rt Runtime, params *EnrollCronEventParams) *adt.EmptyValue ``` This method is invoked by a Miner from any of the following exported methods: * Miner.Constructor * Miner.TerminateSectors * Miner.OnDeferredCronEvent `EnrollCronEvent` allows a Miner to schedule a CronEvent with the StoragePower actor, which will be processed at some future epoch as part of StoragePower.OnEpochTickEnd. At the specified epoch (`EventEpoch`), OnEpochTickEnd invokes Miner.OnDeferredCronEvent, supplying a `Payload` that allows the Miner to determine how to handle the CronEvent. There are a few types of `Payload` (defined in `miner_actor.go`): * **Proving Deadline**: Miners have recurring proving deadlines. At the end of each proving deadline, a scheduled CronEvent prompts the Miner to invoke `Miner.handleProvingDeadline`. * Among other things, this method will schedule another CronEvent for the next proving deadline. * **Early Sector Termination**: Sectors are occasionally terminated before their expiration. In this case, the Miner processes as many early terminations as possible, and schedules additional terminations for processing at a future epoch. If an enrolled CronEvent has an `EventEpoch` before `st.FirstCronEpoch`, `st.FirstCronEpoch` is set to `EventEpoch`. ##### Parameters ```go= type EnrollCronEventParams struct { EventEpoch abi.ChainEpoch Payload []byte } ``` **`EventEpoch`**: The epoch at which the CronEvent will be processed. * Requirements: * `EventEpoch >= 0` **`Payload`**: The payload that will be supplied to Miner.OnDeferredCronEvent. ##### Failure conditions * Caller is not a Miner actor * `params.EventEpoch < 0` #### 5. OnEpochTickEnd ```go= func (a Actor) OnEpochTickEnd(rt Runtime, _ *adt.EmptyValue) *adt.EmptyValue ``` `OnEpochTickEnd` is a special method invoked by the Cron actor at the end of each tipset. `OnEpochTickEnd` has 3 responsibilities: * **Batch Verify PoReps**: If `st.ProofValidationBatch` contains proofs-of-replication (PoRep) submitted by Miners, these are verified in bulk via `rt.Syscalls().BatchVerifySeals`. For each Miner with successfully-proven Sectors, Miner.ConfirmSectorProofsValid is invoked and provided the successfully-proven SectorNumbers. * After processing the PoReps in `st.ProofValidationBatch`, `st.ProofValidationBatch` is set to `nil` * Miners that do not have valid Claims will have proof verification skipped. * See SubmitPoRepForBulkVerify for more info. * **Process Deferred CronEvents**: Iterates over `st.CronEventQueue` for each epoch from `st.FirstCronEpoch` to `rt.CurrEpoch()`. Each CronEvent is processed by invoking the specified Miner's OnDeferredCronEvent method. * If a Miner's CronEvent fails, their Claim is zeroed out and deleted as a penalty. * This method does not process deferred cron events for Miners without valid Claims (it skips them). * Once CronEvents are processed, `st.FirstCronEpoch` is set to `rt.CurrEpoch() + 1`. * See EnrollCronEvent for more info. * **Update Network KPI**: As the last action taken, StoragePower updates its current epoch values for pledge collateral, quality-adjusted power, smoothed quality-adjusted power, and raw byte power. This last value, `st.ThisEpochRawBytePower`, is passed to Reward.UpdateNetworkKPI. ##### Failure conditions * Caller is not the Cron actor * Invocation of Reward.UpdateNetworkKPI fails #### 6. UpdatePledgeTotal ```go= func (a Actor) UpdatePledgeTotal(rt Runtime, pledgeDelta *abi.TokenAmount) *adt.EmptyValue ``` Each time a Miner's active Sectors change, their pledge total is updated and this method is invoked. `pledgeDelta` may be a positive or negative value, signifying a gain or loss respectively. ##### Failure conditions * Caller is not a Miner actor * Caller does not have a valid claim in `st.Claims` * Change causes `st.TotalPledgeCollateral` to be negative #### 7. Deprecated1 This method was deprecated. See [this PR](https://github.com/filecoin-project/specs-actors/pull/1095). #### 8. SubmitPoRepForBulkVerify ```go= func (a Actor) SubmitPoRepForBulkVerify(rt Runtime, sealInfo *abi.SealVerifyInfo) *adt.EmptyValue ``` This method is invoked by Miner.ProveCommitSector. When ProveCommitting a Sector, a Miner submits a proof-of-replication (PoRep) to the StoragePower actor via `SubmitPoRepForBulkVerify`. `SubmitPoRepForBulkVerify` inserts the Miner's proof in `st.ProofValidationBatch`. At the end of the same epoch, StoragePower.OnEpochTickEnd will batch-verify all submitted PoReps. ##### Failure conditions * Caller is not a Miner actor * Caller does not have a valid claim in `st.Claims` * Caller has submitted `MaxMinerProveCommitsPerEpoch` (8000) already #### 9. CurrentTotalPower ```go= func (a Actor) CurrentTotalPower(rt Runtime, _ *adt.EmptyValue) *CurrentTotalPowerReturn ``` This method is a simple getter which returns the total power and pledge collateral recorded by the StoragePower actor during the last cron tick. This method is a simple read of these state fields: * `st.ThisEpochRawBytePower`: Sum of RawBytePower for consensus-eligible Miners * `st.ThisEpochQualityAdjPower`: Sum of QualityAdjPower for consensus-eligible Miners * `st.ThisEpochPledgeCollateral`: Sum of pledge collateral across all Miners * `st.ThisEpochQAPowerSmoothed`: TODO