lotus/cmd/tvx/extract.go

162 lines
4.6 KiB
Go
Raw Normal View History

2020-09-27 19:10:05 +00:00
package main
import (
"encoding/json"
2020-09-27 19:10:05 +00:00
"fmt"
"io"
"log"
"os"
"path/filepath"
2020-09-27 19:10:05 +00:00
"github.com/filecoin-project/test-vectors/schema"
2020-09-27 19:10:05 +00:00
"github.com/urfave/cli/v2"
)
const (
PrecursorSelectAll = "all"
PrecursorSelectParticipants = "participants"
)
2020-09-28 16:02:56 +00:00
type extractOpts struct {
id string
block string
class string
cid string
2020-12-15 16:55:57 +00:00
tsk string
file string
retain string
precursor string
ignoreSanityChecks bool
squash bool
2020-09-27 19:10:05 +00:00
}
2020-09-28 16:02:56 +00:00
var extractFlags extractOpts
2020-09-27 19:10:05 +00:00
var extractCmd = &cli.Command{
Name: "extract",
2020-09-28 11:35:01 +00:00
Description: "generate a test vector by extracting it from a live chain",
2020-09-27 19:10:05 +00:00
Action: runExtract,
2020-10-23 12:30:04 +00:00
Before: initialize,
After: destroy,
2020-09-27 19:10:05 +00:00
Flags: []cli.Flag{
2020-09-28 11:35:01 +00:00
&repoFlag,
2020-09-27 19:10:05 +00:00
&cli.StringFlag{
Name: "class",
2020-12-15 16:55:57 +00:00
Usage: "class of vector to extract; values: 'message', 'tipset'",
2020-09-27 19:10:05 +00:00
Value: "message",
Destination: &extractFlags.class,
},
&cli.StringFlag{
Name: "id",
Usage: "identifier to name this test vector with",
2020-09-27 19:30:32 +00:00
Value: "(undefined)",
2020-09-27 19:10:05 +00:00
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",
2020-11-20 14:05:50 +00:00
Usage: "optionally, the block CID of a block where this message was executed, to avoid expensive chain scanning",
Destination: &extractFlags.block,
},
2020-09-27 19:10:05 +00:00
&cli.StringFlag{
Name: "cid",
Usage: "message CID to generate test vector from",
Destination: &extractFlags.cid,
},
2020-12-15 16:55:57 +00:00
&cli.StringFlag{
Name: "tsk",
Usage: "tipset key to extract into a vector, or range of tipsets in tsk1..tsk2 form",
2020-12-15 16:55:57 +00:00
Destination: &extractFlags.tsk,
},
2020-09-27 19:10:05 +00:00
&cli.StringFlag{
Name: "out",
Aliases: []string{"o"},
Usage: "file to write test vector to, or directory to write the batch to",
2020-09-27 19:10:05 +00:00
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,
},
2020-09-27 19:10:05 +00:00
},
}
func runExtract(_ *cli.Context) error {
2020-12-15 16:55:57 +00:00
switch extractFlags.class {
case "message":
return doExtractMessage(extractFlags)
case "tipset":
return doExtractTipset(extractFlags)
2020-09-27 19:10:05 +00:00
default:
2020-12-15 16:55:57 +00:00
return fmt.Errorf("unsupported vector class")
2020-09-27 19:10:05 +00:00
}
}
// 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
}