2019-07-19 09:24:11 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2020-03-06 08:06:59 +00:00
|
|
|
"bytes"
|
2019-08-16 21:50:00 +00:00
|
|
|
"context"
|
2019-10-03 00:02:06 +00:00
|
|
|
"crypto/rand"
|
2020-03-04 02:24:08 +00:00
|
|
|
"encoding/binary"
|
2019-11-29 19:11:01 +00:00
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
2020-02-27 21:45:31 +00:00
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
2020-03-05 01:12:52 +00:00
|
|
|
"path/filepath"
|
2020-02-27 21:45:31 +00:00
|
|
|
"strconv"
|
|
|
|
|
2020-03-05 01:12:52 +00:00
|
|
|
"github.com/google/uuid"
|
2019-11-16 06:47:04 +00:00
|
|
|
"github.com/ipfs/go-datastore"
|
|
|
|
"github.com/libp2p/go-libp2p-core/crypto"
|
|
|
|
"github.com/libp2p/go-libp2p-core/peer"
|
|
|
|
"github.com/mitchellh/go-homedir"
|
|
|
|
"golang.org/x/xerrors"
|
|
|
|
"gopkg.in/urfave/cli.v2"
|
2019-07-19 09:24:11 +00:00
|
|
|
|
2020-03-17 20:19:52 +00:00
|
|
|
"github.com/filecoin-project/go-address"
|
|
|
|
cborutil "github.com/filecoin-project/go-cbor-util"
|
|
|
|
paramfetch "github.com/filecoin-project/go-paramfetch"
|
|
|
|
"github.com/filecoin-project/go-sectorbuilder"
|
|
|
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
|
|
|
"github.com/filecoin-project/specs-actors/actors/builtin"
|
|
|
|
"github.com/filecoin-project/specs-actors/actors/builtin/market"
|
|
|
|
miner2 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
|
|
|
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
|
|
|
crypto2 "github.com/filecoin-project/specs-actors/actors/crypto"
|
|
|
|
|
2019-11-29 19:11:01 +00:00
|
|
|
lapi "github.com/filecoin-project/lotus/api"
|
2019-10-18 04:47:41 +00:00
|
|
|
"github.com/filecoin-project/lotus/build"
|
|
|
|
"github.com/filecoin-project/lotus/chain/actors"
|
|
|
|
"github.com/filecoin-project/lotus/chain/types"
|
|
|
|
lcli "github.com/filecoin-project/lotus/cli"
|
2019-11-29 19:11:01 +00:00
|
|
|
"github.com/filecoin-project/lotus/genesis"
|
2019-11-25 04:45:13 +00:00
|
|
|
"github.com/filecoin-project/lotus/miner"
|
2020-02-04 22:57:51 +00:00
|
|
|
"github.com/filecoin-project/lotus/node/config"
|
2019-11-27 01:39:07 +00:00
|
|
|
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
2019-10-18 04:47:41 +00:00
|
|
|
"github.com/filecoin-project/lotus/node/repo"
|
2019-11-25 04:45:13 +00:00
|
|
|
"github.com/filecoin-project/lotus/storage"
|
2020-01-15 20:49:11 +00:00
|
|
|
"github.com/filecoin-project/lotus/storage/sealing"
|
2020-03-23 11:40:02 +00:00
|
|
|
"github.com/filecoin-project/lotus/storage/sectorstorage"
|
|
|
|
"github.com/filecoin-project/lotus/storage/sectorstorage/stores"
|
2019-07-19 09:24:11 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var initCmd = &cli.Command{
|
|
|
|
Name: "init",
|
|
|
|
Usage: "Initialize a lotus storage miner repo",
|
2019-08-16 21:50:00 +00:00
|
|
|
Flags: []cli.Flag{
|
|
|
|
&cli.StringFlag{
|
|
|
|
Name: "actor",
|
|
|
|
Usage: "specify the address of an already created miner actor",
|
|
|
|
},
|
2019-08-20 18:17:59 +00:00
|
|
|
&cli.BoolFlag{
|
2019-09-26 20:57:20 +00:00
|
|
|
Name: "genesis-miner",
|
|
|
|
Usage: "enable genesis mining (DON'T USE ON BOOTSTRAPPED NETWORK)",
|
2019-09-26 12:19:21 +00:00
|
|
|
Hidden: true,
|
2019-08-20 18:17:59 +00:00
|
|
|
},
|
2019-09-26 00:47:53 +00:00
|
|
|
&cli.BoolFlag{
|
|
|
|
Name: "create-worker-key",
|
|
|
|
Usage: "create separate worker key",
|
|
|
|
},
|
2019-09-26 12:19:21 +00:00
|
|
|
&cli.StringFlag{
|
2019-09-26 20:57:20 +00:00
|
|
|
Name: "worker",
|
2019-09-26 12:19:21 +00:00
|
|
|
Aliases: []string{"w"},
|
2019-09-26 20:57:20 +00:00
|
|
|
Usage: "worker key to use (overrides --create-worker-key)",
|
2019-09-26 12:19:21 +00:00
|
|
|
},
|
|
|
|
&cli.StringFlag{
|
2019-09-26 20:57:20 +00:00
|
|
|
Name: "owner",
|
2019-09-26 12:19:21 +00:00
|
|
|
Aliases: []string{"o"},
|
2019-09-26 20:57:20 +00:00
|
|
|
Usage: "owner key to use",
|
2019-09-26 12:19:21 +00:00
|
|
|
},
|
2019-10-16 07:07:16 +00:00
|
|
|
&cli.Uint64Flag{
|
|
|
|
Name: "sector-size",
|
|
|
|
Usage: "specify sector size to use",
|
2020-02-10 18:21:10 +00:00
|
|
|
Value: uint64(build.SectorSizes[0]),
|
2019-10-16 07:07:16 +00:00
|
|
|
},
|
2020-03-03 22:19:22 +00:00
|
|
|
&cli.StringSliceFlag{
|
2019-11-25 04:45:13 +00:00
|
|
|
Name: "pre-sealed-sectors",
|
|
|
|
Usage: "specify set of presealed sectors for starting as a genesis miner",
|
|
|
|
},
|
2020-02-04 22:56:56 +00:00
|
|
|
&cli.StringFlag{
|
|
|
|
Name: "pre-sealed-metadata",
|
|
|
|
Usage: "specify the metadata file for the presealed sectors",
|
|
|
|
},
|
2019-12-04 16:53:32 +00:00
|
|
|
&cli.BoolFlag{
|
|
|
|
Name: "nosync",
|
|
|
|
Usage: "don't check full-node sync status",
|
|
|
|
},
|
2019-12-10 17:11:59 +00:00
|
|
|
&cli.BoolFlag{
|
|
|
|
Name: "symlink-imported-sectors",
|
|
|
|
Usage: "attempt to symlink to presealed sectors instead of copying them into place",
|
|
|
|
},
|
2020-03-05 01:12:52 +00:00
|
|
|
&cli.BoolFlag{
|
|
|
|
Name: "no-local-storage",
|
|
|
|
Usage: "don't use storageminer repo for sector storage",
|
|
|
|
},
|
2019-08-16 21:50:00 +00:00
|
|
|
},
|
2019-07-19 09:24:11 +00:00
|
|
|
Action: func(cctx *cli.Context) error {
|
|
|
|
log.Info("Initializing lotus storage miner")
|
|
|
|
|
2020-02-09 06:06:32 +00:00
|
|
|
ssize := abi.SectorSize(cctx.Uint64("sector-size"))
|
2019-12-04 19:44:15 +00:00
|
|
|
|
2019-12-10 17:11:59 +00:00
|
|
|
symlink := cctx.Bool("symlink-imported-sectors")
|
|
|
|
if symlink {
|
|
|
|
log.Info("will attempt to symlink to imported sectors")
|
|
|
|
}
|
|
|
|
|
2019-10-02 17:20:30 +00:00
|
|
|
log.Info("Checking proof parameters")
|
2020-02-09 06:06:32 +00:00
|
|
|
if err := paramfetch.GetParams(build.ParametersJson(), uint64(ssize)); err != nil {
|
2019-10-02 17:20:30 +00:00
|
|
|
return xerrors.Errorf("fetching proof parameters: %w", err)
|
|
|
|
}
|
|
|
|
|
2019-12-04 00:25:18 +00:00
|
|
|
log.Info("Trying to connect to full node RPC")
|
|
|
|
|
|
|
|
api, closer, err := lcli.GetFullNodeAPI(cctx) // TODO: consider storing full node address in config
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer closer()
|
|
|
|
ctx := lcli.ReqContext(cctx)
|
|
|
|
|
|
|
|
log.Info("Checking full node sync status")
|
|
|
|
|
2019-12-04 16:53:32 +00:00
|
|
|
if !cctx.Bool("genesis-miner") && !cctx.Bool("nosync") {
|
2019-12-04 00:25:18 +00:00
|
|
|
if err := lcli.SyncWait(ctx, api); err != nil {
|
|
|
|
return xerrors.Errorf("sync wait: %w", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-02 20:29:40 +00:00
|
|
|
log.Info("Checking if repo exists")
|
|
|
|
|
2019-10-18 05:13:36 +00:00
|
|
|
repoPath := cctx.String(FlagStorageRepo)
|
|
|
|
r, err := repo.NewFS(repoPath)
|
2019-07-19 09:24:11 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-07-23 21:54:54 +00:00
|
|
|
ok, err := r.Exists()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if ok {
|
2019-07-23 21:50:52 +00:00
|
|
|
return xerrors.Errorf("repo at '%s' is already initialized", cctx.String(FlagStorageRepo))
|
2019-07-19 09:24:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
log.Info("Checking full node version")
|
|
|
|
|
2019-07-19 10:15:22 +00:00
|
|
|
v, err := api.Version(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-12-17 15:26:16 +00:00
|
|
|
if !v.APIVersion.EqMajorMinor(build.APIVersion) {
|
2019-12-17 15:27:41 +00:00
|
|
|
return xerrors.Errorf("Remote API version didn't match (local %s, remote %s)", build.APIVersion, v.APIVersion)
|
2019-07-19 10:15:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
log.Info("Initializing repo")
|
|
|
|
|
2019-11-12 17:59:38 +00:00
|
|
|
if err := r.Init(repo.StorageMiner); err != nil {
|
2019-07-19 09:24:11 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-03-05 01:12:52 +00:00
|
|
|
{
|
2019-11-27 01:39:07 +00:00
|
|
|
lr, err := r.Lock(repo.StorageMiner)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-03-05 01:12:52 +00:00
|
|
|
|
2020-03-09 19:22:30 +00:00
|
|
|
var localPaths []config.LocalPath
|
2020-02-27 21:45:31 +00:00
|
|
|
|
2020-03-05 01:12:52 +00:00
|
|
|
if pssb := cctx.StringSlice("pre-sealed-sectors"); len(pssb) != 0 {
|
2020-03-20 00:20:01 +00:00
|
|
|
log.Infof("Setting up storage config with presealed sectors: %v", pssb)
|
2020-03-05 01:12:52 +00:00
|
|
|
|
|
|
|
for _, psp := range pssb {
|
|
|
|
psp, err := homedir.Expand(psp)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-03-09 19:22:30 +00:00
|
|
|
localPaths = append(localPaths, config.LocalPath{
|
2020-03-05 01:12:52 +00:00
|
|
|
Path: psp,
|
|
|
|
})
|
2020-03-03 22:19:22 +00:00
|
|
|
}
|
2019-12-01 05:55:20 +00:00
|
|
|
}
|
2019-11-30 23:17:50 +00:00
|
|
|
|
2020-03-05 01:12:52 +00:00
|
|
|
if !cctx.Bool("no-local-storage") {
|
2020-03-19 15:10:19 +00:00
|
|
|
b, err := json.MarshalIndent(&stores.LocalStorageMeta{
|
2020-03-13 11:59:19 +00:00
|
|
|
ID: stores.ID(uuid.New().String()),
|
2020-03-05 19:21:06 +00:00
|
|
|
Weight: 10,
|
|
|
|
CanSeal: true,
|
|
|
|
CanStore: true,
|
|
|
|
}, "", " ")
|
|
|
|
if err != nil {
|
|
|
|
return xerrors.Errorf("marshaling storage config: %w", err)
|
|
|
|
}
|
2020-03-05 01:12:52 +00:00
|
|
|
|
2020-03-05 19:21:06 +00:00
|
|
|
if err := ioutil.WriteFile(filepath.Join(lr.Path(), "sectorstore.json"), b, 0644); err != nil {
|
2020-03-09 06:13:22 +00:00
|
|
|
return xerrors.Errorf("persisting storage metadata (%s): %w", filepath.Join(lr.Path(), "sectorstore.json"), err)
|
2020-03-05 19:21:06 +00:00
|
|
|
}
|
2020-03-09 05:45:12 +00:00
|
|
|
|
2020-03-09 19:22:30 +00:00
|
|
|
localPaths = append(localPaths, config.LocalPath{
|
2020-03-09 05:45:12 +00:00
|
|
|
Path: lr.Path(),
|
|
|
|
})
|
2020-03-05 01:12:52 +00:00
|
|
|
}
|
|
|
|
|
2020-03-09 19:22:30 +00:00
|
|
|
if err := lr.SetStorage(func(sc *config.StorageConfig) {
|
|
|
|
sc.StoragePaths = append(sc.StoragePaths, localPaths...)
|
|
|
|
}); err != nil {
|
2020-03-03 22:19:22 +00:00
|
|
|
return xerrors.Errorf("set storage config: %w", err)
|
2019-12-01 05:55:20 +00:00
|
|
|
}
|
2019-11-30 23:17:50 +00:00
|
|
|
|
2020-03-04 02:24:08 +00:00
|
|
|
if err := lr.Close(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-11-25 04:45:13 +00:00
|
|
|
}
|
|
|
|
|
2020-03-04 02:24:08 +00:00
|
|
|
if err := storageMinerInit(ctx, cctx, api, r, ssize); err != nil {
|
2019-11-16 06:16:18 +00:00
|
|
|
log.Errorf("Failed to initialize lotus-storage-miner: %+v", err)
|
2019-11-16 06:47:04 +00:00
|
|
|
path, err := homedir.Expand(repoPath)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2019-10-18 05:13:36 +00:00
|
|
|
}
|
2019-11-16 06:47:04 +00:00
|
|
|
log.Infof("Cleaning up %s after attempt...", path)
|
|
|
|
if err := os.RemoveAll(path); err != nil {
|
2019-11-15 11:54:12 +00:00
|
|
|
log.Errorf("Failed to clean up failed storage repo: %s", err)
|
|
|
|
}
|
|
|
|
return xerrors.Errorf("Storage-miner init failed")
|
2019-07-25 12:50:34 +00:00
|
|
|
}
|
|
|
|
|
2019-10-18 05:13:36 +00:00
|
|
|
// TODO: Point to setting storage price, maybe do it interactively or something
|
|
|
|
log.Info("Storage miner successfully created, you can now start it with 'lotus-storage-miner run'")
|
2019-07-25 12:50:34 +00:00
|
|
|
|
2019-10-18 05:13:36 +00:00
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
2019-07-25 12:50:34 +00:00
|
|
|
|
2020-02-04 22:56:56 +00:00
|
|
|
func migratePreSealMeta(ctx context.Context, api lapi.FullNode, metadata string, maddr address.Address, mds dtypes.MetadataDS) error {
|
|
|
|
metadata, err := homedir.Expand(metadata)
|
2019-11-30 09:25:31 +00:00
|
|
|
if err != nil {
|
|
|
|
return xerrors.Errorf("expanding preseal dir: %w", err)
|
|
|
|
}
|
|
|
|
|
2020-02-04 22:56:56 +00:00
|
|
|
b, err := ioutil.ReadFile(metadata)
|
2019-11-29 19:11:01 +00:00
|
|
|
if err != nil {
|
|
|
|
return xerrors.Errorf("reading preseal metadata: %w", err)
|
|
|
|
}
|
|
|
|
|
2020-03-20 00:20:01 +00:00
|
|
|
psm := map[string]genesis.Miner{}
|
|
|
|
if err := json.Unmarshal(b, &psm); err != nil {
|
2019-11-29 19:11:01 +00:00
|
|
|
return xerrors.Errorf("unmarshaling preseal metadata: %w", err)
|
|
|
|
}
|
|
|
|
|
2020-03-20 00:20:01 +00:00
|
|
|
meta, ok := psm[maddr.String()]
|
|
|
|
if !ok {
|
|
|
|
return xerrors.Errorf("preseal file didn't contain metadata for miner %s", maddr)
|
|
|
|
}
|
|
|
|
|
2020-03-04 02:24:08 +00:00
|
|
|
maxSectorID := abi.SectorNumber(0)
|
2019-11-29 19:11:01 +00:00
|
|
|
for _, sector := range meta.Sectors {
|
2020-01-15 20:49:11 +00:00
|
|
|
sectorKey := datastore.NewKey(sealing.SectorStorePrefix).ChildString(fmt.Sprint(sector.SectorID))
|
2019-11-29 19:11:01 +00:00
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
2020-02-27 21:45:31 +00:00
|
|
|
commD := sector.CommD
|
|
|
|
commR := sector.CommR
|
2019-11-29 19:11:01 +00:00
|
|
|
|
2020-01-15 20:49:11 +00:00
|
|
|
info := &sealing.SectorInfo{
|
2019-11-29 19:11:01 +00:00
|
|
|
State: lapi.Proving,
|
|
|
|
SectorID: sector.SectorID,
|
2020-01-15 20:49:11 +00:00
|
|
|
Pieces: []sealing.Piece{
|
2019-11-29 19:11:01 +00:00
|
|
|
{
|
2020-02-23 00:47:47 +00:00
|
|
|
DealID: &dealID,
|
2020-02-09 06:06:32 +00:00
|
|
|
Size: abi.PaddedPieceSize(meta.SectorSize).Unpadded(),
|
2020-02-27 21:45:31 +00:00
|
|
|
CommP: sector.CommD,
|
2019-11-29 19:11:01 +00:00
|
|
|
},
|
|
|
|
},
|
2020-02-27 21:45:31 +00:00
|
|
|
CommD: &commD,
|
|
|
|
CommR: &commR,
|
2019-11-29 19:11:01 +00:00
|
|
|
Proof: nil,
|
2020-02-27 21:45:31 +00:00
|
|
|
Ticket: lapi.SealTicket{},
|
2019-11-29 19:11:01 +00:00
|
|
|
PreCommitMessage: nil,
|
2020-02-27 21:45:31 +00:00
|
|
|
Seed: lapi.SealSeed{},
|
2019-11-29 19:11:01 +00:00
|
|
|
CommitMessage: nil,
|
|
|
|
}
|
|
|
|
|
|
|
|
b, err := cborutil.Dump(info)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := mds.Put(sectorKey, b); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-03-04 02:24:08 +00:00
|
|
|
if sector.SectorID > maxSectorID {
|
|
|
|
maxSectorID = sector.SectorID
|
|
|
|
}
|
|
|
|
|
2020-02-21 18:20:22 +00:00
|
|
|
/* // TODO: Import deals into market
|
2020-02-10 18:21:10 +00:00
|
|
|
pnd, err := cborutil.AsIpld(sector.Deal)
|
2019-11-29 19:11:01 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-02-10 18:21:10 +00:00
|
|
|
dealKey := datastore.NewKey(deals.ProviderDsPrefix).ChildString(pnd.Cid().String())
|
2019-11-29 19:11:01 +00:00
|
|
|
|
|
|
|
deal := &deals.MinerDeal{
|
2019-12-17 10:46:39 +00:00
|
|
|
MinerDeal: storagemarket.MinerDeal{
|
2020-02-21 18:20:22 +00:00
|
|
|
ClientDealProposal: sector.Deal,
|
2020-02-10 18:21:10 +00:00
|
|
|
ProposalCid: pnd.Cid(),
|
2020-01-24 21:44:28 +00:00
|
|
|
State: storagemarket.StorageDealActive,
|
2020-02-08 00:18:14 +00:00
|
|
|
Ref: &storagemarket.DataRef{Root: 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,
|
2019-12-17 10:46:39 +00:00
|
|
|
},
|
2019-11-29 19:11:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
b, err = cborutil.Dump(deal)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := mds.Put(dealKey, b); err != nil {
|
|
|
|
return err
|
2020-02-21 18:20:22 +00:00
|
|
|
}*/
|
2019-11-29 19:11:01 +00:00
|
|
|
}
|
|
|
|
|
2020-03-20 00:20:01 +00:00
|
|
|
log.Infof("Setting next sector ID to %d", maxSectorID+1)
|
|
|
|
|
2020-03-04 02:24:08 +00:00
|
|
|
buf := make([]byte, binary.MaxVarintLen64)
|
|
|
|
size := binary.PutUvarint(buf, uint64(maxSectorID+1))
|
|
|
|
return mds.Put(datastore.NewKey("/storage/nextid"), buf[:size])
|
2019-11-29 19:11:01 +00:00
|
|
|
}
|
|
|
|
|
2020-02-25 20:35:15 +00:00
|
|
|
func findMarketDealID(ctx context.Context, api lapi.FullNode, deal market.DealProposal) (abi.DealID, error) {
|
2019-11-29 19:11:01 +00:00
|
|
|
// TODO: find a better way
|
|
|
|
// (this is only used by genesis miners)
|
|
|
|
|
2020-02-11 23:29:45 +00:00
|
|
|
deals, err := api.StateMarketDeals(ctx, types.EmptyTSK)
|
2019-11-29 19:11:01 +00:00
|
|
|
if err != nil {
|
|
|
|
return 0, xerrors.Errorf("getting market deals: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
for k, v := range deals {
|
2020-02-10 18:21:10 +00:00
|
|
|
if v.Proposal.PieceCID.Equals(deal.PieceCID) {
|
|
|
|
id, err := strconv.ParseUint(k, 10, 64)
|
|
|
|
return abi.DealID(id), err
|
2019-11-29 19:11:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0, xerrors.New("deal not found")
|
|
|
|
}
|
|
|
|
|
2020-03-04 02:24:08 +00:00
|
|
|
func storageMinerInit(ctx context.Context, cctx *cli.Context, api lapi.FullNode, r repo.Repo, ssize abi.SectorSize) error {
|
2019-11-16 06:47:04 +00:00
|
|
|
lr, err := r.Lock(repo.StorageMiner)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer lr.Close()
|
|
|
|
|
2019-10-18 05:13:36 +00:00
|
|
|
log.Info("Initializing libp2p identity")
|
2019-08-16 21:50:00 +00:00
|
|
|
|
2019-10-18 05:13:36 +00:00
|
|
|
p2pSk, err := makeHostKey(lr)
|
|
|
|
if err != nil {
|
2019-11-15 03:19:16 +00:00
|
|
|
return xerrors.Errorf("make host key: %w", err)
|
2019-10-18 05:13:36 +00:00
|
|
|
}
|
2019-08-16 21:50:00 +00:00
|
|
|
|
2019-10-18 05:13:36 +00:00
|
|
|
peerid, err := peer.IDFromPrivateKey(p2pSk)
|
|
|
|
if err != nil {
|
2019-11-15 03:19:16 +00:00
|
|
|
return xerrors.Errorf("peer ID from private key: %w", err)
|
2019-10-18 05:13:36 +00:00
|
|
|
}
|
2019-07-25 12:50:34 +00:00
|
|
|
|
2019-11-29 19:11:01 +00:00
|
|
|
mds, err := lr.Datastore("/metadata")
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-10-18 05:13:36 +00:00
|
|
|
var addr address.Address
|
|
|
|
if act := cctx.String("actor"); act != "" {
|
|
|
|
a, err := address.NewFromString(act)
|
2019-07-25 12:50:34 +00:00
|
|
|
if err != nil {
|
2019-11-15 03:19:16 +00:00
|
|
|
return xerrors.Errorf("failed parsing actor flag value (%q): %w", act, err)
|
2019-07-25 12:50:34 +00:00
|
|
|
}
|
2019-10-18 05:13:36 +00:00
|
|
|
|
2019-11-25 04:45:13 +00:00
|
|
|
if cctx.Bool("genesis-miner") {
|
|
|
|
if err := mds.Put(datastore.NewKey("miner-address"), a.Bytes()); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-03-04 02:24:08 +00:00
|
|
|
ppt, spt, err := lapi.ProofTypeFromSectorSize(ssize)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-03-17 20:19:52 +00:00
|
|
|
mid, err := address.IDFromAddress(a)
|
|
|
|
if err != nil {
|
|
|
|
return xerrors.Errorf("getting id address: %w", err)
|
|
|
|
}
|
|
|
|
|
2020-03-24 18:00:08 +00:00
|
|
|
smgr, err := sectorstorage.New(ctx, lr, stores.NewIndex(), §orbuilder.Config{
|
2020-03-04 02:24:08 +00:00
|
|
|
SealProofType: spt,
|
|
|
|
PoStProofType: ppt,
|
2020-03-24 19:38:00 +00:00
|
|
|
}, config.Storage{true, true, true}, nil, api)
|
2020-03-04 02:24:08 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-03-18 01:08:11 +00:00
|
|
|
epp := storage.NewElectionPoStProver(smgr, dtypes.MinerID(mid))
|
2019-11-25 04:45:13 +00:00
|
|
|
|
|
|
|
m := miner.NewMiner(api, epp)
|
|
|
|
{
|
|
|
|
if err := m.Register(a); err != nil {
|
|
|
|
return xerrors.Errorf("failed to start up genesis miner: %w", err)
|
|
|
|
}
|
|
|
|
|
2020-03-20 00:20:01 +00:00
|
|
|
cerr := configureStorageMiner(ctx, api, a, peerid)
|
2019-11-25 04:45:13 +00:00
|
|
|
|
2020-03-20 00:20:01 +00:00
|
|
|
if err := m.Unregister(ctx, a); err != nil {
|
|
|
|
log.Error("failed to shut down storage miner: ", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if cerr != nil {
|
2019-11-25 04:45:13 +00:00
|
|
|
return xerrors.Errorf("failed to configure storage miner: %w", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-20 00:20:01 +00:00
|
|
|
if pssb := cctx.String("pre-sealed-metadata"); pssb != "" {
|
|
|
|
pssb, err := homedir.Expand(pssb)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Infof("Importing pre-sealed sector metadata for %s", a)
|
|
|
|
|
|
|
|
if err := migratePreSealMeta(ctx, api, pssb, a, mds); err != nil {
|
|
|
|
return xerrors.Errorf("migrating presealed sector metadata: %w", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-04 22:56:56 +00:00
|
|
|
return nil
|
|
|
|
}
|
2019-11-29 19:11:01 +00:00
|
|
|
|
2020-02-04 22:56:56 +00:00
|
|
|
if pssb := cctx.String("pre-sealed-metadata"); pssb != "" {
|
|
|
|
pssb, err := homedir.Expand(pssb)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2019-11-29 19:11:01 +00:00
|
|
|
}
|
|
|
|
|
2020-02-04 22:56:56 +00:00
|
|
|
log.Infof("Importing pre-sealed sector metadata for %s", a)
|
|
|
|
|
|
|
|
if err := migratePreSealMeta(ctx, api, pssb, a, mds); err != nil {
|
|
|
|
return xerrors.Errorf("migrating presealed sector metadata: %w", err)
|
|
|
|
}
|
2019-12-02 12:51:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if err := configureStorageMiner(ctx, api, a, peerid); err != nil {
|
|
|
|
return xerrors.Errorf("failed to configure storage miner: %w", err)
|
2019-10-18 05:13:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
addr = a
|
|
|
|
} else {
|
|
|
|
a, err := createStorageMiner(ctx, api, peerid, cctx)
|
|
|
|
if err != nil {
|
2020-03-06 08:06:59 +00:00
|
|
|
return xerrors.Errorf("creating miner failed: %w", err)
|
2019-07-25 12:50:34 +00:00
|
|
|
}
|
|
|
|
|
2019-10-18 05:13:36 +00:00
|
|
|
addr = a
|
|
|
|
}
|
2019-07-25 12:50:34 +00:00
|
|
|
|
2019-10-18 05:13:36 +00:00
|
|
|
log.Infof("Created new storage miner: %s", addr)
|
2019-11-25 04:45:13 +00:00
|
|
|
if err := mds.Put(datastore.NewKey("miner-address"), addr.Bytes()); err != nil {
|
2019-10-18 05:13:36 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
2019-08-16 21:50:00 +00:00
|
|
|
}
|
2019-07-25 12:50:34 +00:00
|
|
|
|
2019-10-03 00:02:06 +00:00
|
|
|
func makeHostKey(lr repo.LockedRepo) (crypto.PrivKey, error) {
|
|
|
|
pk, _, err := crypto.GenerateEd25519Key(rand.Reader)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
ks, err := lr.KeyStore()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
kbytes, err := pk.Bytes()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := ks.Put("libp2p-host", types.KeyInfo{
|
|
|
|
Type: "libp2p-host",
|
|
|
|
PrivateKey: kbytes,
|
|
|
|
}); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return pk, nil
|
|
|
|
}
|
|
|
|
|
2019-11-29 19:11:01 +00:00
|
|
|
func configureStorageMiner(ctx context.Context, api lapi.FullNode, addr address.Address, peerid peer.ID) error {
|
2020-02-24 17:32:02 +00:00
|
|
|
waddr, err := api.StateMinerWorker(ctx, addr, types.EmptyTSK)
|
2019-08-16 21:50:00 +00:00
|
|
|
if err != nil {
|
|
|
|
return xerrors.Errorf("getWorkerAddr returned bad address: %w", err)
|
|
|
|
}
|
|
|
|
|
2020-02-21 18:20:22 +00:00
|
|
|
enc, err := actors.SerializeParams(&miner2.ChangePeerIDParams{NewID: peerid})
|
2019-08-16 21:50:00 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
msg := &types.Message{
|
|
|
|
To: addr,
|
|
|
|
From: waddr,
|
2020-02-21 18:20:22 +00:00
|
|
|
Method: builtin.MethodsMiner.ChangePeerID,
|
2019-08-16 21:50:00 +00:00
|
|
|
Params: enc,
|
2019-08-16 22:10:34 +00:00
|
|
|
Value: types.NewInt(0),
|
2019-08-16 21:50:00 +00:00
|
|
|
GasPrice: types.NewInt(0),
|
2020-03-18 20:45:37 +00:00
|
|
|
GasLimit: 100000000,
|
2019-08-16 21:50:00 +00:00
|
|
|
}
|
|
|
|
|
2019-09-17 08:15:26 +00:00
|
|
|
smsg, err := api.MpoolPushMessage(ctx, msg)
|
2019-08-16 21:50:00 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-08-16 22:10:34 +00:00
|
|
|
log.Info("Waiting for message: ", smsg.Cid())
|
2019-10-08 05:51:34 +00:00
|
|
|
ret, err := api.StateWaitMsg(ctx, smsg.Cid())
|
2019-08-16 21:50:00 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if ret.Receipt.ExitCode != 0 {
|
|
|
|
return xerrors.Errorf("update peer id message failed with exit code %d", ret.Receipt.ExitCode)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2019-07-25 12:50:34 +00:00
|
|
|
|
2020-03-06 22:23:21 +00:00
|
|
|
func createStorageMiner(ctx context.Context, api lapi.FullNode, peerid peer.ID, cctx *cli.Context) (address.Address, error) {
|
2019-08-16 21:50:00 +00:00
|
|
|
log.Info("Creating StorageMarket.CreateStorageMiner message")
|
2019-07-25 12:50:34 +00:00
|
|
|
|
2020-03-06 22:23:21 +00:00
|
|
|
var err error
|
2019-09-26 12:19:21 +00:00
|
|
|
var owner address.Address
|
|
|
|
if cctx.String("owner") != "" {
|
|
|
|
owner, err = address.NewFromString(cctx.String("owner"))
|
|
|
|
} else {
|
|
|
|
owner, err = api.WalletDefaultAddress(ctx)
|
|
|
|
}
|
2019-08-16 21:50:00 +00:00
|
|
|
if err != nil {
|
|
|
|
return address.Undef, err
|
|
|
|
}
|
2019-07-25 12:50:34 +00:00
|
|
|
|
2019-10-16 07:07:16 +00:00
|
|
|
ssize := cctx.Uint64("sector-size")
|
|
|
|
|
2019-09-26 12:19:21 +00:00
|
|
|
worker := owner
|
|
|
|
if cctx.String("worker") != "" {
|
|
|
|
worker, err = address.NewFromString(cctx.String("worker"))
|
|
|
|
} else if cctx.Bool("create-worker-key") { // TODO: Do we need to force this if owner is Secpk?
|
2020-02-21 18:20:22 +00:00
|
|
|
worker, err = api.WalletNew(ctx, crypto2.SigTypeBLS)
|
2019-09-26 12:19:21 +00:00
|
|
|
}
|
|
|
|
// TODO: Transfer some initial funds to worker
|
|
|
|
if err != nil {
|
|
|
|
return address.Undef, err
|
2019-08-16 21:50:00 +00:00
|
|
|
}
|
2019-07-25 12:50:34 +00:00
|
|
|
|
2020-02-11 23:29:45 +00:00
|
|
|
collateral, err := api.StatePledgeCollateral(ctx, types.EmptyTSK)
|
2019-09-25 23:32:33 +00:00
|
|
|
if err != nil {
|
|
|
|
return address.Undef, err
|
|
|
|
}
|
2019-07-25 12:50:34 +00:00
|
|
|
|
2020-02-21 18:20:22 +00:00
|
|
|
params, err := actors.SerializeParams(&power.CreateMinerParams{
|
2020-03-06 08:06:59 +00:00
|
|
|
Owner: owner,
|
2019-09-26 12:19:21 +00:00
|
|
|
Worker: worker,
|
2020-02-09 06:06:32 +00:00
|
|
|
SectorSize: abi.SectorSize(ssize),
|
2020-02-21 19:28:20 +00:00
|
|
|
Peer: peerid,
|
2019-08-16 21:50:00 +00:00
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return address.Undef, err
|
|
|
|
}
|
2019-07-25 12:50:34 +00:00
|
|
|
|
2019-09-17 08:15:26 +00:00
|
|
|
createStorageMinerMsg := &types.Message{
|
2020-02-25 20:54:58 +00:00
|
|
|
To: builtin.StoragePowerActorAddr,
|
2019-09-26 12:19:21 +00:00
|
|
|
From: owner,
|
2020-01-15 17:30:01 +00:00
|
|
|
Value: types.BigAdd(collateral, types.BigDiv(collateral, types.NewInt(100))),
|
2019-07-25 12:50:34 +00:00
|
|
|
|
2020-02-21 18:20:22 +00:00
|
|
|
Method: builtin.MethodsPower.CreateMiner,
|
2019-08-16 21:50:00 +00:00
|
|
|
Params: params,
|
2019-08-19 18:06:39 +00:00
|
|
|
|
2020-03-18 20:45:37 +00:00
|
|
|
GasLimit: 10000000,
|
2019-08-19 18:06:39 +00:00
|
|
|
GasPrice: types.NewInt(0),
|
2019-08-16 21:50:00 +00:00
|
|
|
}
|
2019-07-25 12:50:34 +00:00
|
|
|
|
2019-09-17 08:15:26 +00:00
|
|
|
signed, err := api.MpoolPushMessage(ctx, createStorageMinerMsg)
|
2019-08-16 21:50:00 +00:00
|
|
|
if err != nil {
|
|
|
|
return address.Undef, err
|
|
|
|
}
|
|
|
|
|
2019-09-17 08:15:26 +00:00
|
|
|
log.Infof("Pushed StorageMarket.CreateStorageMiner, %s to Mpool", signed.Cid())
|
2019-08-16 21:50:00 +00:00
|
|
|
log.Infof("Waiting for confirmation")
|
|
|
|
|
2019-10-08 05:51:34 +00:00
|
|
|
mw, err := api.StateWaitMsg(ctx, signed.Cid())
|
2019-08-16 21:50:00 +00:00
|
|
|
if err != nil {
|
|
|
|
return address.Undef, err
|
|
|
|
}
|
|
|
|
|
2019-10-16 07:45:48 +00:00
|
|
|
if mw.Receipt.ExitCode != 0 {
|
|
|
|
return address.Undef, xerrors.Errorf("create storage miner failed: exit code %d", mw.Receipt.ExitCode)
|
|
|
|
}
|
|
|
|
|
2020-03-06 08:06:59 +00:00
|
|
|
var retval power.CreateMinerReturn
|
|
|
|
if err := retval.UnmarshalCBOR(bytes.NewReader(mw.Receipt.Return)); err != nil {
|
2019-08-16 21:50:00 +00:00
|
|
|
return address.Undef, err
|
|
|
|
}
|
|
|
|
|
2020-03-06 08:06:59 +00:00
|
|
|
log.Infof("New storage miners address is: %s (%s)", retval.IDAddress, retval.RobustAddress)
|
2020-03-06 22:23:21 +00:00
|
|
|
return retval.IDAddress, nil
|
2019-07-19 09:24:11 +00:00
|
|
|
}
|