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

Configurable CC Sector Expiration #6803

Merged
merged 9 commits into from
Jul 28, 2021
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 {
placer14 marked this conversation as resolved.
Show resolved Hide resolved
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))
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The math is a little obtuse here so I put literal expecteds for both paths (zero config for CC and non-CC sectors) as well as show how the custom value is applied. I kept the later units with literals in the assert and simply updated the values.


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))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm pretty sure this math is unchanged, but please double-check this against the impl. 🙇

}

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))
placer14 marked this conversation as resolved.
Show resolved Hide resolved
}

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)
placer14 marked this conversation as resolved.
Show resolved Hide resolved

// 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