generator; single main() entrypoint for each suite. (#232)
This commit is contained in:
parent
9ba87d4613
commit
acbb80920b
@ -5,10 +5,9 @@ import (
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/ipfs/go-cid"
|
||||
@ -31,8 +30,8 @@ const (
|
||||
|
||||
func init() {
|
||||
// disable logs, as we need a clean stdout output.
|
||||
log.SetOutput(ioutil.Discard)
|
||||
log.SetFlags(0)
|
||||
log.SetOutput(os.Stderr)
|
||||
log.SetPrefix(">>> ")
|
||||
}
|
||||
|
||||
// TODO use stage.Surgeon with non-proxying blockstore.
|
||||
@ -131,7 +130,6 @@ func (b *Builder) applyMessage(am *ApplicableMessage) {
|
||||
Bytes: MustSerialize(am.Message),
|
||||
Epoch: &am.Epoch,
|
||||
})
|
||||
fmt.Println(am.Result.ExitCode)
|
||||
b.vector.Post.Receipts = append(b.vector.Post.Receipts, &schema.Receipt{
|
||||
ExitCode: am.Result.ExitCode,
|
||||
ReturnValue: am.Result.Return,
|
||||
|
175
tvx/builders/generator.go
Normal file
175
tvx/builders/generator.go
Normal file
@ -0,0 +1,175 @@
|
||||
package builders
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sync"
|
||||
|
||||
"github.com/filecoin-project/oni/tvx/schema"
|
||||
)
|
||||
|
||||
// Generator is a batch generator and organizer of test vectors.
|
||||
//
|
||||
// Test vector scripts are simple programs (main function). Test vector scripts
|
||||
// can delegate to the Generator to handle the execution, reporting and capture
|
||||
// of emitted test vectors into files.
|
||||
//
|
||||
// Generator supports the following CLI flags:
|
||||
//
|
||||
// -o <directory>
|
||||
// directory where test vector JSON files will be saved; if omitted,
|
||||
// vectors will be written to stdout.
|
||||
//
|
||||
// -f <regex>
|
||||
// regex filter to select a subset of vectors to execute; matched against
|
||||
// the vector's ID.
|
||||
//
|
||||
// Scripts can bundle test vectors into "groups". The generator will execute
|
||||
// each group in parallel, and will write each vector in a file:
|
||||
// <output_dir>/<group>--<vector_id>.json
|
||||
type Generator struct {
|
||||
OutputPath string
|
||||
Filter *regexp.Regexp
|
||||
|
||||
wg sync.WaitGroup
|
||||
}
|
||||
|
||||
type MessageVectorGenItem struct {
|
||||
Metadata *schema.Metadata
|
||||
Func func(*Builder)
|
||||
}
|
||||
|
||||
func NewGenerator() *Generator {
|
||||
// Consume CLI parameters.
|
||||
var (
|
||||
outputDir = flag.String("o", "", "directory where test vector JSON files will be saved; if omitted, vectors will be written to stdout")
|
||||
filter = flag.String("f", "", "regex filter to select a subset of vectors to execute; matched against the vector's ID")
|
||||
)
|
||||
|
||||
flag.Parse()
|
||||
|
||||
ret := new(Generator)
|
||||
|
||||
// If output directory is provided, we ensure it exists, or create it.
|
||||
// Else, we'll output to stdout.
|
||||
if dir := *outputDir; dir != "" {
|
||||
err := ensureDirectory(dir)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
ret.OutputPath = dir
|
||||
}
|
||||
|
||||
// If a filter has been provided, compile it into a regex.
|
||||
if *filter != "" {
|
||||
exp, err := regexp.Compile(*filter)
|
||||
if err != nil {
|
||||
log.Fatalf("supplied regex %s is invalid: %s", *filter, err)
|
||||
}
|
||||
ret.Filter = exp
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (g *Generator) Wait() {
|
||||
g.wg.Wait()
|
||||
}
|
||||
|
||||
func (g *Generator) MessageVectorGroup(group string, vectors ...*MessageVectorGenItem) {
|
||||
g.wg.Add(1)
|
||||
go func() {
|
||||
defer g.wg.Done()
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for _, item := range vectors {
|
||||
if id := item.Metadata.ID; g.Filter != nil && !g.Filter.MatchString(id) {
|
||||
log.Printf("skipping %s", id)
|
||||
continue
|
||||
}
|
||||
|
||||
var w io.Writer
|
||||
if g.OutputPath == "" {
|
||||
w = os.Stdout
|
||||
} else {
|
||||
file := filepath.Join(g.OutputPath, fmt.Sprintf("%s--%s.json", group, item.Metadata.ID))
|
||||
out, err := os.OpenFile(file, os.O_WRONLY|os.O_CREATE, 0644)
|
||||
if err != nil {
|
||||
log.Printf("failed to write to file %s: %s", file, err)
|
||||
return
|
||||
}
|
||||
w = out
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
go func(item *MessageVectorGenItem) {
|
||||
g.generateOne(w, item, w != os.Stdout)
|
||||
wg.Done()
|
||||
}(item)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
}()
|
||||
}
|
||||
|
||||
func (g *Generator) generateOne(w io.Writer, b *MessageVectorGenItem, indent bool) {
|
||||
log.Printf("generating test vector: %s", b.Metadata.ID)
|
||||
|
||||
vector := MessageVector(b.Metadata)
|
||||
|
||||
// TODO: currently if an assertion fails, we call os.Exit(1), which
|
||||
// aborts all ongoing vector generations. The Asserter should
|
||||
// call runtime.Goexit() instead so only that goroutine is
|
||||
// cancelled. The assertion error must bubble up somehow.
|
||||
b.Func(vector)
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
vector.Finish(buf)
|
||||
|
||||
final := buf
|
||||
if indent {
|
||||
// reparse and reindent.
|
||||
final = new(bytes.Buffer)
|
||||
if err := json.Indent(final, buf.Bytes(), "", "\t"); err != nil {
|
||||
log.Printf("failed to indent json: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
n, err := w.Write(final.Bytes())
|
||||
if err != nil {
|
||||
log.Printf("failed to write to output: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("generated test vector: %s (size: %d bytes)", b.Metadata.ID, n)
|
||||
}
|
||||
|
||||
// ensureDirectory checks if the provided path is a directory. If yes, it
|
||||
// returns nil. If the path doesn't exist, it creates the directory and
|
||||
// returns nil. If the path is not a directory, or another error occurs, an
|
||||
// error is returned.
|
||||
func ensureDirectory(path string) error {
|
||||
switch stat, err := os.Stat(path); {
|
||||
case os.IsNotExist(err):
|
||||
// create directory.
|
||||
log.Printf("creating directory %s", path)
|
||||
err := os.MkdirAll(path, 0700)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create directory %s: %s", path, err)
|
||||
}
|
||||
|
||||
case err == nil && !stat.IsDir():
|
||||
return fmt.Errorf("path %s exists, but it's not a directory", path)
|
||||
|
||||
case err != nil:
|
||||
return fmt.Errorf("failed to stat directory %s: %w", path, err)
|
||||
}
|
||||
return nil
|
||||
}
|
@ -1,247 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
||||
|
||||
. "github.com/filecoin-project/oni/tvx/builders"
|
||||
"github.com/filecoin-project/oni/tvx/schema"
|
||||
)
|
||||
|
||||
var (
|
||||
unknown = MustNewIDAddr(10000000)
|
||||
balance1T = abi.NewTokenAmount(1_000_000_000_000)
|
||||
transferAmnt = abi.NewTokenAmount(10)
|
||||
)
|
||||
|
||||
func main() {
|
||||
failCoverReceiptGasCost()
|
||||
failCoverOnChainSizeGasCost()
|
||||
failUnknownSender()
|
||||
failInvalidActorNonce()
|
||||
failInvalidReceiverMethod()
|
||||
failInexistentReceiver()
|
||||
failCoverTransferAccountCreationGasStepwise()
|
||||
failActorExecutionAborted()
|
||||
}
|
||||
|
||||
func failCoverReceiptGasCost() {
|
||||
metadata := &schema.Metadata{
|
||||
ID: "msg-apply-fail-receipt-gas",
|
||||
Version: "v1",
|
||||
Desc: "fail to cover gas cost for message receipt on chain",
|
||||
}
|
||||
|
||||
v := MessageVector(metadata)
|
||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPrice(1))
|
||||
|
||||
alice := v.Actors.Account(address.SECP256K1, balance1T)
|
||||
v.CommitPreconditions()
|
||||
|
||||
v.Messages.Sugar().Transfer(alice.ID, alice.ID, Value(transferAmnt), Nonce(0), GasLimit(8))
|
||||
v.CommitApplies()
|
||||
|
||||
v.Assert.EveryMessageResultSatisfies(ExitCode(exitcode.SysErrOutOfGas))
|
||||
v.Finish(os.Stdout)
|
||||
}
|
||||
|
||||
func failCoverOnChainSizeGasCost() {
|
||||
metadata := &schema.Metadata{
|
||||
ID: "msg-apply-fail-onchainsize-gas",
|
||||
Version: "v1",
|
||||
Desc: "not enough gas to pay message on-chain-size cost",
|
||||
}
|
||||
|
||||
v := MessageVector(metadata)
|
||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPrice(10))
|
||||
|
||||
alice := v.Actors.Account(address.SECP256K1, balance1T)
|
||||
v.CommitPreconditions()
|
||||
|
||||
v.Messages.Sugar().Transfer(alice.ID, alice.ID, Value(transferAmnt), Nonce(0), GasLimit(1))
|
||||
v.CommitApplies()
|
||||
|
||||
v.Assert.EveryMessageResultSatisfies(ExitCode(exitcode.SysErrOutOfGas))
|
||||
v.Finish(os.Stdout)
|
||||
}
|
||||
|
||||
func failUnknownSender() {
|
||||
metadata := &schema.Metadata{
|
||||
ID: "msg-apply-fail-unknown-sender",
|
||||
Version: "v1",
|
||||
Desc: "fail due to lack of gas when sender is unknown",
|
||||
}
|
||||
|
||||
v := MessageVector(metadata)
|
||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPrice(1))
|
||||
|
||||
alice := v.Actors.Account(address.SECP256K1, balance1T)
|
||||
v.CommitPreconditions()
|
||||
|
||||
v.Messages.Sugar().Transfer(unknown, alice.ID, Value(transferAmnt), Nonce(0))
|
||||
v.CommitApplies()
|
||||
|
||||
v.Assert.EveryMessageResultSatisfies(ExitCode(exitcode.SysErrSenderInvalid))
|
||||
v.Finish(os.Stdout)
|
||||
}
|
||||
|
||||
func failInvalidActorNonce() {
|
||||
metadata := &schema.Metadata{
|
||||
ID: "msg-apply-fail-invalid-nonce",
|
||||
Version: "v1",
|
||||
Desc: "invalid actor nonce",
|
||||
}
|
||||
|
||||
v := MessageVector(metadata)
|
||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPrice(1))
|
||||
|
||||
alice := v.Actors.Account(address.SECP256K1, balance1T)
|
||||
v.CommitPreconditions()
|
||||
|
||||
// invalid nonce from known account.
|
||||
msg1 := v.Messages.Sugar().Transfer(alice.ID, alice.ID, Value(transferAmnt), Nonce(1))
|
||||
|
||||
// invalid nonce from an unknown account.
|
||||
msg2 := v.Messages.Sugar().Transfer(unknown, alice.ID, Value(transferAmnt), Nonce(1))
|
||||
v.CommitApplies()
|
||||
|
||||
v.Assert.Equal(msg1.Result.ExitCode, exitcode.SysErrSenderStateInvalid)
|
||||
v.Assert.Equal(msg2.Result.ExitCode, exitcode.SysErrSenderInvalid)
|
||||
|
||||
v.Finish(os.Stdout)
|
||||
}
|
||||
|
||||
func failInvalidReceiverMethod() {
|
||||
metadata := &schema.Metadata{
|
||||
ID: "msg-apply-fail-invalid-receiver-method",
|
||||
Version: "v1",
|
||||
Desc: "invalid receiver method",
|
||||
}
|
||||
|
||||
v := MessageVector(metadata)
|
||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPrice(1))
|
||||
|
||||
alice := v.Actors.Account(address.SECP256K1, balance1T)
|
||||
v.CommitPreconditions()
|
||||
|
||||
v.Messages.Typed(alice.ID, alice.ID, MarketComputeDataCommitment(nil), Nonce(0), Value(big.Zero()))
|
||||
v.CommitApplies()
|
||||
|
||||
v.Assert.EveryMessageResultSatisfies(ExitCode(exitcode.SysErrInvalidMethod))
|
||||
|
||||
v.Finish(os.Stdout)
|
||||
}
|
||||
|
||||
func failInexistentReceiver() {
|
||||
metadata := &schema.Metadata{
|
||||
ID: "msg-apply-fail-inexistent-receiver",
|
||||
Version: "v1",
|
||||
Desc: "inexistent receiver",
|
||||
Comment: `Note that this test is not a valid message, since it is using
|
||||
an unknown actor. However in the event that an invalid message isn't filtered by
|
||||
block validation we need to ensure behaviour is consistent across VM implementations.`,
|
||||
}
|
||||
|
||||
v := MessageVector(metadata)
|
||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPrice(1))
|
||||
|
||||
alice := v.Actors.Account(address.SECP256K1, balance1T)
|
||||
v.CommitPreconditions()
|
||||
|
||||
// Sending a message to non-existent ID address must produce an error.
|
||||
unknownID := MustNewIDAddr(10000000)
|
||||
v.Messages.Sugar().Transfer(alice.ID, unknownID, Value(transferAmnt), Nonce(0))
|
||||
|
||||
unknownActor := MustNewActorAddr("1234")
|
||||
v.Messages.Sugar().Transfer(alice.ID, unknownActor, Value(transferAmnt), Nonce(1))
|
||||
v.CommitApplies()
|
||||
|
||||
v.Assert.EveryMessageResultSatisfies(ExitCode(exitcode.SysErrInvalidReceiver))
|
||||
v.Finish(os.Stdout)
|
||||
}
|
||||
|
||||
func failCoverTransferAccountCreationGasStepwise() {
|
||||
metadata := &schema.Metadata{
|
||||
ID: "msg-apply-fail-transfer-accountcreation-gas",
|
||||
Version: "v1",
|
||||
Desc: "fail not enough gas to cover account actor creation on transfer",
|
||||
}
|
||||
|
||||
v := MessageVector(metadata)
|
||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPrice(1))
|
||||
|
||||
var alice, bob, charlie AddressHandle
|
||||
alice = v.Actors.Account(address.SECP256K1, balance1T)
|
||||
bob.Robust, charlie.Robust = MustNewSECP256K1Addr("1"), MustNewSECP256K1Addr("2")
|
||||
v.CommitPreconditions()
|
||||
|
||||
var nonce uint64
|
||||
ref := v.Messages.Sugar().Transfer(alice.Robust, bob.Robust, Value(transferAmnt), Nonce(nonce))
|
||||
nonce++
|
||||
v.Messages.ApplyOne(ref)
|
||||
v.Assert.EveryMessageResultSatisfies(ExitCode(exitcode.Ok))
|
||||
|
||||
// decrease the gas cost by `gasStep` for each apply and ensure `SysErrOutOfGas` is always returned.
|
||||
trueGas := ref.Result.GasUsed
|
||||
gasStep := trueGas / 100
|
||||
for tryGas := trueGas - gasStep; tryGas > 0; tryGas -= gasStep {
|
||||
v.Messages.Sugar().Transfer(alice.Robust, charlie.Robust, Value(transferAmnt), Nonce(nonce), GasPrice(1), GasLimit(tryGas))
|
||||
nonce++
|
||||
}
|
||||
v.CommitApplies()
|
||||
|
||||
v.Assert.EveryMessageResultSatisfies(ExitCode(exitcode.SysErrOutOfGas), ref)
|
||||
v.Finish(os.Stdout)
|
||||
}
|
||||
|
||||
func failActorExecutionAborted() {
|
||||
metadata := &schema.Metadata{
|
||||
ID: "msg-apply-fail-actor-execution-illegal-arg",
|
||||
Version: "v1",
|
||||
Desc: "abort during actor execution due to illegal argument",
|
||||
}
|
||||
|
||||
// Set up sender and receiver accounts.
|
||||
var sender, receiver AddressHandle
|
||||
var paychAddr AddressHandle
|
||||
|
||||
v := MessageVector(metadata)
|
||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPrice(1))
|
||||
|
||||
v.Actors.AccountN(address.SECP256K1, balance1T, &sender, &receiver)
|
||||
paychAddr = AddressHandle{
|
||||
ID: MustNewIDAddr(MustIDFromAddress(receiver.ID) + 1),
|
||||
Robust: sender.NextActorAddress(0, 0),
|
||||
}
|
||||
v.CommitPreconditions()
|
||||
|
||||
// Construct the payment channel.
|
||||
createMsg := v.Messages.Sugar().CreatePaychActor(sender.Robust, receiver.Robust, Value(abi.NewTokenAmount(10_000)))
|
||||
|
||||
// Update the payment channel.
|
||||
updateMsg := v.Messages.Typed(sender.Robust, paychAddr.Robust, PaychUpdateChannelState(&paych.UpdateChannelStateParams{
|
||||
Sv: paych.SignedVoucher{
|
||||
ChannelAddr: paychAddr.Robust,
|
||||
TimeLockMin: abi.ChainEpoch(10),
|
||||
Lane: 123,
|
||||
Nonce: 1,
|
||||
Amount: big.NewInt(10),
|
||||
Signature: &crypto.Signature{
|
||||
Type: crypto.SigTypeBLS,
|
||||
Data: []byte("Grrr im an invalid signature, I cause panics in the payment channel actor"),
|
||||
},
|
||||
}}), Nonce(1), Value(big.Zero()))
|
||||
|
||||
v.CommitApplies()
|
||||
|
||||
v.Assert.Equal(exitcode.Ok, createMsg.Result.ExitCode)
|
||||
v.Assert.Equal(exitcode.ErrIllegalArgument, updateMsg.Result.ExitCode)
|
||||
|
||||
v.Finish(os.Stdout)
|
||||
}
|
49
tvx/scripts/msg_application/actor_exec.go
Normal file
49
tvx/scripts/msg_application/actor_exec.go
Normal file
@ -0,0 +1,49 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
||||
|
||||
. "github.com/filecoin-project/oni/tvx/builders"
|
||||
)
|
||||
|
||||
func failActorExecutionAborted(v *Builder) {
|
||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPrice(1))
|
||||
|
||||
// Set up sender and receiver accounts.
|
||||
var sender, receiver AddressHandle
|
||||
var paychAddr AddressHandle
|
||||
|
||||
v.Actors.AccountN(address.SECP256K1, balance1T, &sender, &receiver)
|
||||
paychAddr = AddressHandle{
|
||||
ID: MustNewIDAddr(MustIDFromAddress(receiver.ID) + 1),
|
||||
Robust: sender.NextActorAddress(0, 0),
|
||||
}
|
||||
v.CommitPreconditions()
|
||||
|
||||
// Construct the payment channel.
|
||||
createMsg := v.Messages.Sugar().CreatePaychActor(sender.Robust, receiver.Robust, Value(abi.NewTokenAmount(10_000)))
|
||||
|
||||
// Update the payment channel.
|
||||
updateMsg := v.Messages.Typed(sender.Robust, paychAddr.Robust, PaychUpdateChannelState(&paych.UpdateChannelStateParams{
|
||||
Sv: paych.SignedVoucher{
|
||||
ChannelAddr: paychAddr.Robust,
|
||||
TimeLockMin: abi.ChainEpoch(10),
|
||||
Lane: 123,
|
||||
Nonce: 1,
|
||||
Amount: big.NewInt(10),
|
||||
Signature: &crypto.Signature{
|
||||
Type: crypto.SigTypeBLS,
|
||||
Data: []byte("Grrr im an invalid signature, I cause panics in the payment channel actor"),
|
||||
},
|
||||
}}), Nonce(1), Value(big.Zero()))
|
||||
|
||||
v.CommitApplies()
|
||||
|
||||
v.Assert.Equal(exitcode.Ok, createMsg.Result.ExitCode)
|
||||
v.Assert.Equal(exitcode.ErrIllegalArgument, updateMsg.Result.ExitCode)
|
||||
}
|
58
tvx/scripts/msg_application/gas_cost.go
Normal file
58
tvx/scripts/msg_application/gas_cost.go
Normal file
@ -0,0 +1,58 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
||||
|
||||
. "github.com/filecoin-project/oni/tvx/builders"
|
||||
)
|
||||
|
||||
func failCoverReceiptGasCost(v *Builder) {
|
||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPrice(1))
|
||||
|
||||
alice := v.Actors.Account(address.SECP256K1, balance1T)
|
||||
v.CommitPreconditions()
|
||||
|
||||
v.Messages.Sugar().Transfer(alice.ID, alice.ID, Value(transferAmnt), Nonce(0), GasLimit(8))
|
||||
v.CommitApplies()
|
||||
|
||||
v.Assert.EveryMessageResultSatisfies(ExitCode(exitcode.SysErrOutOfGas))
|
||||
}
|
||||
|
||||
func failCoverOnChainSizeGasCost(v *Builder) {
|
||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPrice(10))
|
||||
|
||||
alice := v.Actors.Account(address.SECP256K1, balance1T)
|
||||
v.CommitPreconditions()
|
||||
|
||||
v.Messages.Sugar().Transfer(alice.ID, alice.ID, Value(transferAmnt), Nonce(0), GasLimit(1))
|
||||
v.CommitApplies()
|
||||
|
||||
v.Assert.EveryMessageResultSatisfies(ExitCode(exitcode.SysErrOutOfGas))
|
||||
}
|
||||
|
||||
func failCoverTransferAccountCreationGasStepwise(v *Builder) {
|
||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPrice(1))
|
||||
|
||||
var alice, bob, charlie AddressHandle
|
||||
alice = v.Actors.Account(address.SECP256K1, balance1T)
|
||||
bob.Robust, charlie.Robust = MustNewSECP256K1Addr("1"), MustNewSECP256K1Addr("2")
|
||||
v.CommitPreconditions()
|
||||
|
||||
var nonce uint64
|
||||
ref := v.Messages.Sugar().Transfer(alice.Robust, bob.Robust, Value(transferAmnt), Nonce(nonce))
|
||||
nonce++
|
||||
v.Messages.ApplyOne(ref)
|
||||
v.Assert.EveryMessageResultSatisfies(ExitCode(exitcode.Ok))
|
||||
|
||||
// decrease the gas cost by `gasStep` for each apply and ensure `SysErrOutOfGas` is always returned.
|
||||
trueGas := ref.Result.GasUsed
|
||||
gasStep := trueGas / 100
|
||||
for tryGas := trueGas - gasStep; tryGas > 0; tryGas -= gasStep {
|
||||
v.Messages.Sugar().Transfer(alice.Robust, charlie.Robust, Value(transferAmnt), Nonce(nonce), GasPrice(1), GasLimit(tryGas))
|
||||
nonce++
|
||||
}
|
||||
v.CommitApplies()
|
||||
|
||||
v.Assert.EveryMessageResultSatisfies(ExitCode(exitcode.SysErrOutOfGas), ref)
|
||||
}
|
38
tvx/scripts/msg_application/invalid_msgs.go
Normal file
38
tvx/scripts/msg_application/invalid_msgs.go
Normal file
@ -0,0 +1,38 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
||||
|
||||
. "github.com/filecoin-project/oni/tvx/builders"
|
||||
)
|
||||
|
||||
func failInvalidActorNonce(v *Builder) {
|
||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPrice(1))
|
||||
|
||||
alice := v.Actors.Account(address.SECP256K1, balance1T)
|
||||
v.CommitPreconditions()
|
||||
|
||||
// invalid nonce from known account.
|
||||
msg1 := v.Messages.Sugar().Transfer(alice.ID, alice.ID, Value(transferAmnt), Nonce(1))
|
||||
|
||||
// invalid nonce from an unknown account.
|
||||
msg2 := v.Messages.Sugar().Transfer(unknown, alice.ID, Value(transferAmnt), Nonce(1))
|
||||
v.CommitApplies()
|
||||
|
||||
v.Assert.Equal(msg1.Result.ExitCode, exitcode.SysErrSenderStateInvalid)
|
||||
v.Assert.Equal(msg2.Result.ExitCode, exitcode.SysErrSenderInvalid)
|
||||
}
|
||||
|
||||
func failInvalidReceiverMethod(v *Builder) {
|
||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPrice(1))
|
||||
|
||||
alice := v.Actors.Account(address.SECP256K1, balance1T)
|
||||
v.CommitPreconditions()
|
||||
|
||||
v.Messages.Typed(alice.ID, alice.ID, MarketComputeDataCommitment(nil), Nonce(0), Value(big.Zero()))
|
||||
v.CommitApplies()
|
||||
|
||||
v.Assert.EveryMessageResultSatisfies(ExitCode(exitcode.SysErrInvalidMethod))
|
||||
}
|
98
tvx/scripts/msg_application/main.go
Normal file
98
tvx/scripts/msg_application/main.go
Normal file
@ -0,0 +1,98 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
|
||||
. "github.com/filecoin-project/oni/tvx/builders"
|
||||
"github.com/filecoin-project/oni/tvx/schema"
|
||||
)
|
||||
|
||||
var (
|
||||
unknown = MustNewIDAddr(10000000)
|
||||
balance1T = abi.NewTokenAmount(1_000_000_000_000)
|
||||
transferAmnt = abi.NewTokenAmount(10)
|
||||
)
|
||||
|
||||
func main() {
|
||||
g := NewGenerator()
|
||||
|
||||
g.MessageVectorGroup("gas_cost",
|
||||
&MessageVectorGenItem{
|
||||
Metadata: &schema.Metadata{
|
||||
ID: "msg-apply-fail-receipt-gas",
|
||||
Version: "v1",
|
||||
Desc: "fail to cover gas cost for message receipt on chain",
|
||||
},
|
||||
Func: failCoverReceiptGasCost,
|
||||
},
|
||||
&MessageVectorGenItem{
|
||||
Metadata: &schema.Metadata{
|
||||
ID: "msg-apply-fail-onchainsize-gas",
|
||||
Version: "v1",
|
||||
Desc: "not enough gas to pay message on-chain-size cost",
|
||||
},
|
||||
Func: failCoverOnChainSizeGasCost,
|
||||
},
|
||||
&MessageVectorGenItem{
|
||||
Metadata: &schema.Metadata{
|
||||
ID: "msg-apply-fail-transfer-accountcreation-gas",
|
||||
Version: "v1",
|
||||
Desc: "fail not enough gas to cover account actor creation on transfer",
|
||||
},
|
||||
Func: failCoverTransferAccountCreationGasStepwise,
|
||||
})
|
||||
|
||||
g.MessageVectorGroup("invalid_msgs",
|
||||
&MessageVectorGenItem{
|
||||
Metadata: &schema.Metadata{
|
||||
ID: "msg-apply-fail-invalid-nonce",
|
||||
Version: "v1",
|
||||
Desc: "invalid actor nonce",
|
||||
},
|
||||
Func: failInvalidActorNonce,
|
||||
},
|
||||
&MessageVectorGenItem{
|
||||
Metadata: &schema.Metadata{
|
||||
ID: "msg-apply-fail-invalid-receiver-method",
|
||||
Version: "v1",
|
||||
Desc: "invalid receiver method",
|
||||
},
|
||||
Func: failInvalidReceiverMethod,
|
||||
},
|
||||
)
|
||||
|
||||
g.MessageVectorGroup("unknown_actors",
|
||||
&MessageVectorGenItem{
|
||||
Metadata: &schema.Metadata{
|
||||
ID: "msg-apply-fail-unknown-sender",
|
||||
Version: "v1",
|
||||
Desc: "fail due to lack of gas when sender is unknown",
|
||||
},
|
||||
Func: failUnknownSender,
|
||||
},
|
||||
&MessageVectorGenItem{
|
||||
Metadata: &schema.Metadata{
|
||||
ID: "msg-apply-fail-unknown-receiver",
|
||||
Version: "v1",
|
||||
Desc: "inexistent receiver",
|
||||
Comment: `Note that this test is not a valid message, since it is using
|
||||
an unknown actor. However in the event that an invalid message isn't filtered by
|
||||
block validation we need to ensure behaviour is consistent across VM implementations.`,
|
||||
},
|
||||
Func: failUnknownReceiver,
|
||||
},
|
||||
)
|
||||
|
||||
g.MessageVectorGroup("actor_exec",
|
||||
&MessageVectorGenItem{
|
||||
Metadata: &schema.Metadata{
|
||||
ID: "msg-apply-fail-actor-execution-illegal-arg",
|
||||
Version: "v1",
|
||||
Desc: "abort during actor execution due to illegal argument",
|
||||
},
|
||||
Func: failActorExecutionAborted,
|
||||
},
|
||||
)
|
||||
|
||||
g.Wait()
|
||||
}
|
37
tvx/scripts/msg_application/unknown_actors.go
Normal file
37
tvx/scripts/msg_application/unknown_actors.go
Normal file
@ -0,0 +1,37 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
||||
|
||||
. "github.com/filecoin-project/oni/tvx/builders"
|
||||
)
|
||||
|
||||
func failUnknownSender(v *Builder) {
|
||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPrice(1))
|
||||
|
||||
alice := v.Actors.Account(address.SECP256K1, balance1T)
|
||||
v.CommitPreconditions()
|
||||
|
||||
v.Messages.Sugar().Transfer(unknown, alice.ID, Value(transferAmnt), Nonce(0))
|
||||
v.CommitApplies()
|
||||
|
||||
v.Assert.EveryMessageResultSatisfies(ExitCode(exitcode.SysErrSenderInvalid))
|
||||
}
|
||||
|
||||
func failUnknownReceiver(v *Builder) {
|
||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPrice(1))
|
||||
|
||||
alice := v.Actors.Account(address.SECP256K1, balance1T)
|
||||
v.CommitPreconditions()
|
||||
|
||||
// Sending a message to non-existent ID address must produce an error.
|
||||
unknownID := MustNewIDAddr(10000000)
|
||||
v.Messages.Sugar().Transfer(alice.ID, unknownID, Value(transferAmnt), Nonce(0))
|
||||
|
||||
unknownActor := MustNewActorAddr("1234")
|
||||
v.Messages.Sugar().Transfer(alice.ID, unknownActor, Value(transferAmnt), Nonce(1))
|
||||
v.CommitApplies()
|
||||
|
||||
v.Assert.EveryMessageResultSatisfies(ExitCode(exitcode.SysErrInvalidReceiver))
|
||||
}
|
14
tvx/scripts/paych/main.go
Normal file
14
tvx/scripts/paych/main.go
Normal file
@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import "github.com/filecoin-project/specs-actors/actors/abi"
|
||||
|
||||
var (
|
||||
initialBal = abi.NewTokenAmount(200_000_000_000)
|
||||
toSend = abi.NewTokenAmount(10_000)
|
||||
)
|
||||
|
||||
func main() {
|
||||
happyPathCreate()
|
||||
happyPathUpdate()
|
||||
happyPathCollect()
|
||||
}
|
@ -15,17 +15,6 @@ import (
|
||||
"github.com/filecoin-project/oni/tvx/schema"
|
||||
)
|
||||
|
||||
var (
|
||||
balance200B = abi.NewTokenAmount(200_000_000_000)
|
||||
toSend = abi.NewTokenAmount(10_000)
|
||||
)
|
||||
|
||||
func main() {
|
||||
happyPathCreate()
|
||||
happyPathUpdate()
|
||||
happyPathCollect()
|
||||
}
|
||||
|
||||
func happyPathCreate() {
|
||||
metadata := &schema.Metadata{ID: "paych-create-ok", Version: "v1", Desc: "payment channel create"}
|
||||
|
||||
@ -34,7 +23,7 @@ func happyPathCreate() {
|
||||
|
||||
// Set up sender and receiver accounts.
|
||||
var sender, receiver AddressHandle
|
||||
v.Actors.AccountN(address.SECP256K1, balance200B, &sender, &receiver)
|
||||
v.Actors.AccountN(address.SECP256K1, initialBal, &sender, &receiver)
|
||||
v.CommitPreconditions()
|
||||
|
||||
// Add the constructor message.
|
||||
@ -79,7 +68,7 @@ func happyPathUpdate() {
|
||||
v := MessageVector(metadata)
|
||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPrice(1))
|
||||
|
||||
v.Actors.AccountN(address.SECP256K1, balance200B, &sender, &receiver)
|
||||
v.Actors.AccountN(address.SECP256K1, initialBal, &sender, &receiver)
|
||||
paychAddr = AddressHandle{
|
||||
ID: MustNewIDAddr(MustIDFromAddress(receiver.ID) + 1),
|
||||
Robust: sender.NextActorAddress(0, 0),
|
||||
@ -136,7 +125,7 @@ func happyPathCollect() {
|
||||
// Set up sender and receiver accounts.
|
||||
var sender, receiver AddressHandle
|
||||
var paychAddr AddressHandle
|
||||
v.Actors.AccountN(address.SECP256K1, balance200B, &sender, &receiver)
|
||||
v.Actors.AccountN(address.SECP256K1, initialBal, &sender, &receiver)
|
||||
paychAddr = AddressHandle{
|
||||
ID: MustNewIDAddr(MustIDFromAddress(receiver.ID) + 1),
|
||||
Robust: sender.NextActorAddress(0, 0),
|
||||
@ -175,7 +164,7 @@ func happyPathCollect() {
|
||||
|
||||
// receiver_balance = initial_balance + paych_send - settle_paych_msg_gas - collect_paych_msg_gas
|
||||
gasUsed := big.Add(big.NewInt(settleMsg.Result.MessageReceipt.GasUsed), big.NewInt(collectMsg.Result.MessageReceipt.GasUsed))
|
||||
v.Assert.BalanceEq(receiver.Robust, big.Sub(big.Add(toSend, balance200B), gasUsed))
|
||||
v.Assert.BalanceEq(receiver.Robust, big.Sub(big.Add(toSend, initialBal), gasUsed))
|
||||
|
||||
// the paych actor should have been deleted after the collect
|
||||
v.Assert.ActorMissing(paychAddr.Robust)
|
Loading…
Reference in New Issue
Block a user