Skip to content

Commit a4cd57e

Browse files
Kubuxurvagg
andauthored
feat(f3): tool for explicit power table generation (#12723)
* feat(f3): tool for explicit power table generation Signed-off-by: Jakub Sztandera <[email protected]> * Fix indent, ignore # lines and empty lines Signed-off-by: Jakub Sztandera <[email protected]> * Fix good list with no power and allow to specify tipset Signed-off-by: Jakub Sztandera <[email protected]> * appease formatter Signed-off-by: Jakub Sztandera <[email protected]> * I'm on my knees linter Signed-off-by: Jakub Sztandera <[email protected]> * Update cmd/lotus-shed/f3.go Co-authored-by: Rod Vagg <[email protected]> * Update cmd/lotus-shed/f3.go Co-authored-by: Rod Vagg <[email protected]> --------- Signed-off-by: Jakub Sztandera <[email protected]> Co-authored-by: Rod Vagg <[email protected]>
1 parent 70996d0 commit a4cd57e

File tree

1 file changed

+175
-0
lines changed

1 file changed

+175
-0
lines changed

cmd/lotus-shed/f3.go

+175
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,25 @@
11
package main
22

33
import (
4+
"bufio"
45
"context"
6+
"encoding/json"
57
"fmt"
8+
"math/rand"
9+
"os"
10+
"sort"
11+
"strconv"
12+
"time"
613

714
"github.com/ipfs/go-datastore"
815
dsq "github.com/ipfs/go-datastore/query"
916
"github.com/urfave/cli/v2"
1017
"golang.org/x/xerrors"
1118

19+
"github.com/filecoin-project/go-f3/gpbft"
20+
21+
lcli "github.com/filecoin-project/lotus/cli"
22+
cliutil "github.com/filecoin-project/lotus/cli/util"
1223
"github.com/filecoin-project/lotus/node/repo"
1324
)
1425

@@ -17,6 +28,170 @@ var f3Cmd = &cli.Command{
1728
Description: "f3 related commands",
1829
Subcommands: []*cli.Command{
1930
f3ClearStateCmd,
31+
f3GenExplicitPower,
32+
},
33+
}
34+
35+
func loadF3IDList(path string) ([]gpbft.ActorID, error) {
36+
file, err := os.Open(path)
37+
if err != nil {
38+
return nil, fmt.Errorf("failed to open file: %w", err)
39+
}
40+
defer file.Close() //nolint:errcheck
41+
42+
var ids []gpbft.ActorID
43+
scanner := bufio.NewScanner(file)
44+
for scanner.Scan() {
45+
line := scanner.Text()
46+
if line == "" || line[0] == '#' {
47+
continue
48+
}
49+
id, err := strconv.ParseUint(line, 10, 64)
50+
if err != nil {
51+
return nil, fmt.Errorf("failed to parse ID: %w", err)
52+
}
53+
54+
ids = append(ids, gpbft.ActorID(id))
55+
}
56+
57+
if err := scanner.Err(); err != nil {
58+
return nil, fmt.Errorf("error reading file: %w", err)
59+
}
60+
61+
return ids, nil
62+
}
63+
64+
var f3GenExplicitPower = &cli.Command{
65+
Name: "gen-explicit-power",
66+
Description: "generates an explicit power table",
67+
68+
Flags: []cli.Flag{
69+
&cli.PathFlag{
70+
Name: "good-list",
71+
Usage: "new line delimited file with known good IDs to be included",
72+
},
73+
&cli.PathFlag{
74+
Name: "bad-list",
75+
Usage: "new line delimited file with known bad IDs to be excluded",
76+
},
77+
&cli.IntFlag{
78+
Name: "n",
79+
Usage: "generate N entries, exclusive with ratio",
80+
},
81+
&cli.Float64Flag{
82+
Name: "ratio",
83+
Usage: "generate given ratio of full power table, exclusive with N",
84+
},
85+
&cli.Int64Flag{
86+
Name: "seed",
87+
Usage: "seed for randomization, -1 will use current nano time",
88+
Value: -1,
89+
},
90+
&cli.Uint64Flag{
91+
Name: "iteration",
92+
Usage: "the iteration of randomization, random entries will be exclusive across iterations",
93+
Value: 0,
94+
},
95+
&cli.StringFlag{
96+
Name: "tipset",
97+
Usage: "specify tipset to call method on (pass comma separated array of cids) or @epoch",
98+
},
99+
},
100+
101+
Action: func(cctx *cli.Context) error {
102+
ctx := cliutil.ReqContext(cctx)
103+
api, closer, err := cliutil.GetFullNodeAPIV1(cctx)
104+
if err != nil {
105+
return fmt.Errorf("getting api: %w", err)
106+
}
107+
defer closer()
108+
109+
ts, err := lcli.LoadTipSet(ctx, cctx, api)
110+
if err != nil {
111+
return fmt.Errorf("getting chain head: %w", err)
112+
}
113+
if cctx.IsSet("N") && cctx.IsSet("ratio") {
114+
return fmt.Errorf("N and ratio options are exclusive")
115+
}
116+
117+
allPowerEntries, err := api.F3GetECPowerTable(ctx, ts.Key())
118+
if err != nil {
119+
return fmt.Errorf("getting power entries: %w", err)
120+
}
121+
122+
powerMap := map[gpbft.ActorID]gpbft.PowerEntry{}
123+
for _, pe := range allPowerEntries {
124+
powerMap[pe.ID] = pe
125+
}
126+
var goodList []gpbft.ActorID
127+
if goodPath := cctx.Path("good-list"); goodPath != "" {
128+
goodList, err = loadF3IDList(goodPath)
129+
if err != nil {
130+
return fmt.Errorf("loading good list: %w", err)
131+
}
132+
}
133+
134+
var badList []gpbft.ActorID
135+
if badPath := cctx.Path("bad-list"); badPath != "" {
136+
badList, err = loadF3IDList(badPath)
137+
if err != nil {
138+
return fmt.Errorf("loading bad list: %w", err)
139+
}
140+
}
141+
total := len(powerMap)
142+
for _, id := range badList {
143+
delete(powerMap, id)
144+
}
145+
146+
var result gpbft.PowerEntries
147+
add := func(id gpbft.ActorID) {
148+
result = append(result, powerMap[id])
149+
delete(powerMap, id)
150+
}
151+
152+
for _, id := range goodList {
153+
if _, ok := powerMap[id]; ok {
154+
add(id)
155+
}
156+
}
157+
158+
seed := cctx.Int64("seed")
159+
if seed == -1 {
160+
seed = time.Now().UnixNano()
161+
}
162+
rng := rand.New(rand.NewSource(seed))
163+
164+
endSize := cctx.Int("N")
165+
if cctx.IsSet("ratio") {
166+
endSize = int(float64(total) * cctx.Float64("ratio"))
167+
}
168+
if toAdd := endSize - len(result); toAdd > 0 {
169+
var powerList gpbft.PowerEntries
170+
for _, pe := range powerMap {
171+
powerList = append(powerList, pe)
172+
}
173+
rng.Shuffle(len(powerList), powerList.Swap)
174+
175+
iteration := cctx.Int("iteration")
176+
startIdx := min(toAdd*iteration, len(powerList))
177+
endIdx := min(toAdd*(iteration+1), len(powerList))
178+
result = append(result, powerList[startIdx:endIdx]...)
179+
}
180+
181+
if len(result) > endSize {
182+
result = result[:endSize]
183+
}
184+
sort.Sort(result)
185+
res, err := json.MarshalIndent(result, " ", " ")
186+
if err != nil {
187+
return fmt.Errorf("marshalling to json: %w", err)
188+
}
189+
_, err = cctx.App.Writer.Write(res)
190+
if err != nil {
191+
return fmt.Errorf("writing result: %w", err)
192+
}
193+
194+
return nil
20195
},
21196
}
22197

0 commit comments

Comments
 (0)