-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
extract.go
162 lines (151 loc) · 4.57 KB
/
extract.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
package main
import (
"encoding/json"
"fmt"
"io"
"log"
"os"
"path/filepath"
"github.com/urfave/cli/v2"
"github.com/filecoin-project/test-vectors/schema"
)
const (
PrecursorSelectAll = "all"
PrecursorSelectParticipants = "participants"
)
type extractOpts struct {
id string
block string
class string
cid string
tsk string
file string
retain string
precursor string
ignoreSanityChecks bool
squash bool
}
var extractFlags extractOpts
var extractCmd = &cli.Command{
Name: "extract",
Description: "generate a test vector by extracting it from a live chain",
Action: runExtract,
Before: initialize,
After: destroy,
Flags: []cli.Flag{
&repoFlag,
&cli.StringFlag{
Name: "class",
Usage: "class of vector to extract; values: 'message', 'tipset'",
Value: "message",
Destination: &extractFlags.class,
},
&cli.StringFlag{
Name: "id",
Usage: "identifier to name this test vector with",
Value: "(undefined)",
Destination: &extractFlags.id,
},
&cli.StringFlag{
Name: "block",
Usage: "optionally, the block CID the message was included in, to avoid expensive chain scanning",
Destination: &extractFlags.block,
},
&cli.StringFlag{
Name: "exec-block",
Usage: "optionally, the block CID of a block where this message was executed, to avoid expensive chain scanning",
Destination: &extractFlags.block,
},
&cli.StringFlag{
Name: "cid",
Usage: "message CID to generate test vector from",
Destination: &extractFlags.cid,
},
&cli.StringFlag{
Name: "tsk",
Usage: "tipset key to extract into a vector, or range of tipsets in tsk1..tsk2 form",
Destination: &extractFlags.tsk,
},
&cli.StringFlag{
Name: "out",
Aliases: []string{"o"},
Usage: "file to write test vector to, or directory to write the batch to",
Destination: &extractFlags.file,
},
&cli.StringFlag{
Name: "state-retain",
Usage: "state retention policy; values: 'accessed-cids', 'accessed-actors'",
Value: "accessed-cids",
Destination: &extractFlags.retain,
},
&cli.StringFlag{
Name: "precursor-select",
Usage: "precursors to apply; values: 'all', 'participants'; 'all' selects all preceding " +
"messages in the canonicalised tipset, 'participants' selects only preceding messages from the same " +
"participants. Usually, 'participants' is a good tradeoff and gives you sufficient accuracy. If the receipt sanity " +
"check fails due to gas reasons, switch to 'all', as previous messages in the tipset may have " +
"affected state in a disruptive way",
Value: "participants",
Destination: &extractFlags.precursor,
},
&cli.BoolFlag{
Name: "ignore-sanity-checks",
Usage: "generate vector even if sanity checks fail",
Value: false,
Destination: &extractFlags.ignoreSanityChecks,
},
&cli.BoolFlag{
Name: "squash",
Usage: "when extracting a tipset range, squash all tipsets into a single vector",
Value: false,
Destination: &extractFlags.squash,
},
},
}
func runExtract(_ *cli.Context) error {
switch extractFlags.class {
case "message":
return doExtractMessage(extractFlags)
case "tipset":
return doExtractTipset(extractFlags)
default:
return fmt.Errorf("unsupported vector class")
}
}
// writeVector writes the vector into the specified file, or to stdout if
// file is empty.
func writeVector(vector *schema.TestVector, file string) (err error) {
output := io.WriteCloser(os.Stdout)
if file := file; file != "" {
dir := filepath.Dir(file)
if err := os.MkdirAll(dir, 0755); err != nil {
return fmt.Errorf("unable to create directory %s: %w", dir, err)
}
output, err = os.Create(file)
if err != nil {
return err
}
defer output.Close() //nolint:errcheck
defer log.Printf("wrote test vector to file: %s", file)
}
enc := json.NewEncoder(output)
enc.SetIndent("", " ")
return enc.Encode(&vector)
}
// writeVectors writes each vector to a different file under the specified
// directory.
func writeVectors(dir string, vectors ...*schema.TestVector) error {
// verify the output directory exists.
if err := ensureDir(dir); err != nil {
return err
}
// write each vector to its file.
for _, v := range vectors {
id := v.Meta.ID
path := filepath.Join(dir, fmt.Sprintf("%s.json", id))
if err := writeVector(v, path); err != nil {
return err
}
}
return nil
}