diff --git a/api/api_full.go b/api/api_full.go index a6763a310..70f822198 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -122,6 +122,7 @@ type FullNode interface { StateNetworkName(context.Context) (dtypes.NetworkName, error) StateMinerSectors(context.Context, address.Address, *abi.BitField, bool, types.TipSetKey) ([]*ChainSectorInfo, error) StateMinerProvingSet(context.Context, address.Address, types.TipSetKey) ([]*ChainSectorInfo, error) + StateMinerProvingDeadline(context.Context, address.Address, types.TipSetKey) (*miner.DeadlineInfo, error) StateMinerPower(context.Context, address.Address, types.TipSetKey) (*MinerPower, error) StateMinerInfo(context.Context, address.Address, types.TipSetKey) (miner.MinerInfo, error) StateMinerDeadlines(context.Context, address.Address, types.TipSetKey) (*miner.Deadlines, error) diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index cd5c6797a..ca55f2b36 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -116,6 +116,7 @@ type FullNodeStruct struct { StateNetworkName func(context.Context) (dtypes.NetworkName, error) `perm:"read"` StateMinerSectors func(context.Context, address.Address, *abi.BitField, bool, types.TipSetKey) ([]*api.ChainSectorInfo, error) `perm:"read"` StateMinerProvingSet func(context.Context, address.Address, types.TipSetKey) ([]*api.ChainSectorInfo, error) `perm:"read"` + StateMinerProvingDeadline func(context.Context, address.Address, types.TipSetKey) (*miner.DeadlineInfo, error) `perm:"read"` StateMinerPower func(context.Context, address.Address, types.TipSetKey) (*api.MinerPower, error) `perm:"read"` StateMinerInfo func(context.Context, address.Address, types.TipSetKey) (miner.MinerInfo, error) `perm:"read"` StateMinerDeadlines func(context.Context, address.Address, types.TipSetKey) (*miner.Deadlines, error) `perm:"read"` @@ -503,6 +504,10 @@ func (c *FullNodeStruct) StateMinerProvingSet(ctx context.Context, addr address. return c.Internal.StateMinerProvingSet(ctx, addr, tsk) } +func (c *FullNodeStruct) StateMinerProvingDeadline(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*miner.DeadlineInfo, error) { + return c.Internal.StateMinerProvingDeadline(ctx, addr, tsk) +} + func (c *FullNodeStruct) StateMinerPower(ctx context.Context, a address.Address, tsk types.TipSetKey) (*api.MinerPower, error) { return c.Internal.StateMinerPower(ctx, a, tsk) } diff --git a/cmd/lotus-storage-miner/proving.go b/cmd/lotus-storage-miner/proving.go index 40b6a745b..bb6c16e51 100644 --- a/cmd/lotus-storage-miner/proving.go +++ b/cmd/lotus-storage-miner/proving.go @@ -1,6 +1,7 @@ package main import ( + "bytes" "fmt" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/types" @@ -47,13 +48,11 @@ var provingInfoCmd = &cli.Command{ return xerrors.Errorf("getting chain head: %w", err) } - mi, err := api.StateMinerInfo(ctx, maddr, head.Key()) + cd, err := api.StateMinerProvingDeadline(ctx, maddr, head.Key()) if err != nil { return xerrors.Errorf("getting miner info: %w", err) } - cd, _ := miner.ComputeProvingPeriodDeadline(mi.ProvingPeriodBoundary, head.Height()) - deadlines, err := api.StateMinerDeadlines(ctx, maddr, head.Key()) if err != nil { return xerrors.Errorf("getting miner deadlines: %w", err) @@ -64,15 +63,58 @@ var provingInfoCmd = &cli.Command{ return xerrors.Errorf("counting deadline sectors: %w", err) } + var mas miner.State + { + mact, err := api.StateGetActor(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + rmas, err := api.ChainReadObj(ctx, mact.Head) + if err != nil { + return err + } + if err := mas.UnmarshalCBOR(bytes.NewReader(rmas)); err != nil { + return err + } + } + + newSectors, err := mas.NewSectors.Count() + if err != nil { + return err + } + + faults, err := mas.Faults.Count() + if err != nil { + return err + } + + recoveries, err := mas.Recoveries.Count() + if err != nil { + return err + } + + var provenSectors uint64 + for _, d := range deadlines.Due { + c, err := d.Count() + if err != nil { + return err + } + provenSectors += c + } + fmt.Printf("Current Epoch: %d\n", cd.CurrentEpoch) fmt.Printf("Chain Period: %d\n", cd.CurrentEpoch/miner.WPoStProvingPeriod) fmt.Printf("Chain Period Start: %s\n", epochTime(cd.CurrentEpoch, (cd.CurrentEpoch/miner.WPoStProvingPeriod)*miner.WPoStProvingPeriod)) fmt.Printf("Chain Period End: %s\n\n", epochTime(cd.CurrentEpoch, (cd.CurrentEpoch/miner.WPoStProvingPeriod+1)*miner.WPoStProvingPeriod)) - fmt.Printf("Proving Period Boundary: %d\n", mi.ProvingPeriodBoundary) + fmt.Printf("Proving Period Boundary: %d\n", cd.PeriodStart % miner.WPoStProvingPeriod) fmt.Printf("Proving Period Start: %s\n", epochTime(cd.CurrentEpoch, cd.PeriodStart)) fmt.Printf("Next Period Start: %s\n\n", epochTime(cd.CurrentEpoch, cd.PeriodStart+miner.WPoStProvingPeriod)) + fmt.Printf("Faults: %d (%.2f%%)\n", faults, float64(faults*10000/provenSectors)/100) + fmt.Printf("Recovering: %d\n", recoveries) + fmt.Printf("New Sectors: %d\n\n", newSectors) + fmt.Printf("Deadline Index: %d\n", cd.Index) fmt.Printf("Deadline Sectors: %d\n", curDeadlineSectors) fmt.Printf("Deadline Open: %s\n", epochTime(cd.CurrentEpoch, cd.Open)) @@ -123,13 +165,46 @@ var provingDeadlinesCmd = &cli.Command{ return xerrors.Errorf("getting deadlines: %w", err) } + di, err := api.StateMinerProvingDeadline(ctx, maddr, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting deadlines: %w", err) + } + + var mas miner.State + { + mact, err := api.StateGetActor(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + rmas, err := api.ChainReadObj(ctx, mact.Head) + if err != nil { + return err + } + if err := mas.UnmarshalCBOR(bytes.NewReader(rmas)); err != nil { + return err + } + } + for i, field := range deadlines.Due { c, err := field.Count() if err != nil { return err } - fmt.Printf("%d: %d sectors\n", i, c) + var info string + proven, err := mas.PostSubmissions.IsSet(uint64(i)) + if err != nil { + return err + } + + if proven { + info += ", proven" + } + + if di.Index == uint64(i) { + info += " (current)" + } + fmt.Printf("%d: %d sectors%s\n", i, c, info) } return nil diff --git a/go.mod b/go.mod index af5f0dd62..a296dcf86 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( github.com/filecoin-project/go-paramfetch v0.0.2-0.20200218225740-47c639bab663 github.com/filecoin-project/go-statestore v0.1.0 github.com/filecoin-project/sector-storage v0.0.0-20200423222053-9eb049a833b9 - github.com/filecoin-project/specs-actors v1.0.0 + github.com/filecoin-project/specs-actors v1.0.1-0.20200424162204-fcb213d54806 github.com/filecoin-project/specs-storage v0.0.0-20200417134612-61b2d91a6102 github.com/filecoin-project/storage-fsm v0.0.0-20200423114251-f3bea4aa8bd7 github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1 diff --git a/go.sum b/go.sum index ed2c60f83..1de3119ed 100644 --- a/go.sum +++ b/go.sum @@ -170,8 +170,9 @@ github.com/filecoin-project/sector-storage v0.0.0-20200423222053-9eb049a833b9 h1 github.com/filecoin-project/sector-storage v0.0.0-20200423222053-9eb049a833b9/go.mod h1:ooso9kOFQaZwk50u+Wc/tRISeETwuDREef8pC3EHQCI= github.com/filecoin-project/specs-actors v0.0.0-20200210130641-2d1fbd8672cf/go.mod h1:xtDZUB6pe4Pksa/bAJbJ693OilaC5Wbot9jMhLm3cZA= github.com/filecoin-project/specs-actors v0.0.0-20200409043918-e569f4a2f504/go.mod h1:mdJraXq5vMy0+/FqVQIrnNlpQ/Em6zeu06G/ltQ0/lA= -github.com/filecoin-project/specs-actors v1.0.0 h1:H0G6n2R8MnfvYuI0irmY7Bj5FI/JHUxnIldg/YX472I= github.com/filecoin-project/specs-actors v1.0.0/go.mod h1:nQYnFbQ7Y0bHZyq6HDEuVlCPR+U3z5Q3wMOQ+2aiV+Y= +github.com/filecoin-project/specs-actors v1.0.1-0.20200424162204-fcb213d54806 h1:nd0t/NvUFFAbml8etVqr9UHnpUib0IZuJ2eajGa0xqU= +github.com/filecoin-project/specs-actors v1.0.1-0.20200424162204-fcb213d54806/go.mod h1:nQYnFbQ7Y0bHZyq6HDEuVlCPR+U3z5Q3wMOQ+2aiV+Y= github.com/filecoin-project/specs-storage v0.0.0-20200410185809-9fbaaa08f275 h1:6OTcpsTQBQM0f/A67oEi4E4YtYd6fzkMqbU8cPIWMMs= github.com/filecoin-project/specs-storage v0.0.0-20200410185809-9fbaaa08f275/go.mod h1:xJ1/xl9+8zZeSSSFmDC3Wr6uusCTxyYPI0VeNVSFmPE= github.com/filecoin-project/specs-storage v0.0.0-20200417134612-61b2d91a6102 h1:T3f/zkuvgtgqcXrb0NO3BicuveGOxxUAMPa/Yif2kuE= diff --git a/node/impl/client/client.go b/node/impl/client/client.go index 3a5cb3bc7..a001d0296 100644 --- a/node/impl/client/client.go +++ b/node/impl/client/client.go @@ -66,12 +66,12 @@ type API struct { Filestore dtypes.ClientFilestore `optional:"true"` } -func calcDealExpiration(minDuration uint64, mi miner.MinerInfo, ts *types.TipSet) abi.ChainEpoch { +func calcDealExpiration(minDuration uint64, md *miner.DeadlineInfo, ts *types.TipSet) abi.ChainEpoch { // Make sure we give some time for the miner to seal minExp := ts.Height() + dealStartBuffer + abi.ChainEpoch(minDuration) // Align on miners ProvingPeriodBoundary - return minExp + miner.WPoStProvingPeriod - (minExp % miner.WPoStProvingPeriod) + mi.ProvingPeriodBoundary - 1 + return minExp + miner.WPoStProvingPeriod - (minExp % miner.WPoStProvingPeriod) + (md.PeriodStart % miner.WPoStProvingPeriod) - 1 } func (a *API) ClientStartDeal(ctx context.Context, params *api.StartDealParams) (*cid.Cid, error) { @@ -88,6 +88,11 @@ func (a *API) ClientStartDeal(ctx context.Context, params *api.StartDealParams) return nil, xerrors.Errorf("failed getting peer ID: %w", err) } + md, err := a.StateMinerProvingDeadline(ctx, params.Miner, types.EmptyTSK) + if err != nil { + return nil, xerrors.Errorf("failed getting peer ID: %w", err) + } + rt, err := ffiwrapper.SealProofTypeFromSectorSize(mi.SectorSize) if err != nil { return nil, xerrors.Errorf("bad sector size: %w", err) @@ -109,7 +114,7 @@ func (a *API) ClientStartDeal(ctx context.Context, params *api.StartDealParams) &providerInfo, params.Data, ts.Height()+dealStartBuffer, - calcDealExpiration(params.MinBlocksDuration, mi, ts), + calcDealExpiration(params.MinBlocksDuration, md, ts), params.EpochPrice, big.Zero(), rt, diff --git a/node/impl/full/state.go b/node/impl/full/state.go index 04902978b..26ecb0523 100644 --- a/node/impl/full/state.go +++ b/node/impl/full/state.go @@ -91,6 +91,21 @@ func (a *StateAPI) StateMinerDeadlines(ctx context.Context, m address.Address, t return stmgr.GetMinerDeadlines(ctx, a.StateManager, ts, m) } +func (a *StateAPI) StateMinerProvingDeadline(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*miner.DeadlineInfo, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + + var mas miner.State + _, err = a.StateManager.LoadActorState(ctx, addr, &mas, ts) + if err != nil { + return nil, xerrors.Errorf("(get sset) failed to load miner actor state: %w", err) + } + + return miner.ComputeProvingPeriodDeadline(mas.ProvingPeriodStart, ts.Height()), nil +} + func (a *StateAPI) StateMinerFaults(ctx context.Context, addr address.Address, tsk types.TipSetKey) ([]abi.SectorNumber, error) { ts, err := a.Chain.GetTipSetFromKey(tsk) if err != nil { diff --git a/storage/miner.go b/storage/miner.go index c3b9d404f..b15b67019 100644 --- a/storage/miner.go +++ b/storage/miner.go @@ -51,6 +51,7 @@ type storageMinerApi interface { StateMinerSectors(context.Context, address.Address, *abi.BitField, bool, types.TipSetKey) ([]*api.ChainSectorInfo, error) StateSectorPreCommitInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error) StateMinerInfo(context.Context, address.Address, types.TipSetKey) (miner.MinerInfo, error) + StateMinerProvingDeadline(context.Context, address.Address, types.TipSetKey) (*miner.DeadlineInfo, error) StateMinerInitialPledgeCollateral(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (types.BigInt, error) StateWaitMsg(context.Context, cid.Cid) (*api.MsgLookup, error) // TODO: removeme eventually StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error) @@ -94,14 +95,14 @@ func (m *Miner) Run(ctx context.Context) error { return xerrors.Errorf("miner preflight checks failed: %w", err) } - mi, err := m.api.StateMinerInfo(ctx, m.maddr, types.EmptyTSK) + md, err := m.api.StateMinerProvingDeadline(ctx, m.maddr, types.EmptyTSK) if err != nil { return xerrors.Errorf("getting miner info: %w", err) } evts := events.NewEvents(ctx, m.api) adaptedAPI := NewSealingAPIAdapter(m.api) - pcp := sealing.NewBasicPreCommitPolicy(adaptedAPI, 10000000, mi.ProvingPeriodBoundary) + pcp := sealing.NewBasicPreCommitPolicy(adaptedAPI, 10000000, md.PeriodStart % miner.WPoStProvingPeriod) m.sealing = sealing.New(adaptedAPI, NewEventsAdapter(evts), m.maddr, m.ds, m.sealer, m.sc, m.verif, &pcp) go m.sealing.Run(ctx) diff --git a/storage/wdpost_sched.go b/storage/wdpost_sched.go index 81fc7bc5d..f3b61e29f 100644 --- a/storage/wdpost_sched.go +++ b/storage/wdpost_sched.go @@ -148,13 +148,11 @@ func (s *WindowPoStScheduler) revert(ctx context.Context, newLowest *types.TipSe } s.cur = newLowest - mi, err := s.api.StateMinerInfo(ctx, s.actor, newLowest.Key()) + newDeadline, err := s.api.StateMinerProvingDeadline(ctx, s.actor, newLowest.Key()) if err != nil { return err } - newDeadline, _ := deadlineInfo(mi, newLowest) - if !deadlineEquals(s.activeDeadline, newDeadline) { s.abortActivePoSt() } @@ -167,16 +165,15 @@ func (s *WindowPoStScheduler) update(ctx context.Context, new *types.TipSet) err return xerrors.Errorf("no new tipset in WindowPoStScheduler.update") } - mi, err := s.api.StateMinerInfo(ctx, s.actor, new.Key()) + di, err := s.api.StateMinerProvingDeadline(ctx, s.actor, new.Key()) if err != nil { return err } - di, nn := deadlineInfo(mi, new) if deadlineEquals(s.activeDeadline, di) { return nil // already working on this deadline } - if !nn { + if !di.PeriodStarted() { return nil // not proving anything yet } @@ -214,7 +211,3 @@ func (s *WindowPoStScheduler) abortActivePoSt() { s.activeDeadline = nil s.abort = nil } - -func deadlineInfo(mi miner.MinerInfo, new *types.TipSet) (*miner.DeadlineInfo, bool) { - return miner.ComputeProvingPeriodDeadline(mi.ProvingPeriodBoundary, new.Height()) -}