lotus/cmd/tvx/main.go
2023-08-22 13:17:31 -04:00

133 lines
4.0 KiB
Go

package main
import (
"fmt"
"log"
"os"
"sort"
"github.com/urfave/cli/v2"
"github.com/filecoin-project/go-jsonrpc"
"github.com/filecoin-project/lotus/api/v1api"
lcli "github.com/filecoin-project/lotus/cli"
)
// FullAPI is a JSON-RPC client targeting a full node. It's initialized in a
// cli.BeforeFunc.
var FullAPI v1api.FullNode
// Closer is the closer for the JSON-RPC client, which must be called on
// cli.AfterFunc.
var Closer jsonrpc.ClientCloser
// DefaultLotusRepoPath is where the fallback path where to look for a Lotus
// client repo. It is expanded with mitchellh/go-homedir, so it'll work with all
// OSes despite the Unix twiddle notation.
const DefaultLotusRepoPath = "~/.lotus"
var repoFlag = cli.StringFlag{
Name: "repo",
EnvVars: []string{"LOTUS_PATH"},
Value: DefaultLotusRepoPath,
TakesFile: true,
}
func main() {
app := &cli.App{
Name: "tvx",
Description: `tvx is a tool for extracting and executing test vectors. It has four subcommands.
tvx extract extracts a test vector from a live network. It requires access to
a Filecoin client that exposes the standard JSON-RPC API endpoint. Only
message class test vectors are supported at this time.
tvx exec executes test vectors against Lotus. Either you can supply one in a
file, or many as an ndjson stdin stream.
tvx extract-many performs a batch extraction of many messages, supplied in a
CSV file. Refer to the help of that subcommand for more info.
tvx simulate takes a raw message and simulates it on top of the supplied
epoch, reporting the result on stderr and writing a test vector on stdout
or into the specified file.
SETTING THE JSON-RPC API ENDPOINT
You can set the JSON-RPC API endpoint through one of the following methods.
1. Directly set the API endpoint on the FULLNODE_API_INFO env variable.
The format is [token]:multiaddr, where token is optional for commands not
accessing privileged operations.
2. If you're running tvx against a local Lotus client, you can set the REPO
env variable to have the API endpoint and token extracted from the repo.
Alternatively, you can pass the --repo CLI flag.
3. Rely on the default fallback, which inspects ~/.lotus and extracts the
API endpoint string if the location is a Lotus repo.
tvx will apply these methods in the same order of precedence they're listed.
`,
Usage: "tvx is a tool for extracting and executing test vectors",
Commands: []*cli.Command{
extractCmd,
execCmd,
extractManyCmd,
simulateCmd,
},
}
sort.Sort(cli.CommandsByName(app.Commands))
for _, c := range app.Commands {
sort.Sort(cli.FlagsByName(c.Flags))
}
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
func initialize(c *cli.Context) error {
// LOTUS_DISABLE_VM_BUF disables what's called "VM state tree buffering",
// which stashes write operations in a BufferedBlockstore
// (https://github.com/filecoin-project/lotus/blob/b7a4dbb07fd8332b4492313a617e3458f8003b2a/lib/bufbstore/buf_bstore.go#L21)
// such that they're not written until the VM is actually flushed.
//
// For some reason, the standard behaviour was not working for me (raulk),
// and disabling it (such that the state transformations are written immediately
// to the blockstore) worked.
_ = os.Setenv("LOTUS_DISABLE_VM_BUF", "iknowitsabadidea")
// Make the API client.
var err error
if FullAPI, Closer, err = lcli.GetFullNodeAPIV1(c); err != nil {
err = fmt.Errorf("failed to locate Lotus node; err: %w", err)
}
return err
}
func destroy(_ *cli.Context) error {
if Closer != nil {
Closer()
}
return nil
}
func ensureDir(path string) error {
switch fi, err := os.Stat(path); {
case os.IsNotExist(err):
if err := os.MkdirAll(path, 0755); err != nil {
return fmt.Errorf("failed to create directory %s: %w", path, err)
}
case err == nil:
if !fi.IsDir() {
return fmt.Errorf("path %s is not a directory: %w", path, err)
}
default:
return fmt.Errorf("failed to stat directory %s: %w", path, err)
}
return nil
}