feat: miner: API/CLI to compute window-post

This commit is contained in:
Łukasz Magiera 2022-03-28 16:54:22 -04:00
parent a709a0a682
commit 54cb55a7ae
13 changed files with 287 additions and 25 deletions

View File

@ -6,6 +6,7 @@ import (
"time" "time"
"github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/actors/builtin"
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
@ -51,6 +52,8 @@ type StorageMiner interface {
MiningBase(context.Context) (*types.TipSet, error) //perm:read MiningBase(context.Context) (*types.TipSet, error) //perm:read
ComputeWindowPoSt(ctx context.Context, dlIdx uint64, tsk types.TipSetKey) ([]miner.SubmitWindowedPoStParams, error) //perm:admin
// Temp api for testing // Temp api for testing
PledgeSector(context.Context) (abi.SectorID, error) //perm:write PledgeSector(context.Context) (abi.SectorID, error) //perm:write

View File

@ -641,6 +641,8 @@ type StorageMinerStruct struct {
ComputeProof func(p0 context.Context, p1 []builtin.ExtendedSectorInfo, p2 abi.PoStRandomness, p3 abi.ChainEpoch, p4 abinetwork.Version) ([]builtin.PoStProof, error) `perm:"read"` ComputeProof func(p0 context.Context, p1 []builtin.ExtendedSectorInfo, p2 abi.PoStRandomness, p3 abi.ChainEpoch, p4 abinetwork.Version) ([]builtin.PoStProof, error) `perm:"read"`
ComputeWindowPoSt func(p0 context.Context, p1 uint64, p2 types.TipSetKey) ([]miner.SubmitWindowedPoStParams, error) `perm:"admin"`
CreateBackup func(p0 context.Context, p1 string) error `perm:"admin"` CreateBackup func(p0 context.Context, p1 string) error `perm:"admin"`
DagstoreGC func(p0 context.Context) ([]DagstoreShardResult, error) `perm:"admin"` DagstoreGC func(p0 context.Context) ([]DagstoreShardResult, error) `perm:"admin"`
@ -3857,6 +3859,17 @@ func (s *StorageMinerStub) ComputeProof(p0 context.Context, p1 []builtin.Extende
return *new([]builtin.PoStProof), ErrNotSupported return *new([]builtin.PoStProof), ErrNotSupported
} }
func (s *StorageMinerStruct) ComputeWindowPoSt(p0 context.Context, p1 uint64, p2 types.TipSetKey) ([]miner.SubmitWindowedPoStParams, error) {
if s.Internal.ComputeWindowPoSt == nil {
return *new([]miner.SubmitWindowedPoStParams), ErrNotSupported
}
return s.Internal.ComputeWindowPoSt(p0, p1, p2)
}
func (s *StorageMinerStub) ComputeWindowPoSt(p0 context.Context, p1 uint64, p2 types.TipSetKey) ([]miner.SubmitWindowedPoStParams, error) {
return *new([]miner.SubmitWindowedPoStParams), ErrNotSupported
}
func (s *StorageMinerStruct) CreateBackup(p0 context.Context, p1 string) error { func (s *StorageMinerStruct) CreateBackup(p0 context.Context, p1 string) error {
if s.Internal.CreateBackup == nil { if s.Internal.CreateBackup == nil {
return ErrNotSupported return ErrNotSupported

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,10 +1,12 @@
package main package main
import ( import (
"encoding/json"
"fmt" "fmt"
"os" "os"
"strconv" "strconv"
"text/tabwriter" "text/tabwriter"
"time"
"github.com/fatih/color" "github.com/fatih/color"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
@ -31,6 +33,7 @@ var provingCmd = &cli.Command{
provingFaultsCmd, provingFaultsCmd,
provingCheckProvableCmd, provingCheckProvableCmd,
workersCmd(false), workersCmd(false),
provingComputeCmd,
}, },
} }
@ -510,3 +513,50 @@ var provingCheckProvableCmd = &cli.Command{
return tw.Flush() return tw.Flush()
}, },
} }
var provingComputeCmd = &cli.Command{
Name: "compute",
Subcommands: []*cli.Command{
provingComputeWindowPoStCmd,
},
}
var provingComputeWindowPoStCmd = &cli.Command{
Name: "window-post",
Usage: "Compute WindowPoSt for a specific deadline",
Description: `Note: This command is intended to be used to verify PoSt compute performance.
It will not send any messages to the chain.`,
ArgsUsage: "[deadline index]",
Action: func(cctx *cli.Context) error {
if cctx.Args().Len() != 1 {
return xerrors.Errorf("must pass deadline index")
}
dlIdx, err := strconv.ParseUint(cctx.Args().Get(0), 10, 64)
if err != nil {
return xerrors.Errorf("could not parse deadline index: %w", err)
}
sapi, scloser, err := lcli.GetStorageMinerAPI(cctx)
if err != nil {
return err
}
defer scloser()
ctx := lcli.ReqContext(cctx)
start := time.Now()
res, err := sapi.ComputeWindowPoSt(ctx, dlIdx, types.EmptyTSK)
fmt.Printf("Took %s\n", time.Now().Sub(start))
if err != nil {
return err
}
jr, err := json.Marshal(res)
if err != nil {
return err
}
fmt.Println(string(jr))
return nil
},
}

View File

@ -16,6 +16,7 @@
* [CheckProvable](#CheckProvable) * [CheckProvable](#CheckProvable)
* [Compute](#Compute) * [Compute](#Compute)
* [ComputeProof](#ComputeProof) * [ComputeProof](#ComputeProof)
* [ComputeWindowPoSt](#ComputeWindowPoSt)
* [Create](#Create) * [Create](#Create)
* [CreateBackup](#CreateBackup) * [CreateBackup](#CreateBackup)
* [Dagstore](#Dagstore) * [Dagstore](#Dagstore)
@ -394,6 +395,52 @@ Response:
] ]
``` ```
### ComputeWindowPoSt
Perms: admin
Inputs:
```json
[
42,
[
{
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
{
"/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve"
}
]
]
```
Response:
```json
[
{
"Deadline": 42,
"Partitions": [
{
"Index": 42,
"Skipped": [
5,
1
]
}
],
"Proofs": [
{
"PoStProof": 8,
"ProofBytes": "Ynl0ZSBhcnJheQ=="
}
],
"ChainCommitEpoch": 10101,
"ChainCommitRand": "Bw=="
}
]
```
## Create ## Create

View File

@ -2041,6 +2041,7 @@ COMMANDS:
faults View the currently known proving faulty sectors information faults View the currently known proving faulty sectors information
check Check sectors provable check Check sectors provable
workers list workers workers list workers
compute
help, h Shows a list of commands or help for one command help, h Shows a list of commands or help for one command
OPTIONS: OPTIONS:
@ -2131,6 +2132,40 @@ OPTIONS:
``` ```
### lotus-miner proving compute
```
NAME:
lotus-miner proving compute - A new cli application
USAGE:
lotus-miner proving compute command [command options] [arguments...]
COMMANDS:
window-post Compute WindowPoSt for a specific deadline
help, h Shows a list of commands or help for one command
OPTIONS:
--help, -h show help (default: false)
```
#### lotus-miner proving compute window-post
```
NAME:
lotus-miner proving compute window-post - Compute WindowPoSt for a specific deadline
USAGE:
lotus-miner proving compute window-post [command options] [deadline index]
DESCRIPTION:
Note: This command is intended to be used to verify PoSt compute performance.
It will not send any messages to the chain.
OPTIONS:
--help, -h show help (default: false)
```
## lotus-miner storage ## lotus-miner storage
``` ```
NAME: NAME:

View File

@ -296,3 +296,49 @@ func TestWindowPostWorkerSkipBadSector(t *testing.T) {
require.Equal(t, p.MinerPower, p.TotalPower) require.Equal(t, p.MinerPower, p.TotalPower)
require.Equal(t, p.MinerPower.RawBytePower, types.NewInt(uint64(ssz)*uint64(sectors-1))) require.Equal(t, p.MinerPower.RawBytePower, types.NewInt(uint64(ssz)*uint64(sectors-1)))
} }
func TestWindowPostWorkerManualPoSt(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
_ = logging.SetLogLevel("storageminer", "INFO")
sectors := 2 * 48 * 2
client, miner, _, ens := kit.EnsembleWorker(t,
kit.PresealSectors(sectors), // 2 sectors per partition, 2 partitions in all 48 deadlines
kit.LatestActorsAt(-1),
kit.ThroughRPC(),
kit.WithTaskTypes([]sealtasks.TaskType{sealtasks.TTGenerateWindowPoSt}))
maddr, err := miner.ActorAddress(ctx)
require.NoError(t, err)
di, err := client.StateMinerProvingDeadline(ctx, maddr, types.EmptyTSK)
require.NoError(t, err)
bm := ens.InterconnectAll().BeginMiningMustPost(2 * time.Millisecond)[0]
di = di.NextNotElapsed()
t.Log("Running one proving period")
waitUntil := di.Open + di.WPoStChallengeWindow*2 - 2
client.WaitTillChain(ctx, kit.HeightAtLeast(waitUntil))
t.Log("Waiting for post message")
bm.Stop()
tryDl := func(dl uint64) {
p, err := miner.ComputeWindowPoSt(ctx, dl, types.EmptyTSK)
require.NoError(t, err)
require.Len(t, p, 1)
require.Equal(t, dl, p[0].Deadline)
}
tryDl(0)
tryDl(40)
tryDl(di.Index + 4)
lastPending, err := client.MpoolPending(ctx, types.EmptyTSK)
require.NoError(t, err)
require.Len(t, lastPending, 0)
}

View File

@ -108,10 +108,10 @@ func ConfigStorageMiner(c interface{}) Option {
// Mining / proving // Mining / proving
Override(new(*slashfilter.SlashFilter), modules.NewSlashFilter), Override(new(*slashfilter.SlashFilter), modules.NewSlashFilter),
Override(new(*storage.Miner), modules.StorageMiner(config.DefaultStorageMiner().Fees)),
Override(new(*miner.Miner), modules.SetupBlockProducer), Override(new(*miner.Miner), modules.SetupBlockProducer),
Override(new(gen.WinningPoStProver), storage.NewWinningPoStProver), Override(new(gen.WinningPoStProver), storage.NewWinningPoStProver),
Override(new(*storage.Miner), modules.StorageMiner(cfg.Fees)), Override(new(*storage.Miner), modules.StorageMiner(cfg.Fees)),
Override(new(*storage.WindowPoStScheduler), modules.WindowPostScheduler(cfg.Fees)),
Override(new(sectorblocks.SectorBuilder), From(new(*storage.Miner))), Override(new(sectorblocks.SectorBuilder), From(new(*storage.Miner))),
), ),

View File

@ -16,6 +16,7 @@ import (
"github.com/filecoin-project/go-jsonrpc/auth" "github.com/filecoin-project/go-jsonrpc/auth"
"github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/actors/builtin"
lminer "github.com/filecoin-project/lotus/chain/actors/builtin/miner"
"github.com/filecoin-project/lotus/chain/gen" "github.com/filecoin-project/lotus/chain/gen"
"github.com/google/uuid" "github.com/google/uuid"
@ -92,6 +93,8 @@ type StorageMinerAPI struct {
storiface.WorkerReturn `optional:"true"` storiface.WorkerReturn `optional:"true"`
AddrSel *storage.AddressSelector AddrSel *storage.AddressSelector
WdPoSt *storage.WindowPoStScheduler
Epp gen.WinningPoStProver `optional:"true"` Epp gen.WinningPoStProver `optional:"true"`
DS dtypes.MetadataDS DS dtypes.MetadataDS
@ -407,6 +410,21 @@ func (sm *StorageMinerAPI) SectorMatchPendingPiecesToOpenSectors(ctx context.Con
return sm.Miner.SectorMatchPendingPiecesToOpenSectors(ctx) return sm.Miner.SectorMatchPendingPiecesToOpenSectors(ctx)
} }
func (sm *StorageMinerAPI) ComputeWindowPoSt(ctx context.Context, dlIdx uint64, tsk types.TipSetKey) ([]lminer.SubmitWindowedPoStParams, error) {
var ts *types.TipSet
var err error
if tsk == types.EmptyTSK {
ts, err = sm.Full.ChainHead(ctx)
} else {
ts, err = sm.Full.ChainGetTipSet(ctx, tsk)
}
if err != nil {
return nil, err
}
return sm.WdPoSt.ComputePoSt(ctx, dlIdx, ts)
}
func (sm *StorageMinerAPI) WorkerConnect(ctx context.Context, url string) error { func (sm *StorageMinerAPI) WorkerConnect(ctx context.Context, url string) error {
w, err := connectRemoteWorker(ctx, sm, url) w, err := connectRemoteWorker(ctx, sm, url)
if err != nil { if err != nil {

View File

@ -215,6 +215,7 @@ type StorageMinerParams struct {
GetSealingConfigFn dtypes.GetSealingConfigFunc GetSealingConfigFn dtypes.GetSealingConfigFunc
Journal journal.Journal Journal journal.Journal
AddrSel *storage.AddressSelector AddrSel *storage.AddressSelector
Maddr dtypes.MinerAddress
} }
func StorageMiner(fc config.MinerFeeConfig) func(params StorageMinerParams) (*storage.Miner, error) { func StorageMiner(fc config.MinerFeeConfig) func(params StorageMinerParams) (*storage.Miner, error) {
@ -231,20 +232,11 @@ func StorageMiner(fc config.MinerFeeConfig) func(params StorageMinerParams) (*st
gsd = params.GetSealingConfigFn gsd = params.GetSealingConfigFn
j = params.Journal j = params.Journal
as = params.AddrSel as = params.AddrSel
maddr = address.Address(params.Maddr)
) )
maddr, err := minerAddrFromDS(ds)
if err != nil {
return nil, err
}
ctx := helpers.LifecycleCtx(mctx, lc) ctx := helpers.LifecycleCtx(mctx, lc)
fps, err := storage.NewWindowedPoStScheduler(api, fc, as, sealer, verif, sealer, j, maddr)
if err != nil {
return nil, err
}
sm, err := storage.NewMiner(api, maddr, ds, sealer, sc, verif, prover, gsd, fc, j, as) sm, err := storage.NewMiner(api, maddr, ds, sealer, sc, verif, prover, gsd, fc, j, as)
if err != nil { if err != nil {
return nil, err return nil, err
@ -252,7 +244,6 @@ func StorageMiner(fc config.MinerFeeConfig) func(params StorageMinerParams) (*st
lc.Append(fx.Hook{ lc.Append(fx.Hook{
OnStart: func(context.Context) error { OnStart: func(context.Context) error {
go fps.Run(ctx)
return sm.Run(ctx) return sm.Run(ctx)
}, },
OnStop: sm.Stop, OnStop: sm.Stop,
@ -262,6 +253,37 @@ func StorageMiner(fc config.MinerFeeConfig) func(params StorageMinerParams) (*st
} }
} }
func WindowPostScheduler(fc config.MinerFeeConfig) func(params StorageMinerParams) (*storage.WindowPoStScheduler, error) {
return func(params StorageMinerParams) (*storage.WindowPoStScheduler, error) {
var (
mctx = params.MetricsCtx
lc = params.Lifecycle
api = params.API
sealer = params.Sealer
verif = params.Verifier
j = params.Journal
as = params.AddrSel
maddr = address.Address(params.Maddr)
)
ctx := helpers.LifecycleCtx(mctx, lc)
fps, err := storage.NewWindowedPoStScheduler(api, fc, as, sealer, verif, sealer, j, maddr)
if err != nil {
return nil, err
}
lc.Append(fx.Hook{
OnStart: func(context.Context) error {
go fps.Run(ctx)
return nil
},
})
return fps, nil
}
}
func HandleRetrieval(host host.Host, lc fx.Lifecycle, m retrievalmarket.RetrievalProvider, j journal.Journal) { func HandleRetrieval(host host.Host, lc fx.Lifecycle, m retrievalmarket.RetrievalProvider, j journal.Journal) {
m.OnReady(marketevents.ReadyLogger("retrieval provider")) m.OnReady(marketevents.ReadyLogger("retrieval provider"))
lc.Append(fx.Hook{ lc.Append(fx.Hook{

View File

@ -93,7 +93,7 @@ func (s *WindowPoStScheduler) runGeneratePoST(
ctx, span := trace.StartSpan(ctx, "WindowPoStScheduler.generatePoST") ctx, span := trace.StartSpan(ctx, "WindowPoStScheduler.generatePoST")
defer span.End() defer span.End()
posts, err := s.runPoStCycle(ctx, *deadline, ts) posts, err := s.runPoStCycle(ctx, false, *deadline, ts)
if err != nil { if err != nil {
log.Errorf("runPoStCycle failed: %+v", err) log.Errorf("runPoStCycle failed: %+v", err)
return nil, err return nil, err
@ -449,19 +449,8 @@ func (s *WindowPoStScheduler) declareFaults(ctx context.Context, dlIdx uint64, p
return faults, sm, nil return faults, sm, nil
} }
// runPoStCycle runs a full cycle of the PoSt process: func (s *WindowPoStScheduler) asyncFaultRecover(di dline.Info, ts *types.TipSet) {
//
// 1. performs recovery declarations for the next deadline.
// 2. performs fault declarations for the next deadline.
// 3. computes and submits proofs, batching partitions and making sure they
// don't exceed message capacity.
func (s *WindowPoStScheduler) runPoStCycle(ctx context.Context, di dline.Info, ts *types.TipSet) ([]miner.SubmitWindowedPoStParams, error) {
ctx, span := trace.StartSpan(ctx, "storage.runPoStCycle")
defer span.End()
go func() { go func() {
// TODO: extract from runPoStCycle, run on fault cutoff boundaries
// check faults / recoveries for the *next* deadline. It's already too // check faults / recoveries for the *next* deadline. It's already too
// late to declare them for this deadline // late to declare them for this deadline
declDeadline := (di.Index + 2) % di.WPoStPeriodDeadlines declDeadline := (di.Index + 2) % di.WPoStPeriodDeadlines
@ -520,6 +509,24 @@ func (s *WindowPoStScheduler) runPoStCycle(ctx context.Context, di dline.Info, t
} }
}) })
}() }()
}
// runPoStCycle runs a full cycle of the PoSt process:
//
// 1. performs recovery declarations for the next deadline.
// 2. performs fault declarations for the next deadline.
// 3. computes and submits proofs, batching partitions and making sure they
// don't exceed message capacity.
//
// When `manual` is set, no messages (fault/recover) will be automatically sent
func (s *WindowPoStScheduler) runPoStCycle(ctx context.Context, manual bool, di dline.Info, ts *types.TipSet) ([]miner.SubmitWindowedPoStParams, error) {
ctx, span := trace.StartSpan(ctx, "storage.runPoStCycle")
defer span.End()
if !manual {
// TODO: extract from runPoStCycle, run on fault cutoff boundaries
s.asyncFaultRecover(di, ts)
}
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
if err := s.actor.MarshalCBOR(buf); err != nil { if err := s.actor.MarshalCBOR(buf); err != nil {
@ -941,3 +948,24 @@ func (s *WindowPoStScheduler) prepareMessage(ctx context.Context, msg *types.Mes
} }
return nil return nil
} }
func (s *WindowPoStScheduler) ComputePoSt(ctx context.Context, dlIdx uint64, ts *types.TipSet) ([]miner.SubmitWindowedPoStParams, error) {
dl, err := s.api.StateMinerProvingDeadline(ctx, s.actor, ts.Key())
if err != nil {
return nil, xerrors.Errorf("getting deadline: %w", err)
}
curIdx := dl.Index
dl.Index = dlIdx
dlDiff := dl.Index - curIdx
if dl.Index > curIdx {
dlDiff -= dl.WPoStPeriodDeadlines
dl.PeriodStart -= dl.WPoStProvingPeriod
}
epochDiff := (dl.WPoStProvingPeriod / abi.ChainEpoch(dl.WPoStPeriodDeadlines)) * abi.ChainEpoch(dlDiff)
// runPoStCycle only needs dl.Index and dl.Challenge
dl.Challenge += epochDiff
return s.runPoStCycle(ctx, true, *dl, ts)
}