Skip to content

Commit

Permalink
Merge pull request #6803 from filecoin-project/mg/feat/configurable-s…
Browse files Browse the repository at this point in the history
…ector-expirations

Configurable CC Sector Expiration
  • Loading branch information
arajasek committed Jul 28, 2021
2 parents ef94509 + 2124470 commit 4a90c0f
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 31 deletions.
54 changes: 44 additions & 10 deletions extern/storage-sealing/precommit_policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package sealing
import (
"context"

"github.com/filecoin-project/lotus/chain/actors/builtin/miner"

"github.com/filecoin-project/go-state-types/network"
"golang.org/x/xerrors"

"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/network"
"github.com/filecoin-project/lotus/chain/actors/builtin"
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
"github.com/filecoin-project/lotus/chain/actors/policy"
)

type PreCommitPolicy interface {
Expand All @@ -34,21 +36,23 @@ type Chain interface {
// If we're in Mode 2: The pre-commit expiration epoch will be set to the
// current epoch + the provided default duration.
type BasicPreCommitPolicy struct {
api Chain
api Chain
getSealingConfig GetSealingConfigFunc

provingBoundary abi.ChainEpoch
duration abi.ChainEpoch
provingBuffer abi.ChainEpoch
}

// NewBasicPreCommitPolicy produces a BasicPreCommitPolicy.
//
// The provided duration is used as the default sector expiry when the sector
// contains no deals. The proving boundary is used to adjust/align the sector's expiration.
func NewBasicPreCommitPolicy(api Chain, duration abi.ChainEpoch, provingBoundary abi.ChainEpoch) BasicPreCommitPolicy {
func NewBasicPreCommitPolicy(api Chain, cfgGetter GetSealingConfigFunc, provingBoundary abi.ChainEpoch, provingBuffer abi.ChainEpoch) BasicPreCommitPolicy {
return BasicPreCommitPolicy{
api: api,
provingBoundary: provingBoundary,
duration: duration,
api: api,
getSealingConfig: cfgGetter,
provingBoundary: provingBoundary,
provingBuffer: provingBuffer,
}
}

Expand Down Expand Up @@ -79,11 +83,41 @@ func (p *BasicPreCommitPolicy) Expiration(ctx context.Context, ps ...Piece) (abi
}

if end == nil {
tmp := epoch + p.duration
// no deal pieces, get expiration for committed capacity sector
expirationDuration, err := p.getCCSectorLifetime()
if err != nil {
return 0, err
}

tmp := epoch + expirationDuration
end = &tmp
}

*end += miner.WPoStProvingPeriod - (*end % miner.WPoStProvingPeriod) + p.provingBoundary - 1

return *end, nil
}

func (p *BasicPreCommitPolicy) getCCSectorLifetime() (abi.ChainEpoch, error) {
c, err := p.getSealingConfig()
if err != nil {
return 0, xerrors.Errorf("sealing config load error: %w", err)
}

var ccLifetimeEpochs = abi.ChainEpoch(uint64(c.CommittedCapacitySectorLifetime.Seconds()) / builtin.EpochDurationSeconds)
// if zero value in config, assume maximum sector extension
if ccLifetimeEpochs == 0 {
ccLifetimeEpochs = policy.GetMaxSectorExpirationExtension()
}

if minExpiration := abi.ChainEpoch(miner.MinSectorExpiration); ccLifetimeEpochs < minExpiration {
log.Warnf("value for CommittedCapacitySectorLiftime is too short, using default minimum (%d epochs)", minExpiration)
return minExpiration, nil
}
if maxExpiration := policy.GetMaxSectorExpirationExtension(); ccLifetimeEpochs > maxExpiration {
log.Warnf("value for CommittedCapacitySectorLiftime is too long, using default maximum (%d epochs)", maxExpiration)
return maxExpiration, nil
}

return (ccLifetimeEpochs - p.provingBuffer), nil
}
81 changes: 66 additions & 15 deletions extern/storage-sealing/precommit_policy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,45 @@ package sealing_test
import (
"context"
"testing"
"time"

"github.com/filecoin-project/go-state-types/network"
api "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors/builtin"
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
"github.com/filecoin-project/lotus/chain/actors/policy"
sealing "github.com/filecoin-project/lotus/extern/storage-sealing"
"github.com/filecoin-project/lotus/extern/storage-sealing/sealiface"

"github.com/ipfs/go-cid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

commcid "github.com/filecoin-project/go-fil-commcid"
"github.com/filecoin-project/go-state-types/abi"

sealing "github.com/filecoin-project/lotus/extern/storage-sealing"
)

type fakeChain struct {
h abi.ChainEpoch
}

type fakeConfigStub struct {
CCSectorLifetime time.Duration
}

func fakeConfigGetter(stub *fakeConfigStub) sealing.GetSealingConfigFunc {
return func() (sealiface.Config, error) {
if stub == nil {
return sealiface.Config{}, nil
}

return sealiface.Config{
CommittedCapacitySectorLifetime: stub.CCSectorLifetime,
}, nil
}
}

func (f *fakeChain) StateNetworkVersion(ctx context.Context, tok sealing.TipSetToken) (network.Version, error) {
return build.NewestNetworkVersion, nil
}
Expand All @@ -38,21 +58,49 @@ func fakePieceCid(t *testing.T) cid.Cid {
}

func TestBasicPolicyEmptySector(t *testing.T) {
policy := sealing.NewBasicPreCommitPolicy(&fakeChain{
h: abi.ChainEpoch(55),
}, 10, 0)
cfg := fakeConfigGetter(nil)
h := abi.ChainEpoch(55)
pBoundary := abi.ChainEpoch(0)
pBuffer := abi.ChainEpoch(2)
pcp := sealing.NewBasicPreCommitPolicy(&fakeChain{h: h}, cfg, pBoundary, pBuffer)
exp, err := pcp.Expiration(context.Background())

require.NoError(t, err)

// as set when there are no deal pieces
expected := h + policy.GetMaxSectorExpirationExtension() - (pBuffer * 2)
// as set just before returning within Expiration()
expected += miner.WPoStProvingPeriod - (expected % miner.WPoStProvingPeriod) + pBoundary - 1
assert.Equal(t, int(expected), int(exp))
}

func TestCustomCCSectorConfig(t *testing.T) {
customLifetime := 200 * 24 * time.Hour
customLifetimeEpochs := abi.ChainEpoch(int64(customLifetime.Seconds()) / builtin.EpochDurationSeconds)
cfgStub := fakeConfigStub{CCSectorLifetime: customLifetime}
cfg := fakeConfigGetter(&cfgStub)
h := abi.ChainEpoch(55)
pBoundary := abi.ChainEpoch(0)
pBuffer := abi.ChainEpoch(2)
pcp := sealing.NewBasicPreCommitPolicy(&fakeChain{h: h}, cfg, pBoundary, pBuffer)
exp, err := pcp.Expiration(context.Background())

exp, err := policy.Expiration(context.Background())
require.NoError(t, err)

assert.Equal(t, 2879, int(exp))
// as set when there are no deal pieces
expected := h + customLifetimeEpochs - (pBuffer * 2)
// as set just before returning within Expiration()
expected += miner.WPoStProvingPeriod - (expected % miner.WPoStProvingPeriod) + pBoundary - 1
assert.Equal(t, int(expected), int(exp))
}

func TestBasicPolicyMostConstrictiveSchedule(t *testing.T) {
cfg := fakeConfigGetter(nil)
pPeriod := abi.ChainEpoch(11)
policy := sealing.NewBasicPreCommitPolicy(&fakeChain{
h: abi.ChainEpoch(55),
}, 100, 11)

}, cfg, pPeriod, 2)
longestDealEpochEnd := abi.ChainEpoch(100)
pieces := []sealing.Piece{
{
Piece: abi.PieceInfo{
Expand All @@ -76,7 +124,7 @@ func TestBasicPolicyMostConstrictiveSchedule(t *testing.T) {
DealID: abi.DealID(43),
DealSchedule: api.DealSchedule{
StartEpoch: abi.ChainEpoch(80),
EndEpoch: abi.ChainEpoch(100),
EndEpoch: longestDealEpochEnd,
},
},
},
Expand All @@ -85,13 +133,15 @@ func TestBasicPolicyMostConstrictiveSchedule(t *testing.T) {
exp, err := policy.Expiration(context.Background(), pieces...)
require.NoError(t, err)

assert.Equal(t, 2890, int(exp))
expected := longestDealEpochEnd + miner.WPoStProvingPeriod - (longestDealEpochEnd % miner.WPoStProvingPeriod) + pPeriod - 1
assert.Equal(t, int(expected), int(exp))
}

func TestBasicPolicyIgnoresExistingScheduleIfExpired(t *testing.T) {
cfg := fakeConfigGetter(nil)
policy := sealing.NewBasicPreCommitPolicy(&fakeChain{
h: abi.ChainEpoch(55),
}, 100, 0)
}, cfg, 0, 0)

pieces := []sealing.Piece{
{
Expand All @@ -112,13 +162,14 @@ func TestBasicPolicyIgnoresExistingScheduleIfExpired(t *testing.T) {
exp, err := policy.Expiration(context.Background(), pieces...)
require.NoError(t, err)

assert.Equal(t, 2879, int(exp))
assert.Equal(t, 1558079, int(exp))
}

func TestMissingDealIsIgnored(t *testing.T) {
cfg := fakeConfigGetter(nil)
policy := sealing.NewBasicPreCommitPolicy(&fakeChain{
h: abi.ChainEpoch(55),
}, 100, 11)
}, cfg, 11, 0)

pieces := []sealing.Piece{
{
Expand Down Expand Up @@ -146,5 +197,5 @@ func TestMissingDealIsIgnored(t *testing.T) {
exp, err := policy.Expiration(context.Background(), pieces...)
require.NoError(t, err)

assert.Equal(t, 2890, int(exp))
assert.Equal(t, 1558090, int(exp))
}
2 changes: 2 additions & 0 deletions extern/storage-sealing/sealiface/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ type Config struct {

WaitDealsDelay time.Duration

CommittedCapacitySectorLifetime time.Duration

AlwaysKeepUnsealedCopy bool

FinalizeEarly bool
Expand Down
4 changes: 4 additions & 0 deletions node/config/def.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"github.com/filecoin-project/go-state-types/big"
miner5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/miner"

"github.com/filecoin-project/lotus/chain/actors/builtin"
"github.com/filecoin-project/lotus/chain/actors/policy"
"github.com/filecoin-project/lotus/chain/types"
sectorstorage "github.com/filecoin-project/lotus/extern/sector-storage"
)
Expand Down Expand Up @@ -100,6 +102,8 @@ func DefaultStorageMiner() *StorageMiner {
PreCommitBatchWait: Duration(24 * time.Hour), // this should be less than 31.5 hours, which is the expiration of a precommit ticket
PreCommitBatchSlack: Duration(3 * time.Hour), // time buffer for forceful batch submission before sectors/deals in batch would start expiring, higher value will lower the chances for message fail due to expiration

CommittedCapacitySectorLifetime: Duration(builtin.EpochDurationSeconds * policy.GetMaxSectorExpirationExtension()),

AggregateCommits: true,
MinCommitBatch: miner5.MinAggregatedSectors, // per FIP13, we must have at least four proofs to aggregate, where 4 is the cross over point where aggregation wins out on single provecommit gas costs
MaxCommitBatch: miner5.MaxAggregatedSectors, // maximum 819 sectors, this is the maximum aggregation per FIP13
Expand Down
8 changes: 8 additions & 0 deletions node/config/doc_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions node/config/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,11 @@ type SealingConfig struct {
// Upper bound on how many sectors can be sealing at the same time when creating new sectors with deals (0 = unlimited)
MaxSealingSectorsForDeals uint64

// CommittedCapacitySectorLifetime is the duration a Committed Capacity (CC) sector will
// live before it must be extended or converted into sector containing deals before it is
// terminated. Value must be between 180-540 days inclusive
CommittedCapacitySectorLifetime Duration

// Period of time that a newly created sector will wait for more deals to be packed in to before it starts to seal.
// Sectors which are fully filled will start sealing immediately
WaitDealsDelay Duration
Expand Down
9 changes: 3 additions & 6 deletions storage/miner.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import (
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors/builtin"
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
"github.com/filecoin-project/lotus/chain/actors/policy"
"github.com/filecoin-project/lotus/chain/events"
"github.com/filecoin-project/lotus/chain/gen"
"github.com/filecoin-project/lotus/chain/types"
Expand Down Expand Up @@ -179,19 +178,17 @@ func (m *Miner) Run(ctx context.Context) error {
adaptedAPI = NewSealingAPIAdapter(m.api)

// Instantiate a precommit policy.
defaultDuration = policy.GetMaxSectorExpirationExtension() - (md.WPoStProvingPeriod * 2)
cfg = sealing.GetSealingConfigFunc(m.getSealConfig)
provingBoundary = md.PeriodStart % md.WPoStProvingPeriod
provingBuffer = md.WPoStProvingPeriod * 2

// TODO: Maybe we update this policy after actor upgrades?
pcp = sealing.NewBasicPreCommitPolicy(adaptedAPI, defaultDuration, provingBoundary)
pcp = sealing.NewBasicPreCommitPolicy(adaptedAPI, cfg, provingBoundary, provingBuffer)

// address selector.
as = func(ctx context.Context, mi miner.MinerInfo, use api.AddrUse, goodFunds, minFunds abi.TokenAmount) (address.Address, abi.TokenAmount, error) {
return m.addrSel.AddressFor(ctx, m.api, mi, use, goodFunds, minFunds)
}

// sealing configuration.
cfg = sealing.GetSealingConfigFunc(m.getSealConfig)
)

// Instantiate the sealing FSM.
Expand Down

0 comments on commit 4a90c0f

Please sign in to comment.