remove interactive UX; add inspect-deal cmd

This commit is contained in:
Anton Evangelatov 2021-03-10 13:25:52 +01:00
parent 84803f82ab
commit 9d6c77d93f
7 changed files with 88 additions and 255 deletions

View File

@ -605,7 +605,7 @@ type DealInfo struct {
ProposalCid cid.Cid ProposalCid cid.Cid
State storagemarket.StorageDealStatus State storagemarket.StorageDealStatus
Message string // more information about deal state, particularly errors Message string // more information about deal state, particularly errors
DealStages storagemarket.DealStages DealStages *storagemarket.DealStages
Provider address.Address Provider address.Address
DataRef *storagemarket.DataRef DataRef *storagemarket.DataRef

View File

@ -60,6 +60,7 @@ type DataTransferChannel struct {
Message string Message string
OtherPeer peer.ID OtherPeer peer.ID
Transferred uint64 Transferred uint64
Stages *datatransfer.ChannelStages
} }
// NewDataTransferChannel constructs an API DataTransferChannel type from full channel state snapshot and a host id // NewDataTransferChannel constructs an API DataTransferChannel type from full channel state snapshot and a host id
@ -70,6 +71,7 @@ func NewDataTransferChannel(hostID peer.ID, channelState datatransfer.ChannelSta
BaseCID: channelState.BaseCID(), BaseCID: channelState.BaseCID(),
IsSender: channelState.Sender() == hostID, IsSender: channelState.Sender() == hostID,
Message: channelState.Message(), Message: channelState.Message(),
Stages: channelState.Stages(),
} }
stringer, ok := channelState.Voucher().(fmt.Stringer) stringer, ok := channelState.Voucher().(fmt.Stringer)
if ok { if ok {

View File

@ -38,6 +38,9 @@ func init() {
policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048)) policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048))
policy.SetMinVerifiedDealSize(abi.NewStoragePower(256)) policy.SetMinVerifiedDealSize(abi.NewStoragePower(256))
//policy.SetWPoStChallengeWindow(abi.ChainEpoch(5))
policy.SetPreCommitChallengeDelay(abi.ChainEpoch(10))
BuildType |= Build2k BuildType |= Build2k
} }

View File

@ -84,7 +84,7 @@ var clientCmd = &cli.Command{
WithCategory("storage", clientGetDealCmd), WithCategory("storage", clientGetDealCmd),
WithCategory("storage", clientListAsksCmd), WithCategory("storage", clientListAsksCmd),
WithCategory("storage", clientDealStatsCmd), WithCategory("storage", clientDealStatsCmd),
WithCategory("storage", clientShowDealsCmd), WithCategory("storage", clientInspectDealCmd),
WithCategory("data", clientImportCmd), WithCategory("data", clientImportCmd),
WithCategory("data", clientDropCmd), WithCategory("data", clientDropCmd),
WithCategory("data", clientLocalCmd), WithCategory("data", clientLocalCmd),
@ -1116,20 +1116,26 @@ var clientRetrieveCmd = &cli.Command{
}, },
} }
var clientShowDealsCmd = &cli.Command{ var clientInspectDealCmd = &cli.Command{
Name: "show-deals", Name: "inspect-deal",
Usage: "Show storage deals", Usage: "Inspect storage deal",
Flags: []cli.Flag{
&cli.IntFlag{
Name: "deal-id",
},
&cli.StringFlag{
Name: "proposal-cid",
},
},
Action: func(cctx *cli.Context) error { Action: func(cctx *cli.Context) error {
//api, closer, err := GetFullNodeAPI(cctx) api, closer, err := GetFullNodeAPI(cctx)
//if err != nil { if err != nil {
// return err return err
//} }
//defer closer() defer closer()
var api api.FullNode
ctx := ReqContext(cctx) ctx := ReqContext(cctx)
//afmt := NewAppFmt(cctx.App) return dealcli.InspectDealCmd(ctx, api, cctx.String("proposal-cid"), cctx.Int("deal-id"))
return dealcli.ShowDealsCmd(ctx, api)
}, },
} }

