import sector/deal into state machines on init
This commit is contained in:
parent
0ca92bdca0
commit
ad978949db
@ -5,7 +5,7 @@ package build
|
|||||||
import "os"
|
import "os"
|
||||||
|
|
||||||
// Seconds
|
// Seconds
|
||||||
const BlockDelay = 2
|
const BlockDelay = 4
|
||||||
|
|
||||||
// Blocks
|
// Blocks
|
||||||
const ProvingPeriodDuration uint64 = 40
|
const ProvingPeriodDuration uint64 = 40
|
||||||
|
@ -3,16 +3,17 @@ package actors
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-amt-ipld"
|
"github.com/filecoin-project/go-amt-ipld"
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
"github.com/ipfs/go-hamt-ipld"
|
"github.com/ipfs/go-hamt-ipld"
|
||||||
"golang.org/x/xerrors"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
||||||
"github.com/filecoin-project/lotus/chain/address"
|
"github.com/filecoin-project/lotus/chain/address"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
"github.com/filecoin-project/lotus/lib/cborutil"
|
||||||
"github.com/filecoin-project/lotus/lib/sectorbuilder"
|
"github.com/filecoin-project/lotus/lib/sectorbuilder"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -110,6 +111,15 @@ func (sdp *StorageDealProposal) Sign(ctx context.Context, sign SignFunc) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (sdp *StorageDealProposal) Cid() (cid.Cid, error) {
|
||||||
|
nd, err := cborutil.AsIpld(sdp)
|
||||||
|
if err != nil {
|
||||||
|
return cid.Undef, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nd.Cid(), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (sdp *StorageDealProposal) Verify() error {
|
func (sdp *StorageDealProposal) Verify() error {
|
||||||
unsigned := *sdp
|
unsigned := *sdp
|
||||||
unsigned.ProposerSignature = nil
|
unsigned.ProposerSignature = nil
|
||||||
|
@ -24,6 +24,8 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/storage/sectorblocks"
|
"github.com/filecoin-project/lotus/storage/sectorblocks"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var ProviderDsPrefix = "/deals/provider"
|
||||||
|
|
||||||
type MinerDeal struct {
|
type MinerDeal struct {
|
||||||
Client peer.ID
|
Client peer.ID
|
||||||
Proposal actors.StorageDealProposal
|
Proposal actors.StorageDealProposal
|
||||||
@ -110,7 +112,7 @@ func NewProvider(ds dtypes.MetadataDS, sminer *storage.Miner, secb *sectorblocks
|
|||||||
|
|
||||||
actor: minerAddress,
|
actor: minerAddress,
|
||||||
|
|
||||||
deals: statestore.New(namespace.Wrap(ds, datastore.NewKey("/deals/client"))),
|
deals: statestore.New(namespace.Wrap(ds, datastore.NewKey(ProviderDsPrefix))),
|
||||||
ds: ds,
|
ds: ds,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,8 +3,12 @@ package main
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/ipfs/go-datastore"
|
"github.com/ipfs/go-datastore"
|
||||||
badger "github.com/ipfs/go-ds-badger"
|
badger "github.com/ipfs/go-ds-badger"
|
||||||
@ -14,12 +18,15 @@ import (
|
|||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
"gopkg.in/urfave/cli.v2"
|
"gopkg.in/urfave/cli.v2"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
lapi "github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain/actors"
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
"github.com/filecoin-project/lotus/chain/address"
|
"github.com/filecoin-project/lotus/chain/address"
|
||||||
|
"github.com/filecoin-project/lotus/chain/deals"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
lcli "github.com/filecoin-project/lotus/cli"
|
lcli "github.com/filecoin-project/lotus/cli"
|
||||||
|
"github.com/filecoin-project/lotus/genesis"
|
||||||
|
"github.com/filecoin-project/lotus/lib/cborutil"
|
||||||
"github.com/filecoin-project/lotus/lib/sectorbuilder"
|
"github.com/filecoin-project/lotus/lib/sectorbuilder"
|
||||||
"github.com/filecoin-project/lotus/miner"
|
"github.com/filecoin-project/lotus/miner"
|
||||||
"github.com/filecoin-project/lotus/node/modules"
|
"github.com/filecoin-project/lotus/node/modules"
|
||||||
@ -199,7 +206,116 @@ func migratePreSealedSectors(presealsb string, repoPath string, mds dtypes.Metad
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func storageMinerInit(ctx context.Context, cctx *cli.Context, api api.FullNode, r repo.Repo) error {
|
func migratePreSealMeta(ctx context.Context, api lapi.FullNode, presealDir string, maddr address.Address, mds dtypes.MetadataDS) error {
|
||||||
|
b, err := ioutil.ReadFile(filepath.Join(presealDir, "pre-seal-"+maddr.String()+".json"))
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("reading preseal metadata: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
preseals := map[string]genesis.GenesisMiner{}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(b, &preseals); err != nil {
|
||||||
|
return xerrors.Errorf("unmarshaling preseal metadata: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
meta, ok := preseals[maddr.String()]
|
||||||
|
if !ok {
|
||||||
|
return xerrors.New("got wrong preseal info")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, sector := range meta.Sectors {
|
||||||
|
sectorKey := datastore.NewKey(storage.SectorStorePrefix).ChildString(fmt.Sprint(sector.SectorID))
|
||||||
|
|
||||||
|
dealID, err := findMarketDealID(ctx, api, sector.Deal)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("finding storage deal for pre-sealed sector %d: %w", sector.SectorID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
info := &storage.SectorInfo{
|
||||||
|
State: lapi.Proving,
|
||||||
|
SectorID: sector.SectorID,
|
||||||
|
Pieces: []storage.Piece{
|
||||||
|
{
|
||||||
|
DealID: dealID,
|
||||||
|
Ref: fmt.Sprintf("preseal-%d", sector.SectorID),
|
||||||
|
Size: meta.SectorSize,
|
||||||
|
CommP: sector.CommD[:],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
CommC: nil,
|
||||||
|
CommD: sector.CommD[:],
|
||||||
|
CommR: sector.CommR[:],
|
||||||
|
CommRLast: nil,
|
||||||
|
Proof: nil,
|
||||||
|
Ticket: storage.SealTicket{},
|
||||||
|
PreCommitMessage: nil,
|
||||||
|
Seed: storage.SealSeed{},
|
||||||
|
CommitMessage: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := cborutil.Dump(info)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := mds.Put(sectorKey, b); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
proposalCid, err := sector.Deal.Proposal.Cid()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
dealKey := datastore.NewKey(deals.ProviderDsPrefix).ChildString(proposalCid.String())
|
||||||
|
|
||||||
|
deal := &deals.MinerDeal{
|
||||||
|
Proposal: sector.Deal.Proposal,
|
||||||
|
ProposalCid: proposalCid,
|
||||||
|
State: lapi.DealComplete,
|
||||||
|
Ref: proposalCid, // TODO: This is super wrong, but there
|
||||||
|
// are no params for CommP CIDs, we can't recover unixfs cid easily,
|
||||||
|
// and this isn't even used after the deal enters Complete state
|
||||||
|
DealID: dealID,
|
||||||
|
SectorID: sector.SectorID,
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err = cborutil.Dump(deal)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := mds.Put(dealKey, b); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func findMarketDealID(ctx context.Context, api lapi.FullNode, deal actors.StorageDeal) (uint64, error) {
|
||||||
|
// TODO: find a better way
|
||||||
|
// (this is only used by genesis miners)
|
||||||
|
|
||||||
|
deals, err := api.StateMarketDeals(ctx, nil)
|
||||||
|
if err != nil {
|
||||||
|
return 0, xerrors.Errorf("getting market deals: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range deals {
|
||||||
|
eq, err := cborutil.Equals(&v.Deal, &deal)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if eq {
|
||||||
|
return strconv.ParseUint(k, 10, 64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0, xerrors.New("deal not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
func storageMinerInit(ctx context.Context, cctx *cli.Context, api lapi.FullNode, r repo.Repo) error {
|
||||||
lr, err := r.Lock(repo.StorageMiner)
|
lr, err := r.Lock(repo.StorageMiner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -218,6 +334,11 @@ func storageMinerInit(ctx context.Context, cctx *cli.Context, api api.FullNode,
|
|||||||
return xerrors.Errorf("peer ID from private key: %w", err)
|
return xerrors.Errorf("peer ID from private key: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mds, err := lr.Datastore("/metadata")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
var addr address.Address
|
var addr address.Address
|
||||||
if act := cctx.String("actor"); act != "" {
|
if act := cctx.String("actor"); act != "" {
|
||||||
a, err := address.NewFromString(act)
|
a, err := address.NewFromString(act)
|
||||||
@ -226,10 +347,6 @@ func storageMinerInit(ctx context.Context, cctx *cli.Context, api api.FullNode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if cctx.Bool("genesis-miner") {
|
if cctx.Bool("genesis-miner") {
|
||||||
mds, err := lr.Datastore("/metadata")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := mds.Put(datastore.NewKey("miner-address"), a.Bytes()); err != nil {
|
if err := mds.Put(datastore.NewKey("miner-address"), a.Bytes()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -261,6 +378,14 @@ func storageMinerInit(ctx context.Context, cctx *cli.Context, api api.FullNode,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if pssb := cctx.String("pre-sealed-sectors"); pssb != "" {
|
||||||
|
log.Infof("Importing pre-sealed sector metadata for %s", a)
|
||||||
|
|
||||||
|
if err := migratePreSealMeta(ctx, api, cctx.String("pre-sealed-sectors"), a, mds); err != nil {
|
||||||
|
return xerrors.Errorf("migrating presealed sector metadata: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
} else {
|
} else {
|
||||||
if err := configureStorageMiner(ctx, api, a, peerid); err != nil {
|
if err := configureStorageMiner(ctx, api, a, peerid); err != nil {
|
||||||
@ -279,10 +404,6 @@ func storageMinerInit(ctx context.Context, cctx *cli.Context, api api.FullNode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("Created new storage miner: %s", addr)
|
log.Infof("Created new storage miner: %s", addr)
|
||||||
mds, err := lr.Datastore("/metadata")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := mds.Put(datastore.NewKey("miner-address"), addr.Bytes()); err != nil {
|
if err := mds.Put(datastore.NewKey("miner-address"), addr.Bytes()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -316,7 +437,7 @@ func makeHostKey(lr repo.LockedRepo) (crypto.PrivKey, error) {
|
|||||||
return pk, nil
|
return pk, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func configureStorageMiner(ctx context.Context, api api.FullNode, addr address.Address, peerid peer.ID) error {
|
func configureStorageMiner(ctx context.Context, api lapi.FullNode, addr address.Address, peerid peer.ID) error {
|
||||||
// This really just needs to be an api call at this point...
|
// This really just needs to be an api call at this point...
|
||||||
recp, err := api.StateCall(ctx, &types.Message{
|
recp, err := api.StateCall(ctx, &types.Message{
|
||||||
To: addr,
|
To: addr,
|
||||||
@ -369,7 +490,7 @@ func configureStorageMiner(ctx context.Context, api api.FullNode, addr address.A
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createStorageMiner(ctx context.Context, api api.FullNode, peerid peer.ID, cctx *cli.Context) (addr address.Address, err error) {
|
func createStorageMiner(ctx context.Context, api lapi.FullNode, peerid peer.ID, cctx *cli.Context) (addr address.Address, err error) {
|
||||||
log.Info("Creating StorageMarket.CreateStorageMiner message")
|
log.Info("Creating StorageMarket.CreateStorageMiner message")
|
||||||
|
|
||||||
var owner address.Address
|
var owner address.Address
|
||||||
|
@ -33,6 +33,7 @@ var runCmd = &cli.Command{
|
|||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "enable-gpu-proving",
|
Name: "enable-gpu-proving",
|
||||||
Usage: "Enable use of GPU for mining operations",
|
Usage: "Enable use of GPU for mining operations",
|
||||||
|
Value: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
|
@ -40,7 +40,7 @@ var DaemonCmd = &cli.Command{
|
|||||||
Hidden: true,
|
Hidden: true,
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "genesis-presealed-sectors",
|
Name: preSealedSectorsFlag,
|
||||||
Hidden: true,
|
Hidden: true,
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
|
@ -24,7 +24,7 @@ import (
|
|||||||
|
|
||||||
var log = logging.Logger("storageminer")
|
var log = logging.Logger("storageminer")
|
||||||
|
|
||||||
const PoStConfidence = 3
|
const SectorStorePrefix = "/sectors"
|
||||||
|
|
||||||
type Miner struct {
|
type Miner struct {
|
||||||
api storageMinerApi
|
api storageMinerApi
|
||||||
@ -83,7 +83,7 @@ func NewMiner(api storageMinerApi, addr address.Address, h host.Host, ds datasto
|
|||||||
sb: sb,
|
sb: sb,
|
||||||
tktFn: tktFn,
|
tktFn: tktFn,
|
||||||
|
|
||||||
sectors: statestore.New(namespace.Wrap(ds, datastore.NewKey("/sectors"))),
|
sectors: statestore.New(namespace.Wrap(ds, datastore.NewKey(SectorStorePrefix))),
|
||||||
|
|
||||||
sectorIncoming: make(chan *SectorInfo),
|
sectorIncoming: make(chan *SectorInfo),
|
||||||
sectorUpdated: make(chan sectorUpdate),
|
sectorUpdated: make(chan sectorUpdate),
|
||||||
|
@ -125,13 +125,13 @@ func (t *SectorInfo) rspco() sectorbuilder.RawSealPreCommitOutput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *Miner) sectorStateLoop(ctx context.Context) error {
|
func (m *Miner) sectorStateLoop(ctx context.Context) error {
|
||||||
toRestart, err := m.ListSectors()
|
trackedSectors, err := m.ListSectors()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for _, si := range toRestart {
|
for _, si := range trackedSectors {
|
||||||
select {
|
select {
|
||||||
case m.sectorUpdated <- sectorUpdate{
|
case m.sectorUpdated <- sectorUpdate{
|
||||||
newState: si.State,
|
newState: si.State,
|
||||||
@ -146,6 +146,32 @@ func (m *Miner) sectorStateLoop(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
{
|
||||||
|
// verify on-chain state
|
||||||
|
trackedByID := map[uint64]*SectorInfo{}
|
||||||
|
for _, si := range trackedSectors {
|
||||||
|
trackedByID[si.SectorID] = &si
|
||||||
|
}
|
||||||
|
|
||||||
|
curTs, err := m.api.ChainHead(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("getting chain head: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ps, err := m.api.StateMinerProvingSet(ctx, m.maddr, curTs)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, ocs := range ps {
|
||||||
|
if _, ok := trackedByID[ocs.SectorID]; ok {
|
||||||
|
continue // TODO: check state
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: attempt recovery
|
||||||
|
log.Warnf("untracked sector %d found on chain", ocs.SectorID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer log.Warn("quitting deal provider loop")
|
defer log.Warn("quitting deal provider loop")
|
||||||
defer close(m.stopped)
|
defer close(m.stopped)
|
||||||
@ -217,15 +243,15 @@ func (m *Miner) onSectorUpdated(ctx context.Context, update sectorUpdate) {
|
|||||||
|
|
||||||
switch update.newState {
|
switch update.newState {
|
||||||
case api.Packing:
|
case api.Packing:
|
||||||
m.handle(ctx, sector, m.finishPacking, api.Unsealed)
|
m.handleSectorUpdate(ctx, sector, m.finishPacking, api.Unsealed)
|
||||||
case api.Unsealed:
|
case api.Unsealed:
|
||||||
m.handle(ctx, sector, m.sealPreCommit, api.PreCommitting)
|
m.handleSectorUpdate(ctx, sector, m.sealPreCommit, api.PreCommitting)
|
||||||
case api.PreCommitting:
|
case api.PreCommitting:
|
||||||
m.handle(ctx, sector, m.preCommit, api.PreCommitted)
|
m.handleSectorUpdate(ctx, sector, m.preCommit, api.PreCommitted)
|
||||||
case api.PreCommitted:
|
case api.PreCommitted:
|
||||||
m.handle(ctx, sector, m.preCommitted, api.SectorNoUpdate)
|
m.handleSectorUpdate(ctx, sector, m.preCommitted, api.SectorNoUpdate)
|
||||||
case api.Committing:
|
case api.Committing:
|
||||||
m.handle(ctx, sector, m.committing, api.Proving)
|
m.handleSectorUpdate(ctx, sector, m.committing, api.Proving)
|
||||||
case api.Proving:
|
case api.Proving:
|
||||||
// TODO: track sector health / expiration
|
// TODO: track sector health / expiration
|
||||||
log.Infof("Proving sector %d", update.id)
|
log.Infof("Proving sector %d", update.id)
|
||||||
|
@ -14,7 +14,7 @@ import (
|
|||||||
|
|
||||||
type providerHandlerFunc func(ctx context.Context, deal SectorInfo) (func(*SectorInfo), error)
|
type providerHandlerFunc func(ctx context.Context, deal SectorInfo) (func(*SectorInfo), error)
|
||||||
|
|
||||||
func (m *Miner) handle(ctx context.Context, sector SectorInfo, cb providerHandlerFunc, next api.SectorState) {
|
func (m *Miner) handleSectorUpdate(ctx context.Context, sector SectorInfo, cb providerHandlerFunc, next api.SectorState) {
|
||||||
go func() {
|
go func() {
|
||||||
mut, err := cb(ctx, sector)
|
mut, err := cb(ctx, sector)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user