Merge pull request #7881 from filecoin-project/raulk/fix/test-vector-runner
test vector runner fixes for v6 vectors
This commit is contained in:
commit
6f316cddbb
@ -10,8 +10,9 @@ import (
|
|||||||
addr "github.com/filecoin-project/go-address"
|
addr "github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/crypto"
|
"github.com/filecoin-project/go-state-types/crypto"
|
||||||
"github.com/filecoin-project/lotus/build"
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/build"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GasCharge struct {
|
type GasCharge struct {
|
||||||
@ -81,7 +82,9 @@ type Pricelist interface {
|
|||||||
OnVerifyConsensusFault() GasCharge
|
OnVerifyConsensusFault() GasCharge
|
||||||
}
|
}
|
||||||
|
|
||||||
var prices = map[abi.ChainEpoch]Pricelist{
|
// Prices are the price lists per starting epoch. Public for testing purposes
|
||||||
|
// (concretely to allow the test vector runner to rebase prices).
|
||||||
|
var Prices = map[abi.ChainEpoch]Pricelist{
|
||||||
abi.ChainEpoch(0): &pricelistV0{
|
abi.ChainEpoch(0): &pricelistV0{
|
||||||
computeGasMulti: 1,
|
computeGasMulti: 1,
|
||||||
storageGasMulti: 1000,
|
storageGasMulti: 1000,
|
||||||
@ -214,8 +217,8 @@ func PricelistByEpoch(epoch abi.ChainEpoch) Pricelist {
|
|||||||
// since we are storing the prices as map or epoch to price
|
// since we are storing the prices as map or epoch to price
|
||||||
// we need to get the price with the highest epoch that is lower or equal to the `epoch` arg
|
// we need to get the price with the highest epoch that is lower or equal to the `epoch` arg
|
||||||
bestEpoch := abi.ChainEpoch(0)
|
bestEpoch := abi.ChainEpoch(0)
|
||||||
bestPrice := prices[bestEpoch]
|
bestPrice := Prices[bestEpoch]
|
||||||
for e, pl := range prices {
|
for e, pl := range Prices {
|
||||||
// if `e` happened after `bestEpoch` and `e` is earlier or equal to the target `epoch`
|
// if `e` happened after `bestEpoch` and `e` is earlier or equal to the target `epoch`
|
||||||
if e > bestEpoch && e <= epoch {
|
if e > bestEpoch && e <= epoch {
|
||||||
bestEpoch = e
|
bestEpoch = e
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/fs"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -136,25 +137,31 @@ func processTipsetOpts() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func execVectorDir(path string, outdir string) error {
|
func execVectorDir(path string, outdir string) error {
|
||||||
files, err := filepath.Glob(filepath.Join(path, "*"))
|
return filepath.WalkDir(path, func(path string, d fs.DirEntry, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to glob input directory %s: %w", path, err)
|
return fmt.Errorf("failed while visiting path %s: %w", path, err)
|
||||||
}
|
}
|
||||||
for _, f := range files {
|
if d.IsDir() || !strings.HasSuffix(path, "json") {
|
||||||
outfile := strings.TrimSuffix(filepath.Base(f), filepath.Ext(f)) + ".out"
|
return nil
|
||||||
|
}
|
||||||
|
// Create an output file to capture the output from the run of the vector.
|
||||||
|
outfile := strings.TrimSuffix(filepath.Base(path), filepath.Ext(path)) + ".out"
|
||||||
outpath := filepath.Join(outdir, outfile)
|
outpath := filepath.Join(outdir, outfile)
|
||||||
outw, err := os.Create(outpath)
|
outw, err := os.Create(outpath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create file %s: %w", outpath, err)
|
return fmt.Errorf("failed to create file %s: %w", outpath, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("processing vector %s; sending output to %s", f, outpath)
|
log.Printf("processing vector %s; sending output to %s", path, outpath)
|
||||||
|
|
||||||
|
// Actually run the vector.
|
||||||
log.SetOutput(io.MultiWriter(os.Stderr, outw)) // tee the output.
|
log.SetOutput(io.MultiWriter(os.Stderr, outw)) // tee the output.
|
||||||
_, _ = execVectorFile(new(conformance.LogReporter), f)
|
_, _ = execVectorFile(new(conformance.LogReporter), path)
|
||||||
log.SetOutput(os.Stderr)
|
log.SetOutput(os.Stderr)
|
||||||
_ = outw.Close()
|
_ = outw.Close()
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func execVectorsStdin() error {
|
func execVectorsStdin() error {
|
||||||
|
@ -5,6 +5,8 @@ import (
|
|||||||
gobig "math/big"
|
gobig "math/big"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-state-types/network"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/blockstore"
|
"github.com/filecoin-project/lotus/blockstore"
|
||||||
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||||
"github.com/filecoin-project/lotus/chain/state"
|
"github.com/filecoin-project/lotus/chain/state"
|
||||||
@ -187,11 +189,12 @@ func (d *Driver) ExecuteTipset(bs blockstore.Blockstore, ds ds.Batching, params
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ExecuteMessageParams struct {
|
type ExecuteMessageParams struct {
|
||||||
Preroot cid.Cid
|
Preroot cid.Cid
|
||||||
Epoch abi.ChainEpoch
|
Epoch abi.ChainEpoch
|
||||||
Message *types.Message
|
Message *types.Message
|
||||||
CircSupply abi.TokenAmount
|
CircSupply abi.TokenAmount
|
||||||
BaseFee abi.TokenAmount
|
BaseFee abi.TokenAmount
|
||||||
|
NetworkVersion network.Version
|
||||||
|
|
||||||
// Rand is an optional vm.Rand implementation to use. If nil, the driver
|
// Rand is an optional vm.Rand implementation to use. If nil, the driver
|
||||||
// will use a vm.Rand that returns a fixed value for all calls.
|
// will use a vm.Rand that returns a fixed value for all calls.
|
||||||
@ -210,13 +213,6 @@ func (d *Driver) ExecuteMessage(bs blockstore.Blockstore, params ExecuteMessageP
|
|||||||
params.Rand = NewFixedRand()
|
params.Rand = NewFixedRand()
|
||||||
}
|
}
|
||||||
|
|
||||||
// dummy state manager; only to reference the GetNetworkVersion method,
|
|
||||||
// which does not depend on state.
|
|
||||||
sm, err := stmgr.NewStateManager(nil, filcns.NewTipSetExecutor(), nil, filcns.DefaultUpgradeSchedule(), nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, cid.Cid{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
vmOpts := &vm.VMOpts{
|
vmOpts := &vm.VMOpts{
|
||||||
StateBase: params.Preroot,
|
StateBase: params.Preroot,
|
||||||
Epoch: params.Epoch,
|
Epoch: params.Epoch,
|
||||||
@ -227,7 +223,7 @@ func (d *Driver) ExecuteMessage(bs blockstore.Blockstore, params ExecuteMessageP
|
|||||||
},
|
},
|
||||||
Rand: params.Rand,
|
Rand: params.Rand,
|
||||||
BaseFee: params.BaseFee,
|
BaseFee: params.BaseFee,
|
||||||
NetworkVersion: sm.GetNetworkVersion(context.Background(), params.Epoch),
|
NetworkVersion: params.NetworkVersion,
|
||||||
}
|
}
|
||||||
|
|
||||||
lvm, err := vm.NewVM(context.TODO(), vmOpts)
|
lvm, err := vm.NewVM(context.TODO(), vmOpts)
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -14,6 +15,7 @@ import (
|
|||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/exitcode"
|
"github.com/filecoin-project/go-state-types/exitcode"
|
||||||
|
"github.com/filecoin-project/go-state-types/network"
|
||||||
"github.com/hashicorp/go-multierror"
|
"github.com/hashicorp/go-multierror"
|
||||||
blocks "github.com/ipfs/go-block-format"
|
blocks "github.com/ipfs/go-block-format"
|
||||||
"github.com/ipfs/go-blockservice"
|
"github.com/ipfs/go-blockservice"
|
||||||
@ -27,6 +29,7 @@ import (
|
|||||||
"github.com/filecoin-project/test-vectors/schema"
|
"github.com/filecoin-project/test-vectors/schema"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/blockstore"
|
"github.com/filecoin-project/lotus/blockstore"
|
||||||
|
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/chain/vm"
|
"github.com/filecoin-project/lotus/chain/vm"
|
||||||
)
|
)
|
||||||
@ -50,11 +53,58 @@ var TipsetVectorOpts struct {
|
|||||||
OnTipsetApplied []func(bs blockstore.Blockstore, params *ExecuteTipsetParams, res *ExecuteTipsetResult)
|
OnTipsetApplied []func(bs blockstore.Blockstore, params *ExecuteTipsetParams, res *ExecuteTipsetResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GasPricingRestoreFn func()
|
||||||
|
|
||||||
|
// adjustGasPricing adjusts the global gas price mapping to make sure that the
|
||||||
|
// gas pricelist for vector's network version is used at the vector's epoch.
|
||||||
|
// Because it manipulates a global, it returns a function that reverts the
|
||||||
|
// change. The caller MUST invoke this function or the test vector runner will
|
||||||
|
// become invalid.
|
||||||
|
func adjustGasPricing(vectorEpoch abi.ChainEpoch, vectorNv network.Version) GasPricingRestoreFn {
|
||||||
|
// Stash the current pricing mapping.
|
||||||
|
// Ok to take a reference instead of a copy, because we override the map
|
||||||
|
// with a new one below.
|
||||||
|
var old = vm.Prices
|
||||||
|
|
||||||
|
// Resolve the epoch at which the vector network version kicks in.
|
||||||
|
var epoch abi.ChainEpoch = math.MaxInt64
|
||||||
|
if vectorNv == network.Version0 {
|
||||||
|
// genesis is not an upgrade.
|
||||||
|
epoch = 0
|
||||||
|
} else {
|
||||||
|
for _, u := range filcns.DefaultUpgradeSchedule() {
|
||||||
|
if u.Network == vectorNv {
|
||||||
|
epoch = u.Height
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if epoch == math.MaxInt64 {
|
||||||
|
panic(fmt.Sprintf("could not resolve network version %d to height", vectorNv))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the right pricelist for this network version.
|
||||||
|
pricelist := vm.PricelistByEpoch(epoch)
|
||||||
|
|
||||||
|
// Override the pricing mapping by setting the relevant pricelist for the
|
||||||
|
// network version at the epoch where the vector runs.
|
||||||
|
vm.Prices = map[abi.ChainEpoch]vm.Pricelist{
|
||||||
|
vectorEpoch: pricelist,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a function to restore the original mapping.
|
||||||
|
return func() {
|
||||||
|
vm.Prices = old
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ExecuteMessageVector executes a message-class test vector.
|
// ExecuteMessageVector executes a message-class test vector.
|
||||||
func ExecuteMessageVector(r Reporter, vector *schema.TestVector, variant *schema.Variant) (diffs []string, err error) {
|
func ExecuteMessageVector(r Reporter, vector *schema.TestVector, variant *schema.Variant) (diffs []string, err error) {
|
||||||
var (
|
var (
|
||||||
ctx = context.Background()
|
ctx = context.Background()
|
||||||
baseEpoch = variant.Epoch
|
baseEpoch = abi.ChainEpoch(variant.Epoch)
|
||||||
|
nv = network.Version(variant.NetworkVersion)
|
||||||
root = vector.Pre.StateTree.RootCID
|
root = vector.Pre.StateTree.RootCID
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -67,6 +117,10 @@ func ExecuteMessageVector(r Reporter, vector *schema.TestVector, variant *schema
|
|||||||
// Create a new Driver.
|
// Create a new Driver.
|
||||||
driver := NewDriver(ctx, vector.Selector, DriverOpts{DisableVMFlush: true})
|
driver := NewDriver(ctx, vector.Selector, DriverOpts{DisableVMFlush: true})
|
||||||
|
|
||||||
|
// Monkey patch the gas pricing.
|
||||||
|
revertFn := adjustGasPricing(baseEpoch, nv)
|
||||||
|
defer revertFn()
|
||||||
|
|
||||||
// Apply every message.
|
// Apply every message.
|
||||||
for i, m := range vector.ApplyMessages {
|
for i, m := range vector.ApplyMessages {
|
||||||
msg, err := types.DecodeMessage(m.Bytes)
|
msg, err := types.DecodeMessage(m.Bytes)
|
||||||
@ -76,18 +130,19 @@ func ExecuteMessageVector(r Reporter, vector *schema.TestVector, variant *schema
|
|||||||
|
|
||||||
// add the epoch offset if one is set.
|
// add the epoch offset if one is set.
|
||||||
if m.EpochOffset != nil {
|
if m.EpochOffset != nil {
|
||||||
baseEpoch += *m.EpochOffset
|
baseEpoch += abi.ChainEpoch(*m.EpochOffset)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute the message.
|
// Execute the message.
|
||||||
var ret *vm.ApplyRet
|
var ret *vm.ApplyRet
|
||||||
ret, root, err = driver.ExecuteMessage(bs, ExecuteMessageParams{
|
ret, root, err = driver.ExecuteMessage(bs, ExecuteMessageParams{
|
||||||
Preroot: root,
|
Preroot: root,
|
||||||
Epoch: abi.ChainEpoch(baseEpoch),
|
Epoch: baseEpoch,
|
||||||
Message: msg,
|
Message: msg,
|
||||||
BaseFee: BaseFeeOrDefault(vector.Pre.BaseFee),
|
BaseFee: BaseFeeOrDefault(vector.Pre.BaseFee),
|
||||||
CircSupply: CircSupplyOrDefault(vector.Pre.CircSupply),
|
CircSupply: CircSupplyOrDefault(vector.Pre.CircSupply),
|
||||||
Rand: NewReplayingRand(r, vector.Randomness),
|
Rand: NewReplayingRand(r, vector.Randomness),
|
||||||
|
NetworkVersion: nv,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.Fatalf("fatal failure when executing message: %s", err)
|
r.Fatalf("fatal failure when executing message: %s", err)
|
||||||
@ -184,8 +239,10 @@ func ExecuteTipsetVector(r Reporter, vector *schema.TestVector, variant *schema.
|
|||||||
func AssertMsgResult(r Reporter, expected *schema.Receipt, actual *vm.ApplyRet, label string) {
|
func AssertMsgResult(r Reporter, expected *schema.Receipt, actual *vm.ApplyRet, label string) {
|
||||||
r.Helper()
|
r.Helper()
|
||||||
|
|
||||||
|
applyret := actual
|
||||||
if expected, actual := exitcode.ExitCode(expected.ExitCode), actual.ExitCode; expected != actual {
|
if expected, actual := exitcode.ExitCode(expected.ExitCode), actual.ExitCode; expected != actual {
|
||||||
r.Errorf("exit code of msg %s did not match; expected: %s, got: %s", label, expected, actual)
|
r.Errorf("exit code of msg %s did not match; expected: %s, got: %s", label, expected, actual)
|
||||||
|
r.Errorf("\t\\==> actor error: %s", applyret.ActorErr)
|
||||||
}
|
}
|
||||||
if expected, actual := expected.GasUsed, actual.GasUsed; expected != actual {
|
if expected, actual := expected.GasUsed, actual.GasUsed; expected != actual {
|
||||||
r.Errorf("gas used of msg %s did not match; expected: %d, got: %d", label, expected, actual)
|
r.Errorf("gas used of msg %s did not match; expected: %d, got: %d", label, expected, actual)
|
||||||
|
Loading…
Reference in New Issue
Block a user