Skip to content
This repository has been archived by the owner on Jun 6, 2023. It is now read-only.

Specs Actors Params Audit #695

Merged
merged 6 commits into from
Aug 28, 2020
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions actors/abi/sector.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,11 @@ func (p RegisteredSealProof) RegisteredWindowPoStProof() (RegisteredPoStProof, e
return info.WindowPoStProof, nil
}

// The maximum duration a sector sealed with this proof may exist between activation and expiration.
// This ensures that SDR is secure in the cost model for Window PoSt and in the time model for Winning PoSt
// This is based on estimation of hardware latency improvement and hardware and software cost reduction.
const SectorMaximumLifetimeSDR = ChainEpoch(1_262_277 * 5)

// SectorMaximumLifetime is the maximum duration a sector sealed with this proof may exist between activation and expiration
func (p RegisteredSealProof) SectorMaximumLifetime() (ChainEpoch, error) {
info, ok := SealProofInfos[p]
Expand Down Expand Up @@ -232,6 +237,8 @@ func (p RegisteredPoStProof) WindowPoStPartitionSectors() (uint64, error) {
return sp.WindowPoStPartitionSectors()
}



///
/// Sealing
///
Expand Down
8 changes: 4 additions & 4 deletions actors/builtin/market/market_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -507,8 +507,8 @@ func TestPublishStorageDeals(t *testing.T) {
// given power and circ supply cancel this should be 5*dealqapower / 100
dealSize := abi.PaddedPieceSize(2048) // generateDealProposal's deal size
providerCollateral := big.Div(
big.Mul(big.NewInt(int64(dealSize)), market.ProvCollateralPercentSupplyNum),
market.ProvCollateralPercentSupplyDenom,
big.Mul(big.NewInt(int64(dealSize)), market.ProviderCollateralSupplyTarget.Numerator),
market.ProviderCollateralSupplyTarget.Denominator,
)
deal := actor.generateDealWithCollateralAndAddFunds(rt, client, mAddr, providerCollateral, clientCollateral, startEpoch, endEpoch)
rt.SetCirculatingSupply(actor.networkQAPower) // convenient for these two numbers to cancel out
Expand Down Expand Up @@ -679,8 +679,8 @@ func TestPublishStorageDealsFailures(t *testing.T) {
rt.SetCirculatingSupply(h.networkQAPower)
dealSize := big.NewInt(2048) // default deal size used
providerMin := big.Div(
big.Mul(dealSize, market.ProvCollateralPercentSupplyNum),
market.ProvCollateralPercentSupplyDenom,
big.Mul(dealSize, market.ProviderCollateralSupplyTarget.Numerator),
market.ProviderCollateralSupplyTarget.Denominator,
)
d.ProviderCollateral = big.Sub(providerMin, big.NewInt(1))
},
Expand Down
33 changes: 19 additions & 14 deletions actors/builtin/market/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,28 @@ import (
"github.com/filecoin-project/specs-actors/actors/builtin"
)

// DealUpdatesInterval is the number of blocks between payouts for deals
const DealUpdatesInterval = builtin.EpochsInDay
// The number of epochs between payment and other state processing for deals.
const DealUpdatesInterval = builtin.EpochsInDay // PARAM_SPEC

// ProvCollateralPercentSupplyNum is the numerator of the percentage of normalized cirulating
// supply that must be covered by provider collateral
var ProvCollateralPercentSupplyNum = big.NewInt(5)
// The percentage of normalized cirulating
// supply that must be covered by provider collateral in a deal
var ProviderCollateralSupplyTarget = builtin.BigFrac{
Numerator: big.NewInt(5), // PARAM_SPEC
Denominator: big.NewInt(100),
}

// Minimum deal duration.
var DealMinDuration = abi.ChainEpoch(180 * builtin.EpochsInDay) // PARAM_SPEC

// ProvCollateralPercentSupplyDenom is the denominator of the percentage of normalized cirulating
// supply that must be covered by provider collateral
var ProvCollateralPercentSupplyDenom = big.NewInt(100)
// Maximum deal duration
var DealMaxDuration = abi.ChainEpoch(540 * builtin.EpochsInDay) // PARAM_SPEC

// Bounds (inclusive) on deal duration
func dealDurationBounds(size abi.PaddedPieceSize) (min abi.ChainEpoch, max abi.ChainEpoch) {
return abi.ChainEpoch(180 * builtin.EpochsInDay), abi.ChainEpoch(540 * builtin.EpochsInDay) // PARAM_FINISH
func dealDurationBounds(_ abi.PaddedPieceSize) (min abi.ChainEpoch, max abi.ChainEpoch) {
return DealMinDuration, DealMaxDuration // PARAM_FINISH
}

func dealPricePerEpochBounds(size abi.PaddedPieceSize, duration abi.ChainEpoch) (min abi.TokenAmount, max abi.TokenAmount) {
func dealPricePerEpochBounds(_ abi.PaddedPieceSize, _ abi.ChainEpoch) (min abi.TokenAmount, max abi.TokenAmount) {
return abi.NewTokenAmount(0), abi.TotalFilecoin // PARAM_FINISH
}

Expand All @@ -31,8 +36,8 @@ func DealProviderCollateralBounds(pieceSize abi.PaddedPieceSize, verified bool,
// normalizedCirculatingSupply = FILCirculatingSupply * dealPowerShare
// dealPowerShare = dealQAPower / max(BaselinePower(t), NetworkQAPower(t), dealQAPower)

lockTargetNum := big.Mul(ProvCollateralPercentSupplyNum, networkCirculatingSupply)
lockTargetDenom := ProvCollateralPercentSupplyDenom
lockTargetNum := big.Mul(ProviderCollateralSupplyTarget.Numerator, networkCirculatingSupply)
lockTargetDenom := ProviderCollateralSupplyTarget.Denominator

qaPower := dealQAPower(pieceSize, verified)
powerShareNum := qaPower
Expand All @@ -44,7 +49,7 @@ func DealProviderCollateralBounds(pieceSize abi.PaddedPieceSize, verified bool,
return minCollateral, abi.TotalFilecoin // PARAM_FINISH
}

func DealClientCollateralBounds(pieceSize abi.PaddedPieceSize, duration abi.ChainEpoch) (min abi.TokenAmount, max abi.TokenAmount) {
func DealClientCollateralBounds(_ abi.PaddedPieceSize, _ abi.ChainEpoch) (min abi.TokenAmount, max abi.TokenAmount) {
return abi.NewTokenAmount(0), abi.TotalFilecoin // PARAM_FINISH
}

Expand Down
17 changes: 11 additions & 6 deletions actors/builtin/miner/expiration_queue.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,11 @@ type ExpirationQueue struct {
quant QuantSpec
}

// An internal limit on the cardinality of a bitfield in a queue entry.
// This must be at least large enough to support the maximum number of sectors in a partition.
// It would be a bit better to derive this number from an enumeration over all partition sizes.
const entrySectorsMax = 10_000

// Loads a queue root.
// Epochs provided to subsequent method calls will be quantized upwards to quanta mod offsetSeed before being
// written to/read from queue entries.
Expand Down Expand Up @@ -314,11 +319,11 @@ func (q ExpirationQueue) RescheduleRecovered(sectors []*SectorOnChainInfo, ssize
var sectorsRescheduled []*SectorOnChainInfo
recoveredPower := NewPowerPairZero()
if err := q.traverseMutate(func(epoch abi.ChainEpoch, es *ExpirationSet) (changed, keepGoing bool, err error) {
onTimeSectors, err := es.OnTimeSectors.AllMap(SectorsMax)
onTimeSectors, err := es.OnTimeSectors.AllMap(entrySectorsMax)
if err != nil {
return false, false, err
}
earlySectors, err := es.EarlySectors.AllMap(SectorsMax)
earlySectors, err := es.EarlySectors.AllMap(entrySectorsMax)
if err != nil {
return false, false, err
}
Expand Down Expand Up @@ -391,11 +396,11 @@ func (q ExpirationQueue) RemoveSectors(sectors []*SectorOnChainInfo, faults bitf
for _, s := range sectors {
remaining[s.SectorNumber] = struct{}{}
}
faultsMap, err := faults.AllMap(SectorsMax)
faultsMap, err := faults.AllMap(AddressedSectorsMax)
if err != nil {
return nil, NewPowerPairZero(), xerrors.Errorf("failed to expand faults: %w", err)
}
recoveringMap, err := recovering.AllMap(SectorsMax)
recoveringMap, err := recovering.AllMap(AddressedSectorsMax)
if err != nil {
return nil, NewPowerPairZero(), xerrors.Errorf("failed to expand recoveries: %w", err)
}
Expand Down Expand Up @@ -431,11 +436,11 @@ func (q ExpirationQueue) RemoveSectors(sectors []*SectorOnChainInfo, faults bitf
// queue is quantized, we should be able to stop traversing the queue
// after 14 entries.
if err = q.traverseMutate(func(epoch abi.ChainEpoch, es *ExpirationSet) (changed, keepGoing bool, err error) {
onTimeSectors, err := es.OnTimeSectors.AllMap(SectorsMax)
onTimeSectors, err := es.OnTimeSectors.AllMap(entrySectorsMax)
if err != nil {
return false, false, err
}
earlySectors, err := es.EarlySectors.AllMap(SectorsMax)
earlySectors, err := es.EarlySectors.AllMap(entrySectorsMax)
if err != nil {
return false, false, err
}
Expand Down
6 changes: 6 additions & 0 deletions actors/builtin/miner/miner_actor.go
Original file line number Diff line number Diff line change
Expand Up @@ -2225,6 +2225,12 @@ func PowerForSectors(ssize abi.SectorSize, sectors []*SectorOnChainInfo) PowerPa
}
}

func ConsensusFaultActive(info *MinerInfo, currEpoch abi.ChainEpoch) bool {
// For penalization period to last for exactly finality epochs
// consensus faults are active until currEpoch exceeds ConsensusFaultElapsed
return currEpoch <= info.ConsensusFaultElapsed
}

func getMinerInfo(rt Runtime, st *State) *MinerInfo {
info, err := st.GetInfo(adt.AsStore(rt))
builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "could not read miner info")
Expand Down
4 changes: 2 additions & 2 deletions actors/builtin/miner/miner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2177,7 +2177,7 @@ func TestExtendSectorExpiration(t *testing.T) {
require.NoError(t, err)
var partition miner.Partition
require.NoError(t, partitions.ForEach(&partition, func(partIdx int64) error {
oldSectorNos, err := partition.Sectors.All(miner.SectorsMax)
oldSectorNos, err := partition.Sectors.All(miner.AddressedSectorsMax)
require.NoError(t, err)

// filter out even-numbered sectors.
Expand Down Expand Up @@ -3263,7 +3263,7 @@ func (h *actorHarness) collectDeadlineExpirations(rt *mock.Runtime, deadline *mi
require.NoError(h.t, err)
expirations := map[abi.ChainEpoch][]uint64{}
_ = queue.ForEach(func(epoch abi.ChainEpoch, bf bitfield.BitField) error {
expanded, err := bf.All(miner.SectorsMax)
expanded, err := bf.All(miner.AddressedSectorsMax)
require.NoError(h.t, err)
expirations[epoch] = expanded
return nil
Expand Down
64 changes: 42 additions & 22 deletions actors/builtin/miner/monies.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,56 @@ import (
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/abi/big"
"github.com/filecoin-project/specs-actors/actors/builtin"
exitcode "github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
"github.com/filecoin-project/specs-actors/actors/util/math"
"github.com/filecoin-project/specs-actors/actors/util/smoothing"
)

// PARAM_FINISH
var PreCommitDepositFactor = 20
var InitialPledgeFactor = 20
// Projection period of expected sector block reward for deposit required to pre-commit a sector.
// This deposit is lost if the pre-commitment is not timely followed up by a commitment proof.
var PreCommitDepositFactor = 20 // PARAM_SPEC PARAM_FINISH
var PreCommitDepositProjectionPeriod = abi.ChainEpoch(PreCommitDepositFactor) * builtin.EpochsInDay

// Projection period of expected sector block rewards for storage pledge required to commit a sector.
// This pledge is lost if a sector is terminated before its full committed lifetime.
var InitialPledgeFactor = 20 // PARAM_SPEC PARAM_FINISH
var InitialPledgeProjectionPeriod = abi.ChainEpoch(InitialPledgeFactor) * builtin.EpochsInDay
var LockTargetFactorNum = big.NewInt(3)
var LockTargetFactorDenom = big.NewInt(10)

// Multiplier of share of circulating money supply for consensus pledge required to commit a sector.
// This pledge is lost if a sector is terminated before its full committed lifetime.
var InitialPledgeLockTarget = builtin.BigFrac{
Numerator: big.NewInt(3), // PARAM_SPEC PARAM_FINISH
Denominator: big.NewInt(10),
}

// Projection period of expected daily sector block reward penalised when a fault is declared "on time".
// This guarantees that a miner pays back at least the expected block reward earned since the last successful PoSt.
// The network conservatively assumes the sector was faulty since the last time it was proven.
// This penalty is currently overly punitive for continued faults.
// FF = BR(t, DeclaredFaultProjectionPeriod)
// projection period of 2.14 days: 2880 * 2.14 = 6163.2. Rounded to nearest epoch 6163
var DeclaredFaultFactorNum = 214
var DeclaredFaultFactorNum = 214 // PARAM_SPEC
var DeclaredFaultFactorDenom = 100
var DeclaredFaultProjectionPeriod = abi.ChainEpoch((builtin.EpochsInDay * DeclaredFaultFactorNum) / DeclaredFaultFactorDenom)

// Projection period of expected daily sector block reward penalised when a fault is not declared in advance.
// This fee is higher than the declared fault fee for two reasons:
// (1) it incentivizes a miner to declare a fault early;
// (2) when a miner stores less than (1-spacegap) of a sector, does not declare it as faulty,
// and hopes to be challenged on the stored parts, it means the miner would not be expected to earn positive rewards.
// SP = BR(t, UndeclaredFaultProjectionPeriod)
var UndeclaredFaultProjectionPeriod = abi.ChainEpoch(5) * builtin.EpochsInDay
var UndeclaredFaultProjectionPeriod = abi.ChainEpoch(5) * builtin.EpochsInDay // PARAM_SPEC

// Maximum number of days of BR a terminated sector can be penalized
// Maximum number of lifetime days penalized when a sector is terminated.
const TerminationLifetimeCap = abi.ChainEpoch(70)

// Number of whole per-winner rewards covered by consensus fault penalty
// Multiplier of whole per-winner rewards for a consensus fault penalty.
const ConsensusFaultFactor = 5

// This is the BR(t) value of the given sector for the current epoch.
// It is the expected reward this sector would pay out over a t-day period.
// BR(t) = CurrEpochReward(t) * SectorQualityAdjustedPower * EpochsInDay / TotalNetworkQualityAdjustedPower(t)
// The projected block reward a sector would earn over some period.
// Also known as "BR(t)".
// BR(t) = ProjectedRewardFraction(t) * SectorQualityAdjustedPower
// ProjectedRewardFraction(t) is the sum of estimated reward over estimated total power
// over all epochs in the projection period [t t+projectionDuration]
func ExpectedRewardForPower(rewardEstimate, networkQAPowerEstimate *smoothing.FilterEstimate, qaSectorPower abi.StoragePower, projectionDuration abi.ChainEpoch) abi.TokenAmount {
networkQAPowerSmoothed := networkQAPowerEstimate.Estimate()
if networkQAPowerSmoothed.IsZero() {
Expand All @@ -46,15 +65,16 @@ func ExpectedRewardForPower(rewardEstimate, networkQAPowerEstimate *smoothing.Fi
return big.Max(br, big.Zero()) // negative BR is clamped at 0
}

// This is the FF(t) penalty for a sector expected to be in the fault state either because the fault was declared or because
// it has been previously detected by the network.
// FF(t) = DeclaredFaultFactor * BR(t)
// The penalty for a sector declared faulty or continuing faulty for another proving period.
// It is a projection of the expected reward earned by the sector.
// Also known as "FF(t)"
func PledgePenaltyForDeclaredFault(rewardEstimate, networkQAPowerEstimate *smoothing.FilterEstimate, qaSectorPower abi.StoragePower) abi.TokenAmount {
return ExpectedRewardForPower(rewardEstimate, networkQAPowerEstimate, qaSectorPower, DeclaredFaultProjectionPeriod)
}

// This is the SP(t) penalty for a newly faulty sector that has not been declared.
// SP(t) = UndeclaredFaultFactor * BR(t)
// The penalty for a newly faulty sector that was been declared in advance.
// It is a projection of the expected reward earned by the sector.
// Also known as "SP(t)"
func PledgePenaltyForUndeclaredFault(rewardEstimate, networkQAPowerEstimate *smoothing.FilterEstimate, qaSectorPower abi.StoragePower) abi.TokenAmount {
return ExpectedRewardForPower(rewardEstimate, networkQAPowerEstimate, qaSectorPower, UndeclaredFaultProjectionPeriod)
}
Expand Down Expand Up @@ -97,7 +117,7 @@ func PreCommitDepositForPower(rewardEstimate, networkQAPowerEstimate *smoothing.
// network total and baseline power, per-epoch reward, and circulating token supply.
// The pledge comprises two parts:
// - storage pledge, aka IP base: a multiple of the reward expected to be earned by newly-committed power
// - pledge share, aka additional IP: a pro-rata fraction of the circulating money supply
// - consensus pledge, aka additional IP: a pro-rata fraction of the circulating money supply
//
// IP = IPBase(t) + AdditionalIP(t)
// IPBase(t) = BR(t, InitialPledgeProjectionPeriod)
Expand All @@ -107,8 +127,8 @@ func PreCommitDepositForPower(rewardEstimate, networkQAPowerEstimate *smoothing.
func InitialPledgeForPower(qaPower, baselinePower abi.StoragePower, rewardEstimate, networkQAPowerEstimate *smoothing.FilterEstimate, circulatingSupply abi.TokenAmount) abi.TokenAmount {
ipBase := ExpectedRewardForPower(rewardEstimate, networkQAPowerEstimate, qaPower, InitialPledgeProjectionPeriod)

lockTargetNum := big.Mul(LockTargetFactorNum, circulatingSupply)
lockTargetDenom := LockTargetFactorDenom
lockTargetNum := big.Mul(InitialPledgeLockTarget.Numerator, circulatingSupply)
lockTargetDenom := InitialPledgeLockTarget.Denominator
pledgeShareNum := qaPower
networkQAPower := networkQAPowerEstimate.Estimate()
pledgeShareDenom := big.Max(big.Max(networkQAPower, baselinePower), qaPower) // use qaPower in case others are 0
Expand Down
4 changes: 2 additions & 2 deletions actors/builtin/miner/partition_state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1062,7 +1062,7 @@ func bf(secNos ...uint64) bitfield.BitField {
}

func selectSectors(t *testing.T, sectors []*miner.SectorOnChainInfo, field bitfield.BitField) []*miner.SectorOnChainInfo {
toInclude, err := field.AllMap(miner.SectorsMax)
toInclude, err := field.AllMap(miner.AddressedSectorsMax)
require.NoError(t, err)

included := []*miner.SectorOnChainInfo{}
Expand All @@ -1085,7 +1085,7 @@ func emptyPartition(t *testing.T, store adt.Store) *miner.Partition {
}

func rescheduleSectors(t *testing.T, target abi.ChainEpoch, sectors []*miner.SectorOnChainInfo, filter bitfield.BitField) []*miner.SectorOnChainInfo {
toReschedule, err := filter.AllMap(miner.SectorsMax)
toReschedule, err := filter.AllMap(miner.AddressedSectorsMax)
require.NoError(t, err)
output := make([]*miner.SectorOnChainInfo, len(sectors))
for i, sector := range sectors {
Expand Down