Merge pull request #134 from filecoin-project/feat/more-deals
More deals progress
This commit is contained in:
commit
3a7a21ee83
@ -75,7 +75,7 @@ Pond is a graphical testbed for lotus. It can be used to spin up nodes, connect
|
|||||||
them in a given topology, start them mining, and observe how they function over
|
them in a given topology, start them mining, and observe how they function over
|
||||||
time.
|
time.
|
||||||
|
|
||||||
To try it out, run `make pond`, then run the `pond` binary that gets created.
|
To try it out, run `make pond`, then run `./pond run`.
|
||||||
Once it is running, visit localhost:2222 in your browser.
|
Once it is running, visit localhost:2222 in your browser.
|
||||||
|
|
||||||
## Tracing
|
## Tracing
|
||||||
|
@ -4,8 +4,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-lotus/api"
|
||||||
"github.com/filecoin-project/go-lotus/chain/address"
|
"github.com/filecoin-project/go-lotus/chain/address"
|
||||||
"github.com/filecoin-project/go-lotus/chain/wallet"
|
|
||||||
"github.com/filecoin-project/go-lotus/lib/sectorbuilder"
|
"github.com/filecoin-project/go-lotus/lib/sectorbuilder"
|
||||||
"github.com/filecoin-project/go-lotus/node/modules/dtypes"
|
"github.com/filecoin-project/go-lotus/node/modules/dtypes"
|
||||||
|
|
||||||
@ -29,12 +29,14 @@ type MinerDeal struct {
|
|||||||
|
|
||||||
Ref cid.Cid
|
Ref cid.Cid
|
||||||
|
|
||||||
|
SectorID uint64 // Set when State >= Staged
|
||||||
|
|
||||||
s inet.Stream
|
s inet.Stream
|
||||||
}
|
}
|
||||||
|
|
||||||
type Handler struct {
|
type Handler struct {
|
||||||
w *wallet.Wallet
|
sb *sectorbuilder.SectorBuilder
|
||||||
sb *sectorbuilder.SectorBuilder
|
full api.FullNode
|
||||||
|
|
||||||
// TODO: Use a custom protocol or graphsync in the future
|
// TODO: Use a custom protocol or graphsync in the future
|
||||||
// TODO: GC
|
// TODO: GC
|
||||||
@ -55,9 +57,10 @@ type dealUpdate struct {
|
|||||||
newState DealState
|
newState DealState
|
||||||
id cid.Cid
|
id cid.Cid
|
||||||
err error
|
err error
|
||||||
|
mut func(*MinerDeal)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHandler(w *wallet.Wallet, ds dtypes.MetadataDS, sb *sectorbuilder.SectorBuilder, dag dtypes.StagingDAG) (*Handler, error) {
|
func NewHandler(ds dtypes.MetadataDS, sb *sectorbuilder.SectorBuilder, dag dtypes.StagingDAG, fullNode api.FullNode) (*Handler, error) {
|
||||||
addr, err := ds.Get(datastore.NewKey("miner-address"))
|
addr, err := ds.Get(datastore.NewKey("miner-address"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -68,9 +71,9 @@ func NewHandler(w *wallet.Wallet, ds dtypes.MetadataDS, sb *sectorbuilder.Sector
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &Handler{
|
return &Handler{
|
||||||
w: w,
|
|
||||||
sb: sb,
|
sb: sb,
|
||||||
dag: dag,
|
dag: dag,
|
||||||
|
full: fullNode,
|
||||||
|
|
||||||
conns: map[cid.Cid]inet.Stream{},
|
conns: map[cid.Cid]inet.Stream{},
|
||||||
|
|
||||||
@ -136,6 +139,9 @@ func (h *Handler) onUpdated(ctx context.Context, update dealUpdate) {
|
|||||||
var deal MinerDeal
|
var deal MinerDeal
|
||||||
err := h.deals.MutateMiner(update.id, func(d *MinerDeal) error {
|
err := h.deals.MutateMiner(update.id, func(d *MinerDeal) error {
|
||||||
d.State = update.newState
|
d.State = update.newState
|
||||||
|
if update.mut != nil {
|
||||||
|
update.mut(d)
|
||||||
|
}
|
||||||
deal = *d
|
deal = *d
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
@ -150,7 +156,7 @@ func (h *Handler) onUpdated(ctx context.Context, update dealUpdate) {
|
|||||||
case Staged:
|
case Staged:
|
||||||
h.handle(ctx, deal, h.staged, Sealing)
|
h.handle(ctx, deal, h.staged, Sealing)
|
||||||
case Sealing:
|
case Sealing:
|
||||||
log.Error("TODO")
|
h.handle(ctx, deal, h.sealing, Complete)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,9 @@ package deals
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-lotus/lib/sectorbuilder"
|
||||||
|
|
||||||
files "github.com/ipfs/go-ipfs-files"
|
files "github.com/ipfs/go-ipfs-files"
|
||||||
"github.com/ipfs/go-merkledag"
|
"github.com/ipfs/go-merkledag"
|
||||||
@ -9,16 +12,17 @@ import (
|
|||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
type handlerFunc func(ctx context.Context, deal MinerDeal) error
|
type handlerFunc func(ctx context.Context, deal MinerDeal) (func(*MinerDeal), error)
|
||||||
|
|
||||||
func (h *Handler) handle(ctx context.Context, deal MinerDeal, cb handlerFunc, next DealState) {
|
func (h *Handler) handle(ctx context.Context, deal MinerDeal, cb handlerFunc, next DealState) {
|
||||||
go func() {
|
go func() {
|
||||||
err := cb(ctx, deal)
|
mut, err := cb(ctx, deal)
|
||||||
select {
|
select {
|
||||||
case h.updated <- dealUpdate{
|
case h.updated <- dealUpdate{
|
||||||
newState: next,
|
newState: next,
|
||||||
id: deal.ProposalCid,
|
id: deal.ProposalCid,
|
||||||
err: err,
|
err: err,
|
||||||
|
mut: mut,
|
||||||
}:
|
}:
|
||||||
case <-h.stop:
|
case <-h.stop:
|
||||||
}
|
}
|
||||||
@ -27,14 +31,13 @@ func (h *Handler) handle(ctx context.Context, deal MinerDeal, cb handlerFunc, ne
|
|||||||
|
|
||||||
// ACCEPTED
|
// ACCEPTED
|
||||||
|
|
||||||
func (h *Handler) accept(ctx context.Context, deal MinerDeal) error {
|
func (h *Handler) accept(ctx context.Context, deal MinerDeal) (func(*MinerDeal), error) {
|
||||||
log.Info("acc")
|
|
||||||
switch deal.Proposal.SerializationMode {
|
switch deal.Proposal.SerializationMode {
|
||||||
//case SerializationRaw:
|
//case SerializationRaw:
|
||||||
//case SerializationIPLD:
|
//case SerializationIPLD:
|
||||||
case SerializationUnixFs:
|
case SerializationUnixFs:
|
||||||
default:
|
default:
|
||||||
return xerrors.Errorf("deal proposal with unsupported serialization: %s", deal.Proposal.SerializationMode)
|
return nil, xerrors.Errorf("deal proposal with unsupported serialization: %s", deal.Proposal.SerializationMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: check payment
|
// TODO: check payment
|
||||||
@ -46,18 +49,17 @@ func (h *Handler) accept(ctx context.Context, deal MinerDeal) error {
|
|||||||
Proposal: deal.ProposalCid,
|
Proposal: deal.ProposalCid,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return merkledag.FetchGraph(ctx, deal.Ref, h.dag)
|
return nil, merkledag.FetchGraph(ctx, deal.Ref, h.dag)
|
||||||
}
|
}
|
||||||
|
|
||||||
// STAGED
|
// STAGED
|
||||||
|
|
||||||
func (h *Handler) staged(ctx context.Context, deal MinerDeal) error {
|
func (h *Handler) staged(ctx context.Context, deal MinerDeal) (func(*MinerDeal), error) {
|
||||||
err := h.sendSignedResponse(StorageDealResponse{
|
err := h.sendSignedResponse(StorageDealResponse{
|
||||||
State: Staged,
|
State: Staged,
|
||||||
Message: "",
|
|
||||||
Proposal: deal.ProposalCid,
|
Proposal: deal.ProposalCid,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -66,24 +68,24 @@ func (h *Handler) staged(ctx context.Context, deal MinerDeal) error {
|
|||||||
|
|
||||||
root, err := h.dag.Get(ctx, deal.Ref)
|
root, err := h.dag.Get(ctx, deal.Ref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("failed to get file root for deal: %s", err)
|
return nil, xerrors.Errorf("failed to get file root for deal: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: abstract this away into ReadSizeCloser + implement different modes
|
// TODO: abstract this away into ReadSizeCloser + implement different modes
|
||||||
n, err := unixfile.NewUnixfsFile(ctx, h.dag, root)
|
n, err := unixfile.NewUnixfsFile(ctx, h.dag, root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("cannot open unixfs file: %s", err)
|
return nil, xerrors.Errorf("cannot open unixfs file: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
uf, ok := n.(files.File)
|
uf, ok := n.(files.File)
|
||||||
if !ok {
|
if !ok {
|
||||||
// we probably got directory, unsupported for now
|
// we probably got directory, unsupported for now
|
||||||
return xerrors.Errorf("unsupported unixfs type")
|
return nil, xerrors.Errorf("unsupported unixfs type")
|
||||||
}
|
}
|
||||||
|
|
||||||
size, err := uf.Size()
|
size, err := uf.Size()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("failed to get file size: %s", err)
|
return nil, xerrors.Errorf("failed to get file size: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var sectorID uint64
|
var sectorID uint64
|
||||||
@ -92,11 +94,77 @@ func (h *Handler) staged(ctx context.Context, deal MinerDeal) error {
|
|||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("AddPiece failed: %s", err)
|
return nil, xerrors.Errorf("AddPiece failed: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Warnf("New Sector: %d", sectorID)
|
log.Warnf("New Sector: %d", sectorID)
|
||||||
return nil
|
return func(deal *MinerDeal) {
|
||||||
|
deal.SectorID = sectorID
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SEALING
|
// SEALING
|
||||||
|
|
||||||
|
func getInclusionProof(ref string, status sectorbuilder.SectorSealingStatus) (PieceInclusionProof, error) {
|
||||||
|
for i, p := range status.Pieces {
|
||||||
|
if p.Key == ref {
|
||||||
|
return PieceInclusionProof{
|
||||||
|
Position: uint64(i),
|
||||||
|
ProofElements: p.InclusionProof,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return PieceInclusionProof{}, xerrors.Errorf("pieceInclusionProof for %s in sector %d not found", ref, status.SectorID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) pollSectorSealed(deal MinerDeal) (status sectorbuilder.SectorSealingStatus, err error) {
|
||||||
|
loop:
|
||||||
|
for {
|
||||||
|
status, err = h.sb.SealStatus(deal.SectorID)
|
||||||
|
if err != nil {
|
||||||
|
return sectorbuilder.SectorSealingStatus{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch status.SealStatusCode {
|
||||||
|
case 0: // sealed
|
||||||
|
break loop
|
||||||
|
case 2: // failed
|
||||||
|
return sectorbuilder.SectorSealingStatus{}, xerrors.Errorf("sealing sector %d for deal %s (ref=%s) failed: %s", deal.SectorID, deal.ProposalCid, deal.Ref, status.SealErrorMsg)
|
||||||
|
case 1: // pending
|
||||||
|
if err := h.sb.SealAllStagedSectors(); err != nil {
|
||||||
|
return sectorbuilder.SectorSealingStatus{}, err
|
||||||
|
}
|
||||||
|
// start seal
|
||||||
|
fallthrough
|
||||||
|
case 3: // sealing
|
||||||
|
// wait
|
||||||
|
default:
|
||||||
|
return sectorbuilder.SectorSealingStatus{}, xerrors.Errorf("unknown SealStatusCode: %d", status.SectorID)
|
||||||
|
}
|
||||||
|
time.Sleep(3 * time.Second)
|
||||||
|
}
|
||||||
|
return status, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) sealing(ctx context.Context, deal MinerDeal) (func(*MinerDeal), error) {
|
||||||
|
status, err := h.pollSectorSealed(deal)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ip, err := getInclusionProof(deal.Ref.String(), status)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = h.sendSignedResponse(StorageDealResponse{
|
||||||
|
State: Sealing,
|
||||||
|
Proposal: deal.ProposalCid,
|
||||||
|
PieceInclusionProof: ip,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("Sending deal response failed: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
@ -1,13 +1,17 @@
|
|||||||
package deals
|
package deals
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-lotus/chain/actors"
|
||||||
|
"github.com/filecoin-project/go-lotus/chain/address"
|
||||||
|
"github.com/filecoin-project/go-lotus/chain/types"
|
||||||
"github.com/filecoin-project/go-lotus/lib/cborrpc"
|
"github.com/filecoin-project/go-lotus/lib/cborrpc"
|
||||||
cbor "github.com/ipfs/go-ipld-cbor"
|
|
||||||
inet "github.com/libp2p/go-libp2p-core/network"
|
|
||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
|
cbor "github.com/ipfs/go-ipld-cbor"
|
||||||
|
inet "github.com/libp2p/go-libp2p-core/network"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -68,18 +72,21 @@ func (h *Handler) sendSignedResponse(resp StorageDealResponse) error {
|
|||||||
return xerrors.Errorf("serializing response: %w", err)
|
return xerrors.Errorf("serializing response: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
def, err := h.w.ListAddrs()
|
getworker := &types.Message{
|
||||||
if err != nil {
|
To: h.actor,
|
||||||
log.Error(err)
|
From: h.actor,
|
||||||
return xerrors.Errorf("listing wallet addresses: %w", err)
|
Method: actors.MAMethods.GetWorkerAddr,
|
||||||
}
|
}
|
||||||
if len(def) != 1 {
|
r, err := h.full.ChainCall(context.TODO(), getworker, nil)
|
||||||
// NOTE: If this ever happens for a good reason, implement this with GetWorker on the miner actor
|
if err != nil {
|
||||||
// TODO: implement with GetWorker on the miner actor
|
return xerrors.Errorf("getting worker address: %w", err)
|
||||||
return xerrors.Errorf("expected only 1 address in wallet, got %d", len(def))
|
}
|
||||||
|
worker, err := address.NewFromBytes(r.Return)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
sig, err := h.w.Sign(def[0], msg)
|
sig, err := h.full.WalletSign(context.TODO(), worker, msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("failed to sign response message: %w", err)
|
return xerrors.Errorf("failed to sign response message: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ type SignedStorageDealProposal struct {
|
|||||||
|
|
||||||
type PieceInclusionProof struct {
|
type PieceInclusionProof struct {
|
||||||
Position uint64
|
Position uint64
|
||||||
ProofElements [32]byte
|
ProofElements []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
type StorageDealResponse struct {
|
type StorageDealResponse struct {
|
||||||
|
203
lotuspond/api.go
Normal file
203
lotuspond/api.go
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/filecoin-project/go-lotus/lib/jsonrpc"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-lotus/node/repo"
|
||||||
|
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type api struct {
|
||||||
|
cmds int32
|
||||||
|
running map[int32]runningNode
|
||||||
|
runningLk sync.Mutex
|
||||||
|
genesis string
|
||||||
|
}
|
||||||
|
|
||||||
|
type nodeInfo struct {
|
||||||
|
Repo string
|
||||||
|
ID int32
|
||||||
|
ApiPort int32
|
||||||
|
|
||||||
|
FullNode string // only for storage nodes
|
||||||
|
Storage bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *api) Spawn() (nodeInfo, error) {
|
||||||
|
dir, err := ioutil.TempDir(os.TempDir(), "lotus-")
|
||||||
|
if err != nil {
|
||||||
|
return nodeInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
genParam := "--genesis=" + api.genesis
|
||||||
|
id := atomic.AddInt32(&api.cmds, 1)
|
||||||
|
if id == 1 {
|
||||||
|
// make genesis
|
||||||
|
genf, err := ioutil.TempFile(os.TempDir(), "lotus-genesis-")
|
||||||
|
if err != nil {
|
||||||
|
return nodeInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
api.genesis = genf.Name()
|
||||||
|
genParam = "--lotus-make-random-genesis=" + api.genesis
|
||||||
|
|
||||||
|
if err := genf.Close(); err != nil {
|
||||||
|
return nodeInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
errlogfile, err := os.OpenFile(dir+".err.log", os.O_CREATE|os.O_WRONLY, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return nodeInfo{}, err
|
||||||
|
}
|
||||||
|
logfile, err := os.OpenFile(dir+".out.log", os.O_CREATE|os.O_WRONLY, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return nodeInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := exec.Command("./lotus", "daemon", genParam, "--api", fmt.Sprintf("%d", 2500+id))
|
||||||
|
cmd.Stderr = io.MultiWriter(os.Stderr, errlogfile)
|
||||||
|
cmd.Stdout = io.MultiWriter(os.Stdout, logfile)
|
||||||
|
cmd.Env = []string{"LOTUS_PATH=" + dir}
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
return nodeInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
info := nodeInfo{
|
||||||
|
Repo: dir,
|
||||||
|
ID: id,
|
||||||
|
ApiPort: 2500 + id,
|
||||||
|
}
|
||||||
|
|
||||||
|
api.runningLk.Lock()
|
||||||
|
api.running[id] = runningNode{
|
||||||
|
cmd: cmd,
|
||||||
|
meta: info,
|
||||||
|
|
||||||
|
stop: func() {
|
||||||
|
defer errlogfile.Close()
|
||||||
|
defer logfile.Close()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
api.runningLk.Unlock()
|
||||||
|
|
||||||
|
time.Sleep(time.Millisecond * 750) // TODO: Something less terrible
|
||||||
|
|
||||||
|
return info, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *api) Nodes() []nodeInfo {
|
||||||
|
api.runningLk.Lock()
|
||||||
|
out := make([]nodeInfo, 0, len(api.running))
|
||||||
|
for _, node := range api.running {
|
||||||
|
out = append(out, node.meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
api.runningLk.Unlock()
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *api) TokenFor(id int32) (string, error) {
|
||||||
|
api.runningLk.Lock()
|
||||||
|
defer api.runningLk.Unlock()
|
||||||
|
|
||||||
|
rnd, ok := api.running[id]
|
||||||
|
if !ok {
|
||||||
|
return "", xerrors.New("no running node with this ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := repo.NewFS(rnd.meta.Repo)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
t, err := r.APIToken()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(t), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *api) SpawnStorage(fullNodeRepo string) (nodeInfo, error) {
|
||||||
|
dir, err := ioutil.TempDir(os.TempDir(), "lotus-storage-")
|
||||||
|
if err != nil {
|
||||||
|
return nodeInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
errlogfile, err := os.OpenFile(dir+".err.log", os.O_CREATE|os.O_WRONLY, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return nodeInfo{}, err
|
||||||
|
}
|
||||||
|
logfile, err := os.OpenFile(dir+".out.log", os.O_CREATE|os.O_WRONLY, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return nodeInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
id := atomic.AddInt32(&api.cmds, 1)
|
||||||
|
cmd := exec.Command("./lotus-storage-miner", "init")
|
||||||
|
cmd.Stderr = io.MultiWriter(os.Stderr, errlogfile)
|
||||||
|
cmd.Stdout = io.MultiWriter(os.Stdout, logfile)
|
||||||
|
cmd.Env = []string{"LOTUS_STORAGE_PATH=" + dir, "LOTUS_PATH=" + fullNodeRepo}
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
return nodeInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(time.Millisecond * 300)
|
||||||
|
|
||||||
|
cmd = exec.Command("./lotus-storage-miner", "run", "--api", fmt.Sprintf("%d", 2500+id))
|
||||||
|
cmd.Stderr = io.MultiWriter(os.Stderr, errlogfile)
|
||||||
|
cmd.Stdout = io.MultiWriter(os.Stdout, logfile)
|
||||||
|
cmd.Env = []string{"LOTUS_STORAGE_PATH=" + dir, "LOTUS_PATH=" + fullNodeRepo}
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
return nodeInfo{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
info := nodeInfo{
|
||||||
|
Repo: dir,
|
||||||
|
ID: id,
|
||||||
|
ApiPort: 2500 + id,
|
||||||
|
|
||||||
|
FullNode: fullNodeRepo,
|
||||||
|
Storage: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
api.runningLk.Lock()
|
||||||
|
api.running[id] = runningNode{
|
||||||
|
cmd: cmd,
|
||||||
|
meta: info,
|
||||||
|
|
||||||
|
stop: func() {
|
||||||
|
defer errlogfile.Close()
|
||||||
|
defer logfile.Close()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
api.runningLk.Unlock()
|
||||||
|
|
||||||
|
time.Sleep(time.Millisecond * 750) // TODO: Something less terrible
|
||||||
|
|
||||||
|
return info, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type client struct {
|
||||||
|
Nodes func() []nodeInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
func apiClient() (*client, error) {
|
||||||
|
c := &client{}
|
||||||
|
if _, err := jsonrpc.NewClient("ws://"+listenAddr+"/rpc/v0", "Pond", c, nil); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return c, nil
|
||||||
|
}
|
@ -2,19 +2,14 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"sync"
|
"strconv"
|
||||||
"sync/atomic"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/go-lotus/lib/jsonrpc"
|
"github.com/filecoin-project/go-lotus/lib/jsonrpc"
|
||||||
"github.com/filecoin-project/go-lotus/node/repo"
|
|
||||||
|
"gopkg.in/urfave/cli.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
const listenAddr = "127.0.0.1:2222"
|
const listenAddr = "127.0.0.1:2222"
|
||||||
@ -26,185 +21,117 @@ type runningNode struct {
|
|||||||
stop func()
|
stop func()
|
||||||
}
|
}
|
||||||
|
|
||||||
type api struct {
|
var onCmd = &cli.Command{
|
||||||
cmds int32
|
Name: "on",
|
||||||
running map[int32]runningNode
|
Usage: "run a command on a given node",
|
||||||
runningLk sync.Mutex
|
Action: func(cctx *cli.Context) error {
|
||||||
genesis string
|
client, err := apiClient()
|
||||||
}
|
|
||||||
|
|
||||||
type nodeInfo struct {
|
|
||||||
Repo string
|
|
||||||
ID int32
|
|
||||||
ApiPort int32
|
|
||||||
|
|
||||||
Storage bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (api *api) Spawn() (nodeInfo, error) {
|
|
||||||
dir, err := ioutil.TempDir(os.TempDir(), "lotus-")
|
|
||||||
if err != nil {
|
|
||||||
return nodeInfo{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
genParam := "--genesis=" + api.genesis
|
|
||||||
id := atomic.AddInt32(&api.cmds, 1)
|
|
||||||
if id == 1 {
|
|
||||||
// make genesis
|
|
||||||
genf, err := ioutil.TempFile(os.TempDir(), "lotus-genesis-")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nodeInfo{}, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
api.genesis = genf.Name()
|
nd, err := strconv.ParseInt(cctx.Args().Get(0), 10, 32)
|
||||||
genParam = "--lotus-make-random-genesis=" + api.genesis
|
if err != nil {
|
||||||
|
return err
|
||||||
if err := genf.Close(); err != nil {
|
|
||||||
return nodeInfo{}, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
node := nodeById(client.Nodes(), int(nd))
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
if !node.Storage {
|
||||||
|
cmd = exec.Command("./lotus", cctx.Args().Slice()[1:]...)
|
||||||
|
cmd.Env = []string{
|
||||||
|
"LOTUS_PATH=" + node.Repo,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command("./lotus-storage-miner")
|
||||||
|
cmd.Env = []string{
|
||||||
|
"LOTUS_STORAGE_PATH=" + node.Repo,
|
||||||
|
"LOTUS_PATH=" + node.FullNode,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
errlogfile, err := os.OpenFile(dir+".err.log", os.O_CREATE|os.O_WRONLY, 0644)
|
cmd.Stdin = os.Stdin
|
||||||
if err != nil {
|
cmd.Stdout = os.Stdout
|
||||||
return nodeInfo{}, err
|
cmd.Stderr = os.Stderr
|
||||||
}
|
|
||||||
logfile, err := os.OpenFile(dir+".out.log", os.O_CREATE|os.O_WRONLY, 0644)
|
|
||||||
if err != nil {
|
|
||||||
return nodeInfo{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd := exec.Command("./lotus", "daemon", genParam, "--api", fmt.Sprintf("%d", 2500+id))
|
err = cmd.Run()
|
||||||
cmd.Stderr = io.MultiWriter(os.Stderr, errlogfile)
|
return err
|
||||||
cmd.Stdout = io.MultiWriter(os.Stdout, logfile)
|
},
|
||||||
cmd.Env = []string{"LOTUS_PATH=" + dir}
|
|
||||||
if err := cmd.Start(); err != nil {
|
|
||||||
return nodeInfo{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
info := nodeInfo{
|
|
||||||
Repo: dir,
|
|
||||||
ID: id,
|
|
||||||
ApiPort: 2500 + id,
|
|
||||||
}
|
|
||||||
|
|
||||||
api.runningLk.Lock()
|
|
||||||
api.running[id] = runningNode{
|
|
||||||
cmd: cmd,
|
|
||||||
meta: info,
|
|
||||||
|
|
||||||
stop: func() {
|
|
||||||
defer errlogfile.Close()
|
|
||||||
defer logfile.Close()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
api.runningLk.Unlock()
|
|
||||||
|
|
||||||
time.Sleep(time.Millisecond * 750) // TODO: Something less terrible
|
|
||||||
|
|
||||||
return info, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *api) Nodes() []nodeInfo {
|
var shCmd = &cli.Command{
|
||||||
api.runningLk.Lock()
|
Name: "sh",
|
||||||
out := make([]nodeInfo, 0, len(api.running))
|
Usage: "spawn shell with node shell variables set",
|
||||||
for _, node := range api.running {
|
Action: func(cctx *cli.Context) error {
|
||||||
out = append(out, node.meta)
|
client, err := apiClient()
|
||||||
}
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
api.runningLk.Unlock()
|
nd, err := strconv.ParseInt(cctx.Args().Get(0), 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return out
|
node := nodeById(client.Nodes(), int(nd))
|
||||||
|
shcmd := exec.Command("/bin/bash")
|
||||||
|
if !node.Storage {
|
||||||
|
shcmd.Env = []string{
|
||||||
|
"LOTUS_PATH=" + node.Repo,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
shcmd.Env = []string{
|
||||||
|
"LOTUS_STORAGE_PATH=" + node.Repo,
|
||||||
|
"LOTUS_PATH=" + node.FullNode,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shcmd.Stdin = os.Stdin
|
||||||
|
shcmd.Stdout = os.Stdout
|
||||||
|
shcmd.Stderr = os.Stderr
|
||||||
|
|
||||||
|
fmt.Printf("Entering shell for Node %d\n", nd)
|
||||||
|
err = shcmd.Run()
|
||||||
|
fmt.Printf("Closed pond shell\n")
|
||||||
|
|
||||||
|
return err
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *api) TokenFor(id int32) (string, error) {
|
func nodeById(nodes []nodeInfo, i int) nodeInfo {
|
||||||
api.runningLk.Lock()
|
for _, n := range nodes {
|
||||||
defer api.runningLk.Unlock()
|
if n.ID == int32(i) {
|
||||||
|
return n
|
||||||
rnd, ok := api.running[id]
|
}
|
||||||
if !ok {
|
|
||||||
return "", errors.New("no running node with this ID")
|
|
||||||
}
|
}
|
||||||
|
panic("no node with this id")
|
||||||
r, err := repo.NewFS(rnd.meta.Repo)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
t, err := r.APIToken()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(t), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *api) SpawnStorage(fullNodeRepo string) (nodeInfo, error) {
|
var runCmd = &cli.Command{
|
||||||
dir, err := ioutil.TempDir(os.TempDir(), "lotus-storage-")
|
Name: "run",
|
||||||
if err != nil {
|
Usage: "run lotuspond daemon",
|
||||||
return nodeInfo{}, err
|
Action: func(cctx *cli.Context) error {
|
||||||
}
|
rpcServer := jsonrpc.NewServer()
|
||||||
|
rpcServer.Register("Pond", &api{running: map[int32]runningNode{}})
|
||||||
|
|
||||||
errlogfile, err := os.OpenFile(dir+".err.log", os.O_CREATE|os.O_WRONLY, 0644)
|
http.Handle("/", http.FileServer(http.Dir("lotuspond/front/build")))
|
||||||
if err != nil {
|
http.Handle("/rpc/v0", rpcServer)
|
||||||
return nodeInfo{}, err
|
|
||||||
}
|
|
||||||
logfile, err := os.OpenFile(dir+".out.log", os.O_CREATE|os.O_WRONLY, 0644)
|
|
||||||
if err != nil {
|
|
||||||
return nodeInfo{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
id := atomic.AddInt32(&api.cmds, 1)
|
fmt.Printf("Listening on http://%s\n", listenAddr)
|
||||||
cmd := exec.Command("./lotus-storage-miner", "init")
|
return http.ListenAndServe(listenAddr, nil)
|
||||||
cmd.Stderr = io.MultiWriter(os.Stderr, errlogfile)
|
},
|
||||||
cmd.Stdout = io.MultiWriter(os.Stdout, logfile)
|
|
||||||
cmd.Env = []string{"LOTUS_STORAGE_PATH=" + dir, "LOTUS_PATH=" + fullNodeRepo}
|
|
||||||
if err := cmd.Run(); err != nil {
|
|
||||||
return nodeInfo{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
time.Sleep(time.Millisecond * 300)
|
|
||||||
|
|
||||||
cmd = exec.Command("./lotus-storage-miner", "run", "--api", fmt.Sprintf("%d", 2500+id))
|
|
||||||
cmd.Stderr = io.MultiWriter(os.Stderr, errlogfile)
|
|
||||||
cmd.Stdout = io.MultiWriter(os.Stdout, logfile)
|
|
||||||
cmd.Env = []string{"LOTUS_STORAGE_PATH=" + dir, "LOTUS_PATH=" + fullNodeRepo}
|
|
||||||
if err := cmd.Start(); err != nil {
|
|
||||||
return nodeInfo{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
info := nodeInfo{
|
|
||||||
Repo: dir,
|
|
||||||
ID: id,
|
|
||||||
ApiPort: 2500 + id,
|
|
||||||
|
|
||||||
Storage: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
api.runningLk.Lock()
|
|
||||||
api.running[id] = runningNode{
|
|
||||||
cmd: cmd,
|
|
||||||
meta: info,
|
|
||||||
|
|
||||||
stop: func() {
|
|
||||||
defer errlogfile.Close()
|
|
||||||
defer logfile.Close()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
api.runningLk.Unlock()
|
|
||||||
|
|
||||||
time.Sleep(time.Millisecond * 750) // TODO: Something less terrible
|
|
||||||
|
|
||||||
return info, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
rpcServer := jsonrpc.NewServer()
|
app := &cli.App{
|
||||||
rpcServer.Register("Pond", &api{running: map[int32]runningNode{}})
|
Name: "pond",
|
||||||
|
Commands: []*cli.Command{
|
||||||
http.Handle("/", http.FileServer(http.Dir("lotuspond/front/build")))
|
runCmd,
|
||||||
http.Handle("/rpc/v0", rpcServer)
|
shCmd,
|
||||||
|
onCmd,
|
||||||
fmt.Printf("Listening on http://%s\n", listenAddr)
|
},
|
||||||
http.ListenAndServe(listenAddr, nil)
|
}
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,7 +181,6 @@ func Online() Option {
|
|||||||
libp2p(),
|
libp2p(),
|
||||||
|
|
||||||
// common
|
// common
|
||||||
Override(new(*wallet.Wallet), wallet.NewWallet),
|
|
||||||
|
|
||||||
// Full node
|
// Full node
|
||||||
|
|
||||||
@ -191,6 +190,7 @@ func Online() Option {
|
|||||||
Override(HandleIncomingMessagesKey, modules.HandleIncomingMessages),
|
Override(HandleIncomingMessagesKey, modules.HandleIncomingMessages),
|
||||||
|
|
||||||
Override(new(*store.ChainStore), modules.ChainStore),
|
Override(new(*store.ChainStore), modules.ChainStore),
|
||||||
|
Override(new(*wallet.Wallet), wallet.NewWallet),
|
||||||
|
|
||||||
Override(new(dtypes.ChainGCLocker), blockstore.NewGCLocker),
|
Override(new(dtypes.ChainGCLocker), blockstore.NewGCLocker),
|
||||||
Override(new(dtypes.ChainGCBlockstore), modules.ChainGCBlockstore),
|
Override(new(dtypes.ChainGCBlockstore), modules.ChainGCBlockstore),
|
||||||
|
@ -96,6 +96,8 @@ func (m *Miner) handlePostingSealedSectors(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *Miner) commitSector(ctx context.Context, sinfo sectorbuilder.SectorSealingStatus) error {
|
func (m *Miner) commitSector(ctx context.Context, sinfo sectorbuilder.SectorSealingStatus) error {
|
||||||
|
log.Info("committing sector")
|
||||||
|
|
||||||
ok, err := sectorbuilder.VerifySeal(1024, sinfo.CommR[:], sinfo.CommD[:], sinfo.CommRStar[:], m.maddr, sinfo.SectorID, sinfo.Proof)
|
ok, err := sectorbuilder.VerifySeal(1024, sinfo.CommR[:], sinfo.CommD[:], sinfo.CommRStar[:], m.maddr, sinfo.SectorID, sinfo.Proof)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("failed to verify seal we just created: ", err)
|
log.Error("failed to verify seal we just created: ", err)
|
||||||
|
Loading…
Reference in New Issue
Block a user