View File

@ -2,270 +2,85 @@ package deal
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"io" "strings"
"time" "time"
tm "github.com/buger/goterm"
"github.com/fatih/color" "github.com/fatih/color"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-fil-markets/storagemarket"
"github.com/filecoin-project/go-state-types/abi"
lapi "github.com/filecoin-project/lotus/api" lapi "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/lib/tablewriter"
"github.com/ipfs/go-cid"
term "github.com/nsf/termbox-go"
) )
var mockDealInfos []lapi.DealInfo var mockDealInfos []lapi.DealInfo
func init() { func InspectDealCmd(ctx context.Context, api lapi.FullNode, proposalCid string, dealId int) error {
dummyCid, err := cid.Parse("bafkqaaa")
if err != nil {
panic(err)
}
mockDealStages := storagemarket.DealStages{
At: time.Now(),
Stages: []storagemarket.DealStage{{
Name: "Reserving Funds",
ExpectedDuration: "5 epochs",
StartedAt: time.Now().Add(-5 * time.Minute),
Logs: []string{
"Sending AddBalance message for 0.3FIL",
"Waiting 5 epochs (2:30) for confirmation",
"Funds for deal reserved successfully",
},
}, {
Name: "Sending Deal Proposal to Provider",
ExpectedDuration: "5 epochs",
StartedAt: time.Now().Add(-2 * time.Minute),
Logs: []string{
"Proposal: 512MB for 300 days @ 0.1FIL / GB / epoch",
"Deal proposal accepted by provider",
"Funds for deal reserved successfully",
},
}, {
Name: "Sending deal data to Provider",
ExpectedDuration: "13 minutes",
StartedAt: time.Now().Add(-53 * time.Second),
Logs: []string{
"Progress: 4:02 254MB / 1024MB (1MB / sec)",
"Connection to Provider f01234 disconnected, retrying in 8s",
},
}, {
Name: "Waiting for deal to be published by Provider",
ExpectedDuration: "several hours",
}, {
Name: "Waiting for pre-commit message from Provider",
ExpectedDuration: "several hours",
}, {
Name: "Waiting for prove-commit message from Provider",
ExpectedDuration: "several hours",
}},
}
mockDealInfos = []lapi.DealInfo{{
State: 3,
Message: "Reserving Client Funds",
DealStages: mockDealStages,
Provider: address.TestAddress,
DataRef: nil,
PieceCID: dummyCid,
Size: 512 * 1024 * 1024,
PricePerEpoch: abi.NewTokenAmount(10),
Duration: 300,
DealID: 10,
CreationTime: time.Now().Add(-5 * time.Second),
Verified: false,
TransferChannelID: nil,
DataTransfer: nil,
}, {
State: 5,
Message: "Publishing Deal",
DealStages: mockDealStages,
Provider: address.TestAddress,
DataRef: nil,
PieceCID: dummyCid,
Size: 482 * 1024 * 1024,
PricePerEpoch: abi.NewTokenAmount(12),
Duration: 323,
DealID: 14,
CreationTime: time.Now().Add(-23 * time.Minute),
Verified: false,
TransferChannelID: nil,
DataTransfer: nil,
}, {
State: 7,
Message: "Waiting for Pre-Commit",
DealStages: mockDealStages,
Provider: address.TestAddress,
DataRef: nil,
PieceCID: dummyCid,
Size: 2 * 1024 * 1024 * 1024,
PricePerEpoch: abi.NewTokenAmount(8),
Duration: 298,
DealID: 8,
CreationTime: time.Now().Add(-3 * time.Hour),
Verified: false,
TransferChannelID: nil,
DataTransfer: nil,
}, {
State: 2,
Message: "Transferring Data",
DealStages: mockDealStages,
Provider: address.TestAddress,
DataRef: nil,
PieceCID: dummyCid,
Size: 23 * 1024 * 1024,
PricePerEpoch: abi.NewTokenAmount(11),
Duration: 328,
DealID: 3,
CreationTime: time.Now().Add(-49 * time.Hour),
Verified: false,
TransferChannelID: nil,
DataTransfer: nil,
}}
}
func ShowDealsCmd(ctx context.Context, api lapi.FullNode) error {
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
defer cancel() defer cancel()
//localDeals, err := api.ClientListDeals(ctx) deals, err := api.ClientListDeals(ctx)
//if err != nil {
// return err
//}
localDeals := mockDealInfos
return showDealsUX(ctx, localDeals)
}
func showDealsUX(ctx context.Context, deals []lapi.DealInfo) error {
err := term.Init()
if err != nil { if err != nil {
return err return err
} }
defer term.Close()
renderer := dealRenderer{out: tm.Screen} var di lapi.DealInfo
found := false
dealIdx := -1 for _, cdi := range deals {
state := "main" if proposalCid != "" && cdi.ProposalCid.String() == proposalCid {
highlighted := -1 di = cdi
for { found = true
if err := ctx.Err(); err != nil { break
return err
} }
switch state { if dealId != 0 && int(cdi.DealID) == dealId {
case "main": di = cdi
renderMain := func(hlite int) error { found = true
tm.Clear() break
tm.MoveCursor(1, 1)
err := renderer.renderDeals(deals, hlite)
if err != nil {
return err
}
tm.Flush()
return nil
}
err := renderMain(highlighted)
if err != nil {
return err
}
switch ev := term.PollEvent(); ev.Type {
case term.EventKey:
switch {
case ev.Ch == 'q', ev.Key == term.KeyEsc:
return nil
case ev.Key == term.KeyArrowUp:
term.Sync()
if highlighted > 0 {
highlighted--
}
case ev.Key == term.KeyArrowDown:
term.Sync()
highlighted++
case ev.Key == term.KeyEnter:
term.Sync()
dealIdx = highlighted
state = "deal"
}
case term.EventError:
return ev.Err
}
case "deal":
tm.Clear()
tm.MoveCursor(1, 1)
renderer.renderDeal(deals[dealIdx])
tm.Flush()
switch ev := term.PollEvent(); ev.Type {
case term.EventKey:
if ev.Ch == 'q' || ev.Key == term.KeyEsc || ev.Key == term.KeyEnter || ev.Key == term.KeyArrowLeft {
term.Sync()
state = "main"
}
case term.EventError:
return ev.Err
}
} }
} }
}
type dealRenderer struct { if !found {
out io.Writer if proposalCid != "" {
} return fmt.Errorf("cannot find deal with proposal cid: %s", proposalCid)
}
if dealId != 0 {
return fmt.Errorf("cannot find deal with deal id: %v", dealId)
}
return errors.New("you must specify proposal cid or deal id in order to inspect a deal")
}
func (r *dealRenderer) renderDeals(deals []lapi.DealInfo, highlighted int) error { renderDeal(di)
tw := tablewriter.New(
tablewriter.Col(""),
tablewriter.Col("Created"),
tablewriter.Col("Provider"),
tablewriter.Col("Size"),
tablewriter.Col("State"),
)
for i, di := range deals {
lineNum := fmt.Sprintf("%d", i+1)
cols := map[string]interface{}{
"": lineNum,
"Created": time.Since(di.CreationTime).Round(time.Second),
"Provider": di.Provider,
"Size": di.Size,
"State": di.Message,
}
if i == highlighted {
for k, v := range cols {
cols[k] = color.YellowString(fmt.Sprint(v))
}
}
tw.Write(cols)
}
return tw.Flush(r.out)
}
func (r *dealRenderer) renderDeal(di lapi.DealInfo) error {
_, err := fmt.Fprintf(r.out, "Deal %d\n", di.DealID)
if err != nil {
return err
}
for _, stg := range di.DealStages.Stages {
msg := fmt.Sprintf("%s (%s)", stg.Name, stg.ExpectedDuration)
if stg.StartedAt.IsZero() {
msg = color.YellowString(msg)
}
_, err := fmt.Fprintf(r.out, "%s\n", msg)
if err != nil {
return err
}
for _, l := range stg.Logs {
_, err = fmt.Fprintf(r.out, " %s\n", l)
if err != nil {
return err
}
}
}
return nil return nil
} }
func renderDeal(di lapi.DealInfo) {
color.Blue("Deal ID: %d\n", int(di.DealID))
color.Blue("Proposal CID: %s\n\n", di.ProposalCid.String())
for _, stg := range di.DealStages.Stages {
msg := fmt.Sprintf("%s %s: %s (%s)", color.BlueString("Stage:"), color.BlueString(strings.TrimPrefix(stg.Name, "StorageDeal")), stg.Description, color.GreenString(stg.ExpectedDuration))
if stg.UpdatedTime.Time().IsZero() {
msg = color.YellowString(msg)
}
fmt.Println(msg)
for _, l := range stg.Logs {
fmt.Printf(" %s %s\n", color.YellowString(l.UpdatedTime.Time().UTC().Round(time.Second).Format(time.Stamp)), l.Log)
}
if stg.Name == "StorageDealStartDataTransfer" {
for _, dt_stg := range di.DataTransfer.Stages.Stages {
msg := fmt.Sprintf("Data transfer stage: %s", dt_stg.Name)
msg = color.BlueString(msg)
if stg.UpdatedTime.Time().IsZero() {
msg = color.YellowString(msg)
}
fmt.Printf(" %s\n", msg)
for _, l := range dt_stg.Logs {
fmt.Printf(" %s %s\n", color.YellowString(l.UpdatedTime.Time().UTC().Round(time.Second).Format(time.Stamp)), l.Log)
}
}
}
}
}

