From 9e34cce1f2f3984573b33f2fef839e81c34ca1ee Mon Sep 17 00:00:00 2001 From: Mike Greenberg Date: Tue, 20 Jul 2021 17:19:28 -0400 Subject: [PATCH 01/17] feat(config): support configurable CC sector expiration --- extern/storage-sealing/sealiface/config.go | 2 ++ node/config/def.go | 6 ++++++ storage/miner.go | 18 ++++++++++++++---- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/extern/storage-sealing/sealiface/config.go b/extern/storage-sealing/sealiface/config.go index e33b36263..59c3d8c4f 100644 --- a/extern/storage-sealing/sealiface/config.go +++ b/extern/storage-sealing/sealiface/config.go @@ -20,6 +20,8 @@ type Config struct { WaitDealsDelay time.Duration + CommittedCapacityDefaultLifetime time.Duration + AlwaysKeepUnsealedCopy bool FinalizeEarly bool diff --git a/node/config/def.go b/node/config/def.go index 7042cf644..bf6526e4d 100644 --- a/node/config/def.go +++ b/node/config/def.go @@ -131,6 +131,12 @@ type SealingConfig struct { WaitDealsDelay Duration + // CommittedCapacityDefaultLifetime is the default 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. + CommittedCapacityDefaultLifetime Duration + AlwaysKeepUnsealedCopy bool // Run sector finalization before submitting sector proof to the chain diff --git a/storage/miner.go b/storage/miner.go index cdacc2734..06ee874a1 100644 --- a/storage/miner.go +++ b/storage/miner.go @@ -178,8 +178,11 @@ func (m *Miner) Run(ctx context.Context) error { // provides extra methods. adaptedAPI = NewSealingAPIAdapter(m.api) + // sealing configuration. + cfg = sealing.GetSealingConfigFunc(m.getSealConfig) + // Instantiate a precommit policy. - defaultDuration = policy.GetMaxSectorExpirationExtension() - (md.WPoStProvingPeriod * 2) + defaultDuration = getDefaultSectorExpirationExtension(cfg) - (md.WPoStProvingPeriod * 2) provingBoundary = md.PeriodStart % md.WPoStProvingPeriod // TODO: Maybe we update this policy after actor upgrades? @@ -189,9 +192,6 @@ func (m *Miner) Run(ctx context.Context) error { 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. @@ -203,6 +203,16 @@ func (m *Miner) Run(ctx context.Context) error { return nil } +func getDefaultSectorExpirationExtension(cfg sealing.GetSealingConfigFunc) abi.ChainEpoch { + c, err := cfg() + if err != nil { + log.Warnf("failed to load sealing config, using default sector extension expiration") + log.Errorf("sealing config load error: %s", err.Error()) + return policy.GetMaxSectorExpirationExtension() + } + return abi.ChainEpoch(c.CommittedCapacityDefaultLifetime.Truncate(builtin.EpochDurationSeconds)) +} + func (m *Miner) handleSealingNotifications(before, after sealing.SectorInfo) { m.journal.RecordEvent(m.sealingEvtType, func() interface{} { return SealingStateEvt{ From adb62a3fff61d74aa07bd450ea4daa6044366546 Mon Sep 17 00:00:00 2001 From: Mike Greenberg Date: Thu, 22 Jul 2021 08:37:35 -0400 Subject: [PATCH 02/17] chore: Move cfg getter into PCPolicy; Clamp values on get --- chain/actors/policy/policy.go | 4 ++ extern/storage-sealing/precommit_policy.go | 48 +++++++++++++++++----- extern/storage-sealing/sealiface/config.go | 2 +- node/config/def.go | 13 +++--- storage/miner.go | 18 +------- 5 files changed, 53 insertions(+), 32 deletions(-) diff --git a/chain/actors/policy/policy.go b/chain/actors/policy/policy.go index c06c85d38..06db09ea8 100644 --- a/chain/actors/policy/policy.go +++ b/chain/actors/policy/policy.go @@ -301,6 +301,10 @@ func GetWinningPoStSectorSetLookback(nwVer network.Version) abi.ChainEpoch { return ChainFinality } +func GetMinSectorExpiration() abi.ChainEpoch { + return miner5.MinSectorExpiration +} + func GetMaxSectorExpirationExtension() abi.ChainEpoch { return miner5.MaxSectorExpirationExtension } diff --git a/extern/storage-sealing/precommit_policy.go b/extern/storage-sealing/precommit_policy.go index a6add5693..bc5a0a530 100644 --- a/extern/storage-sealing/precommit_policy.go +++ b/extern/storage-sealing/precommit_policy.go @@ -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 { @@ -34,21 +36,21 @@ 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 } // 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) BasicPreCommitPolicy { return BasicPreCommitPolicy{ - api: api, - provingBoundary: provingBoundary, - duration: duration, + api: api, + getSealingConfig: cfgGetter, + provingBoundary: provingBoundary, } } @@ -79,7 +81,13 @@ 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 } @@ -87,3 +95,23 @@ func (p *BasicPreCommitPolicy) Expiration(ctx context.Context, ps ...Piece) (abi 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) + } + + sectorExpiration := abi.ChainEpoch(c.CommittedCapacitySectorLifetime.Truncate(builtin.EpochDurationSeconds) / builtin.EpochDurationSeconds) + + if minExpiration := policy.GetMinSectorExpiration(); sectorExpiration < minExpiration { + log.Warnf("value for CommittedCapacitySectorLiftime is too short, using default minimum (%d epochs)", minExpiration) + return minExpiration, nil + } + if maxExpiration := policy.GetMaxSectorExpirationExtension(); sectorExpiration > maxExpiration { + log.Warnf("value for CommittedCapacitySectorLiftime is too long, using default maximum (%d epochs)", maxExpiration) + return maxExpiration, nil + } + + return sectorExpiration, nil +} diff --git a/extern/storage-sealing/sealiface/config.go b/extern/storage-sealing/sealiface/config.go index 59c3d8c4f..95b851609 100644 --- a/extern/storage-sealing/sealiface/config.go +++ b/extern/storage-sealing/sealiface/config.go @@ -20,7 +20,7 @@ type Config struct { WaitDealsDelay time.Duration - CommittedCapacityDefaultLifetime time.Duration + CommittedCapacitySectorLifetime time.Duration AlwaysKeepUnsealedCopy bool diff --git a/node/config/def.go b/node/config/def.go index bf6526e4d..17f43ffc3 100644 --- a/node/config/def.go +++ b/node/config/def.go @@ -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" ) @@ -131,11 +133,10 @@ type SealingConfig struct { WaitDealsDelay Duration - // CommittedCapacityDefaultLifetime is the default 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. - CommittedCapacityDefaultLifetime Duration + // 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 AlwaysKeepUnsealedCopy bool @@ -358,6 +359,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 diff --git a/storage/miner.go b/storage/miner.go index 06ee874a1..c38671c8c 100644 --- a/storage/miner.go +++ b/storage/miner.go @@ -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" @@ -178,15 +177,12 @@ func (m *Miner) Run(ctx context.Context) error { // provides extra methods. adaptedAPI = NewSealingAPIAdapter(m.api) - // sealing configuration. - cfg = sealing.GetSealingConfigFunc(m.getSealConfig) - // Instantiate a precommit policy. - defaultDuration = getDefaultSectorExpirationExtension(cfg) - (md.WPoStProvingPeriod * 2) + cfg = sealing.GetSealingConfigFunc(m.getSealConfig) provingBoundary = md.PeriodStart % md.WPoStProvingPeriod // TODO: Maybe we update this policy after actor upgrades? - pcp = sealing.NewBasicPreCommitPolicy(adaptedAPI, defaultDuration, provingBoundary) + pcp = sealing.NewBasicPreCommitPolicy(adaptedAPI, cfg, provingBoundary) // address selector. as = func(ctx context.Context, mi miner.MinerInfo, use api.AddrUse, goodFunds, minFunds abi.TokenAmount) (address.Address, abi.TokenAmount, error) { @@ -203,16 +199,6 @@ func (m *Miner) Run(ctx context.Context) error { return nil } -func getDefaultSectorExpirationExtension(cfg sealing.GetSealingConfigFunc) abi.ChainEpoch { - c, err := cfg() - if err != nil { - log.Warnf("failed to load sealing config, using default sector extension expiration") - log.Errorf("sealing config load error: %s", err.Error()) - return policy.GetMaxSectorExpirationExtension() - } - return abi.ChainEpoch(c.CommittedCapacityDefaultLifetime.Truncate(builtin.EpochDurationSeconds)) -} - func (m *Miner) handleSealingNotifications(before, after sealing.SectorInfo) { m.journal.RecordEvent(m.sealingEvtType, func() interface{} { return SealingStateEvt{ From 7ee46ad4e0638822c7dfcdf6fb4aa306ec3f9f40 Mon Sep 17 00:00:00 2001 From: Mike Greenberg Date: Thu, 22 Jul 2021 14:44:39 -0400 Subject: [PATCH 03/17] fix: PreCommitPolicy unit tests --- extern/storage-sealing/precommit_policy.go | 16 +++-- .../storage-sealing/precommit_policy_test.go | 63 ++++++++++++++----- storage/miner.go | 3 +- 3 files changed, 61 insertions(+), 21 deletions(-) diff --git a/extern/storage-sealing/precommit_policy.go b/extern/storage-sealing/precommit_policy.go index bc5a0a530..6d1fddc47 100644 --- a/extern/storage-sealing/precommit_policy.go +++ b/extern/storage-sealing/precommit_policy.go @@ -40,17 +40,19 @@ type BasicPreCommitPolicy struct { getSealingConfig GetSealingConfigFunc provingBoundary 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, cfgGetter GetSealingConfigFunc, provingBoundary abi.ChainEpoch) BasicPreCommitPolicy { +func NewBasicPreCommitPolicy(api Chain, cfgGetter GetSealingConfigFunc, provingBoundary abi.ChainEpoch, provingBuffer abi.ChainEpoch) BasicPreCommitPolicy { return BasicPreCommitPolicy{ api: api, getSealingConfig: cfgGetter, provingBoundary: provingBoundary, + provingBuffer: provingBuffer, } } @@ -102,16 +104,20 @@ func (p *BasicPreCommitPolicy) getCCSectorLifetime() (abi.ChainEpoch, error) { return 0, xerrors.Errorf("sealing config load error: %w", err) } - sectorExpiration := abi.ChainEpoch(c.CommittedCapacitySectorLifetime.Truncate(builtin.EpochDurationSeconds) / builtin.EpochDurationSeconds) + var ccLifetimeEpochs = abi.ChainEpoch(uint64(c.CommittedCapacitySectorLifetime.Truncate(builtin.EpochDurationSeconds).Seconds()) / builtin.EpochDurationSeconds) + // if zero value in config, assume maximum sector extension + if ccLifetimeEpochs == 0 { + ccLifetimeEpochs = policy.GetMaxSectorExpirationExtension() + } - if minExpiration := policy.GetMinSectorExpiration(); sectorExpiration < minExpiration { + if minExpiration := policy.GetMinSectorExpiration(); ccLifetimeEpochs < minExpiration { log.Warnf("value for CommittedCapacitySectorLiftime is too short, using default minimum (%d epochs)", minExpiration) return minExpiration, nil } - if maxExpiration := policy.GetMaxSectorExpirationExtension(); sectorExpiration > maxExpiration { + if maxExpiration := policy.GetMaxSectorExpirationExtension(); ccLifetimeEpochs > maxExpiration { log.Warnf("value for CommittedCapacitySectorLiftime is too long, using default maximum (%d epochs)", maxExpiration) return maxExpiration, nil } - return sectorExpiration, nil + return (ccLifetimeEpochs - p.provingBuffer), nil } diff --git a/extern/storage-sealing/precommit_policy_test.go b/extern/storage-sealing/precommit_policy_test.go index a6c17d3fd..aa56f1e6f 100644 --- a/extern/storage-sealing/precommit_policy_test.go +++ b/extern/storage-sealing/precommit_policy_test.go @@ -3,10 +3,15 @@ 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/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" @@ -14,14 +19,31 @@ import ( 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 } +func fakeConfigGetter(stub interface{}, t *testing.T) sealing.GetSealingConfigFunc { + return func() (sealiface.Config, error) { + if stub == nil { + return sealiface.Config{}, nil + } + + castStub, ok := stub.(struct { + CCSectorLifetime time.Duration + }) + if !ok { + t.Fatal("failed to cast fakeConfig") + } + + return sealiface.Config{ + CommittedCapacitySectorLifetime: castStub.CCSectorLifetime, + }, nil + } +} + func (f *fakeChain) StateNetworkVersion(ctx context.Context, tok sealing.TipSetToken) (network.Version, error) { return build.NewestNetworkVersion, nil } @@ -38,21 +60,29 @@ 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, t) + 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 + 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 TestBasicPolicyMostConstrictiveSchedule(t *testing.T) { + cfg := fakeConfigGetter(nil, t) + 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{ @@ -76,7 +106,7 @@ func TestBasicPolicyMostConstrictiveSchedule(t *testing.T) { DealID: abi.DealID(43), DealSchedule: api.DealSchedule{ StartEpoch: abi.ChainEpoch(80), - EndEpoch: abi.ChainEpoch(100), + EndEpoch: longestDealEpochEnd, }, }, }, @@ -85,13 +115,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, t) policy := sealing.NewBasicPreCommitPolicy(&fakeChain{ h: abi.ChainEpoch(55), - }, 100, 0) + }, cfg, 0, 0) pieces := []sealing.Piece{ { @@ -112,13 +144,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, t) policy := sealing.NewBasicPreCommitPolicy(&fakeChain{ h: abi.ChainEpoch(55), - }, 100, 11) + }, cfg, 11, 0) pieces := []sealing.Piece{ { @@ -146,5 +179,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)) } diff --git a/storage/miner.go b/storage/miner.go index c38671c8c..59c64eb41 100644 --- a/storage/miner.go +++ b/storage/miner.go @@ -180,9 +180,10 @@ func (m *Miner) Run(ctx context.Context) error { // Instantiate a precommit policy. 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, cfg, 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) { From 123a976f6247ec84e3bb3ab0ddaa9fe7d1a6532a Mon Sep 17 00:00:00 2001 From: Mike Greenberg Date: Thu, 22 Jul 2021 14:54:52 -0400 Subject: [PATCH 04/17] chore: Add unit test for custom CC lifetime value expiration --- .../storage-sealing/precommit_policy_test.go | 44 +++++++++++++------ 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/extern/storage-sealing/precommit_policy_test.go b/extern/storage-sealing/precommit_policy_test.go index aa56f1e6f..7c92cd061 100644 --- a/extern/storage-sealing/precommit_policy_test.go +++ b/extern/storage-sealing/precommit_policy_test.go @@ -8,6 +8,7 @@ import ( "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" @@ -25,21 +26,18 @@ type fakeChain struct { h abi.ChainEpoch } -func fakeConfigGetter(stub interface{}, t *testing.T) sealing.GetSealingConfigFunc { +type fakeConfigStub struct { + CCSectorLifetime time.Duration +} + +func fakeConfigGetter(stub *fakeConfigStub) sealing.GetSealingConfigFunc { return func() (sealiface.Config, error) { if stub == nil { return sealiface.Config{}, nil } - castStub, ok := stub.(struct { - CCSectorLifetime time.Duration - }) - if !ok { - t.Fatal("failed to cast fakeConfig") - } - return sealiface.Config{ - CommittedCapacitySectorLifetime: castStub.CCSectorLifetime, + CommittedCapacitySectorLifetime: stub.CCSectorLifetime, }, nil } } @@ -60,7 +58,7 @@ func fakePieceCid(t *testing.T) cid.Cid { } func TestBasicPolicyEmptySector(t *testing.T) { - cfg := fakeConfigGetter(nil, t) + cfg := fakeConfigGetter(nil) h := abi.ChainEpoch(55) pBoundary := abi.ChainEpoch(0) pBuffer := abi.ChainEpoch(2) @@ -76,8 +74,28 @@ func TestBasicPolicyEmptySector(t *testing.T) { assert.Equal(t, int(expected), int(exp)) } +func TestCustomCCSectorConfig(t *testing.T) { + customLifetime := 200 * 24 * time.Hour + customLifetimeEpochs := abi.ChainEpoch(int64(customLifetime.Truncate(builtin.EpochDurationSeconds).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()) + + require.NoError(t, err) + + // 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, t) + cfg := fakeConfigGetter(nil) pPeriod := abi.ChainEpoch(11) policy := sealing.NewBasicPreCommitPolicy(&fakeChain{ h: abi.ChainEpoch(55), @@ -120,7 +138,7 @@ func TestBasicPolicyMostConstrictiveSchedule(t *testing.T) { } func TestBasicPolicyIgnoresExistingScheduleIfExpired(t *testing.T) { - cfg := fakeConfigGetter(nil, t) + cfg := fakeConfigGetter(nil) policy := sealing.NewBasicPreCommitPolicy(&fakeChain{ h: abi.ChainEpoch(55), }, cfg, 0, 0) @@ -148,7 +166,7 @@ func TestBasicPolicyIgnoresExistingScheduleIfExpired(t *testing.T) { } func TestMissingDealIsIgnored(t *testing.T) { - cfg := fakeConfigGetter(nil, t) + cfg := fakeConfigGetter(nil) policy := sealing.NewBasicPreCommitPolicy(&fakeChain{ h: abi.ChainEpoch(55), }, cfg, 11, 0) From 3829d6bd9adb22e8ac42f15b7c54e4440308c793 Mon Sep 17 00:00:00 2001 From: Mike Greenberg Date: Thu, 22 Jul 2021 15:05:03 -0400 Subject: [PATCH 05/17] fix: Remove actor method from autogen source; Move inline to pkg --- chain/actors/policy/policy.go | 4 ---- extern/storage-sealing/precommit_policy.go | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/chain/actors/policy/policy.go b/chain/actors/policy/policy.go index 06db09ea8..c06c85d38 100644 --- a/chain/actors/policy/policy.go +++ b/chain/actors/policy/policy.go @@ -301,10 +301,6 @@ func GetWinningPoStSectorSetLookback(nwVer network.Version) abi.ChainEpoch { return ChainFinality } -func GetMinSectorExpiration() abi.ChainEpoch { - return miner5.MinSectorExpiration -} - func GetMaxSectorExpirationExtension() abi.ChainEpoch { return miner5.MaxSectorExpirationExtension } diff --git a/extern/storage-sealing/precommit_policy.go b/extern/storage-sealing/precommit_policy.go index 6d1fddc47..3856fd548 100644 --- a/extern/storage-sealing/precommit_policy.go +++ b/extern/storage-sealing/precommit_policy.go @@ -110,7 +110,7 @@ func (p *BasicPreCommitPolicy) getCCSectorLifetime() (abi.ChainEpoch, error) { ccLifetimeEpochs = policy.GetMaxSectorExpirationExtension() } - if minExpiration := policy.GetMinSectorExpiration(); ccLifetimeEpochs < minExpiration { + 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 } From 41bce7925a1852d2eba72b72357ec5d342402cb0 Mon Sep 17 00:00:00 2001 From: Mike Greenberg Date: Fri, 23 Jul 2021 20:12:30 -0400 Subject: [PATCH 06/17] fix: Remove unnecessary Truncate --- extern/storage-sealing/precommit_policy.go | 2 +- extern/storage-sealing/precommit_policy_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/extern/storage-sealing/precommit_policy.go b/extern/storage-sealing/precommit_policy.go index 3856fd548..c911ccc8c 100644 --- a/extern/storage-sealing/precommit_policy.go +++ b/extern/storage-sealing/precommit_policy.go @@ -104,7 +104,7 @@ func (p *BasicPreCommitPolicy) getCCSectorLifetime() (abi.ChainEpoch, error) { return 0, xerrors.Errorf("sealing config load error: %w", err) } - var ccLifetimeEpochs = abi.ChainEpoch(uint64(c.CommittedCapacitySectorLifetime.Truncate(builtin.EpochDurationSeconds).Seconds()) / builtin.EpochDurationSeconds) + 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() diff --git a/extern/storage-sealing/precommit_policy_test.go b/extern/storage-sealing/precommit_policy_test.go index 7c92cd061..7f5aff0df 100644 --- a/extern/storage-sealing/precommit_policy_test.go +++ b/extern/storage-sealing/precommit_policy_test.go @@ -76,7 +76,7 @@ func TestBasicPolicyEmptySector(t *testing.T) { func TestCustomCCSectorConfig(t *testing.T) { customLifetime := 200 * 24 * time.Hour - customLifetimeEpochs := abi.ChainEpoch(int64(customLifetime.Truncate(builtin.EpochDurationSeconds).Seconds()) / builtin.EpochDurationSeconds) + customLifetimeEpochs := abi.ChainEpoch(int64(customLifetime.Seconds()) / builtin.EpochDurationSeconds) cfgStub := fakeConfigStub{CCSectorLifetime: customLifetime} cfg := fakeConfigGetter(&cfgStub) h := abi.ChainEpoch(55) From e68c59f984b67bacd234a3d27393c96894f7e8d8 Mon Sep 17 00:00:00 2001 From: Mike Greenberg Date: Fri, 23 Jul 2021 21:05:50 -0400 Subject: [PATCH 07/17] fix: Update node config docs --- node/config/doc_gen.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/node/config/doc_gen.go b/node/config/doc_gen.go index ea68dc344..5163ac409 100644 --- a/node/config/doc_gen.go +++ b/node/config/doc_gen.go @@ -562,6 +562,14 @@ Note that setting this number too high in relation to deal ingestion rate may re Comment: `Upper bound on how many sectors can be sealing at the same time when creating new sectors with deals (0 = unlimited)`, }, + { + Name: "CommittedCapacitySectorLifetime", + Type: "Duration", + + Comment: `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`, + }, { Name: "WaitDealsDelay", Type: "Duration", From ac8937245c41259af1caddc21aebcd08bbcca557 Mon Sep 17 00:00:00 2001 From: hunjixin <1084400399@qq.com> Date: Tue, 27 Jul 2021 14:51:45 +0800 Subject: [PATCH 08/17] fix ticket check --- extern/storage-sealing/checks.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/extern/storage-sealing/checks.go b/extern/storage-sealing/checks.go index 5ba23026d..115eedea5 100644 --- a/extern/storage-sealing/checks.go +++ b/extern/storage-sealing/checks.go @@ -93,27 +93,29 @@ func checkPrecommit(ctx context.Context, maddr address.Address, si SectorInfo, t return &ErrBadCommD{xerrors.Errorf("on chain CommD differs from sector: %s != %s", commD, si.CommD)} } - ticketEarliest := height - policy.MaxPreCommitRandomnessLookback - - if si.TicketEpoch < ticketEarliest { - return &ErrExpiredTicket{xerrors.Errorf("ticket expired: seal height: %d, head: %d", si.TicketEpoch+policy.SealRandomnessLookback, height)} - } - pci, err := api.StateSectorPreCommitInfo(ctx, maddr, si.SectorNumber, tok) if err != nil { if err == ErrSectorAllocated { + //committed P2 message but commit C2 message too late, pci should be null in this case return &ErrSectorNumberAllocated{err} } return &ErrApi{xerrors.Errorf("getting precommit info: %w", err)} } if pci != nil { + // committed P2 message if pci.Info.SealRandEpoch != si.TicketEpoch { return &ErrBadTicket{xerrors.Errorf("bad ticket epoch: %d != %d", pci.Info.SealRandEpoch, si.TicketEpoch)} } return &ErrPrecommitOnChain{xerrors.Errorf("precommit already on chain")} } + //never commit P2 message before, check ticket expiration + ticketEarliest := height - policy.MaxPreCommitRandomnessLookback + + if si.TicketEpoch < ticketEarliest { + return &ErrExpiredTicket{xerrors.Errorf("ticket expired: seal height: %d, head: %d", si.TicketEpoch+policy.SealRandomnessLookback, height)} + } return nil } From 66e793531d6f6c0a84df7e01c0a71596bd541171 Mon Sep 17 00:00:00 2001 From: vyzo Date: Wed, 28 Jul 2021 15:59:16 +0300 Subject: [PATCH 09/17] update go-libp2p-pubsub to v0.5.3 --- go.mod | 22 ++++----- go.sum | 146 ++++++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 119 insertions(+), 49 deletions(-) diff --git a/go.mod b/go.mod index 5f968f6e0..080403c20 100644 --- a/go.mod +++ b/go.mod @@ -56,7 +56,7 @@ require ( github.com/gdamore/tcell/v2 v2.2.0 github.com/go-kit/kit v0.10.0 github.com/go-ole/go-ole v1.2.4 // indirect - github.com/golang/mock v1.5.0 + github.com/golang/mock v1.6.0 github.com/google/uuid v1.1.2 github.com/gorilla/mux v1.7.4 github.com/gorilla/websocket v1.4.2 @@ -105,17 +105,17 @@ require ( github.com/libp2p/go-eventbus v0.2.1 github.com/libp2p/go-libp2p v0.14.2 github.com/libp2p/go-libp2p-connmgr v0.2.4 - github.com/libp2p/go-libp2p-core v0.8.5 - github.com/libp2p/go-libp2p-discovery v0.5.0 + github.com/libp2p/go-libp2p-core v0.8.6 + github.com/libp2p/go-libp2p-discovery v0.5.1 github.com/libp2p/go-libp2p-kad-dht v0.11.0 github.com/libp2p/go-libp2p-mplex v0.4.1 github.com/libp2p/go-libp2p-noise v0.2.0 - github.com/libp2p/go-libp2p-peerstore v0.2.7 - github.com/libp2p/go-libp2p-pubsub v0.5.0 - github.com/libp2p/go-libp2p-quic-transport v0.10.0 + github.com/libp2p/go-libp2p-peerstore v0.2.8 + github.com/libp2p/go-libp2p-pubsub v0.5.3 + github.com/libp2p/go-libp2p-quic-transport v0.11.2 github.com/libp2p/go-libp2p-record v0.1.3 github.com/libp2p/go-libp2p-routing-helpers v0.2.3 - github.com/libp2p/go-libp2p-swarm v0.5.0 + github.com/libp2p/go-libp2p-swarm v0.5.3 github.com/libp2p/go-libp2p-tls v0.1.3 github.com/libp2p/go-libp2p-yamux v0.5.4 github.com/libp2p/go-maddr-filter v0.1.0 @@ -124,14 +124,14 @@ require ( github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 github.com/mitchellh/go-homedir v1.1.0 github.com/multiformats/go-base32 v0.0.3 - github.com/multiformats/go-multiaddr v0.3.1 + github.com/multiformats/go-multiaddr v0.3.3 github.com/multiformats/go-multiaddr-dns v0.3.1 github.com/multiformats/go-multibase v0.0.3 github.com/multiformats/go-multihash v0.0.15 github.com/open-rpc/meta-schema v0.0.0-20201029221707-1b72ef2ea333 github.com/opentracing/opentracing-go v1.2.0 github.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a - github.com/prometheus/client_golang v1.6.0 + github.com/prometheus/client_golang v1.10.0 github.com/raulk/clock v1.1.0 github.com/raulk/go-watchdog v1.0.1 github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25 @@ -150,9 +150,9 @@ require ( go.uber.org/fx v1.9.0 go.uber.org/multierr v1.6.0 go.uber.org/zap v1.16.0 - golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6 + golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c - golang.org/x/sys v0.0.0-20210510120138-977fb7262007 + golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 golang.org/x/time v0.0.0-20191024005414-555d28b269f0 golang.org/x/tools v0.1.5 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 diff --git a/go.sum b/go.sum index b22f3dc15..69dabfd3b 100644 --- a/go.sum +++ b/go.sum @@ -27,8 +27,9 @@ dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1 dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= -github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9 h1:HD8gA2tkByhMAwYaFAX9w2l7vxvBQ5NMoxDrkhqhtn4= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= +github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M= +github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= @@ -199,8 +200,9 @@ github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e/go.mod h1: github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= github.com/dgraph-io/badger v1.6.0-rc1/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= -github.com/dgraph-io/badger v1.6.1 h1:w9pSFNSdq/JPM1N12Fz/F/bzo993Is1W+Q7HjPzi7yg= github.com/dgraph-io/badger v1.6.1/go.mod h1:FRmFw3uxvcpa8zG3Rxs0th+hCLIuaQg8HlNV5bjgnuU= +github.com/dgraph-io/badger v1.6.2 h1:mNw0qs90GVgGGWylh0umH5iag1j6n/PeJtNvL6KY/x8= +github.com/dgraph-io/badger v1.6.2/go.mod h1:JW2yswe3V058sS0kZ2h/AXeDSqFjxnZcRrVH//y2UQE= github.com/dgraph-io/badger/v2 v2.0.3/go.mod h1:3KY8+bsP8wI0OEnQJAKpd4wIJW/Mm32yw2j/9FUVnIM= github.com/dgraph-io/badger/v2 v2.2007.2 h1:EjjK0KqwaFMlPin1ajhP943VPENHJdEz1KLIegjaI3k= github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= @@ -397,6 +399,8 @@ github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/godbus/dbus v0.0.0-20190402143921-271e53dc4968 h1:s+PDl6lozQ+dEUtUtQnO7+A2iPG3sK1pI4liU+jxn90= github.com/godbus/dbus v0.0.0-20190402143921-271e53dc4968/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME= @@ -429,8 +433,8 @@ github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFU github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -443,8 +447,10 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.2-0.20190904063534-ff6b7dc882cf h1:gFVkHXmVAhEbxZVDln5V9GKrLaluNoFHDbrZwAWZgws= @@ -457,8 +463,10 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3 h1:x95R7cp+rSeeqAMI2knLtQ0DKlaBhv2NrtrOvafPHRo= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -609,8 +617,9 @@ github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjv github.com/ipfs/go-ds-badger v0.0.5/go.mod h1:g5AuuCGmr7efyzQhLL8MzwqcauPojGPUaHzfGTzuE3s= github.com/ipfs/go-ds-badger v0.0.7/go.mod h1:qt0/fWzZDoPW6jpQeqUjR5kBfhDNB65jd9YlmAvpQBk= github.com/ipfs/go-ds-badger v0.2.1/go.mod h1:Tx7l3aTph3FMFrRS838dcSJh+jjA7cX9DrGVwx/NOwE= -github.com/ipfs/go-ds-badger v0.2.3 h1:J27YvAcpuA5IvZUbeBxOcQgqnYHUPxoygc6QxxkodZ4= github.com/ipfs/go-ds-badger v0.2.3/go.mod h1:pEYw0rgg3FIrywKKnL+Snr+w/LjJZVMTBRn4FS6UHUk= +github.com/ipfs/go-ds-badger v0.2.7 h1:ju5REfIm+v+wgVnQ19xGLYPHYHbYLR6qJfmMbCDSK1I= +github.com/ipfs/go-ds-badger v0.2.7/go.mod h1:02rnztVKA4aZwDuaRPTf8mpqcKmXP7mLl6JPxd14JHA= github.com/ipfs/go-ds-badger2 v0.1.0/go.mod h1:pbR1p817OZbdId9EvLOhKBgUVTM3BMCSTan78lDDVaw= github.com/ipfs/go-ds-badger2 v0.1.1-0.20200708190120-187fc06f714e h1:Xi1nil8K2lBOorBS6Ys7+hmUCzH8fr3U9ipdL/IrcEI= github.com/ipfs/go-ds-badger2 v0.1.1-0.20200708190120-187fc06f714e/go.mod h1:lJnws7amT9Ehqzta0gwMrRsURU04caT0iRPr1W8AsOU= @@ -698,8 +707,9 @@ github.com/ipfs/go-log v1.0.0/go.mod h1:JO7RzlMK6rA+CIxFMLOuB6Wf5b81GDiKElL7UPSI github.com/ipfs/go-log v1.0.1/go.mod h1:HuWlQttfN6FWNHRhlY5yMk/lW7evQC0HHGOxEwMRR8I= github.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk= github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A= -github.com/ipfs/go-log v1.0.4 h1:6nLQdX4W8P9yZZFH7mO+X/PzjN8Laozm/lMJ6esdgzY= github.com/ipfs/go-log v1.0.4/go.mod h1:oDCg2FkjogeFOhqqb+N39l2RpTNPL6F/StPkB3kPgcs= +github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8= +github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JPtIo= github.com/ipfs/go-log/v2 v2.0.1/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= github.com/ipfs/go-log/v2 v2.0.2/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= github.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= @@ -800,12 +810,14 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kabukky/httpscerts v0.0.0-20150320125433-617593d7dcb3/go.mod h1:BYpt4ufZiIGv2nXn4gMxnfKV306n3mWXgNu/d2TqdTU= github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= @@ -819,6 +831,8 @@ github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQL github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/klauspost/compress v1.11.7 h1:0hzRabrMN4tSTvMfnL3SCv1ZGeAP23ynzodBgaHeMeg= +github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/cpuid/v2 v2.0.4 h1:g0I61F2K2DjRHz1cnxlkNSBIaePVoJIjjnHui8QHbiw= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -838,8 +852,9 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lib/pq v1.7.0 h1:h93mCPfUSkaul3Ka/VG8uZdmW1uMHDGxzu0NWHuJmHY= github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ= -github.com/libp2p/go-addr-util v0.0.2 h1:7cWK5cdA5x72jX0g8iLrQWm5TRJZ6CzGdPEhWj7plWU= github.com/libp2p/go-addr-util v0.0.2/go.mod h1:Ecd6Fb3yIuLzq4bD7VcywcVSBtefcAwnUISBM3WG15E= +github.com/libp2p/go-addr-util v0.1.0 h1:acKsntI33w2bTU7tC9a0SaPimJGfSI0bFKC18ChxeVI= +github.com/libp2p/go-addr-util v0.1.0/go.mod h1:6I3ZYuFr2O/9D+SoyM0zEw0EF3YkldtTX406BpdQMqw= github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= @@ -940,9 +955,9 @@ github.com/libp2p/go-libp2p-core v0.7.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJB github.com/libp2p/go-libp2p-core v0.8.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= github.com/libp2p/go-libp2p-core v0.8.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= github.com/libp2p/go-libp2p-core v0.8.2/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-core v0.8.3/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-core v0.8.5 h1:aEgbIcPGsKy6zYcC+5AJivYFedhYa4sW7mIpWpUaLKw= github.com/libp2p/go-libp2p-core v0.8.5/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= +github.com/libp2p/go-libp2p-core v0.8.6 h1:3S8g006qG6Tjpj1JdRK2S+TWc2DJQKX/RG9fdLeiLSU= +github.com/libp2p/go-libp2p-core v0.8.6/go.mod h1:dgHr0l0hIKfWpGpqAMbpo19pen9wJfdCGv51mTmdpmM= github.com/libp2p/go-libp2p-crypto v0.0.1/go.mod h1:yJkNyDmO341d5wwXxDUGO0LykUVT72ImHNUqh5D/dBE= github.com/libp2p/go-libp2p-crypto v0.0.2/go.mod h1:eETI5OUfBnvARGOHrJz2eWNyTUxEGZnBxMcbUjfIj4I= github.com/libp2p/go-libp2p-crypto v0.1.0 h1:k9MFy+o2zGDNGsaoZl0MA3iZ75qXxr9OOoAZF+sD5OQ= @@ -954,8 +969,9 @@ github.com/libp2p/go-libp2p-discovery v0.1.0/go.mod h1:4F/x+aldVHjHDHuX85x1zWoFT github.com/libp2p/go-libp2p-discovery v0.2.0/go.mod h1:s4VGaxYMbw4+4+tsoQTqh7wfxg97AEdo4GYBt6BadWg= github.com/libp2p/go-libp2p-discovery v0.3.0/go.mod h1:o03drFnz9BVAZdzC/QUQ+NeQOu38Fu7LJGEOK2gQltw= github.com/libp2p/go-libp2p-discovery v0.4.0/go.mod h1:bZ0aJSrFc/eX2llP0ryhb1kpgkPyTo23SJ5b7UQCMh4= -github.com/libp2p/go-libp2p-discovery v0.5.0 h1:Qfl+e5+lfDgwdrXdu4YNCWyEo3fWuP+WgN9mN0iWviQ= github.com/libp2p/go-libp2p-discovery v0.5.0/go.mod h1:+srtPIU9gDaBNu//UHvcdliKBIcr4SfDcm0/PfPJLug= +github.com/libp2p/go-libp2p-discovery v0.5.1 h1:CJylx+h2+4+s68GvrM4pGNyfNhOYviWBPtVv5PA7sfo= +github.com/libp2p/go-libp2p-discovery v0.5.1/go.mod h1:+srtPIU9gDaBNu//UHvcdliKBIcr4SfDcm0/PfPJLug= github.com/libp2p/go-libp2p-host v0.0.1/go.mod h1:qWd+H1yuU0m5CwzAkvbSjqKairayEHdR5MMl7Cwa7Go= github.com/libp2p/go-libp2p-host v0.0.3/go.mod h1:Y/qPyA6C8j2coYyos1dfRm0I8+nvd4TGrDGt4tA7JR8= github.com/libp2p/go-libp2p-interface-connmgr v0.0.1/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k= @@ -1009,20 +1025,22 @@ github.com/libp2p/go-libp2p-peerstore v0.2.2/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRj github.com/libp2p/go-libp2p-peerstore v0.2.3/go.mod h1:K8ljLdFn590GMttg/luh4caB/3g0vKuY01psze0upRw= github.com/libp2p/go-libp2p-peerstore v0.2.4/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= github.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= -github.com/libp2p/go-libp2p-peerstore v0.2.7 h1:83JoLxyR9OYTnNfB5vvFqvMUv/xDNa6NoPHnENhBsGw= github.com/libp2p/go-libp2p-peerstore v0.2.7/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= +github.com/libp2p/go-libp2p-peerstore v0.2.8 h1:nJghUlUkFVvyk7ccsM67oFA6kqUkwyCM1G4WPVMCWYA= +github.com/libp2p/go-libp2p-peerstore v0.2.8/go.mod h1:gGiPlXdz7mIHd2vfAsHzBNAMqSDkt2UBFwgcITgw1lA= github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k= github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA= github.com/libp2p/go-libp2p-protocol v0.0.1/go.mod h1:Af9n4PiruirSDjHycM1QuiMi/1VZNHYcK8cLgFJLZ4s= github.com/libp2p/go-libp2p-protocol v0.1.0/go.mod h1:KQPHpAabB57XQxGrXCNvbL6UEXfQqUgC/1adR2Xtflk= github.com/libp2p/go-libp2p-pubsub v0.1.1/go.mod h1:ZwlKzRSe1eGvSIdU5bD7+8RZN/Uzw0t1Bp9R1znpR/Q= github.com/libp2p/go-libp2p-pubsub v0.3.2-0.20200527132641-c0712c6e92cf/go.mod h1:TxPOBuo1FPdsTjFnv+FGZbNbWYsp74Culx+4ViQpato= -github.com/libp2p/go-libp2p-pubsub v0.5.0 h1:OzcIuCWyJpOrWH0PTOfvxTzqFur4tiXpY5jXC8OxjyE= -github.com/libp2p/go-libp2p-pubsub v0.5.0/go.mod h1:MKnrsQkFgPcrQs1KVmOXy6Uz2RDQ1xO7dQo/P0Ba+ig= +github.com/libp2p/go-libp2p-pubsub v0.5.3 h1:XCn5xvgA/AKpbbaeqbomfKtQCbT9QsU39tYsVj0IndQ= +github.com/libp2p/go-libp2p-pubsub v0.5.3/go.mod h1:gVOzwebXVdSMDQBTfH8ACO5EJ4SQrvsHqCmYsCZpD0E= github.com/libp2p/go-libp2p-quic-transport v0.1.1/go.mod h1:wqG/jzhF3Pu2NrhJEvE+IE0NTHNXslOPn9JQzyCAxzU= github.com/libp2p/go-libp2p-quic-transport v0.5.0/go.mod h1:IEcuC5MLxvZ5KuHKjRu+dr3LjCT1Be3rcD/4d8JrX8M= -github.com/libp2p/go-libp2p-quic-transport v0.10.0 h1:koDCbWD9CCHwcHZL3/WEvP2A+e/o5/W5L3QS/2SPMA0= github.com/libp2p/go-libp2p-quic-transport v0.10.0/go.mod h1:RfJbZ8IqXIhxBRm5hqUEJqjiiY8xmEuq3HUDS993MkA= +github.com/libp2p/go-libp2p-quic-transport v0.11.2 h1:p1YQDZRHH4Cv2LPtHubqlQ9ggz4CKng/REZuXZbZMhM= +github.com/libp2p/go-libp2p-quic-transport v0.11.2/go.mod h1:wlanzKtIh6pHrq+0U3p3DY9PJfGqxMgPaGKaK5LifwQ= github.com/libp2p/go-libp2p-record v0.0.1/go.mod h1:grzqg263Rug/sRex85QrDOLntdFAymLDLm7lxMgU79Q= github.com/libp2p/go-libp2p-record v0.1.0/go.mod h1:ujNc8iuE5dlKWVy6wuL6dd58t0n7xI4hAIl8pE6wu5Q= github.com/libp2p/go-libp2p-record v0.1.1/go.mod h1:VRgKajOyMVgP/F0L5g3kH7SVskp17vFi2xheb5uMJtg= @@ -1050,9 +1068,9 @@ github.com/libp2p/go-libp2p-swarm v0.2.7/go.mod h1:ZSJ0Q+oq/B1JgfPHJAT2HTall+xYR github.com/libp2p/go-libp2p-swarm v0.2.8/go.mod h1:JQKMGSth4SMqonruY0a8yjlPVIkb0mdNSwckW7OYziM= github.com/libp2p/go-libp2p-swarm v0.3.0/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk= github.com/libp2p/go-libp2p-swarm v0.3.1/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk= -github.com/libp2p/go-libp2p-swarm v0.4.3/go.mod h1:mmxP1pGBSc1Arw4F5DIjcpjFAmsRzA1KADuMtMuCT4g= -github.com/libp2p/go-libp2p-swarm v0.5.0 h1:HIK0z3Eqoo8ugmN8YqWAhD2RORgR+3iNXYG4U2PFd1E= github.com/libp2p/go-libp2p-swarm v0.5.0/go.mod h1:sU9i6BoHE0Ve5SKz3y9WfKrh8dUat6JknzUehFx8xW4= +github.com/libp2p/go-libp2p-swarm v0.5.3 h1:hsYaD/y6+kZff1o1Mc56NcuwSg80lIphTS/zDk3mO4M= +github.com/libp2p/go-libp2p-swarm v0.5.3/go.mod h1:NBn7eNW2lu568L7Ns9wdFrOhgRlkRnIDg0FLKbuu3i8= github.com/libp2p/go-libp2p-testing v0.0.1/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= @@ -1061,8 +1079,9 @@ github.com/libp2p/go-libp2p-testing v0.1.0/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eq github.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= github.com/libp2p/go-libp2p-testing v0.1.2-0.20200422005655-8775583591d8/go.mod h1:Qy8sAncLKpwXtS2dSnDOP8ktexIAHKu+J+pnZOFZLTc= github.com/libp2p/go-libp2p-testing v0.3.0/go.mod h1:efZkql4UZ7OVsEfaxNHZPzIehtsBXMrXnCfJIgDti5g= -github.com/libp2p/go-libp2p-testing v0.4.0 h1:PrwHRi0IGqOwVQWR3xzgigSlhlLfxgfXgkHxr77EghQ= github.com/libp2p/go-libp2p-testing v0.4.0/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotlKsNSbKQ/lImlOWF0= +github.com/libp2p/go-libp2p-testing v0.4.2 h1:IOiA5mMigi+eEjf4J+B7fepDhsjtsoWA9QbsCqbNp5U= +github.com/libp2p/go-libp2p-testing v0.4.2/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotlKsNSbKQ/lImlOWF0= github.com/libp2p/go-libp2p-tls v0.1.3 h1:twKMhMu44jQO+HgQK9X8NHO5HkeJu2QbhLzLJpa8oNM= github.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M= github.com/libp2p/go-libp2p-transport v0.0.1/go.mod h1:UzbUs9X+PHOSw7S3ZmeOxfnwaQY5vGDzZmKPod3N3tk= @@ -1073,8 +1092,9 @@ github.com/libp2p/go-libp2p-transport-upgrader v0.0.4/go.mod h1:RGq+tupk+oj7PzL2 github.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA= github.com/libp2p/go-libp2p-transport-upgrader v0.2.0/go.mod h1:mQcrHj4asu6ArfSoMuyojOdjx73Q47cYD7s5+gZOlns= github.com/libp2p/go-libp2p-transport-upgrader v0.3.0/go.mod h1:i+SKzbRnvXdVbU3D1dwydnTmKRPXiAR/fyvi1dXuL4o= -github.com/libp2p/go-libp2p-transport-upgrader v0.4.2 h1:4JsnbfJzgZeRS9AWN7B9dPqn/LY/HoQTlO9gtdJTIYM= github.com/libp2p/go-libp2p-transport-upgrader v0.4.2/go.mod h1:NR8ne1VwfreD5VIWIU62Agt/J18ekORFU/j1i2y8zvk= +github.com/libp2p/go-libp2p-transport-upgrader v0.4.6 h1:SHt3g0FslnqIkEWF25YOB8UCOCTpGAVvHRWQYJ+veiI= +github.com/libp2p/go-libp2p-transport-upgrader v0.4.6/go.mod h1:JE0WQuQdy+uLZ5zOaI3Nw9dWGYJIA7mywEtP2lMvnyk= github.com/libp2p/go-libp2p-yamux v0.5.1 h1:sX4WQPHMhRxJE5UZTfjEuBvlQWXB5Bo3A2JK9ZJ9EM0= github.com/libp2p/go-libp2p-yamux v0.5.1/go.mod h1:dowuvDu8CRWmr0iqySMiSxK+W0iL5cMVO9S94Y6gkv4= github.com/libp2p/go-maddr-filter v0.0.1/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= @@ -1103,6 +1123,7 @@ github.com/libp2p/go-nat v0.0.5 h1:qxnwkco8RLKqVh1NmjQ+tJ8p8khNLFxuElYG/TwqW4Q= github.com/libp2p/go-nat v0.0.5/go.mod h1:B7NxsVNPZmRLvMOwiEO1scOSyjA56zxYAGv1yQgRkEU= github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= github.com/libp2p/go-netroute v0.1.3/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= +github.com/libp2p/go-netroute v0.1.5/go.mod h1:V1SR3AaECRkEQCoFFzYwVYWvYIEtlxx89+O3qcpCl4A= github.com/libp2p/go-netroute v0.1.6 h1:ruPJStbYyXVYGQ81uzEDzuvbYRLKRrLvTYd33yomC38= github.com/libp2p/go-netroute v0.1.6/go.mod h1:AqhkMh0VuWmfgtxKPp3Oc1LdU5QSWS7wl0QLhSZqXxQ= github.com/libp2p/go-openssl v0.0.2/go.mod h1:v8Zw2ijCSWBQi8Pq5GAixw6DbFfa9u6VIYDXnvOXkc0= @@ -1117,8 +1138,9 @@ github.com/libp2p/go-reuseport v0.0.2/go.mod h1:SPD+5RwGC7rcnzngoYC86GjPzjSywuQy github.com/libp2p/go-reuseport-transport v0.0.1/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs= github.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs= github.com/libp2p/go-reuseport-transport v0.0.3/go.mod h1:Spv+MPft1exxARzP2Sruj2Wb5JSyHNncjf1Oi2dEbzM= -github.com/libp2p/go-reuseport-transport v0.0.4 h1:OZGz0RB620QDGpv300n1zaOcKGGAoGVf8h9txtt/1uM= github.com/libp2p/go-reuseport-transport v0.0.4/go.mod h1:trPa7r/7TJK/d+0hdBLOCGvpQQVOU74OXbNCIMkufGw= +github.com/libp2p/go-reuseport-transport v0.0.5 h1:lJzi+vSYbyJj2faPKLxNGWEIBcaV/uJmyvsUxXy2mLw= +github.com/libp2p/go-reuseport-transport v0.0.5/go.mod h1:TC62hhPc8qs5c/RoXDZG6YmjK+/YWUPC0yYmeUecbjc= github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= github.com/libp2p/go-sockaddr v0.1.0/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= github.com/libp2p/go-sockaddr v0.1.1 h1:yD80l2ZOdGksnOyHrhxDdTDFrf7Oy+v3FMVArIRgZxQ= @@ -1134,8 +1156,9 @@ github.com/libp2p/go-tcp-transport v0.0.4/go.mod h1:+E8HvC8ezEVOxIo3V5vCK9l1y/19 github.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc= github.com/libp2p/go-tcp-transport v0.1.1/go.mod h1:3HzGvLbx6etZjnFlERyakbaYPdfjg2pWP97dFZworkY= github.com/libp2p/go-tcp-transport v0.2.0/go.mod h1:vX2U0CnWimU4h0SGSEsg++AzvBcroCGYw28kh94oLe0= -github.com/libp2p/go-tcp-transport v0.2.1 h1:ExZiVQV+h+qL16fzCWtd1HSzPsqWottJ8KXwWaVi8Ns= github.com/libp2p/go-tcp-transport v0.2.1/go.mod h1:zskiJ70MEfWz2MKxvFB/Pv+tPIB1PpPUrHIWQ8aFw7M= +github.com/libp2p/go-tcp-transport v0.2.7 h1:Z8Kc/Kb8tD84WiaH55xAlaEnkqzrp88jSEySCKV4+gg= +github.com/libp2p/go-tcp-transport v0.2.7/go.mod h1:lue9p1b3VmZj1MhhEGB/etmvF/nBQ0X9CW2DutBT3MM= github.com/libp2p/go-testutil v0.0.1/go.mod h1:iAcJc/DKJQanJ5ws2V+u5ywdL2n12X1WbbEG+Jjy69I= github.com/libp2p/go-testutil v0.1.0/go.mod h1:81b2n5HypcVyrCg/MJx4Wgfp/VHojytjVe/gLzZ2Ehc= github.com/libp2p/go-ws-transport v0.0.1/go.mod h1:p3bKjDWHEgtuKKj+2OdPYs5dAPIjtpQGHF2tJfGz7Ww= @@ -1156,8 +1179,9 @@ github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-b github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lucas-clemente/quic-go v0.11.2/go.mod h1:PpMmPfPKO9nKJ/psF49ESTAGQSdfXxlg1otPbEB2nOw= github.com/lucas-clemente/quic-go v0.16.0/go.mod h1:I0+fcNTdb9eS1ZcjQZbDVPGchJ86chcIxPALn9lEJqE= -github.com/lucas-clemente/quic-go v0.19.3 h1:eCDQqvGBB+kCTkA0XrAFtNe81FMa0/fn4QSoeAbmiF4= github.com/lucas-clemente/quic-go v0.19.3/go.mod h1:ADXpNbTQjq1hIzCpB+y/k5iz4n4z4IwqoLb94Kh5Hu8= +github.com/lucas-clemente/quic-go v0.21.2 h1:8LqqL7nBQFDUINadW0fHV/xSaCQJgmJC0Gv+qUnjd78= +github.com/lucas-clemente/quic-go v0.21.2/go.mod h1:vF5M1XqhBAHgbjKcJOXY3JZz3GP0T3FQhz/uyOUS38Q= github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac= github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lufia/iostat v1.1.0/go.mod h1:rEPNA0xXgjHQjuI5Cy05sLlS2oRcSlWHRLrvh/AQ+Pg= @@ -1175,10 +1199,17 @@ github.com/marten-seemann/qpack v0.1.0/go.mod h1:LFt1NU/Ptjip0C2CPkhimBz5CGE3WGD github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc= github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= github.com/marten-seemann/qtls v0.9.1/go.mod h1:T1MmAdDPyISzxlK6kjRr0pcZFBVd1OZbBb/j3cvzHhk= -github.com/marten-seemann/qtls v0.10.0 h1:ECsuYUKalRL240rRD4Ri33ISb7kAQ3qGDlrrl55b2pc= github.com/marten-seemann/qtls v0.10.0/go.mod h1:UvMd1oaYDACI99/oZUYLzMCkBXQVT0aGm99sJhbT8hs= -github.com/marten-seemann/qtls-go1-15 v0.1.1 h1:LIH6K34bPVttyXnUWixk0bzH6/N07VxbSabxn5A5gZQ= github.com/marten-seemann/qtls-go1-15 v0.1.1/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= +github.com/marten-seemann/qtls-go1-15 v0.1.4/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= +github.com/marten-seemann/qtls-go1-15 v0.1.5 h1:Ci4EIUN6Rlb+D6GmLdej/bCQ4nPYNtVXQB+xjiXE1nk= +github.com/marten-seemann/qtls-go1-15 v0.1.5/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= +github.com/marten-seemann/qtls-go1-16 v0.1.4 h1:xbHbOGGhrenVtII6Co8akhLEdrawwB2iHl5yhJRpnco= +github.com/marten-seemann/qtls-go1-16 v0.1.4/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk= +github.com/marten-seemann/qtls-go1-17 v0.1.0-rc.1 h1:/rpmWuGvceLwwWuaKPdjpR4JJEUH0tq64/I3hvzaNLM= +github.com/marten-seemann/qtls-go1-17 v0.1.0-rc.1/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8= +github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= +github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= @@ -1215,6 +1246,12 @@ github.com/miekg/dns v1.1.28/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7 github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8= +github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms= +github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUMM0I83AUIT6Hu17AWfgjzIbtrYFc= +github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b/go.mod h1:lxPUiZwKoFL8DUUmalo2yJJUCxbPKtm8OKfqr2/FTNU= +github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdnNMiD9ZejrlswWrCpBEZgWOiTrc= +github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc/go.mod h1:cGKTAVKx4SxOuR/czcZ/E2RSJ3sfHs8FpHhQ5CWMf9s= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= @@ -1256,8 +1293,9 @@ github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y9 github.com/multiformats/go-multiaddr v0.2.1/go.mod h1:s/Apk6IyxfvMjDafnhJgJ3/46z7tZ04iMk5wP4QMGGE= github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y= github.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4fJxp6ggJGteB8HQTI= -github.com/multiformats/go-multiaddr v0.3.1 h1:1bxa+W7j9wZKTZREySx1vPMs2TqrYWjVZ7zE6/XLG1I= github.com/multiformats/go-multiaddr v0.3.1/go.mod h1:uPbspcUPd5AfaP6ql3ujFY+QWzmBD8uLLL4bXW0XfGc= +github.com/multiformats/go-multiaddr v0.3.3 h1:vo2OTSAqnENB2rLk79pLtr+uhj+VAzSe3uef5q0lRSs= +github.com/multiformats/go-multiaddr v0.3.3/go.mod h1:lCKNGP1EQ1eZ35Za2wlqnabm9xQkib3fyB+nZXHLag0= github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= github.com/multiformats/go-multiaddr-dns v0.0.3/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= @@ -1305,6 +1343,7 @@ github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXS github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY= github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= @@ -1319,8 +1358,9 @@ github.com/nikkolasg/hexjson v0.0.0-20181101101858-78e39397e00c h1:5bFTChQxSKNwy github.com/nikkolasg/hexjson v0.0.0-20181101101858-78e39397e00c/go.mod h1:7qN3Y0BvzRUf4LofcoJplQL10lsFDb4PYlePTVwrP28= github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229 h1:E2B8qYyeSgv5MXpmzZXRNp8IAQ4vjxIjhpAf5hv/tAg= github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E= -github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= @@ -1330,16 +1370,19 @@ github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= -github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak= +github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/open-rpc/meta-schema v0.0.0-20201029221707-1b72ef2ea333 h1:CznVS40zms0Dj5he4ERo+fRPtO0qxUk8lA8Xu3ddet0= github.com/open-rpc/meta-schema v0.0.0-20201029221707-1b72ef2ea333/go.mod h1:Ag6rSXkHIckQmjFBCweJEEt1mrTPBv8b9W4aU/NQWfI= @@ -1390,8 +1433,11 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_golang v1.4.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= -github.com/prometheus/client_golang v1.6.0 h1:YVPodQOcK15POxhgARIvnDRVpLcuK8mglnMrWfyrw6A= github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.9.0/go.mod h1:FqZLKOZnGdFAhOK4nqGHa7D66IdsO+O441Eve7ptJDU= +github.com/prometheus/client_golang v1.10.0 h1:/o0BDeWzLWXNZ+4q5gXltUvaMpJqckTa+jTNoB+z4cg= +github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -1406,8 +1452,10 @@ github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= +github.com/prometheus/common v0.18.0 h1:WCVKW7aL6LEe1uryfI9dnEc2ZqNB1Fn0ok930v0iL1Y= +github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/node_exporter v1.0.0-rc.0.0.20200428091818-01054558c289/go.mod h1:FGbBv5OPKjch+jNUJmEQpMZytIdyW0NdBtWFcfSKusc= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -1418,8 +1466,11 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.1.0 h1:jhMy6QXfi3y2HEzFoyuCj40z4OZIIHHPtFyCMftmvKA= github.com/prometheus/procfs v0.1.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/raulk/clock v1.1.0 h1:dpb29+UKMbLqiU/jqIJptgLR1nn23HLgMY0sTCDza5Y= github.com/raulk/clock v1.1.0/go.mod h1:3MpVxdZ/ODBQDxbN+kzshf5OSZwPjtMDx6BBXBmOeY0= github.com/raulk/go-watchdog v1.0.1 h1:qgm3DIJAeb+2byneLrQJ7kvmDLGxN2vy3apXyGaDKN4= @@ -1661,8 +1712,9 @@ go.uber.org/dig v1.10.0 h1:yLmDDj9/zuDjv3gz8GQGviXMs9TfysIUMUilCpgzUJY= go.uber.org/dig v1.10.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw= go.uber.org/fx v1.9.0 h1:7OAz8ucp35AU8eydejpYG7QrbE8rLKzGhHbZlJi5LYY= go.uber.org/fx v1.9.0/go.mod h1:mFdUyAUuJ3w4jAckiKSKbldsxy1ojpAMJ+dVZg5Y0Aw= -go.uber.org/goleak v1.0.0 h1:qsup4IcBdlmsnGfqyLl4Ntn3C2XCCuKAE7DwHpScyUo= go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= @@ -1714,8 +1766,9 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf h1:B2n+Zi5QeYRDAEodEu72OS36gmTWjgpXr2+cWcBW90o= +golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/exp v0.0.0-20181106170214-d68db9428509/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1798,10 +1851,13 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201022231255-08b38378de70/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6 h1:0PC75Fz/kyMGhL0e1QnypqK2kQMqKt9csD1GnMJR+Zk= golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1819,6 +1875,7 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180202135801-37707fdb30a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1884,17 +1941,25 @@ golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200812155832-6a926be9bd1d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200926100807-9d91bd62050c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210317225723-c4fcb01b228e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 h1:yhBbb4IRs2HS9PPlAg6DMC6mUOKexJBNsLf4Z+6En1Q= +golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M= @@ -1953,7 +2018,9 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200711155855-7342f9734a7d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200827010519-17fd2f27a9e3/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20201112185108-eeaa07dd7696/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2035,8 +2102,10 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -2063,8 +2132,9 @@ gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= From de4a847078561d4bab53f15bc2474063a1a01140 Mon Sep 17 00:00:00 2001 From: Anton Evangelatov Date: Wed, 28 Jul 2021 12:10:17 +0300 Subject: [PATCH 10/17] add RuntimeSubsystems API method; use it in `lotus-miner info` --- api/api_storage.go | 2 + api/api_subsystems.go | 63 +++ api/docgen/docgen.go | 11 +- api/proxy_gen.go | 13 + build/openrpc/full.json.gz | Bin 25240 -> 25240 bytes build/openrpc/miner.json.gz | Bin 9479 -> 9540 bytes build/openrpc/worker.json.gz | Bin 2710 -> 2710 bytes cmd/lotus-miner/info.go | 562 ++++++++++++----------- documentation/en/api-v0-methods-miner.md | 14 + node/builder_miner.go | 2 + node/impl/storminer.go | 6 + node/modules/storageminer.go | 17 + 12 files changed, 410 insertions(+), 280 deletions(-) create mode 100644 api/api_subsystems.go diff --git a/api/api_storage.go b/api/api_storage.go index 154abcea7..d52032650 100644 --- a/api/api_storage.go +++ b/api/api_storage.go @@ -166,6 +166,8 @@ type StorageMiner interface { MarketPendingDeals(ctx context.Context) (PendingDealInfo, error) //perm:write MarketPublishPendingDeals(ctx context.Context) error //perm:admin + RuntimeSubsystems(ctx context.Context) (MinerSubsystems, error) //perm:read + DealsImportData(ctx context.Context, dealPropCid cid.Cid, file string) error //perm:admin DealsList(ctx context.Context) ([]MarketDeal, error) //perm:admin DealsConsiderOnlineStorageDeals(context.Context) (bool, error) //perm:admin diff --git a/api/api_subsystems.go b/api/api_subsystems.go new file mode 100644 index 000000000..1894bbdd8 --- /dev/null +++ b/api/api_subsystems.go @@ -0,0 +1,63 @@ +package api + +import ( + "bytes" + "encoding/json" +) + +type MinerSubsystems []MinerSubsystem + +func (ms MinerSubsystems) Has(entry MinerSubsystem) bool { + for _, v := range ms { + if v == entry { + return true + } + + } + return false +} + +type MinerSubsystem int + +const ( + MarketsSubsystem MinerSubsystem = iota + MiningSubsystem + SealingSubsystem + SectorStorageSubsystem +) + +func (ms MinerSubsystem) String() string { + return MinerSubsystemToString[ms] +} + +var MinerSubsystemToString = map[MinerSubsystem]string{ + MarketsSubsystem: "Markets", + MiningSubsystem: "Mining", + SealingSubsystem: "Sealing", + SectorStorageSubsystem: "SectorStorage", +} + +var MinerSubsystemToID = map[string]MinerSubsystem{ + "Markets": MarketsSubsystem, + "Mining": MiningSubsystem, + "Sealing": SealingSubsystem, + "SectorStorage": SectorStorageSubsystem, +} + +func (ms MinerSubsystem) MarshalJSON() ([]byte, error) { + buffer := bytes.NewBufferString(`"`) + buffer.WriteString(MinerSubsystemToString[ms]) + buffer.WriteString(`"`) + return buffer.Bytes(), nil +} + +func (ms *MinerSubsystem) UnmarshalJSON(b []byte) error { + var j string + err := json.Unmarshal(b, &j) + if err != nil { + return err + } + // TODO: handle zero value + *ms = MinerSubsystemToID[j] + return nil +} diff --git a/api/docgen/docgen.go b/api/docgen/docgen.go index 39980023f..1e712a0ae 100644 --- a/api/docgen/docgen.go +++ b/api/docgen/docgen.go @@ -46,11 +46,12 @@ import ( ) var ExampleValues = map[reflect.Type]interface{}{ - reflect.TypeOf(auth.Permission("")): auth.Permission("write"), - reflect.TypeOf(""): "string value", - reflect.TypeOf(uint64(42)): uint64(42), - reflect.TypeOf(byte(7)): byte(7), - reflect.TypeOf([]byte{}): []byte("byte array"), + reflect.TypeOf(api.MinerSubsystem(0)): api.MinerSubsystem(1), + reflect.TypeOf(auth.Permission("")): auth.Permission("write"), + reflect.TypeOf(""): "string value", + reflect.TypeOf(uint64(42)): uint64(42), + reflect.TypeOf(byte(7)): byte(7), + reflect.TypeOf([]byte{}): []byte("byte array"), } func addExample(v interface{}) { diff --git a/api/proxy_gen.go b/api/proxy_gen.go index 7d96425ff..a4feb7be1 100644 --- a/api/proxy_gen.go +++ b/api/proxy_gen.go @@ -699,6 +699,8 @@ type StorageMinerStruct struct { ReturnUnsealPiece func(p0 context.Context, p1 storiface.CallID, p2 *storiface.CallError) error `perm:"admin"` + RuntimeSubsystems func(p0 context.Context) (MinerSubsystems, error) `perm:"read"` + SealingAbort func(p0 context.Context, p1 storiface.CallID) error `perm:"admin"` SealingSchedDiag func(p0 context.Context, p1 bool) (interface{}, error) `perm:"admin"` @@ -4095,6 +4097,17 @@ func (s *StorageMinerStub) ReturnUnsealPiece(p0 context.Context, p1 storiface.Ca return ErrNotSupported } +func (s *StorageMinerStruct) RuntimeSubsystems(p0 context.Context) (MinerSubsystems, error) { + if s.Internal.RuntimeSubsystems == nil { + return *new(MinerSubsystems), ErrNotSupported + } + return s.Internal.RuntimeSubsystems(p0) +} + +func (s *StorageMinerStub) RuntimeSubsystems(p0 context.Context) (MinerSubsystems, error) { + return *new(MinerSubsystems), ErrNotSupported +} + func (s *StorageMinerStruct) SealingAbort(p0 context.Context, p1 storiface.CallID) error { if s.Internal.SealingAbort == nil { return ErrNotSupported diff --git a/build/openrpc/full.json.gz b/build/openrpc/full.json.gz index 4708ec159750bc2464b61b01bbcdfb1e270b2780..db41fb2d3a18922fe3b5b9960853ec350fb7ee91 100644 GIT binary patch delta 20847 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 KonJWA>jVIUfNw_t delta 20863 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 acE!D4?FyCb=l=@;0RR88YkDKp>jVICf>(b4 diff --git a/build/openrpc/miner.json.gz b/build/openrpc/miner.json.gz index 58a76714dc5e83fc937928a04c9da6ad108678c7..69d471dbd5673f06dc006a4d21f0a193b36bbb30 100644 GIT binary patch delta 6074 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 A7ytkO delta 6021 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 diff --git a/build/openrpc/worker.json.gz b/build/openrpc/worker.json.gz index fbf25f4ea060a5e70be819d3d1e2acb5328a62e6..07740e5e2ccfab4bbc3b6ce6333159c762d09d90 100644 GIT binary patch delta 1731 zcmV;!20Zze6_ypS`vL=W&a{*M0zZH5hhkOw6_h>%RE;!iq`7ZM^SD(44=5up{SNV57~+Hsv1xz$YgT?u z*vL5SXL{aR{9lxB1_WvVuoFhQ3jkn2kJn3B84T_3!=VIKZEVBr(wYOaX8Nm+optQo zx7c~oE{>g-Y{(5GrY0%Q&n!L+(KVMvKz+Yb+)J7>ihVJsTS?y(F}K7iWGYp04FBR% z&AZaTA3YK`(7yR{#JGTKkUW17_ALEu;Z(s3{tVvLcp|AyT-@(1HAoPT zT1R!k`PEk${qOem8)%5~Q~iH$3*u)*tnvL$ z0f}9}_irb`S3~a_dhc6IJL?w5v@4><(lDBZG{xXMTEv5F#Gyb}T^5+arj~@HqV|l! z(u~)w!0#gNO7a@HO506toD+5fFYNrEmtK{hbI+qHuRY5xEJbMsN+YEt z?sd3+Vj$)GXk2JB#8&hXay5GK!MgBxP4p1eKVInKoI27Ff7QoGp)Z(6FEk+G= zcOs(h0?^G{#~vP)E4A}CEo*+G^Mc3P`l==D={(Mu#)A?%WTw!i15D8&O>1(JF#SJ& ztYK0kcf7)BX}@04Yt7Rv{TJNS4wDQgoxyiv1L;0VXM8g0lJ1Ebbmaqh{$Kq0Z$FrD z&;M)S4Pi3u_J*_@OiqFTdY#8!vD+8S)5Bmwxk->!FG%YJ>08Fk-I7C` z37*S`@2Z%&W4`Z3m&P#i_du-;b35CAhq;|Phr4UGxeL%Xuf%T;?$vRwj&u7K=Xxb4 z%(X+m60m-HC?VcRhG=0mwMGO?7}{nK%!r*%_tdd)C+v3@V&UGWdFs?hjUs9k@s3c$ zNy$Ot*!K{_RxQ#53q19z(RvSq50-|7Vou6?U>hA;7}R9Rj}SI|9*DMpOqYH zz5%t~OEMF}GMG5v++DKUFKOVlJN`1PEZOy!bm$TBAdwow%qoaP5Z!CetfPUxaD~*E z=pQPP1f?h&-7=3%kRlI&2pYnF6Ov$a=18PC((av%hys0~h4%a-lkxV^kB$?biZeBwEOq%JOHejiWUTs7OE(y*6w$q-JOziJF_`4 zeVxOcu6POT5&v6$;_qZg{W4v)FrK%(WNEyjd7}k$T9RTznAJc>w?V7b1r)uw;MEJ^ z6;kA8WOe;23AdSDX)T?9nO6TL-16!Zr3d9IlW%JLv@$`p->IXsZppEnX#4Iu->gbe zuKQ}Q*@tZYIZ<%Q9C%*w>8ir*8pp_{PUD<9hEH5l{BP@VOLmCr^EmZ$mrAb*%bCR% zzwgv*b9(LkX^#nR^G2yHdIOZmZE64-R*o>JC5$CLLQfFJO7hV_3wa! zGE~VqU7=EzCcoxnug!g>`!80%q^p6;?FWehrl^b57z7|90I}#PokSvFEPS^2N{xMY Z$*9v7o=)$k{|f*B|NqnoW^P$}000n$fOY@? delta 1731 zcmV;!20Zze6_ypS`vL>BkF}Hj0zZGwNwF&Z3d$ZEDpE*ehGr8-8sz#bM(%d(s**z_R2b2+)eusE23~@q+*ff9rH7ma+ zY-AkvGd*uD{x8Zm0|GSw*a;)u1pu(1$Ll4m42Jgi;ZTCAHnw4QY0ZIIGyPS^&N_DP zTkPze701p?Hspp8Q?m|Nl$GL@=0hJSIX z=3Qyvj~>uZG?=^xn6acG@bAX;(yzrC~G+X^O#jw1@}Uh(m#{x-2k-O)UvYMeP}d zr5UeVf!{^kmE<*YmA0GQI4A4|Vziipxca7MsrYW>6>^yL6Ss*Q@?LcJPoSf5rDVzm zQzW};YiI2eTNB&{DQ}ZG1!gygnSJOKo7pwEKqP!+5{UWUp9Sh4`7CCk>us&n@)Fjo zwVlGAyRcfTpT^Wn!g@)#&r8D7R=1Pa1yz4)_lk{6ugcH4=TVi{p5+#nqBH}gkx~-( zI$S?7kaB)BF0>h9EBXkz8ol^nU3k1EdWh;DFLZHE9cc)1Q(|lj;ATf^anG?9qXxP= z5m9#m=;p0s50A=~+WDK7HNVk$!DDTG)e`n}9%oGBK?xl)Q|QtGrs$BSH91L`{vUtV zFsYF{Ug5N~U$5x3=4qDx3vOzMNrsco;5)H_bf2U%KACh$_e2f4@&P>mFaG?uA56IC z|26Q2Fd24xL)r}{CqV$c&SNiH18lNALsyw}ZZ@CkVKAZGB*>~4r1gUIEo0_R$sx`J z&*j5+Rm|Km-*=-+V;K2+pw@=Do$Y_a+)kat-8I|X1!$XB;Nr=&xqXXs-I5dL z+M!R7lF_PYzQaPQMRb?T!=5jBc&D~zPX;od#zGC=Cu_#REBRAtar=5o89uKCnblP zZ$Pd0lFWp#3?>dZcbDw;OB#6Xj=u~mOLqMw9ePAONTkLvvkD>+ME9CA>u8`aTp=|k z`iDv+K`F{cx6C6Gq{ssxf`)(age2IUIT9(3w0kEbqCj6LA|H@ecPDT+xX19vyq&Y& z#P_LpdRB61GTuJ=(Q(34ai)for7mA&3Cc#x>?hmKtBokfR=Fi@Y(*62gsQzDG5!9L zO}>!u-D&lQlH-Yg5czNs`94F9PEnR>GZ0rhL>YDyy~3hYvs3N8R;z!rtZiSTb7EG1 z{b%#B)wIK29W}QJ^`0|UYxld*?smz!o!Ok2 zzRqDzSG)xFi2p4=@pm$$ewi*?7|&Z?vNT@NywQR=ElIH<%xa*c+o09z0*YQ-@al!| z3Mq0kvbuhigxk!nw3dI)OsoGAZh7^I(t~o9$u~8ATA85Q@6^#*r{q{pw0(D-Z&sx! z*L}6u>_ayHoG7?t4m_{;bXDPYjbmg}r*Tdl!zV5&{ z-*@V@x@VjC#M9n>scO&m&*Trl#NKoD%oJ{N$+mS)9VB%35}1F|qDXLuM^T*tWuquc zFolTY2#^vSMCYwF(52D?Fyz7m2Ms2Op#MbQV6+fH=iC7s9XySxJw}u{REwzl@B&v+ zTi-qMiTwc1ycZR&MhJ5dL7#Q4F_Gg&R&h3S*rxtaME#Vqeo7fZ&2GtQme`gJVP;HK zyhNM3hjN$~S6Ooc@!}dr$S&b(EAQ7U8>*yyOHs7j?sh(`9Y=RmA$uj;&i^D-{X3wb z3{`SYSE!Vw$*(!tYja=e{)^Qw>1yC|`$3|BDe59M1_6i&KrDJnCy@vk3!m-1Qe)p; ZGV1sgPp5a&{{;X5|Nl>=ppaR5000ghVSxYu diff --git a/cmd/lotus-miner/info.go b/cmd/lotus-miner/info.go index 3941ce563..4c409788f 100644 --- a/cmd/lotus-miner/info.go +++ b/cmd/lotus-miner/info.go @@ -55,7 +55,7 @@ func infoCmdAct(cctx *cli.Context) error { } defer closer() - api, acloser, err := lcli.GetFullNodeAPI(cctx) + fullapi, acloser, err := lcli.GetFullNodeAPI(cctx) if err != nil { return err } @@ -63,9 +63,16 @@ func infoCmdAct(cctx *cli.Context) error { ctx := lcli.ReqContext(cctx) + subsystems, err := nodeApi.RuntimeSubsystems(ctx) + if err != nil { + return err + } + + fmt.Println("Enabled subsystems:", subsystems) + fmt.Print("Chain: ") - head, err := api.ChainHead(ctx) + head, err := fullapi.ChainHead(ctx) if err != nil { return err } @@ -95,284 +102,289 @@ func infoCmdAct(cctx *cli.Context) error { fmt.Println() - maddr, err := getActorAddress(ctx, cctx) - if err != nil { - return err - } - - mact, err := api.StateGetActor(ctx, maddr, types.EmptyTSK) - if err != nil { - return err - } - - tbs := blockstore.NewTieredBstore(blockstore.NewAPIBlockstore(api), blockstore.NewMemory()) - mas, err := miner.Load(adt.WrapStore(ctx, cbor.NewCborStore(tbs)), mact) - if err != nil { - return err - } - - // Sector size - mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) - if err != nil { - return err - } - - ssize := types.SizeStr(types.NewInt(uint64(mi.SectorSize))) - fmt.Printf("Miner: %s (%s sectors)\n", color.BlueString("%s", maddr), ssize) - - pow, err := api.StateMinerPower(ctx, maddr, types.EmptyTSK) - if err != nil { - return err - } - - fmt.Printf("Power: %s / %s (%0.4f%%)\n", - color.GreenString(types.DeciStr(pow.MinerPower.QualityAdjPower)), - types.DeciStr(pow.TotalPower.QualityAdjPower), - types.BigDivFloat( - types.BigMul(pow.MinerPower.QualityAdjPower, big.NewInt(100)), - pow.TotalPower.QualityAdjPower, - ), - ) - - fmt.Printf("\tRaw: %s / %s (%0.4f%%)\n", - color.BlueString(types.SizeStr(pow.MinerPower.RawBytePower)), - types.SizeStr(pow.TotalPower.RawBytePower), - types.BigDivFloat( - types.BigMul(pow.MinerPower.RawBytePower, big.NewInt(100)), - pow.TotalPower.RawBytePower, - ), - ) - secCounts, err := api.StateMinerSectorCount(ctx, maddr, types.EmptyTSK) - if err != nil { - return err - } - - proving := secCounts.Active + secCounts.Faulty - nfaults := secCounts.Faulty - fmt.Printf("\tCommitted: %s\n", types.SizeStr(types.BigMul(types.NewInt(secCounts.Live), types.NewInt(uint64(mi.SectorSize))))) - if nfaults == 0 { - fmt.Printf("\tProving: %s\n", types.SizeStr(types.BigMul(types.NewInt(proving), types.NewInt(uint64(mi.SectorSize))))) - } else { - var faultyPercentage float64 - if secCounts.Live != 0 { - faultyPercentage = float64(100*nfaults) / float64(secCounts.Live) - } - fmt.Printf("\tProving: %s (%s Faulty, %.2f%%)\n", - types.SizeStr(types.BigMul(types.NewInt(proving), types.NewInt(uint64(mi.SectorSize)))), - types.SizeStr(types.BigMul(types.NewInt(nfaults), types.NewInt(uint64(mi.SectorSize)))), - faultyPercentage) - } - - if !pow.HasMinPower { - fmt.Print("Below minimum power threshold, no blocks will be won") - } else { - - winRatio := new(corebig.Rat).SetFrac( - types.BigMul(pow.MinerPower.QualityAdjPower, types.NewInt(build.BlocksPerEpoch)).Int, - pow.TotalPower.QualityAdjPower.Int, - ) - - if winRatioFloat, _ := winRatio.Float64(); winRatioFloat > 0 { - - // if the corresponding poisson distribution isn't infinitely small then - // throw it into the mix as well, accounting for multi-wins - winRationWithPoissonFloat := -math.Expm1(-winRatioFloat) - winRationWithPoisson := new(corebig.Rat).SetFloat64(winRationWithPoissonFloat) - if winRationWithPoisson != nil { - winRatio = winRationWithPoisson - winRatioFloat = winRationWithPoissonFloat - } - - weekly, _ := new(corebig.Rat).Mul( - winRatio, - new(corebig.Rat).SetInt64(7*builtin.EpochsInDay), - ).Float64() - - avgDuration, _ := new(corebig.Rat).Mul( - new(corebig.Rat).SetInt64(builtin.EpochDurationSeconds), - new(corebig.Rat).Inv(winRatio), - ).Float64() - - fmt.Print("Projected average block win rate: ") - color.Blue( - "%.02f/week (every %s)", - weekly, - (time.Second * time.Duration(avgDuration)).Truncate(time.Second).String(), - ) - - // Geometric distribution of P(Y < k) calculated as described in https://en.wikipedia.org/wiki/Geometric_distribution#Probability_Outcomes_Examples - // https://www.wolframalpha.com/input/?i=t+%3E+0%3B+p+%3E+0%3B+p+%3C+1%3B+c+%3E+0%3B+c+%3C1%3B+1-%281-p%29%5E%28t%29%3Dc%3B+solve+t - // t == how many dice-rolls (epochs) before win - // p == winRate == ( minerPower / netPower ) - // c == target probability of win ( 99.9% in this case ) - fmt.Print("Projected block win with ") - color.Green( - "99.9%% probability every %s", - (time.Second * time.Duration( - builtin.EpochDurationSeconds*math.Log(1-0.999)/ - math.Log(1-winRatioFloat), - )).Truncate(time.Second).String(), - ) - fmt.Println("(projections DO NOT account for future network and miner growth)") - } - } - - fmt.Println() - - deals, err := nodeApi.MarketListIncompleteDeals(ctx) - if err != nil { - return err - } - - type dealStat struct { - count, verifCount int - bytes, verifBytes uint64 - } - dsAdd := func(ds *dealStat, deal storagemarket.MinerDeal) { - ds.count++ - ds.bytes += uint64(deal.Proposal.PieceSize) - if deal.Proposal.VerifiedDeal { - ds.verifCount++ - ds.verifBytes += uint64(deal.Proposal.PieceSize) - } - } - - showDealStates := map[storagemarket.StorageDealStatus]struct{}{ - storagemarket.StorageDealActive: {}, - storagemarket.StorageDealTransferring: {}, - storagemarket.StorageDealStaged: {}, - storagemarket.StorageDealAwaitingPreCommit: {}, - storagemarket.StorageDealSealing: {}, - storagemarket.StorageDealPublish: {}, - storagemarket.StorageDealCheckForAcceptance: {}, - storagemarket.StorageDealPublishing: {}, - } - - var total dealStat - perState := map[storagemarket.StorageDealStatus]*dealStat{} - for _, deal := range deals { - if _, ok := showDealStates[deal.State]; !ok { - continue - } - if perState[deal.State] == nil { - perState[deal.State] = new(dealStat) - } - - dsAdd(&total, deal) - dsAdd(perState[deal.State], deal) - } - - type wstr struct { - str string - status storagemarket.StorageDealStatus - } - sorted := make([]wstr, 0, len(perState)) - for status, stat := range perState { - st := strings.TrimPrefix(storagemarket.DealStates[status], "StorageDeal") - sorted = append(sorted, wstr{ - str: fmt.Sprintf(" %s:\t%d\t\t%s\t(Verified: %d\t%s)\n", st, stat.count, types.SizeStr(types.NewInt(stat.bytes)), stat.verifCount, types.SizeStr(types.NewInt(stat.verifBytes))), - status: status, - }, - ) - } - sort.Slice(sorted, func(i, j int) bool { - if sorted[i].status == storagemarket.StorageDealActive || sorted[j].status == storagemarket.StorageDealActive { - return sorted[i].status == storagemarket.StorageDealActive - } - return sorted[i].status > sorted[j].status - }) - - fmt.Printf("Storage Deals: %d, %s\n", total.count, types.SizeStr(types.NewInt(total.bytes))) - - tw := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', 0) - for _, e := range sorted { - _, _ = tw.Write([]byte(e.str)) - } - - _ = tw.Flush() - fmt.Println() - - retrievals, err := nodeApi.MarketListRetrievalDeals(ctx) - if err != nil { - return xerrors.Errorf("getting retrieval deal list: %w", err) - } - - var retrComplete dealStat - for _, retrieval := range retrievals { - if retrieval.Status == retrievalmarket.DealStatusCompleted { - retrComplete.count++ - retrComplete.bytes += retrieval.TotalSent - } - } - - fmt.Printf("Retrieval Deals (complete): %d, %s\n", retrComplete.count, types.SizeStr(types.NewInt(retrComplete.bytes))) - - fmt.Println() - - spendable := big.Zero() - - // NOTE: there's no need to unlock anything here. Funds only - // vest on deadline boundaries, and they're unlocked by cron. - lockedFunds, err := mas.LockedFunds() - if err != nil { - return xerrors.Errorf("getting locked funds: %w", err) - } - availBalance, err := mas.AvailableBalance(mact.Balance) - if err != nil { - return xerrors.Errorf("getting available balance: %w", err) - } - spendable = big.Add(spendable, availBalance) - - fmt.Printf("Miner Balance: %s\n", color.YellowString("%s", types.FIL(mact.Balance).Short())) - fmt.Printf(" PreCommit: %s\n", types.FIL(lockedFunds.PreCommitDeposits).Short()) - fmt.Printf(" Pledge: %s\n", types.FIL(lockedFunds.InitialPledgeRequirement).Short()) - fmt.Printf(" Vesting: %s\n", types.FIL(lockedFunds.VestingFunds).Short()) - colorTokenAmount(" Available: %s\n", availBalance) - - mb, err := api.StateMarketBalance(ctx, maddr, types.EmptyTSK) - if err != nil { - return xerrors.Errorf("getting market balance: %w", err) - } - spendable = big.Add(spendable, big.Sub(mb.Escrow, mb.Locked)) - - fmt.Printf("Market Balance: %s\n", types.FIL(mb.Escrow).Short()) - fmt.Printf(" Locked: %s\n", types.FIL(mb.Locked).Short()) - colorTokenAmount(" Available: %s\n", big.Sub(mb.Escrow, mb.Locked)) - - wb, err := api.WalletBalance(ctx, mi.Worker) - if err != nil { - return xerrors.Errorf("getting worker balance: %w", err) - } - spendable = big.Add(spendable, wb) - color.Cyan("Worker Balance: %s", types.FIL(wb).Short()) - if len(mi.ControlAddresses) > 0 { - cbsum := big.Zero() - for _, ca := range mi.ControlAddresses { - b, err := api.WalletBalance(ctx, ca) - if err != nil { - return xerrors.Errorf("getting control address balance: %w", err) - } - cbsum = big.Add(cbsum, b) - } - spendable = big.Add(spendable, cbsum) - - fmt.Printf(" Control: %s\n", types.FIL(cbsum).Short()) - } - colorTokenAmount("Total Spendable: %s\n", spendable) - - fmt.Println() - - if !cctx.Bool("hide-sectors-info") { - fmt.Println("Sectors:") - err = sectorsInfo(ctx, nodeApi) + if subsystems.Has(api.SectorStorageSubsystem) { + maddr, err := getActorAddress(ctx, cctx) if err != nil { return err } + + mact, err := fullapi.StateGetActor(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + tbs := blockstore.NewTieredBstore(blockstore.NewAPIBlockstore(fullapi), blockstore.NewMemory()) + mas, err := miner.Load(adt.WrapStore(ctx, cbor.NewCborStore(tbs)), mact) + if err != nil { + return err + } + + // Sector size + mi, err := fullapi.StateMinerInfo(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + ssize := types.SizeStr(types.NewInt(uint64(mi.SectorSize))) + fmt.Printf("Miner: %s (%s sectors)\n", color.BlueString("%s", maddr), ssize) + + pow, err := fullapi.StateMinerPower(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + fmt.Printf("Power: %s / %s (%0.4f%%)\n", + color.GreenString(types.DeciStr(pow.MinerPower.QualityAdjPower)), + types.DeciStr(pow.TotalPower.QualityAdjPower), + types.BigDivFloat( + types.BigMul(pow.MinerPower.QualityAdjPower, big.NewInt(100)), + pow.TotalPower.QualityAdjPower, + ), + ) + + fmt.Printf("\tRaw: %s / %s (%0.4f%%)\n", + color.BlueString(types.SizeStr(pow.MinerPower.RawBytePower)), + types.SizeStr(pow.TotalPower.RawBytePower), + types.BigDivFloat( + types.BigMul(pow.MinerPower.RawBytePower, big.NewInt(100)), + pow.TotalPower.RawBytePower, + ), + ) + secCounts, err := fullapi.StateMinerSectorCount(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + proving := secCounts.Active + secCounts.Faulty + nfaults := secCounts.Faulty + fmt.Printf("\tCommitted: %s\n", types.SizeStr(types.BigMul(types.NewInt(secCounts.Live), types.NewInt(uint64(mi.SectorSize))))) + if nfaults == 0 { + fmt.Printf("\tProving: %s\n", types.SizeStr(types.BigMul(types.NewInt(proving), types.NewInt(uint64(mi.SectorSize))))) + } else { + var faultyPercentage float64 + if secCounts.Live != 0 { + faultyPercentage = float64(100*nfaults) / float64(secCounts.Live) + } + fmt.Printf("\tProving: %s (%s Faulty, %.2f%%)\n", + types.SizeStr(types.BigMul(types.NewInt(proving), types.NewInt(uint64(mi.SectorSize)))), + types.SizeStr(types.BigMul(types.NewInt(nfaults), types.NewInt(uint64(mi.SectorSize)))), + faultyPercentage) + } + + if !pow.HasMinPower { + fmt.Print("Below minimum power threshold, no blocks will be won") + } else { + + winRatio := new(corebig.Rat).SetFrac( + types.BigMul(pow.MinerPower.QualityAdjPower, types.NewInt(build.BlocksPerEpoch)).Int, + pow.TotalPower.QualityAdjPower.Int, + ) + + if winRatioFloat, _ := winRatio.Float64(); winRatioFloat > 0 { + + // if the corresponding poisson distribution isn't infinitely small then + // throw it into the mix as well, accounting for multi-wins + winRationWithPoissonFloat := -math.Expm1(-winRatioFloat) + winRationWithPoisson := new(corebig.Rat).SetFloat64(winRationWithPoissonFloat) + if winRationWithPoisson != nil { + winRatio = winRationWithPoisson + winRatioFloat = winRationWithPoissonFloat + } + + weekly, _ := new(corebig.Rat).Mul( + winRatio, + new(corebig.Rat).SetInt64(7*builtin.EpochsInDay), + ).Float64() + + avgDuration, _ := new(corebig.Rat).Mul( + new(corebig.Rat).SetInt64(builtin.EpochDurationSeconds), + new(corebig.Rat).Inv(winRatio), + ).Float64() + + fmt.Print("Projected average block win rate: ") + color.Blue( + "%.02f/week (every %s)", + weekly, + (time.Second * time.Duration(avgDuration)).Truncate(time.Second).String(), + ) + + // Geometric distribution of P(Y < k) calculated as described in https://en.wikipedia.org/wiki/Geometric_distribution#Probability_Outcomes_Examples + // https://www.wolframalpha.com/input/?i=t+%3E+0%3B+p+%3E+0%3B+p+%3C+1%3B+c+%3E+0%3B+c+%3C1%3B+1-%281-p%29%5E%28t%29%3Dc%3B+solve+t + // t == how many dice-rolls (epochs) before win + // p == winRate == ( minerPower / netPower ) + // c == target probability of win ( 99.9% in this case ) + fmt.Print("Projected block win with ") + color.Green( + "99.9%% probability every %s", + (time.Second * time.Duration( + builtin.EpochDurationSeconds*math.Log(1-0.999)/ + math.Log(1-winRatioFloat), + )).Truncate(time.Second).String(), + ) + fmt.Println("(projections DO NOT account for future network and miner growth)") + } + } + + fmt.Println() + + spendable := big.Zero() + + // NOTE: there's no need to unlock anything here. Funds only + // vest on deadline boundaries, and they're unlocked by cron. + lockedFunds, err := mas.LockedFunds() + if err != nil { + return xerrors.Errorf("getting locked funds: %w", err) + } + availBalance, err := mas.AvailableBalance(mact.Balance) + if err != nil { + return xerrors.Errorf("getting available balance: %w", err) + } + spendable = big.Add(spendable, availBalance) + + fmt.Printf("Miner Balance: %s\n", color.YellowString("%s", types.FIL(mact.Balance).Short())) + fmt.Printf(" PreCommit: %s\n", types.FIL(lockedFunds.PreCommitDeposits).Short()) + fmt.Printf(" Pledge: %s\n", types.FIL(lockedFunds.InitialPledgeRequirement).Short()) + fmt.Printf(" Vesting: %s\n", types.FIL(lockedFunds.VestingFunds).Short()) + colorTokenAmount(" Available: %s\n", availBalance) + + mb, err := fullapi.StateMarketBalance(ctx, maddr, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting market balance: %w", err) + } + spendable = big.Add(spendable, big.Sub(mb.Escrow, mb.Locked)) + + fmt.Printf("Market Balance: %s\n", types.FIL(mb.Escrow).Short()) + fmt.Printf(" Locked: %s\n", types.FIL(mb.Locked).Short()) + colorTokenAmount(" Available: %s\n", big.Sub(mb.Escrow, mb.Locked)) + + wb, err := fullapi.WalletBalance(ctx, mi.Worker) + if err != nil { + return xerrors.Errorf("getting worker balance: %w", err) + } + spendable = big.Add(spendable, wb) + color.Cyan("Worker Balance: %s", types.FIL(wb).Short()) + if len(mi.ControlAddresses) > 0 { + cbsum := big.Zero() + for _, ca := range mi.ControlAddresses { + b, err := fullapi.WalletBalance(ctx, ca) + if err != nil { + return xerrors.Errorf("getting control address balance: %w", err) + } + cbsum = big.Add(cbsum, b) + } + spendable = big.Add(spendable, cbsum) + + fmt.Printf(" Control: %s\n", types.FIL(cbsum).Short()) + } + colorTokenAmount("Total Spendable: %s\n", spendable) + + fmt.Println() + + if !cctx.Bool("hide-sectors-info") { + fmt.Println("Sectors:") + err = sectorsInfo(ctx, nodeApi) + if err != nil { + return err + } + } + + // TODO: grab actr state / info + // * Sealed sectors (count / bytes) + // * Power + } + + if subsystems.Has(api.MarketsSubsystem) { + deals, err := nodeApi.MarketListIncompleteDeals(ctx) + if err != nil { + return err + } + + type dealStat struct { + count, verifCount int + bytes, verifBytes uint64 + } + dsAdd := func(ds *dealStat, deal storagemarket.MinerDeal) { + ds.count++ + ds.bytes += uint64(deal.Proposal.PieceSize) + if deal.Proposal.VerifiedDeal { + ds.verifCount++ + ds.verifBytes += uint64(deal.Proposal.PieceSize) + } + } + + showDealStates := map[storagemarket.StorageDealStatus]struct{}{ + storagemarket.StorageDealActive: {}, + storagemarket.StorageDealTransferring: {}, + storagemarket.StorageDealStaged: {}, + storagemarket.StorageDealAwaitingPreCommit: {}, + storagemarket.StorageDealSealing: {}, + storagemarket.StorageDealPublish: {}, + storagemarket.StorageDealCheckForAcceptance: {}, + storagemarket.StorageDealPublishing: {}, + } + + var total dealStat + perState := map[storagemarket.StorageDealStatus]*dealStat{} + for _, deal := range deals { + if _, ok := showDealStates[deal.State]; !ok { + continue + } + if perState[deal.State] == nil { + perState[deal.State] = new(dealStat) + } + + dsAdd(&total, deal) + dsAdd(perState[deal.State], deal) + } + + type wstr struct { + str string + status storagemarket.StorageDealStatus + } + sorted := make([]wstr, 0, len(perState)) + for status, stat := range perState { + st := strings.TrimPrefix(storagemarket.DealStates[status], "StorageDeal") + sorted = append(sorted, wstr{ + str: fmt.Sprintf(" %s:\t%d\t\t%s\t(Verified: %d\t%s)\n", st, stat.count, types.SizeStr(types.NewInt(stat.bytes)), stat.verifCount, types.SizeStr(types.NewInt(stat.verifBytes))), + status: status, + }, + ) + } + sort.Slice(sorted, func(i, j int) bool { + if sorted[i].status == storagemarket.StorageDealActive || sorted[j].status == storagemarket.StorageDealActive { + return sorted[i].status == storagemarket.StorageDealActive + } + return sorted[i].status > sorted[j].status + }) + + fmt.Printf("Storage Deals: %d, %s\n", total.count, types.SizeStr(types.NewInt(total.bytes))) + + tw := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', 0) + for _, e := range sorted { + _, _ = tw.Write([]byte(e.str)) + } + + _ = tw.Flush() + fmt.Println() + + retrievals, err := nodeApi.MarketListRetrievalDeals(ctx) + if err != nil { + return xerrors.Errorf("getting retrieval deal list: %w", err) + } + + var retrComplete dealStat + for _, retrieval := range retrievals { + if retrieval.Status == retrievalmarket.DealStatusCompleted { + retrComplete.count++ + retrComplete.bytes += retrieval.TotalSent + } + } + + fmt.Printf("Retrieval Deals (complete): %d, %s\n", retrComplete.count, types.SizeStr(types.NewInt(retrComplete.bytes))) + + fmt.Println() } - // TODO: grab actr state / info - // * Sealed sectors (count / bytes) - // * Power return nil } diff --git a/documentation/en/api-v0-methods-miner.md b/documentation/en/api-v0-methods-miner.md index e8598ff0c..dcd3abd4d 100644 --- a/documentation/en/api-v0-methods-miner.md +++ b/documentation/en/api-v0-methods-miner.md @@ -94,6 +94,8 @@ * [ReturnSealPreCommit1](#ReturnSealPreCommit1) * [ReturnSealPreCommit2](#ReturnSealPreCommit2) * [ReturnUnsealPiece](#ReturnUnsealPiece) +* [Runtime](#Runtime) + * [RuntimeSubsystems](#RuntimeSubsystems) * [Sealing](#Sealing) * [SealingAbort](#SealingAbort) * [SealingSchedDiag](#SealingSchedDiag) @@ -1522,6 +1524,18 @@ Inputs: Response: `{}` +## Runtime + + +### RuntimeSubsystems + + +Perms: read + +Inputs: `null` + +Response: `null` + ## Sealing diff --git a/node/builder_miner.go b/node/builder_miner.go index 0c0f9d15a..d62cbcad9 100644 --- a/node/builder_miner.go +++ b/node/builder_miner.go @@ -72,6 +72,7 @@ func ConfigStorageMiner(c interface{}) Option { return Options( ConfigCommon(&cfg.Common, enableLibp2pNode), + Override(new([]api.MinerSubsystem), modules.AddMinerSubsystems(cfg.Subsystems)), Override(new(stores.LocalStorage), From(new(repo.LockedRepo))), Override(new(*stores.Local), modules.LocalStorage), Override(new(*stores.Remote), modules.RemoteStorage), @@ -215,6 +216,7 @@ func StorageMiner(out *api.StorageMiner, subsystemsCfg config.MinerSubsystemConf func(s *Settings) error { resAPI := &impl.StorageMinerAPI{} + s.invokes[ExtractApiKey] = fx.Populate(resAPI) *out = resAPI return nil diff --git a/node/impl/storminer.go b/node/impl/storminer.go index 9db6a3775..86c84fee7 100644 --- a/node/impl/storminer.go +++ b/node/impl/storminer.go @@ -48,6 +48,8 @@ import ( type StorageMinerAPI struct { fx.In + Subsystems api.MinerSubsystems + api.Common api.Net @@ -703,4 +705,8 @@ func (sm *StorageMinerAPI) ComputeProof(ctx context.Context, ssi []builtin.Secto return sm.Epp.ComputeProof(ctx, ssi, rand) } +func (sm *StorageMinerAPI) RuntimeSubsystems(context.Context) (res api.MinerSubsystems, err error) { + return sm.Subsystems, nil +} + var _ api.StorageMiner = &StorageMinerAPI{} diff --git a/node/modules/storageminer.go b/node/modules/storageminer.go index 3a3914e0c..06ef78ca0 100644 --- a/node/modules/storageminer.go +++ b/node/modules/storageminer.go @@ -1007,3 +1007,20 @@ func mutateCfg(r repo.LockedRepo, mutator func(*config.StorageMiner)) error { return multierr.Combine(typeErr, setConfigErr) } + +func AddMinerSubsystems(cfg config.MinerSubsystemConfig) (res api.MinerSubsystems) { + if cfg.EnableMining { + res = append(res, api.MiningSubsystem) + } + if cfg.EnableSealing { + res = append(res, api.SealingSubsystem) + } + if cfg.EnableSectorStorage { + res = append(res, api.SectorStorageSubsystem) + } + if cfg.EnableMarkets { + res = append(res, api.MarketsSubsystem) + } + + return +} From 4cf5c8f656f58f81f69b85fe5b8180592a810e57 Mon Sep 17 00:00:00 2001 From: Anton Evangelatov Date: Wed, 28 Jul 2021 16:23:04 +0300 Subject: [PATCH 11/17] fixup --- node/builder_miner.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/node/builder_miner.go b/node/builder_miner.go index d62cbcad9..830e6d075 100644 --- a/node/builder_miner.go +++ b/node/builder_miner.go @@ -72,7 +72,7 @@ func ConfigStorageMiner(c interface{}) Option { return Options( ConfigCommon(&cfg.Common, enableLibp2pNode), - Override(new([]api.MinerSubsystem), modules.AddMinerSubsystems(cfg.Subsystems)), + Override(new(api.MinerSubsystems), modules.AddMinerSubsystems(cfg.Subsystems)), Override(new(stores.LocalStorage), From(new(repo.LockedRepo))), Override(new(*stores.Local), modules.LocalStorage), Override(new(*stores.Remote), modules.RemoteStorage), @@ -216,7 +216,6 @@ func StorageMiner(out *api.StorageMiner, subsystemsCfg config.MinerSubsystemConf func(s *Settings) error { resAPI := &impl.StorageMinerAPI{} - s.invokes[ExtractApiKey] = fx.Populate(resAPI) *out = resAPI return nil From 54c6a3a45413f1fd4bb0857f453d2820ce80400e Mon Sep 17 00:00:00 2001 From: Anton Evangelatov Date: Wed, 28 Jul 2021 17:30:59 +0300 Subject: [PATCH 12/17] extract outputs for mining node and markets node in separate functions --- cmd/lotus-miner/info.go | 561 +++++++++++++++++++++------------------- 1 file changed, 290 insertions(+), 271 deletions(-) diff --git a/cmd/lotus-miner/info.go b/cmd/lotus-miner/info.go index 4c409788f..2a3627959 100644 --- a/cmd/lotus-miner/info.go +++ b/cmd/lotus-miner/info.go @@ -21,6 +21,7 @@ import ( "github.com/filecoin-project/go-fil-markets/storagemarket" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/lotus/api/v0api" sealing "github.com/filecoin-project/lotus/extern/storage-sealing" "github.com/filecoin-project/lotus/api" @@ -103,291 +104,309 @@ func infoCmdAct(cctx *cli.Context) error { fmt.Println() if subsystems.Has(api.SectorStorageSubsystem) { - maddr, err := getActorAddress(ctx, cctx) + err := handleMiningInfo(cctx, ctx, fullapi, nodeApi) if err != nil { return err } - - mact, err := fullapi.StateGetActor(ctx, maddr, types.EmptyTSK) - if err != nil { - return err - } - - tbs := blockstore.NewTieredBstore(blockstore.NewAPIBlockstore(fullapi), blockstore.NewMemory()) - mas, err := miner.Load(adt.WrapStore(ctx, cbor.NewCborStore(tbs)), mact) - if err != nil { - return err - } - - // Sector size - mi, err := fullapi.StateMinerInfo(ctx, maddr, types.EmptyTSK) - if err != nil { - return err - } - - ssize := types.SizeStr(types.NewInt(uint64(mi.SectorSize))) - fmt.Printf("Miner: %s (%s sectors)\n", color.BlueString("%s", maddr), ssize) - - pow, err := fullapi.StateMinerPower(ctx, maddr, types.EmptyTSK) - if err != nil { - return err - } - - fmt.Printf("Power: %s / %s (%0.4f%%)\n", - color.GreenString(types.DeciStr(pow.MinerPower.QualityAdjPower)), - types.DeciStr(pow.TotalPower.QualityAdjPower), - types.BigDivFloat( - types.BigMul(pow.MinerPower.QualityAdjPower, big.NewInt(100)), - pow.TotalPower.QualityAdjPower, - ), - ) - - fmt.Printf("\tRaw: %s / %s (%0.4f%%)\n", - color.BlueString(types.SizeStr(pow.MinerPower.RawBytePower)), - types.SizeStr(pow.TotalPower.RawBytePower), - types.BigDivFloat( - types.BigMul(pow.MinerPower.RawBytePower, big.NewInt(100)), - pow.TotalPower.RawBytePower, - ), - ) - secCounts, err := fullapi.StateMinerSectorCount(ctx, maddr, types.EmptyTSK) - if err != nil { - return err - } - - proving := secCounts.Active + secCounts.Faulty - nfaults := secCounts.Faulty - fmt.Printf("\tCommitted: %s\n", types.SizeStr(types.BigMul(types.NewInt(secCounts.Live), types.NewInt(uint64(mi.SectorSize))))) - if nfaults == 0 { - fmt.Printf("\tProving: %s\n", types.SizeStr(types.BigMul(types.NewInt(proving), types.NewInt(uint64(mi.SectorSize))))) - } else { - var faultyPercentage float64 - if secCounts.Live != 0 { - faultyPercentage = float64(100*nfaults) / float64(secCounts.Live) - } - fmt.Printf("\tProving: %s (%s Faulty, %.2f%%)\n", - types.SizeStr(types.BigMul(types.NewInt(proving), types.NewInt(uint64(mi.SectorSize)))), - types.SizeStr(types.BigMul(types.NewInt(nfaults), types.NewInt(uint64(mi.SectorSize)))), - faultyPercentage) - } - - if !pow.HasMinPower { - fmt.Print("Below minimum power threshold, no blocks will be won") - } else { - - winRatio := new(corebig.Rat).SetFrac( - types.BigMul(pow.MinerPower.QualityAdjPower, types.NewInt(build.BlocksPerEpoch)).Int, - pow.TotalPower.QualityAdjPower.Int, - ) - - if winRatioFloat, _ := winRatio.Float64(); winRatioFloat > 0 { - - // if the corresponding poisson distribution isn't infinitely small then - // throw it into the mix as well, accounting for multi-wins - winRationWithPoissonFloat := -math.Expm1(-winRatioFloat) - winRationWithPoisson := new(corebig.Rat).SetFloat64(winRationWithPoissonFloat) - if winRationWithPoisson != nil { - winRatio = winRationWithPoisson - winRatioFloat = winRationWithPoissonFloat - } - - weekly, _ := new(corebig.Rat).Mul( - winRatio, - new(corebig.Rat).SetInt64(7*builtin.EpochsInDay), - ).Float64() - - avgDuration, _ := new(corebig.Rat).Mul( - new(corebig.Rat).SetInt64(builtin.EpochDurationSeconds), - new(corebig.Rat).Inv(winRatio), - ).Float64() - - fmt.Print("Projected average block win rate: ") - color.Blue( - "%.02f/week (every %s)", - weekly, - (time.Second * time.Duration(avgDuration)).Truncate(time.Second).String(), - ) - - // Geometric distribution of P(Y < k) calculated as described in https://en.wikipedia.org/wiki/Geometric_distribution#Probability_Outcomes_Examples - // https://www.wolframalpha.com/input/?i=t+%3E+0%3B+p+%3E+0%3B+p+%3C+1%3B+c+%3E+0%3B+c+%3C1%3B+1-%281-p%29%5E%28t%29%3Dc%3B+solve+t - // t == how many dice-rolls (epochs) before win - // p == winRate == ( minerPower / netPower ) - // c == target probability of win ( 99.9% in this case ) - fmt.Print("Projected block win with ") - color.Green( - "99.9%% probability every %s", - (time.Second * time.Duration( - builtin.EpochDurationSeconds*math.Log(1-0.999)/ - math.Log(1-winRatioFloat), - )).Truncate(time.Second).String(), - ) - fmt.Println("(projections DO NOT account for future network and miner growth)") - } - } - - fmt.Println() - - spendable := big.Zero() - - // NOTE: there's no need to unlock anything here. Funds only - // vest on deadline boundaries, and they're unlocked by cron. - lockedFunds, err := mas.LockedFunds() - if err != nil { - return xerrors.Errorf("getting locked funds: %w", err) - } - availBalance, err := mas.AvailableBalance(mact.Balance) - if err != nil { - return xerrors.Errorf("getting available balance: %w", err) - } - spendable = big.Add(spendable, availBalance) - - fmt.Printf("Miner Balance: %s\n", color.YellowString("%s", types.FIL(mact.Balance).Short())) - fmt.Printf(" PreCommit: %s\n", types.FIL(lockedFunds.PreCommitDeposits).Short()) - fmt.Printf(" Pledge: %s\n", types.FIL(lockedFunds.InitialPledgeRequirement).Short()) - fmt.Printf(" Vesting: %s\n", types.FIL(lockedFunds.VestingFunds).Short()) - colorTokenAmount(" Available: %s\n", availBalance) - - mb, err := fullapi.StateMarketBalance(ctx, maddr, types.EmptyTSK) - if err != nil { - return xerrors.Errorf("getting market balance: %w", err) - } - spendable = big.Add(spendable, big.Sub(mb.Escrow, mb.Locked)) - - fmt.Printf("Market Balance: %s\n", types.FIL(mb.Escrow).Short()) - fmt.Printf(" Locked: %s\n", types.FIL(mb.Locked).Short()) - colorTokenAmount(" Available: %s\n", big.Sub(mb.Escrow, mb.Locked)) - - wb, err := fullapi.WalletBalance(ctx, mi.Worker) - if err != nil { - return xerrors.Errorf("getting worker balance: %w", err) - } - spendable = big.Add(spendable, wb) - color.Cyan("Worker Balance: %s", types.FIL(wb).Short()) - if len(mi.ControlAddresses) > 0 { - cbsum := big.Zero() - for _, ca := range mi.ControlAddresses { - b, err := fullapi.WalletBalance(ctx, ca) - if err != nil { - return xerrors.Errorf("getting control address balance: %w", err) - } - cbsum = big.Add(cbsum, b) - } - spendable = big.Add(spendable, cbsum) - - fmt.Printf(" Control: %s\n", types.FIL(cbsum).Short()) - } - colorTokenAmount("Total Spendable: %s\n", spendable) - - fmt.Println() - - if !cctx.Bool("hide-sectors-info") { - fmt.Println("Sectors:") - err = sectorsInfo(ctx, nodeApi) - if err != nil { - return err - } - } - - // TODO: grab actr state / info - // * Sealed sectors (count / bytes) - // * Power } if subsystems.Has(api.MarketsSubsystem) { - deals, err := nodeApi.MarketListIncompleteDeals(ctx) + err := handleMarketsInfo(ctx, nodeApi) if err != nil { return err } - - type dealStat struct { - count, verifCount int - bytes, verifBytes uint64 - } - dsAdd := func(ds *dealStat, deal storagemarket.MinerDeal) { - ds.count++ - ds.bytes += uint64(deal.Proposal.PieceSize) - if deal.Proposal.VerifiedDeal { - ds.verifCount++ - ds.verifBytes += uint64(deal.Proposal.PieceSize) - } - } - - showDealStates := map[storagemarket.StorageDealStatus]struct{}{ - storagemarket.StorageDealActive: {}, - storagemarket.StorageDealTransferring: {}, - storagemarket.StorageDealStaged: {}, - storagemarket.StorageDealAwaitingPreCommit: {}, - storagemarket.StorageDealSealing: {}, - storagemarket.StorageDealPublish: {}, - storagemarket.StorageDealCheckForAcceptance: {}, - storagemarket.StorageDealPublishing: {}, - } - - var total dealStat - perState := map[storagemarket.StorageDealStatus]*dealStat{} - for _, deal := range deals { - if _, ok := showDealStates[deal.State]; !ok { - continue - } - if perState[deal.State] == nil { - perState[deal.State] = new(dealStat) - } - - dsAdd(&total, deal) - dsAdd(perState[deal.State], deal) - } - - type wstr struct { - str string - status storagemarket.StorageDealStatus - } - sorted := make([]wstr, 0, len(perState)) - for status, stat := range perState { - st := strings.TrimPrefix(storagemarket.DealStates[status], "StorageDeal") - sorted = append(sorted, wstr{ - str: fmt.Sprintf(" %s:\t%d\t\t%s\t(Verified: %d\t%s)\n", st, stat.count, types.SizeStr(types.NewInt(stat.bytes)), stat.verifCount, types.SizeStr(types.NewInt(stat.verifBytes))), - status: status, - }, - ) - } - sort.Slice(sorted, func(i, j int) bool { - if sorted[i].status == storagemarket.StorageDealActive || sorted[j].status == storagemarket.StorageDealActive { - return sorted[i].status == storagemarket.StorageDealActive - } - return sorted[i].status > sorted[j].status - }) - - fmt.Printf("Storage Deals: %d, %s\n", total.count, types.SizeStr(types.NewInt(total.bytes))) - - tw := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', 0) - for _, e := range sorted { - _, _ = tw.Write([]byte(e.str)) - } - - _ = tw.Flush() - fmt.Println() - - retrievals, err := nodeApi.MarketListRetrievalDeals(ctx) - if err != nil { - return xerrors.Errorf("getting retrieval deal list: %w", err) - } - - var retrComplete dealStat - for _, retrieval := range retrievals { - if retrieval.Status == retrievalmarket.DealStatusCompleted { - retrComplete.count++ - retrComplete.bytes += retrieval.TotalSent - } - } - - fmt.Printf("Retrieval Deals (complete): %d, %s\n", retrComplete.count, types.SizeStr(types.NewInt(retrComplete.bytes))) - - fmt.Println() } return nil } +func handleMiningInfo(cctx *cli.Context, ctx context.Context, fullapi v0api.FullNode, nodeApi api.StorageMiner) error { + maddr, err := getActorAddress(ctx, cctx) + if err != nil { + return err + } + + mact, err := fullapi.StateGetActor(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + tbs := blockstore.NewTieredBstore(blockstore.NewAPIBlockstore(fullapi), blockstore.NewMemory()) + mas, err := miner.Load(adt.WrapStore(ctx, cbor.NewCborStore(tbs)), mact) + if err != nil { + return err + } + + // Sector size + mi, err := fullapi.StateMinerInfo(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + ssize := types.SizeStr(types.NewInt(uint64(mi.SectorSize))) + fmt.Printf("Miner: %s (%s sectors)\n", color.BlueString("%s", maddr), ssize) + + pow, err := fullapi.StateMinerPower(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + fmt.Printf("Power: %s / %s (%0.4f%%)\n", + color.GreenString(types.DeciStr(pow.MinerPower.QualityAdjPower)), + types.DeciStr(pow.TotalPower.QualityAdjPower), + types.BigDivFloat( + types.BigMul(pow.MinerPower.QualityAdjPower, big.NewInt(100)), + pow.TotalPower.QualityAdjPower, + ), + ) + + fmt.Printf("\tRaw: %s / %s (%0.4f%%)\n", + color.BlueString(types.SizeStr(pow.MinerPower.RawBytePower)), + types.SizeStr(pow.TotalPower.RawBytePower), + types.BigDivFloat( + types.BigMul(pow.MinerPower.RawBytePower, big.NewInt(100)), + pow.TotalPower.RawBytePower, + ), + ) + secCounts, err := fullapi.StateMinerSectorCount(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + proving := secCounts.Active + secCounts.Faulty + nfaults := secCounts.Faulty + fmt.Printf("\tCommitted: %s\n", types.SizeStr(types.BigMul(types.NewInt(secCounts.Live), types.NewInt(uint64(mi.SectorSize))))) + if nfaults == 0 { + fmt.Printf("\tProving: %s\n", types.SizeStr(types.BigMul(types.NewInt(proving), types.NewInt(uint64(mi.SectorSize))))) + } else { + var faultyPercentage float64 + if secCounts.Live != 0 { + faultyPercentage = float64(100*nfaults) / float64(secCounts.Live) + } + fmt.Printf("\tProving: %s (%s Faulty, %.2f%%)\n", + types.SizeStr(types.BigMul(types.NewInt(proving), types.NewInt(uint64(mi.SectorSize)))), + types.SizeStr(types.BigMul(types.NewInt(nfaults), types.NewInt(uint64(mi.SectorSize)))), + faultyPercentage) + } + + if !pow.HasMinPower { + fmt.Print("Below minimum power threshold, no blocks will be won") + } else { + + winRatio := new(corebig.Rat).SetFrac( + types.BigMul(pow.MinerPower.QualityAdjPower, types.NewInt(build.BlocksPerEpoch)).Int, + pow.TotalPower.QualityAdjPower.Int, + ) + + if winRatioFloat, _ := winRatio.Float64(); winRatioFloat > 0 { + + // if the corresponding poisson distribution isn't infinitely small then + // throw it into the mix as well, accounting for multi-wins + winRationWithPoissonFloat := -math.Expm1(-winRatioFloat) + winRationWithPoisson := new(corebig.Rat).SetFloat64(winRationWithPoissonFloat) + if winRationWithPoisson != nil { + winRatio = winRationWithPoisson + winRatioFloat = winRationWithPoissonFloat + } + + weekly, _ := new(corebig.Rat).Mul( + winRatio, + new(corebig.Rat).SetInt64(7*builtin.EpochsInDay), + ).Float64() + + avgDuration, _ := new(corebig.Rat).Mul( + new(corebig.Rat).SetInt64(builtin.EpochDurationSeconds), + new(corebig.Rat).Inv(winRatio), + ).Float64() + + fmt.Print("Projected average block win rate: ") + color.Blue( + "%.02f/week (every %s)", + weekly, + (time.Second * time.Duration(avgDuration)).Truncate(time.Second).String(), + ) + + // Geometric distribution of P(Y < k) calculated as described in https://en.wikipedia.org/wiki/Geometric_distribution#Probability_Outcomes_Examples + // https://www.wolframalpha.com/input/?i=t+%3E+0%3B+p+%3E+0%3B+p+%3C+1%3B+c+%3E+0%3B+c+%3C1%3B+1-%281-p%29%5E%28t%29%3Dc%3B+solve+t + // t == how many dice-rolls (epochs) before win + // p == winRate == ( minerPower / netPower ) + // c == target probability of win ( 99.9% in this case ) + fmt.Print("Projected block win with ") + color.Green( + "99.9%% probability every %s", + (time.Second * time.Duration( + builtin.EpochDurationSeconds*math.Log(1-0.999)/ + math.Log(1-winRatioFloat), + )).Truncate(time.Second).String(), + ) + fmt.Println("(projections DO NOT account for future network and miner growth)") + } + } + + fmt.Println() + + spendable := big.Zero() + + // NOTE: there's no need to unlock anything here. Funds only + // vest on deadline boundaries, and they're unlocked by cron. + lockedFunds, err := mas.LockedFunds() + if err != nil { + return xerrors.Errorf("getting locked funds: %w", err) + } + availBalance, err := mas.AvailableBalance(mact.Balance) + if err != nil { + return xerrors.Errorf("getting available balance: %w", err) + } + spendable = big.Add(spendable, availBalance) + + fmt.Printf("Miner Balance: %s\n", color.YellowString("%s", types.FIL(mact.Balance).Short())) + fmt.Printf(" PreCommit: %s\n", types.FIL(lockedFunds.PreCommitDeposits).Short()) + fmt.Printf(" Pledge: %s\n", types.FIL(lockedFunds.InitialPledgeRequirement).Short()) + fmt.Printf(" Vesting: %s\n", types.FIL(lockedFunds.VestingFunds).Short()) + colorTokenAmount(" Available: %s\n", availBalance) + + mb, err := fullapi.StateMarketBalance(ctx, maddr, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting market balance: %w", err) + } + spendable = big.Add(spendable, big.Sub(mb.Escrow, mb.Locked)) + + fmt.Printf("Market Balance: %s\n", types.FIL(mb.Escrow).Short()) + fmt.Printf(" Locked: %s\n", types.FIL(mb.Locked).Short()) + colorTokenAmount(" Available: %s\n", big.Sub(mb.Escrow, mb.Locked)) + + wb, err := fullapi.WalletBalance(ctx, mi.Worker) + if err != nil { + return xerrors.Errorf("getting worker balance: %w", err) + } + spendable = big.Add(spendable, wb) + color.Cyan("Worker Balance: %s", types.FIL(wb).Short()) + if len(mi.ControlAddresses) > 0 { + cbsum := big.Zero() + for _, ca := range mi.ControlAddresses { + b, err := fullapi.WalletBalance(ctx, ca) + if err != nil { + return xerrors.Errorf("getting control address balance: %w", err) + } + cbsum = big.Add(cbsum, b) + } + spendable = big.Add(spendable, cbsum) + + fmt.Printf(" Control: %s\n", types.FIL(cbsum).Short()) + } + colorTokenAmount("Total Spendable: %s\n", spendable) + + fmt.Println() + + if !cctx.Bool("hide-sectors-info") { + fmt.Println("Sectors:") + err = sectorsInfo(ctx, nodeApi) + if err != nil { + return err + } + } + + // TODO: grab actr state / info + // * Sealed sectors (count / bytes) + // * Power + + return nil +} + +func handleMarketsInfo(ctx context.Context, nodeApi api.StorageMiner) error { + deals, err := nodeApi.MarketListIncompleteDeals(ctx) + if err != nil { + return err + } + + type dealStat struct { + count, verifCount int + bytes, verifBytes uint64 + } + dsAdd := func(ds *dealStat, deal storagemarket.MinerDeal) { + ds.count++ + ds.bytes += uint64(deal.Proposal.PieceSize) + if deal.Proposal.VerifiedDeal { + ds.verifCount++ + ds.verifBytes += uint64(deal.Proposal.PieceSize) + } + } + + showDealStates := map[storagemarket.StorageDealStatus]struct{}{ + storagemarket.StorageDealActive: {}, + storagemarket.StorageDealTransferring: {}, + storagemarket.StorageDealStaged: {}, + storagemarket.StorageDealAwaitingPreCommit: {}, + storagemarket.StorageDealSealing: {}, + storagemarket.StorageDealPublish: {}, + storagemarket.StorageDealCheckForAcceptance: {}, + storagemarket.StorageDealPublishing: {}, + } + + var total dealStat + perState := map[storagemarket.StorageDealStatus]*dealStat{} + for _, deal := range deals { + if _, ok := showDealStates[deal.State]; !ok { + continue + } + if perState[deal.State] == nil { + perState[deal.State] = new(dealStat) + } + + dsAdd(&total, deal) + dsAdd(perState[deal.State], deal) + } + + type wstr struct { + str string + status storagemarket.StorageDealStatus + } + sorted := make([]wstr, 0, len(perState)) + for status, stat := range perState { + st := strings.TrimPrefix(storagemarket.DealStates[status], "StorageDeal") + sorted = append(sorted, wstr{ + str: fmt.Sprintf(" %s:\t%d\t\t%s\t(Verified: %d\t%s)\n", st, stat.count, types.SizeStr(types.NewInt(stat.bytes)), stat.verifCount, types.SizeStr(types.NewInt(stat.verifBytes))), + status: status, + }, + ) + } + sort.Slice(sorted, func(i, j int) bool { + if sorted[i].status == storagemarket.StorageDealActive || sorted[j].status == storagemarket.StorageDealActive { + return sorted[i].status == storagemarket.StorageDealActive + } + return sorted[i].status > sorted[j].status + }) + + fmt.Printf("Storage Deals: %d, %s\n", total.count, types.SizeStr(types.NewInt(total.bytes))) + + tw := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', 0) + for _, e := range sorted { + _, _ = tw.Write([]byte(e.str)) + } + + _ = tw.Flush() + fmt.Println() + + retrievals, err := nodeApi.MarketListRetrievalDeals(ctx) + if err != nil { + return xerrors.Errorf("getting retrieval deal list: %w", err) + } + + var retrComplete dealStat + for _, retrieval := range retrievals { + if retrieval.Status == retrievalmarket.DealStatusCompleted { + retrComplete.count++ + retrComplete.bytes += retrieval.TotalSent + } + } + + fmt.Printf("Retrieval Deals (complete): %d, %s\n", retrComplete.count, types.SizeStr(types.NewInt(retrComplete.bytes))) + + fmt.Println() + + return nil +} + type stateMeta struct { i int col color.Attribute From 6969202a03466e7f46d280c05ae5bf0ca2ed0468 Mon Sep 17 00:00:00 2001 From: Anton Evangelatov Date: Wed, 28 Jul 2021 17:47:01 +0300 Subject: [PATCH 13/17] make linter happy --- cmd/lotus-miner/info.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/lotus-miner/info.go b/cmd/lotus-miner/info.go index 2a3627959..92f25667c 100644 --- a/cmd/lotus-miner/info.go +++ b/cmd/lotus-miner/info.go @@ -104,7 +104,7 @@ func infoCmdAct(cctx *cli.Context) error { fmt.Println() if subsystems.Has(api.SectorStorageSubsystem) { - err := handleMiningInfo(cctx, ctx, fullapi, nodeApi) + err := handleMiningInfo(ctx, cctx, fullapi, nodeApi) if err != nil { return err } @@ -120,7 +120,7 @@ func infoCmdAct(cctx *cli.Context) error { return nil } -func handleMiningInfo(cctx *cli.Context, ctx context.Context, fullapi v0api.FullNode, nodeApi api.StorageMiner) error { +func handleMiningInfo(ctx context.Context, cctx *cli.Context, fullapi v0api.FullNode, nodeApi api.StorageMiner) error { maddr, err := getActorAddress(ctx, cctx) if err != nil { return err From 07f40b94882e1233d29b9c7868a5755c6fbec688 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Wed, 28 Jul 2021 19:51:45 +0100 Subject: [PATCH 14/17] fix docs and nits. --- api/api_storage.go | 2 + api/api_subsystems.go | 63 ------------------ api/docgen/docgen.go | 10 ++- api/miner_subsystems.go | 79 +++++++++++++++++++++++ build/openrpc/miner.json.gz | Bin 9540 -> 9596 bytes cmd/lotus-miner/info.go | 4 +- documentation/en/api-v0-methods-miner.md | 12 +++- node/builder_miner.go | 2 +- node/impl/storminer.go | 10 +-- node/modules/storageminer.go | 11 ++-- 10 files changed, 113 insertions(+), 80 deletions(-) delete mode 100644 api/api_subsystems.go create mode 100644 api/miner_subsystems.go diff --git a/api/api_storage.go b/api/api_storage.go index d52032650..c39114929 100644 --- a/api/api_storage.go +++ b/api/api_storage.go @@ -166,6 +166,8 @@ type StorageMiner interface { MarketPendingDeals(ctx context.Context) (PendingDealInfo, error) //perm:write MarketPublishPendingDeals(ctx context.Context) error //perm:admin + // RuntimeSubsystems returns the subsystems that are enabled + // in this instance. RuntimeSubsystems(ctx context.Context) (MinerSubsystems, error) //perm:read DealsImportData(ctx context.Context, dealPropCid cid.Cid, file string) error //perm:admin diff --git a/api/api_subsystems.go b/api/api_subsystems.go deleted file mode 100644 index 1894bbdd8..000000000 --- a/api/api_subsystems.go +++ /dev/null @@ -1,63 +0,0 @@ -package api - -import ( - "bytes" - "encoding/json" -) - -type MinerSubsystems []MinerSubsystem - -func (ms MinerSubsystems) Has(entry MinerSubsystem) bool { - for _, v := range ms { - if v == entry { - return true - } - - } - return false -} - -type MinerSubsystem int - -const ( - MarketsSubsystem MinerSubsystem = iota - MiningSubsystem - SealingSubsystem - SectorStorageSubsystem -) - -func (ms MinerSubsystem) String() string { - return MinerSubsystemToString[ms] -} - -var MinerSubsystemToString = map[MinerSubsystem]string{ - MarketsSubsystem: "Markets", - MiningSubsystem: "Mining", - SealingSubsystem: "Sealing", - SectorStorageSubsystem: "SectorStorage", -} - -var MinerSubsystemToID = map[string]MinerSubsystem{ - "Markets": MarketsSubsystem, - "Mining": MiningSubsystem, - "Sealing": SealingSubsystem, - "SectorStorage": SectorStorageSubsystem, -} - -func (ms MinerSubsystem) MarshalJSON() ([]byte, error) { - buffer := bytes.NewBufferString(`"`) - buffer.WriteString(MinerSubsystemToString[ms]) - buffer.WriteString(`"`) - return buffer.Bytes(), nil -} - -func (ms *MinerSubsystem) UnmarshalJSON(b []byte) error { - var j string - err := json.Unmarshal(b, &j) - if err != nil { - return err - } - // TODO: handle zero value - *ms = MinerSubsystemToID[j] - return nil -} diff --git a/api/docgen/docgen.go b/api/docgen/docgen.go index 1e712a0ae..f9addc940 100644 --- a/api/docgen/docgen.go +++ b/api/docgen/docgen.go @@ -16,10 +16,10 @@ import ( "github.com/google/uuid" "github.com/ipfs/go-cid" "github.com/ipfs/go-filestore" - metrics "github.com/libp2p/go-libp2p-core/metrics" + "github.com/libp2p/go-libp2p-core/metrics" "github.com/libp2p/go-libp2p-core/network" "github.com/libp2p/go-libp2p-core/peer" - protocol "github.com/libp2p/go-libp2p-core/protocol" + "github.com/libp2p/go-libp2p-core/protocol" pubsub "github.com/libp2p/go-libp2p-pubsub" "github.com/multiformats/go-multiaddr" @@ -265,6 +265,12 @@ func init() { addExample(api.CheckStatusCode(0)) addExample(map[string]interface{}{"abc": 123}) + addExample(api.MinerSubsystems{ + api.SubsystemMining, + api.SubsystemSealing, + api.SubsystemSectorStorage, + api.SubsystemMarkets, + }) } func GetAPIType(name, pkg string) (i interface{}, t reflect.Type, permStruct []reflect.Type) { diff --git a/api/miner_subsystems.go b/api/miner_subsystems.go new file mode 100644 index 000000000..a77de7e3c --- /dev/null +++ b/api/miner_subsystems.go @@ -0,0 +1,79 @@ +package api + +import ( + "encoding/json" +) + +// MinerSubsystem represents a miner subsystem. Int and string values are not +// guaranteed to be stable over time is not +// guaranteed to be stable over time. +type MinerSubsystem int + +const ( + // SubsystemUnknown is a placeholder for the zero value. It should never + // be used. + SubsystemUnknown MinerSubsystem = iota + // SubsystemMarkets signifies the storage and retrieval + // deal-making subsystem. + SubsystemMarkets + // SubsystemMining signifies the mining subsystem. + SubsystemMining + // SubsystemSealing signifies the sealing subsystem. + SubsystemSealing + // SubsystemSectorStorage signifies the sector storage subsystem. + SubsystemSectorStorage +) + +var MinerSubsystemToString = map[MinerSubsystem]string{ + SubsystemUnknown: "Unknown", + SubsystemMarkets: "Markets", + SubsystemMining: "Mining", + SubsystemSealing: "Sealing", + SubsystemSectorStorage: "SectorStorage", +} + +var MinerSubsystemToID = map[string]MinerSubsystem{ + "Unknown": SubsystemUnknown, + "Markets": SubsystemMarkets, + "Mining": SubsystemMining, + "Sealing": SubsystemSealing, + "SectorStorage": SubsystemSectorStorage, +} + +func (ms MinerSubsystem) MarshalJSON() ([]byte, error) { + return json.Marshal(MinerSubsystemToString[ms]) +} + +func (ms *MinerSubsystem) UnmarshalJSON(b []byte) error { + var j string + err := json.Unmarshal(b, &j) + if err != nil { + return err + } + s, ok := MinerSubsystemToID[j] + if !ok { + *ms = SubsystemUnknown + } else { + *ms = s + } + return nil +} + +type MinerSubsystems []MinerSubsystem + +func (ms MinerSubsystems) Has(entry MinerSubsystem) bool { + for _, v := range ms { + if v == entry { + return true + } + } + return false +} + +func (ms MinerSubsystem) String() string { + s, ok := MinerSubsystemToString[ms] + if !ok { + return MinerSubsystemToString[SubsystemUnknown] + } + return s +} diff --git a/build/openrpc/miner.json.gz b/build/openrpc/miner.json.gz index 69d471dbd5673f06dc006a4d21f0a193b36bbb30..57a56d94fffd25d9f55069cc5127c44ce67d0b69 100644 GIT binary patch literal 9596 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 Date: Wed, 28 Jul 2021 14:46:13 -0700 Subject: [PATCH 15/17] feat(deps): update to branches with improved logging update sub repos with improved logging around data transfer processing --- go.mod | 8 ++++---- go.sum | 14 ++++++++------ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index b45284c8f..11d24b0f6 100644 --- a/go.mod +++ b/go.mod @@ -33,16 +33,16 @@ require ( github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2 github.com/filecoin-project/go-commp-utils v0.1.1-0.20210427191551-70bf140d31c7 github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 - github.com/filecoin-project/go-data-transfer v1.7.0 + github.com/filecoin-project/go-data-transfer v1.7.1 github.com/filecoin-project/go-fil-commcid v0.1.0 github.com/filecoin-project/go-fil-commp-hashhash v0.1.0 - github.com/filecoin-project/go-fil-markets v1.6.0 + github.com/filecoin-project/go-fil-markets v1.6.1 github.com/filecoin-project/go-jsonrpc v0.1.4-0.20210217175800-45ea43ac2bec github.com/filecoin-project/go-multistore v0.0.3 github.com/filecoin-project/go-padreader v0.0.0-20210723183308-812a16dc01b1 github.com/filecoin-project/go-paramfetch v0.0.2-0.20210614165157-25a6c7769498 github.com/filecoin-project/go-state-types v0.1.1-0.20210722133031-ad9bfe54c124 - github.com/filecoin-project/go-statemachine v0.0.0-20200925024713-05bd7c71fbfe + github.com/filecoin-project/go-statemachine v1.0.0 github.com/filecoin-project/go-statestore v0.1.1 github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b github.com/filecoin-project/specs-actors v0.9.14 @@ -78,7 +78,7 @@ require ( github.com/ipfs/go-ds-pebble v0.0.2-0.20200921225637-ce220f8ac459 github.com/ipfs/go-filestore v1.0.0 github.com/ipfs/go-fs-lock v0.0.6 - github.com/ipfs/go-graphsync v0.6.5 + github.com/ipfs/go-graphsync v0.6.6 github.com/ipfs/go-ipfs-blockstore v1.0.3 github.com/ipfs/go-ipfs-chunker v0.0.5 github.com/ipfs/go-ipfs-ds-help v1.0.0 diff --git a/go.sum b/go.sum index 88a31e57f..ca71b27d2 100644 --- a/go.sum +++ b/go.sum @@ -276,8 +276,9 @@ github.com/filecoin-project/go-commp-utils v0.1.1-0.20210427191551-70bf140d31c7/ github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 h1:2pMXdBnCiXjfCYx/hLqFxccPoqsSveQFxVLvNxy9bus= github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03/go.mod h1:+viYnvGtUTgJRdy6oaeF4MTFKAfatX071MPDPBL11EQ= github.com/filecoin-project/go-data-transfer v1.0.1/go.mod h1:UxvfUAY9v3ub0a21BSK9u3pB2aq30Y0KMsG+w9/ysyo= -github.com/filecoin-project/go-data-transfer v1.7.0 h1:mFRn+UuTdPROmhplLSekzd4rAs9ug8ubtSY4nw9wYkU= github.com/filecoin-project/go-data-transfer v1.7.0/go.mod h1:GLRr5BmLEqsLwXfiRDG7uJvph22KGL2M4iOuF8EINaU= +github.com/filecoin-project/go-data-transfer v1.7.1 h1:Co4bTenvCc3WnOhQWyXRt59FLZvxwH8UeF0ZCOc1ik0= +github.com/filecoin-project/go-data-transfer v1.7.1/go.mod h1:GLRr5BmLEqsLwXfiRDG7uJvph22KGL2M4iOuF8EINaU= github.com/filecoin-project/go-ds-versioning v0.1.0 h1:y/X6UksYTsK8TLCI7rttCKEvl8btmWxyFMEeeWGUxIQ= github.com/filecoin-project/go-ds-versioning v0.1.0/go.mod h1:mp16rb4i2QPmxBnmanUx8i/XANp+PFCCJWiAb+VW4/s= github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ= @@ -287,8 +288,8 @@ github.com/filecoin-project/go-fil-commcid v0.1.0/go.mod h1:Eaox7Hvus1JgPrL5+M3+ github.com/filecoin-project/go-fil-commp-hashhash v0.1.0 h1:imrrpZWEHRnNqqv0tN7LXep5bFEVOVmQWHJvl2mgsGo= github.com/filecoin-project/go-fil-commp-hashhash v0.1.0/go.mod h1:73S8WSEWh9vr0fDJVnKADhfIv/d6dCbAGaAGWbdJEI8= github.com/filecoin-project/go-fil-markets v1.0.5-0.20201113164554-c5eba40d5335/go.mod h1:AJySOJC00JRWEZzRG2KsfUnqEf5ITXxeX09BE9N4f9c= -github.com/filecoin-project/go-fil-markets v1.6.0 h1:+1usyX7rXz6Ey6hbHd/Fhx616ZvGCI94rW7wneMcptU= -github.com/filecoin-project/go-fil-markets v1.6.0/go.mod h1:ZuFDagROUV6GfvBU//KReTQDw+EZci4rH7jMYTD10vs= +github.com/filecoin-project/go-fil-markets v1.6.1 h1:8xdFyWrELfOzwcGa229bLu/olD+1l4sEWFIsZR7oz5U= +github.com/filecoin-project/go-fil-markets v1.6.1/go.mod h1:ZuFDagROUV6GfvBU//KReTQDw+EZci4rH7jMYTD10vs= github.com/filecoin-project/go-hamt-ipld v0.1.5 h1:uoXrKbCQZ49OHpsTCkrThPNelC4W3LPEk0OrS/ytIBM= github.com/filecoin-project/go-hamt-ipld v0.1.5/go.mod h1:6Is+ONR5Cd5R6XZoCse1CWaXZc0Hdb/JeX+EQCQzX24= github.com/filecoin-project/go-hamt-ipld/v2 v2.0.0 h1:b3UDemBYN2HNfk3KOXNuxgTTxlWi3xVvbQP0IT38fvM= @@ -313,8 +314,9 @@ github.com/filecoin-project/go-state-types v0.1.0/go.mod h1:ezYnPf0bNkTsDibL/psS github.com/filecoin-project/go-state-types v0.1.1-0.20210506134452-99b279731c48/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= github.com/filecoin-project/go-state-types v0.1.1-0.20210722133031-ad9bfe54c124 h1:veGrNABg/9I7prngrowkhwbvW5d5JN55MNKmbsr5FqA= github.com/filecoin-project/go-state-types v0.1.1-0.20210722133031-ad9bfe54c124/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= -github.com/filecoin-project/go-statemachine v0.0.0-20200925024713-05bd7c71fbfe h1:dF8u+LEWeIcTcfUcCf3WFVlc81Fr2JKg8zPzIbBDKDw= github.com/filecoin-project/go-statemachine v0.0.0-20200925024713-05bd7c71fbfe/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= +github.com/filecoin-project/go-statemachine v1.0.0 h1:b8FpFewPSklyAIUqH0oHt4nvKf03bU7asop1bJpjAtQ= +github.com/filecoin-project/go-statemachine v1.0.0/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= github.com/filecoin-project/go-statestore v0.1.0/go.mod h1:LFc9hD+fRxPqiHiaqUEZOinUJB4WARkRfNl10O7kTnI= github.com/filecoin-project/go-statestore v0.1.1 h1:ufMFq00VqnT2CAuDpcGnwLnCX1I/c3OROw/kXVNSTZk= github.com/filecoin-project/go-statestore v0.1.1/go.mod h1:LFc9hD+fRxPqiHiaqUEZOinUJB4WARkRfNl10O7kTnI= @@ -640,8 +642,8 @@ github.com/ipfs/go-graphsync v0.1.0/go.mod h1:jMXfqIEDFukLPZHqDPp8tJMbHO9Rmeb9CE github.com/ipfs/go-graphsync v0.4.2/go.mod h1:/VmbZTUdUMTbNkgzAiCEucIIAU3BkLE2cZrDCVUhyi0= github.com/ipfs/go-graphsync v0.4.3/go.mod h1:mPOwDYv128gf8gxPFgXnz4fNrSYPsWyqisJ7ych+XDY= github.com/ipfs/go-graphsync v0.6.4/go.mod h1:5WyaeigpNdpiYQuW2vwpuecOoEfB4h747ZGEOKmAGTg= -github.com/ipfs/go-graphsync v0.6.5 h1:YAJl6Yit23PQcaawzb1rPK9PSnbbq2jjMRPpRpJ0Y5U= -github.com/ipfs/go-graphsync v0.6.5/go.mod h1:GdHT8JeuIZ0R4lSjFR16Oe4zPi5dXwKi9zR9ADVlcdk= +github.com/ipfs/go-graphsync v0.6.6 h1:In7jjzvSXlrAUz4OjN41lxYf/dzkf1bVeVxLpwKMRo8= +github.com/ipfs/go-graphsync v0.6.6/go.mod h1:GdHT8JeuIZ0R4lSjFR16Oe4zPi5dXwKi9zR9ADVlcdk= github.com/ipfs/go-hamt-ipld v0.1.1/go.mod h1:1EZCr2v0jlCnhpa+aZ0JZYp8Tt2w16+JJOAVz17YcDk= github.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma1gROTlovZKBmN08= github.com/ipfs/go-ipfs-blockstore v0.1.0/go.mod h1:5aD0AvHPi7mZc6Ci1WCAhiBQu2IsfTduLl+422H6Rqw= From d3742048f9cff5565f34f9725c7fbd27ca078da9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Wed, 28 Jul 2021 23:46:21 +0100 Subject: [PATCH 16/17] address nits. --- node/builder_miner.go | 2 +- node/modules/storageminer.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/node/builder_miner.go b/node/builder_miner.go index acb9d3d43..3be055de7 100644 --- a/node/builder_miner.go +++ b/node/builder_miner.go @@ -72,7 +72,7 @@ func ConfigStorageMiner(c interface{}) Option { return Options( ConfigCommon(&cfg.Common, enableLibp2pNode), - Override(new(api.MinerSubsystems), modules.PopulateEnabledMinerSubsystems(cfg.Subsystems)), + Override(new(api.MinerSubsystems), modules.ExtractEnabledMinerSubsystems(cfg.Subsystems)), Override(new(stores.LocalStorage), From(new(repo.LockedRepo))), Override(new(*stores.Local), modules.LocalStorage), Override(new(*stores.Remote), modules.RemoteStorage), diff --git a/node/modules/storageminer.go b/node/modules/storageminer.go index 26792ca19..5497eab58 100644 --- a/node/modules/storageminer.go +++ b/node/modules/storageminer.go @@ -1008,7 +1008,7 @@ func mutateCfg(r repo.LockedRepo, mutator func(*config.StorageMiner)) error { return multierr.Combine(typeErr, setConfigErr) } -func PopulateEnabledMinerSubsystems(cfg config.MinerSubsystemConfig) (res api.MinerSubsystems) { +func ExtractEnabledMinerSubsystems(cfg config.MinerSubsystemConfig) (res api.MinerSubsystems) { if cfg.EnableMining { res = append(res, api.SubsystemMining) } @@ -1021,5 +1021,5 @@ func PopulateEnabledMinerSubsystems(cfg config.MinerSubsystemConfig) (res api.Mi if cfg.EnableMarkets { res = append(res, api.SubsystemMarkets) } - return + return res } From 256d12773be0adc008a0aa4642c77d141126cecc Mon Sep 17 00:00:00 2001 From: frrist Date: Wed, 28 Jul 2021 17:50:22 -0700 Subject: [PATCH 17/17] polish(errors): better state tree errors --- chain/state/statetree.go | 2 +- chain/stmgr/stmgr.go | 6 +++--- chain/store/messages.go | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/chain/state/statetree.go b/chain/state/statetree.go index 8705aeff8..8140cd4db 100644 --- a/chain/state/statetree.go +++ b/chain/state/statetree.go @@ -273,7 +273,7 @@ func LoadStateTree(cst cbor.IpldStore, c cid.Cid) (*StateTree, error) { } if err != nil { log.Errorf("failed to load state tree: %s", err) - return nil, xerrors.Errorf("failed to load state tree: %w", err) + return nil, xerrors.Errorf("failed to load state tree %s: %w", c, err) } s := &StateTree{ diff --git a/chain/stmgr/stmgr.go b/chain/stmgr/stmgr.go index b76dd0faf..1748c341e 100644 --- a/chain/stmgr/stmgr.go +++ b/chain/stmgr/stmgr.go @@ -221,7 +221,7 @@ func (sm *StateManager) ResolveToKeyAddress(ctx context.Context, addr address.Ad // First try to resolve the actor in the parent state, so we don't have to compute anything. tree, err := state.LoadStateTree(cst, ts.ParentState()) if err != nil { - return address.Undef, xerrors.Errorf("failed to load parent state tree: %w", err) + return address.Undef, xerrors.Errorf("failed to load parent state tree at tipset %s: %w", ts.Parents(), err) } resolved, err := vm.ResolveToKeyAddr(tree, cst, addr) @@ -232,12 +232,12 @@ func (sm *StateManager) ResolveToKeyAddress(ctx context.Context, addr address.Ad // If that fails, compute the tip-set and try again. st, _, err := sm.TipSetState(ctx, ts) if err != nil { - return address.Undef, xerrors.Errorf("resolve address failed to get tipset state: %w", err) + return address.Undef, xerrors.Errorf("resolve address failed to get tipset %s state: %w", ts, err) } tree, err = state.LoadStateTree(cst, st) if err != nil { - return address.Undef, xerrors.Errorf("failed to load state tree") + return address.Undef, xerrors.Errorf("failed to load state tree at tipset %s: %w", ts, err) } return vm.ResolveToKeyAddr(tree, cst, addr) diff --git a/chain/store/messages.go b/chain/store/messages.go index 50cf0e6a2..9f5160559 100644 --- a/chain/store/messages.go +++ b/chain/store/messages.go @@ -110,7 +110,7 @@ func (cs *ChainStore) BlockMsgsForTipset(ts *types.TipSet) ([]BlockMessages, err cst := cbor.NewCborStore(cs.stateBlockstore) st, err := state.LoadStateTree(cst, ts.Blocks()[0].ParentStateRoot) if err != nil { - return nil, xerrors.Errorf("failed to load state tree") + return nil, xerrors.Errorf("failed to load state tree at tipset %s: %w", ts, err) } selectMsg := func(m *types.Message) (bool, error) {