From ba408cc2be97cffb633b582a26d53172f9943710 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Thu, 10 Mar 2022 17:14:38 +0000 Subject: [PATCH 1/5] tvx: print out epoch numbers that weren't found. --- cmd/tvx/extract_message.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/tvx/extract_message.go b/cmd/tvx/extract_message.go index 68376654a..e948baaa5 100644 --- a/cmd/tvx/extract_message.go +++ b/cmd/tvx/extract_message.go @@ -368,13 +368,13 @@ func resolveFromChain(ctx context.Context, api v0api.FullNode, mcid cid.Cid, blo // types.EmptyTSK hints to use the HEAD. execTs, err = api.ChainGetTipSetByHeight(ctx, blk.Height+1, types.EmptyTSK) 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. incTs, err = api.ChainGetTipSetByHeight(ctx, blk.Height, execTs.Key()) 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 From 92c97165951fa533921eebc2cc6f312c3b2df91a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Thu, 10 Mar 2022 22:13:08 +0000 Subject: [PATCH 2/5] tvx: widen 'sender' precursor strategy to match against both participants. And also use inclusion tipset to run the message, which is more correct than the execution tipset. --- cmd/tvx/extract.go | 12 +++++----- cmd/tvx/extract_many.go | 9 ++++---- cmd/tvx/extract_message.go | 46 ++++++++++++++++++++++++++++---------- 3 files changed, 45 insertions(+), 22 deletions(-) diff --git a/cmd/tvx/extract.go b/cmd/tvx/extract.go index a3d538abd..281e469bb 100644 --- a/cmd/tvx/extract.go +++ b/cmd/tvx/extract.go @@ -13,8 +13,8 @@ import ( ) const ( - PrecursorSelectAll = "all" - PrecursorSelectSender = "sender" + PrecursorSelectAll = "all" + PrecursorSelectParticipants = "participants" ) type extractOpts struct { @@ -86,12 +86,12 @@ var extractCmd = &cli.Command{ }, &cli.StringFlag{ Name: "precursor-select", - Usage: "precursors to apply; values: 'all', 'sender'; 'all' selects all preceding " + - "messages in the canonicalised tipset, 'sender' selects only preceding messages from the same " + - "sender. Usually, 'sender' is a good tradeoff and gives you sufficient accuracy. If the receipt sanity " + + Usage: "precursors to apply; values: 'all', 'participants'; 'all' selects all preceding " + + "messages in the canonicalised tipset, 'participants' selects only preceding messages from the same " + + "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 " + "affected state in a disruptive way", - Value: "sender", + Value: "participants", Destination: &extractFlags.precursor, }, &cli.BoolFlag{ diff --git a/cmd/tvx/extract_many.go b/cmd/tvx/extract_many.go index ae196542e..3520cd2ad 100644 --- a/cmd/tvx/extract_many.go +++ b/cmd/tvx/extract_many.go @@ -13,11 +13,12 @@ import ( "github.com/fatih/color" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/exitcode" - "github.com/filecoin-project/lotus/chain/consensus/filcns" "github.com/hashicorp/go-multierror" "github.com/ipfs/go-cid" "github.com/multiformats/go-multihash" "github.com/urfave/cli/v2" + + "github.com/filecoin-project/lotus/chain/consensus/filcns" ) var extractManyFlags struct { @@ -176,7 +177,7 @@ func runExtractMany(c *cli.Context) error { // Vector filename, using a base of outdir. 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{ id: id, @@ -185,7 +186,7 @@ func runExtractMany(c *cli.Context) error { cid: mcid, file: file, retain: "accessed-cids", - precursor: PrecursorSelectSender, + precursor: PrecursorSelectParticipants, } if err := doExtractMessage(opts); err != nil { @@ -199,7 +200,7 @@ func runExtractMany(c *cli.Context) error { 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 { log.Printf("retrying %s: %s", r.cid, r.id) diff --git a/cmd/tvx/extract_message.go b/cmd/tvx/extract_message.go index e948baaa5..eb71319da 100644 --- a/cmd/tvx/extract_message.go +++ b/cmd/tvx/extract_message.go @@ -71,7 +71,7 @@ func doExtractMessage(opts extractOpts) error { 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 { 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()) _, root, err = driver.ExecuteMessage(pst.Blockstore, conformance.ExecuteMessageParams{ Preroot: root, - Epoch: execTs.Height(), + Epoch: incTs.Height(), Message: m, CircSupply: circSupplyDetail.FilCirculating, BaseFee: basefee, @@ -139,6 +139,7 @@ func doExtractMessage(opts extractOpts) error { ) log.Printf("using state retention strategy: %s", retention) + log.Printf("now applying requested message: %s", msg.Cid()) switch retention { case "accessed-cids": tbs, ok := pst.Blockstore.(TracingBlockstore) @@ -151,7 +152,7 @@ func doExtractMessage(opts extractOpts) error { preroot = root applyret, postroot, err = driver.ExecuteMessage(pst.Blockstore, conformance.ExecuteMessageParams{ Preroot: preroot, - Epoch: execTs.Height(), + Epoch: incTs.Height(), Message: msg, CircSupply: circSupplyDetail.FilCirculating, BaseFee: basefee, @@ -184,7 +185,7 @@ func doExtractMessage(opts extractOpts) error { } applyret, postroot, err = driver.ExecuteMessage(pst.Blockstore, conformance.ExecuteMessageParams{ Preroot: preroot, - Epoch: execTs.Height(), + Epoch: incTs.Height(), Message: msg, CircSupply: circSupplyDetail.FilCirculating, BaseFee: basefee, @@ -299,7 +300,7 @@ func doExtractMessage(opts extractOpts) error { CAR: out.Bytes(), Pre: &schema.Preconditions{ Variants: []schema.Variant{ - {ID: codename, Epoch: int64(execTs.Height()), NetworkVersion: uint(nv)}, + {ID: codename, Epoch: int64(incTs.Height()), NetworkVersion: uint(nv)}, }, CircSupply: circSupply.Int, BaseFee: basefee.Int, @@ -403,19 +404,40 @@ func fetchThisAndPrevTipset(ctx context.Context, api v0api.FullNode, target type // findMsgAndPrecursors ranges through the canonical messages slice, locating // the target message and returning precursors in accordance to the supplied // mode. -func findMsgAndPrecursors(mode string, msgCid cid.Cid, sender address.Address, msgs []api.Message) (related []*types.Message, found bool, err error) { - // Range through canonicalised messages, selecting only the precursors based - // on selection mode. - for _, other := range msgs { +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) { + // Resolve addresses to IDs for canonicality. + senderID, err := FullAPI.StateLookupID(ctx, sender, types.EmptyTSK) + if err != nil { + return nil, false, err + } + recipientID, err := FullAPI.StateLookupID(ctx, recipient, types.EmptyTSK) + if err != nil { + return nil, false, err + } + + // Range through messages, selecting only the precursors based on selection mode. + for _, m := range msgs { + msgSenderID, err := FullAPI.StateLookupID(ctx, m.Message.From, types.EmptyTSK) + if err != nil { + return nil, false, err + } + msgRecipientID, err := FullAPI.StateLookupID(ctx, m.Message.To, types.EmptyTSK) + if err != nil { + return nil, false, err + } switch { case mode == PrecursorSelectAll: fallthrough - case mode == PrecursorSelectSender && other.Message.From == sender: - related = append(related, other.Message) + case mode == PrecursorSelectParticipants && + msgSenderID == senderID || + msgRecipientID == recipientID || + msgSenderID == recipientID || + msgRecipientID == senderID: + related = append(related, m.Message) } // this message is the target; we're done. - if other.Cid == msgCid { + if m.Cid == msgCid { return related, true, nil } } From 5434cfdaa9b644ece08534d1c059be11cb654da2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Fri, 11 Mar 2022 18:49:07 +0000 Subject: [PATCH 3/5] tvx: use addresses when scanning precursors. --- cmd/tvx/extract_message.go | 43 ++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/cmd/tvx/extract_message.go b/cmd/tvx/extract_message.go index eb71319da..e223996ab 100644 --- a/cmd/tvx/extract_message.go +++ b/cmd/tvx/extract_message.go @@ -406,33 +406,22 @@ func fetchThisAndPrevTipset(ctx context.Context, api v0api.FullNode, target type // mode. 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) { // Resolve addresses to IDs for canonicality. - senderID, err := FullAPI.StateLookupID(ctx, sender, types.EmptyTSK) - if err != nil { - return nil, false, err - } - recipientID, err := FullAPI.StateLookupID(ctx, recipient, types.EmptyTSK) - if err != nil { - return nil, false, err - } + senderID := mustResolveAddr(ctx, sender) + recipientID := mustResolveAddr(ctx, recipient) // Range through messages, selecting only the precursors based on selection mode. for _, m := range msgs { - msgSenderID, err := FullAPI.StateLookupID(ctx, m.Message.From, types.EmptyTSK) - if err != nil { - return nil, false, err - } - msgRecipientID, err := FullAPI.StateLookupID(ctx, m.Message.To, types.EmptyTSK) - if err != nil { - return nil, false, err - } + msgSenderID := mustResolveAddr(ctx, m.Message.From) + msgRecipientID := mustResolveAddr(ctx, m.Message.To) + switch { case mode == PrecursorSelectAll: fallthrough case mode == PrecursorSelectParticipants && - msgSenderID == senderID || - msgRecipientID == recipientID || - msgSenderID == recipientID || - msgRecipientID == senderID: + msgSenderID == senderID || + msgRecipientID == recipientID || + msgSenderID == recipientID || + msgRecipientID == senderID: related = append(related, m.Message) } @@ -447,3 +436,17 @@ func findMsgAndPrecursors(ctx context.Context, mode string, msgCid cid.Cid, send // target). 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 +} \ No newline at end of file From 9eb81038668216d6746ff2614be72bbca66e21f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Fri, 11 Mar 2022 18:56:19 +0000 Subject: [PATCH 4/5] tvx and conformance: use precondition state tree as the lookback tree. --- conformance/driver.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/conformance/driver.go b/conformance/driver.go index a065d1530..4d87dfcf3 100644 --- a/conformance/driver.go +++ b/conformance/driver.go @@ -6,6 +6,7 @@ import ( "os" "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/chain/consensus/filcns" @@ -199,6 +200,9 @@ type ExecuteMessageParams struct { // 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. 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. @@ -213,6 +217,17 @@ func (d *Driver) ExecuteMessage(bs blockstore.Blockstore, params ExecuteMessageP 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{ StateBase: params.Preroot, Epoch: params.Epoch, @@ -224,6 +239,7 @@ func (d *Driver) ExecuteMessage(bs blockstore.Blockstore, params ExecuteMessageP Rand: params.Rand, BaseFee: params.BaseFee, NetworkVersion: params.NetworkVersion, + LookbackState: lookback, } lvm, err := vm.NewVM(context.TODO(), vmOpts) From eef436b0305620c5615e2e8734189fe1ce18dab9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Fri, 11 Mar 2022 19:05:07 +0000 Subject: [PATCH 5/5] go fmt. --- cmd/tvx/extract_message.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/tvx/extract_message.go b/cmd/tvx/extract_message.go index e223996ab..33ae5ab8f 100644 --- a/cmd/tvx/extract_message.go +++ b/cmd/tvx/extract_message.go @@ -449,4 +449,4 @@ func mustResolveAddr(ctx context.Context, addr address.Address) address.Address } addressCache[addr] = id return id -} \ No newline at end of file +}