3
go.mod
View File

@ -15,6 +15,7 @@ require (
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e
github.com/cockroachdb/pebble v0.0.0-20201001221639-879f3bfeef07 github.com/cockroachdb/pebble v0.0.0-20201001221639-879f3bfeef07
github.com/coreos/go-systemd/v22 v22.1.0 github.com/coreos/go-systemd/v22 v22.1.0
github.com/davecgh/go-spew v1.1.1
github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e
github.com/dgraph-io/badger/v2 v2.2007.2 github.com/dgraph-io/badger/v2 v2.2007.2
github.com/docker/go-units v0.4.0 github.com/docker/go-units v0.4.0
@ -163,3 +164,5 @@ replace github.com/filecoin-project/filecoin-ffi => ./extern/filecoin-ffi
replace github.com/filecoin-project/test-vectors => ./extern/test-vectors replace github.com/filecoin-project/test-vectors => ./extern/test-vectors
replace github.com/filecoin-project/go-fil-markets => ../go-fil-markets replace github.com/filecoin-project/go-fil-markets => ../go-fil-markets
replace github.com/filecoin-project/go-data-transfer => ../go-data-transfer

View File

@ -7,6 +7,7 @@ import (
"io" "io"
"os" "os"
"github.com/davecgh/go-spew/spew"
"github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/actors/builtin/miner"
"golang.org/x/xerrors" "golang.org/x/xerrors"
@ -215,6 +216,8 @@ func (a *API) ClientListDeals(ctx context.Context) ([]api.DealInfo, error) {
out[k] = a.newDealInfoWithTransfer(transferCh, v) out[k] = a.newDealInfoWithTransfer(transferCh, v)
} }
spew.Dump(out)
return out, nil return out, nil
} }
@ -289,6 +292,7 @@ func (a *API) newDealInfoWithTransfer(transferCh *api.DataTransferChannel, v sto
Verified: v.Proposal.VerifiedDeal, Verified: v.Proposal.VerifiedDeal,
TransferChannelID: v.TransferChannelID, TransferChannelID: v.TransferChannelID,
DataTransfer: transferCh, DataTransfer: transferCh,
DealStages: v.DealStages,
} }
} }