Merge pull request #8302 from filecoin-project/raulk/tvx-fixes
feat: conformance & tvx: support ReportConsensusFault messages
This commit is contained in:
commit
27eaebad7e
@ -13,8 +13,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PrecursorSelectAll = "all"
|
PrecursorSelectAll = "all"
|
||||||
PrecursorSelectSender = "sender"
|
PrecursorSelectParticipants = "participants"
|
||||||
)
|
)
|
||||||
|
|
||||||
type extractOpts struct {
|
type extractOpts struct {
|
||||||
@ -86,12 +86,12 @@ var extractCmd = &cli.Command{
|
|||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "precursor-select",
|
Name: "precursor-select",
|
||||||
Usage: "precursors to apply; values: 'all', 'sender'; 'all' selects all preceding " +
|
Usage: "precursors to apply; values: 'all', 'participants'; 'all' selects all preceding " +
|
||||||
"messages in the canonicalised tipset, 'sender' selects only preceding messages from the same " +
|
"messages in the canonicalised tipset, 'participants' selects only preceding messages from the same " +
|
||||||
"sender. Usually, 'sender' is a good tradeoff and gives you sufficient accuracy. If the receipt sanity " +
|
"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 " +
|
"check fails due to gas reasons, switch to 'all', as previous messages in the tipset may have " +
|
||||||
"affected state in a disruptive way",
|
"affected state in a disruptive way",
|
||||||
Value: "sender",
|
Value: "participants",
|
||||||
Destination: &extractFlags.precursor,
|
Destination: &extractFlags.precursor,
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
|
@ -13,11 +13,12 @@ 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/lotus/chain/consensus/filcns"
|
|
||||||
"github.com/hashicorp/go-multierror"
|
"github.com/hashicorp/go-multierror"
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
"github.com/multiformats/go-multihash"
|
"github.com/multiformats/go-multihash"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||||
)
|
)
|
||||||
|
|
||||||
var extractManyFlags struct {
|
var extractManyFlags struct {
|
||||||
@ -176,7 +177,7 @@ func runExtractMany(c *cli.Context) error {
|
|||||||
// Vector filename, using a base of outdir.
|
// Vector filename, using a base of outdir.
|
||||||
file := filepath.Join(outdir, actorcodename, methodname, exitcodename, id) + ".json"
|
file := filepath.Join(outdir, actorcodename, methodname, exitcodename, id) + ".json"
|
||||||
|
|
||||||
log.Println(color.YellowString("processing message cid with 'sender' precursor mode: %s", id))
|
log.Println(color.YellowString("processing message cid with 'participants' precursor mode: %s", id))
|
||||||
|
|
||||||
opts := extractOpts{
|
opts := extractOpts{
|
||||||
id: id,
|
id: id,
|
||||||
@ -185,7 +186,7 @@ func runExtractMany(c *cli.Context) error {
|
|||||||
cid: mcid,
|
cid: mcid,
|
||||||
file: file,
|
file: file,
|
||||||
retain: "accessed-cids",
|
retain: "accessed-cids",
|
||||||
precursor: PrecursorSelectSender,
|
precursor: PrecursorSelectParticipants,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := doExtractMessage(opts); err != nil {
|
if err := doExtractMessage(opts); err != nil {
|
||||||
@ -199,7 +200,7 @@ func runExtractMany(c *cli.Context) error {
|
|||||||
generated = append(generated, file)
|
generated = append(generated, file)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("extractions to try with canonical precursor selection mode: %d", len(retry))
|
log.Printf("extractions to try with 'all' precursor selection mode: %d", len(retry))
|
||||||
|
|
||||||
for _, r := range retry {
|
for _, r := range retry {
|
||||||
log.Printf("retrying %s: %s", r.cid, r.id)
|
log.Printf("retrying %s: %s", r.cid, r.id)
|
||||||
|
@ -71,7 +71,7 @@ func doExtractMessage(opts extractOpts) error {
|
|||||||
return fmt.Errorf("failed to fetch messages in canonical order from inclusion tipset: %w", err)
|
return fmt.Errorf("failed to fetch messages in canonical order from inclusion tipset: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
related, found, err := findMsgAndPrecursors(opts.precursor, mcid, msg.From, msgs)
|
related, found, err := findMsgAndPrecursors(ctx, opts.precursor, mcid, msg.From, msg.To, msgs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed while finding message and precursors: %w", err)
|
return fmt.Errorf("failed while finding message and precursors: %w", err)
|
||||||
}
|
}
|
||||||
@ -114,7 +114,7 @@ func doExtractMessage(opts extractOpts) error {
|
|||||||
log.Printf("applying precursor %d, cid: %s", i, m.Cid())
|
log.Printf("applying precursor %d, cid: %s", i, m.Cid())
|
||||||
_, root, err = driver.ExecuteMessage(pst.Blockstore, conformance.ExecuteMessageParams{
|
_, root, err = driver.ExecuteMessage(pst.Blockstore, conformance.ExecuteMessageParams{
|
||||||
Preroot: root,
|
Preroot: root,
|
||||||
Epoch: execTs.Height(),
|
Epoch: incTs.Height(),
|
||||||
Message: m,
|
Message: m,
|
||||||
CircSupply: circSupplyDetail.FilCirculating,
|
CircSupply: circSupplyDetail.FilCirculating,
|
||||||
BaseFee: basefee,
|
BaseFee: basefee,
|
||||||
@ -139,6 +139,7 @@ func doExtractMessage(opts extractOpts) error {
|
|||||||
)
|
)
|
||||||
|
|
||||||
log.Printf("using state retention strategy: %s", retention)
|
log.Printf("using state retention strategy: %s", retention)
|
||||||
|
log.Printf("now applying requested message: %s", msg.Cid())
|
||||||
switch retention {
|
switch retention {
|
||||||
case "accessed-cids":
|
case "accessed-cids":
|
||||||
tbs, ok := pst.Blockstore.(TracingBlockstore)
|
tbs, ok := pst.Blockstore.(TracingBlockstore)
|
||||||
@ -151,7 +152,7 @@ func doExtractMessage(opts extractOpts) error {
|
|||||||
preroot = root
|
preroot = root
|
||||||
applyret, postroot, err = driver.ExecuteMessage(pst.Blockstore, conformance.ExecuteMessageParams{
|
applyret, postroot, err = driver.ExecuteMessage(pst.Blockstore, conformance.ExecuteMessageParams{
|
||||||
Preroot: preroot,
|
Preroot: preroot,
|
||||||
Epoch: execTs.Height(),
|
Epoch: incTs.Height(),
|
||||||
Message: msg,
|
Message: msg,
|
||||||
CircSupply: circSupplyDetail.FilCirculating,
|
CircSupply: circSupplyDetail.FilCirculating,
|
||||||
BaseFee: basefee,
|
BaseFee: basefee,
|
||||||
@ -184,7 +185,7 @@ func doExtractMessage(opts extractOpts) error {
|
|||||||
}
|
}
|
||||||
applyret, postroot, err = driver.ExecuteMessage(pst.Blockstore, conformance.ExecuteMessageParams{
|
applyret, postroot, err = driver.ExecuteMessage(pst.Blockstore, conformance.ExecuteMessageParams{
|
||||||
Preroot: preroot,
|
Preroot: preroot,
|
||||||
Epoch: execTs.Height(),
|
Epoch: incTs.Height(),
|
||||||
Message: msg,
|
Message: msg,
|
||||||
CircSupply: circSupplyDetail.FilCirculating,
|
CircSupply: circSupplyDetail.FilCirculating,
|
||||||
BaseFee: basefee,
|
BaseFee: basefee,
|
||||||
@ -299,7 +300,7 @@ func doExtractMessage(opts extractOpts) error {
|
|||||||
CAR: out.Bytes(),
|
CAR: out.Bytes(),
|
||||||
Pre: &schema.Preconditions{
|
Pre: &schema.Preconditions{
|
||||||
Variants: []schema.Variant{
|
Variants: []schema.Variant{
|
||||||
{ID: codename, Epoch: int64(execTs.Height()), NetworkVersion: uint(nv)},
|
{ID: codename, Epoch: int64(incTs.Height()), NetworkVersion: uint(nv)},
|
||||||
},
|
},
|
||||||
CircSupply: circSupply.Int,
|
CircSupply: circSupply.Int,
|
||||||
BaseFee: basefee.Int,
|
BaseFee: basefee.Int,
|
||||||
@ -368,13 +369,13 @@ func resolveFromChain(ctx context.Context, api v0api.FullNode, mcid cid.Cid, blo
|
|||||||
// types.EmptyTSK hints to use the HEAD.
|
// types.EmptyTSK hints to use the HEAD.
|
||||||
execTs, err = api.ChainGetTipSetByHeight(ctx, blk.Height+1, types.EmptyTSK)
|
execTs, err = api.ChainGetTipSetByHeight(ctx, blk.Height+1, types.EmptyTSK)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, fmt.Errorf("failed to get message execution tipset: %w", err)
|
return nil, nil, nil, fmt.Errorf("failed to get message execution tipset (%d) : %w", blk.Height+1, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// walk back from the execTs instead of HEAD, to save time.
|
// walk back from the execTs instead of HEAD, to save time.
|
||||||
incTs, err = api.ChainGetTipSetByHeight(ctx, blk.Height, execTs.Key())
|
incTs, err = api.ChainGetTipSetByHeight(ctx, blk.Height, execTs.Key())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, fmt.Errorf("failed to get message inclusion tipset: %w", err)
|
return nil, nil, nil, fmt.Errorf("failed to get message inclusion tipset (%d): %w", blk.Height, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return msg, execTs, incTs, nil
|
return msg, execTs, incTs, nil
|
||||||
@ -403,19 +404,29 @@ func fetchThisAndPrevTipset(ctx context.Context, api v0api.FullNode, target type
|
|||||||
// findMsgAndPrecursors ranges through the canonical messages slice, locating
|
// findMsgAndPrecursors ranges through the canonical messages slice, locating
|
||||||
// the target message and returning precursors in accordance to the supplied
|
// the target message and returning precursors in accordance to the supplied
|
||||||
// mode.
|
// mode.
|
||||||
func findMsgAndPrecursors(mode string, msgCid cid.Cid, sender address.Address, msgs []api.Message) (related []*types.Message, found bool, err error) {
|
func findMsgAndPrecursors(ctx context.Context, mode string, msgCid cid.Cid, sender address.Address, recipient address.Address, msgs []api.Message) (related []*types.Message, found bool, err error) {
|
||||||
// Range through canonicalised messages, selecting only the precursors based
|
// Resolve addresses to IDs for canonicality.
|
||||||
// on selection mode.
|
senderID := mustResolveAddr(ctx, sender)
|
||||||
for _, other := range msgs {
|
recipientID := mustResolveAddr(ctx, recipient)
|
||||||
|
|
||||||
|
// Range through messages, selecting only the precursors based on selection mode.
|
||||||
|
for _, m := range msgs {
|
||||||
|
msgSenderID := mustResolveAddr(ctx, m.Message.From)
|
||||||
|
msgRecipientID := mustResolveAddr(ctx, m.Message.To)
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case mode == PrecursorSelectAll:
|
case mode == PrecursorSelectAll:
|
||||||
fallthrough
|
fallthrough
|
||||||
case mode == PrecursorSelectSender && other.Message.From == sender:
|
case mode == PrecursorSelectParticipants &&
|
||||||
related = append(related, other.Message)
|
msgSenderID == senderID ||
|
||||||
|
msgRecipientID == recipientID ||
|
||||||
|
msgSenderID == recipientID ||
|
||||||
|
msgRecipientID == senderID:
|
||||||
|
related = append(related, m.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// this message is the target; we're done.
|
// this message is the target; we're done.
|
||||||
if other.Cid == msgCid {
|
if m.Cid == msgCid {
|
||||||
return related, true, nil
|
return related, true, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -425,3 +436,17 @@ func findMsgAndPrecursors(mode string, msgCid cid.Cid, sender address.Address, m
|
|||||||
// target).
|
// target).
|
||||||
return related, false, nil
|
return related, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var addressCache = make(map[address.Address]address.Address)
|
||||||
|
|
||||||
|
func mustResolveAddr(ctx context.Context, addr address.Address) address.Address {
|
||||||
|
if resolved, ok := addressCache[addr]; ok {
|
||||||
|
return resolved
|
||||||
|
}
|
||||||
|
id, err := FullAPI.StateLookupID(ctx, addr, types.EmptyTSK)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("failed to resolve addr: %w", err))
|
||||||
|
}
|
||||||
|
addressCache[addr] = id
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/network"
|
"github.com/filecoin-project/go-state-types/network"
|
||||||
|
cbor "github.com/ipfs/go-ipld-cbor"
|
||||||
|
|
||||||
"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"
|
||||||
@ -199,6 +200,9 @@ type ExecuteMessageParams struct {
|
|||||||
// 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.
|
||||||
Rand vm.Rand
|
Rand vm.Rand
|
||||||
|
|
||||||
|
// Lookback is the LookbackStateGetter; returns the state tree at a given epoch.
|
||||||
|
Lookback vm.LookbackStateGetter
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecuteMessage executes a conformance test vector message in a temporary VM.
|
// ExecuteMessage executes a conformance test vector message in a temporary VM.
|
||||||
@ -213,6 +217,17 @@ func (d *Driver) ExecuteMessage(bs blockstore.Blockstore, params ExecuteMessageP
|
|||||||
params.Rand = NewFixedRand()
|
params.Rand = NewFixedRand()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: This lookback state returns the supplied precondition state tree, unconditionally.
|
||||||
|
// This is obviously not correct, but the lookback state tree is only used to validate the
|
||||||
|
// worker key when verifying a consensus fault. If the worker key hasn't changed in the
|
||||||
|
// current finality window, this workaround is enough.
|
||||||
|
// The correct solutions are documented in https://github.com/filecoin-project/ref-fvm/issues/381,
|
||||||
|
// but they're much harder to implement, and the tradeoffs aren't clear.
|
||||||
|
var lookback vm.LookbackStateGetter = func(ctx context.Context, epoch abi.ChainEpoch) (*state.StateTree, error) {
|
||||||
|
cst := cbor.NewCborStore(bs)
|
||||||
|
return state.LoadStateTree(cst, params.Preroot)
|
||||||
|
}
|
||||||
|
|
||||||
vmOpts := &vm.VMOpts{
|
vmOpts := &vm.VMOpts{
|
||||||
StateBase: params.Preroot,
|
StateBase: params.Preroot,
|
||||||
Epoch: params.Epoch,
|
Epoch: params.Epoch,
|
||||||
@ -224,6 +239,7 @@ func (d *Driver) ExecuteMessage(bs blockstore.Blockstore, params ExecuteMessageP
|
|||||||
Rand: params.Rand,
|
Rand: params.Rand,
|
||||||
BaseFee: params.BaseFee,
|
BaseFee: params.BaseFee,
|
||||||
NetworkVersion: params.NetworkVersion,
|
NetworkVersion: params.NetworkVersion,
|
||||||
|
LookbackState: lookback,
|
||||||
}
|
}
|
||||||
|
|
||||||
lvm, err := vm.NewLegacyVM(context.TODO(), vmOpts)
|
lvm, err := vm.NewLegacyVM(context.TODO(), vmOpts)
|
||||||
|
Loading…
Reference in New Issue
Block a user