Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tvx: a test vector extraction and execution tool #4064

Merged
merged 20 commits into from
Sep 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@
### Conformance testing.
conformance/ @raulk
extern/test-vectors @raulk
cmd/tvx @raulk
44 changes: 44 additions & 0 deletions cmd/tvx/actor_mapping.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package main

import (
"reflect"

"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/ipfs/go-cid"
"github.com/multiformats/go-multihash"
)

var ActorMethodTable = make(map[string][]string, 64)

var Actors = map[cid.Cid]interface{}{
builtin.InitActorCodeID: builtin.MethodsInit,
builtin.CronActorCodeID: builtin.MethodsCron,
builtin.AccountActorCodeID: builtin.MethodsAccount,
builtin.StoragePowerActorCodeID: builtin.MethodsPower,
builtin.StorageMinerActorCodeID: builtin.MethodsMiner,
builtin.StorageMarketActorCodeID: builtin.MethodsMarket,
builtin.PaymentChannelActorCodeID: builtin.MethodsPaych,
builtin.MultisigActorCodeID: builtin.MethodsMultisig,
builtin.RewardActorCodeID: builtin.MethodsReward,
builtin.VerifiedRegistryActorCodeID: builtin.MethodsVerifiedRegistry,
Comment on lines +14 to +23
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With #3936 there are multiple code CIDs depending on actor version.

Ideally we would deduplicate this with the registry in chain/vm/invoker.go

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think there's anything I can do right now. When that PR lands, we can enhance the invoker so that it can be introspected from the outside and return metadata about the actors/methods it knows about. For that to be usable here, we'd need to record the method name too (probably just the name of the actor function).

}

func init() {
for code, methods := range Actors {
cmh, err := multihash.Decode(code.Hash()) // identity hash.
if err != nil {
panic(err)
}

var (
aname = string(cmh.Digest)
rt = reflect.TypeOf(methods)
nf = rt.NumField()
)

ActorMethodTable[aname] = append(ActorMethodTable[aname], "Send")
for i := 0; i < nf; i++ {
ActorMethodTable[aname] = append(ActorMethodTable[aname], rt.Field(i).Name)
}
}
}
92 changes: 92 additions & 0 deletions cmd/tvx/exec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package main

import (
"encoding/json"
"fmt"
"io"
"log"
"os"

"github.com/fatih/color"
"github.com/urfave/cli/v2"

"github.com/filecoin-project/lotus/conformance"

"github.com/filecoin-project/test-vectors/schema"
)

var execFlags struct {
file string
}

var execCmd = &cli.Command{
Name: "exec",
Description: "execute one or many test vectors against Lotus; supplied as a single JSON file, or a ndjson stdin stream",
Action: runExecLotus,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "file",
Usage: "input file; if not supplied, the vector will be read from stdin",
TakesFile: true,
Destination: &execFlags.file,
},
},
}

func runExecLotus(_ *cli.Context) error {
if file := execFlags.file; file != "" {
// we have a single test vector supplied as a file.
file, err := os.Open(file)
if err != nil {
return fmt.Errorf("failed to open test vector: %w", err)
}

var (
dec = json.NewDecoder(file)
tv schema.TestVector
)

if err = dec.Decode(&tv); err != nil {
return fmt.Errorf("failed to decode test vector: %w", err)
}

return executeTestVector(tv)
}

for dec := json.NewDecoder(os.Stdin); ; {
var tv schema.TestVector
switch err := dec.Decode(&tv); err {
case nil:
if err = executeTestVector(tv); err != nil {
return err
}
case io.EOF:
// we're done.
return nil
default:
// something bad happened.
return err
}
}
}

func executeTestVector(tv schema.TestVector) error {
log.Println("executing test vector:", tv.Meta.ID)
r := new(conformance.LogReporter)
switch class := tv.Class; class {
case "message":
conformance.ExecuteMessageVector(r, &tv)
case "tipset":
conformance.ExecuteTipsetVector(r, &tv)
default:
return fmt.Errorf("test vector class %s not supported", class)
}

if r.Failed() {
log.Println(color.HiRedString("❌ test vector failed"))
} else {
log.Println(color.GreenString("✅ test vector succeeded"))
}

return nil
}
Loading