-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
Copy pathf3.go
180 lines (163 loc) · 5.33 KB
/
f3.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
package cli
import (
"encoding/json"
"fmt"
"io"
"strings"
"text/template"
"github.com/urfave/cli/v2"
"github.com/filecoin-project/go-f3/manifest"
"github.com/filecoin-project/lotus/lib/tablewriter"
)
var (
F3Cmd = &cli.Command{
Name: "f3",
Usage: "Manages Filecoin Fast Finality (F3) interactions",
Subcommands: []*cli.Command{
{
Name: "list-miners",
Aliases: []string{"lp"},
Usage: "Lists the miners that currently participate in F3 via this node.",
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPIV1(cctx)
if err != nil {
return err
}
defer closer()
miners, err := api.F3ListParticipants(cctx.Context)
if err != nil {
return fmt.Errorf("listing participants: %w", err)
}
if len(miners) == 0 {
_, err = fmt.Fprintln(cctx.App.Writer, "No miners.")
return err
}
const (
idColumn = "ID"
fromColumn = "From"
ToColumn = "To"
)
tw := tablewriter.New(
tablewriter.Col(idColumn),
tablewriter.Col(fromColumn),
tablewriter.Col(ToColumn),
)
for _, participant := range miners {
tw.Write(map[string]interface{}{
idColumn: participant.MinerID,
fromColumn: participant.FromInstance,
ToColumn: participant.FromInstance + participant.ValidityTerm,
})
}
return tw.Flush(cctx.App.Writer)
},
},
{
Name: "manifest",
Usage: "Gets the current manifest used by F3.",
Flags: []cli.Flag{f3FlagOutput},
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPIV1(cctx)
if err != nil {
return err
}
defer closer()
manifest, err := api.F3GetManifest(cctx.Context)
if err != nil {
return fmt.Errorf("getting manifest: %w", err)
}
switch output := cctx.String(f3FlagOutput.Name); strings.ToLower(output) {
case "text":
return prettyPrintManifest(cctx.App.Writer, manifest)
case "json":
encoder := json.NewEncoder(cctx.App.Writer)
encoder.SetIndent("", " ")
return encoder.Encode(manifest)
default:
return fmt.Errorf("unknown output format: %s", output)
}
},
},
{
Name: "status",
Usage: "Checks the F3 status.",
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPIV1(cctx)
if err != nil {
return err
}
defer closer()
running, err := api.F3IsRunning(cctx.Context)
if err != nil {
return fmt.Errorf("getting running state: %w", err)
}
_, _ = fmt.Fprintf(cctx.App.Writer, "Running: %t\n", running)
if !running {
return nil
}
progress, err := api.F3GetProgress(cctx.Context)
if err != nil {
return fmt.Errorf("getting progress: %w", err)
}
_, _ = fmt.Fprintln(cctx.App.Writer, "Progress:")
_, _ = fmt.Fprintf(cctx.App.Writer, " Instance: %d\n", progress.ID)
_, _ = fmt.Fprintf(cctx.App.Writer, " Round: %d\n", progress.Round)
_, _ = fmt.Fprintf(cctx.App.Writer, " Phase: %s\n", progress.Phase)
manifest, err := api.F3GetManifest(cctx.Context)
if err != nil {
return fmt.Errorf("getting manifest: %w", err)
}
return prettyPrintManifest(cctx.App.Writer, manifest)
},
},
},
}
// TODO: we should standardise format as a top level flag. For now, here is an f3
// specific one.
// See: https://github.com/filecoin-project/lotus/issues/12616
f3FlagOutput = &cli.StringFlag{
Name: "output",
Usage: "The output format. Supported formats: text, json",
Value: "text",
Action: func(cctx *cli.Context, output string) error {
switch output {
case "text", "json":
return nil
default:
return fmt.Errorf("unknown output format: %s", output)
}
},
}
)
func prettyPrintManifest(out io.Writer, manifest *manifest.Manifest) error {
if manifest == nil {
_, err := fmt.Fprintln(out, "Manifest: None")
return err
}
const manifestTemplate = `Manifest:
Protocol Version: {{.ProtocolVersion}}
Paused: {{.Pause}}
Initial Instance: {{.InitialInstance}}
Bootstrap Epoch: {{.BootstrapEpoch}}
Network Name: {{.NetworkName}}
Ignore EC Power: {{.IgnoreECPower}}
Committee Lookback: {{.CommitteeLookback}}
Catch Up Alignment: {{.CatchUpAlignment}}
GPBFT Delta: {{.Gpbft.Delta}}
GPBFT Delta BackOff Exponent: {{.Gpbft.DeltaBackOffExponent}}
GPBFT Max Lookahead Rounds: {{.Gpbft.MaxLookaheadRounds}}
GPBFT Rebroadcast Backoff Base: {{.Gpbft.RebroadcastBackoffBase}}
GPBFT Rebroadcast Backoff Spread: {{.Gpbft.RebroadcastBackoffSpread}}
GPBFT Rebroadcast Backoff Max: {{.Gpbft.RebroadcastBackoffMax}}
EC Period: {{.EC.Period}}
EC Finality: {{.EC.Finality}}
EC Delay Multiplier: {{.EC.DelayMultiplier}}
EC Head Lookback: {{.EC.HeadLookback}}
EC Finalize: {{.EC.Finalize}}
Certificate Exchange Client Timeout: {{.CertificateExchange.ClientRequestTimeout}}
Certificate Exchange Server Timeout: {{.CertificateExchange.ServerRequestTimeout}}
Certificate Exchange Min Poll Interval: {{.CertificateExchange.MinimumPollInterval}}
Certificate Exchange Max Poll Interval: {{.CertificateExchange.MaximumPollInterval}}
`
return template.New("manifest").ExecuteTemplate(out, manifestTemplate, manifest)
}