2019-07-19 09:24:11 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2019-07-25 12:50:34 +00:00
|
|
|
"github.com/libp2p/go-libp2p-core/peer"
|
2019-07-19 09:24:11 +00:00
|
|
|
"golang.org/x/xerrors"
|
|
|
|
"gopkg.in/urfave/cli.v2"
|
|
|
|
|
2019-07-19 10:15:22 +00:00
|
|
|
"github.com/filecoin-project/go-lotus/build"
|
2019-07-25 12:50:34 +00:00
|
|
|
"github.com/filecoin-project/go-lotus/chain/actors"
|
2019-07-28 05:35:32 +00:00
|
|
|
"github.com/filecoin-project/go-lotus/chain/address"
|
2019-07-25 12:50:34 +00:00
|
|
|
"github.com/filecoin-project/go-lotus/chain/types"
|
2019-07-26 12:28:29 +00:00
|
|
|
"github.com/filecoin-project/go-lotus/chain/wallet"
|
2019-07-19 09:24:11 +00:00
|
|
|
lcli "github.com/filecoin-project/go-lotus/cli"
|
|
|
|
"github.com/filecoin-project/go-lotus/node/repo"
|
|
|
|
)
|
|
|
|
|
|
|
|
var initCmd = &cli.Command{
|
|
|
|
Name: "init",
|
|
|
|
Usage: "Initialize a lotus storage miner repo",
|
|
|
|
Action: func(cctx *cli.Context) error {
|
|
|
|
log.Info("Initializing lotus storage miner")
|
|
|
|
log.Info("Checking if repo exists")
|
|
|
|
|
2019-07-23 21:50:52 +00:00
|
|
|
r, err := repo.NewFS(cctx.String(FlagStorageRepo))
|
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("Trying to connect to full node RPC")
|
|
|
|
|
2019-07-19 10:15:22 +00:00
|
|
|
api, err := lcli.GetAPI(cctx) // TODO: consider storing full node address in config
|
2019-07-19 09:24:11 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
ctx := lcli.ReqContext(cctx)
|
|
|
|
|
|
|
|
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-07-23 21:55:19 +00:00
|
|
|
if v.APIVersion&build.MinorMask != build.APIVersion&build.MinorMask {
|
2019-07-19 10:15:22 +00:00
|
|
|
return xerrors.Errorf("Remote API version didn't match (local %x, remote %x)", build.APIVersion, v.APIVersion)
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Info("Initializing repo")
|
|
|
|
|
2019-07-19 09:24:11 +00:00
|
|
|
if err := r.Init(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-07-25 12:50:34 +00:00
|
|
|
lr, err := r.Lock()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer lr.Close()
|
|
|
|
|
|
|
|
log.Info("Initializing wallet")
|
|
|
|
|
|
|
|
ks, err := lr.KeyStore()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-07-26 12:28:29 +00:00
|
|
|
wallet, err := wallet.NewWallet(ks)
|
2019-07-25 12:50:34 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Info("Initializing libp2p identity")
|
|
|
|
|
|
|
|
p2pSk, err := lr.Libp2pIdentity()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
peerid, err := peer.IDFromPrivateKey(p2pSk)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Info("Creating StorageMarket.CreateStorageMiner message")
|
|
|
|
|
|
|
|
defOwner, err := api.WalletDefaultAddress(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
nonce, err := api.MpoolGetNonce(ctx, defOwner)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-07-26 12:34:01 +00:00
|
|
|
k, err := wallet.GenerateKey(types.KTSecp256k1) // TODO: review: is this right?
|
2019-07-25 12:50:34 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
collateral := types.NewInt(1000) // TODO: Get this from params
|
|
|
|
|
|
|
|
params, err := actors.SerializeParams(actors.CreateStorageMinerParams{
|
|
|
|
Owner: defOwner,
|
|
|
|
Worker: k,
|
|
|
|
SectorSize: types.NewInt(actors.SectorSize),
|
|
|
|
PeerID: peerid,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
createStorageMinerMsg := types.Message{
|
2019-07-26 17:33:54 +00:00
|
|
|
To: actors.StorageMarketAddress,
|
2019-07-25 12:50:34 +00:00
|
|
|
From: defOwner,
|
|
|
|
|
|
|
|
Nonce: nonce,
|
|
|
|
|
|
|
|
Value: collateral,
|
|
|
|
|
2019-07-26 21:42:38 +00:00
|
|
|
Method: actors.SMAMethods.CreateStorageMiner,
|
2019-07-25 12:50:34 +00:00
|
|
|
Params: params,
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned, err := createStorageMinerMsg.Serialize()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Info("Signing StorageMarket.CreateStorageMiner")
|
|
|
|
|
|
|
|
sig, err := api.WalletSign(ctx, defOwner, unsigned)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-07-26 12:34:01 +00:00
|
|
|
signed := &types.SignedMessage{
|
2019-07-25 12:50:34 +00:00
|
|
|
Message: createStorageMinerMsg,
|
|
|
|
Signature: *sig,
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Infof("Pushing %s to Mpool", signed.Cid())
|
|
|
|
|
|
|
|
err = api.MpoolPush(ctx, signed)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-07-27 12:18:36 +00:00
|
|
|
log.Infof("Waiting for confirmation (TODO: actually wait)")
|
2019-07-25 12:50:34 +00:00
|
|
|
|
2019-07-28 05:35:32 +00:00
|
|
|
mw, err := api.ChainWaitMsg(ctx, signed.Cid())
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
addr, err := address.NewFromBytes(mw.Receipt.Return)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-07-25 12:50:34 +00:00
|
|
|
|
2019-07-28 05:35:32 +00:00
|
|
|
// TODO: persist this address in the storage-miner repo
|
|
|
|
log.Infof("New storage miners address is: %s", addr)
|
2019-07-19 10:15:22 +00:00
|
|
|
|
2019-07-25 12:50:34 +00:00
|
|
|
// TODO: Point to setting storage price, maybe do it interactively or something
|
2019-07-19 10:15:22 +00:00
|
|
|
log.Info("Storage miner successfully created, you can now start it with 'lotus-storage-miner run'")
|
|
|
|
|
2019-07-19 09:24:11 +00:00
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|