dedup state tree CARs from test vectors. (#187)

This commit is contained in:
Raúl Kripalani 2020-08-05 15:52:57 +01:00 committed by GitHub
parent b7e3b4ff77
commit 163721651a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 81 additions and 71 deletions

View File

@ -49,46 +49,49 @@
} }
} }
}, },
"state_tree": {
"additionalProperties": false,
"required": [
"root_cid"
],
"properties": {
"root_cid": {
"additionalProperties": false,
"required": [
"/"
],
"properties": {
"/": {
"type": "string"
}
}
}
}
},
"preconditions": { "preconditions": {
"title": "execution preconditions", "title": "execution preconditions",
"description": "preconditions that need to be applied and satisfied before this test vector can be executed", "description": "preconditions that need to be applied and satisfied before this test vector can be executed",
"type": "object",
"additionalProperties": false, "additionalProperties": false,
"properties": { "properties": {
"epoch": {
"type": "integer"
},
"state_tree": { "state_tree": {
"title": "state tree to seed", "title": "state tree to seed",
"description": "state tree to seed before applying this test vector; mapping of actor addresses => serialized state", "description": "state tree to seed before applying this test vector; mapping of actor addresses => serialized state",
"type": "object", "$ref": "#/definitions/state_tree"
"additionalProperties": {
"$ref": "#/definitions/hex"
},
"examples": [
{
"t01": "0x0123456789abcdef",
"t02": "0x0123456789abcdef",
"t03": "0x0123456789abcdef"
}
]
} }
} }
}, },
"postconditions": { "postconditions": {
"title": "execution preconditions", "title": "execution preconditions",
"description": "postconditions that need to be satisfied after execution for this test vector to pass", "description": "postconditions that need to be satisfied after execution for this test vector to pass",
"type": "object",
"additionalProperties": false, "additionalProperties": false,
"properties": { "properties": {
"state_tree": { "state_tree": {
"title": "state tree postconditions", "title": "state tree postconditions",
"description": "state tree postconditions that must be true for this test vector to pass", "description": "state tree postconditions that must be true for this test vector to pass",
"type": "object", "$ref": "#/definitions/state_tree"
"properties": {
"car_bytes": {
"title": "the hex-encoded CAR containing the full state tree",
"description": "the hex-encoded CAR containing the full state tree, for debugging/diffing purposes",
"$ref": "#/definitions/hex"
}
}
} }
} }
}, },
@ -120,6 +123,11 @@
"_meta": { "_meta": {
"$ref": "#/definitions/meta" "$ref": "#/definitions/meta"
}, },
"car_bytes": {
"title": "car containing state trees",
"description": "the gzipped, hex-encoded CAR containing the pre- and post-condition state trees for this test vector",
"$ref": "#/definitions/hex"
},
"preconditions": { "preconditions": {
"$ref": "#/definitions/preconditions" "$ref": "#/definitions/preconditions"
}, },
@ -137,7 +145,9 @@
} }
}, },
"then": { "then": {
"required": ["apply_message"], "required": [
"apply_message"
],
"properties": { "properties": {
"apply_message": { "apply_message": {
"$ref": "#/definitions/apply_message" "$ref": "#/definitions/apply_message"

View File

@ -11,11 +11,14 @@
} }
}, },
"car_bytes": "0x890043009920583103b5b1fab6769fcb464146d192af785915d8e1dacff264b2be3bcb7bf4064a77cb3b13e27063ea4825dc48cd0a7df77e211916e748002740f0c493a2824200011a09d9c4dc0758c68219091c58c083e7c59e748e070b382a813f4ffe8ead2a090469aaa37f0664b82c092bc78b43fac300335cd2d6e4a8c71ce138003c0fa8ee1707b41aa87f35c811613d59ac53449aef8263aa51c876f2e67c185118ec9628f73442f58e093909ce952e431e770ac693cdbe99f2f9404ad3ca754196ab443c6c66afa41310e705e453496bdcedf0f271529dc7374021d7b80d343397f996d06bf11e753a49eaed7b3ce80a8e9bbaa48bf83223527bd8a2933f002949fdb8058103336a4a979375d5e963cdd7b1",
"preconditions": { "preconditions": {
"height": 100,
"state_tree": { "state_tree": {
"t01": "0x0123456789abcdef", "root_cid": {
"t02": "0x0123456789abcdef", "/": "bafy2bzacebbxsepazfgwepawspvzenb2x64pmqjyan3wgtfpxu5nxez33wzkc"
"t03": "0x0123456789abcdef" }
} }
}, },
@ -23,7 +26,9 @@
"postconditions": { "postconditions": {
"state_tree": { "state_tree": {
"car_bytes": "0x890043009920583103b5b1fab6769fcb464146d192af785915d8e1dacff264b2be3bcb7bf4064a77cb3b13e27063ea4825dc48cd0a7df77e211916e748002740f0c493a2824200011a09d9c4dc0758c68219091c58c083e7c59e748e070b382a813f4ffe8ead2a090469aaa37f0664b82c092bc78b43fac300335cd2d6e4a8c71ce138003c0fa8ee1707b41aa87f35c811613d59ac53449aef8263aa51c876f2e67c185118ec9628f73442f58e093909ce952e431e770ac693cdbe99f2f9404ad3ca754196ab443c6c66afa41310e705e453496bdcedf0f271529dc7374021d7b80d343397f996d06bf11e753a49eaed7b3ce80a8e9bbaa48bf83223527bd8a2933f002949fdb8058103336a4a979375d5e963cdd7b1" "root_cid": {
"/": "bafy2bzacebbxsepazfgwepawspvzenb2x64pmqjyan3wgtfpxu5nxez33wzkc"
}
} }
} }
} }

View File

@ -7,6 +7,7 @@ import (
"log" "log"
"os" "os"
"github.com/ipfs/go-cid"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin"
@ -66,8 +67,9 @@ func runExamineCmd(_ *cli.Context) error {
return err return err
} }
examine := func(encoded []byte) error { examine := func(root cid.Cid) error {
tree, err := state.RecoverStateTree(context.TODO(), encoded) encoded := tv.CAR
tree, err := state.RecoverStateTree(context.TODO(), encoded, root)
if err != nil { if err != nil {
return err return err
} }
@ -96,14 +98,14 @@ func runExamineCmd(_ *cli.Context) error {
if examineFlags.pre { if examineFlags.pre {
log.Print("examining precondition tree") log.Print("examining precondition tree")
if err := examine(tv.Pre.StateTree.CAR); err != nil { if err := examine(tv.Pre.StateTree.RootCID); err != nil {
return err return err
} }
} }
if examineFlags.post { if examineFlags.post {
log.Print("examining postcondition tree") log.Print("examining postcondition tree")
if err := examine(tv.Post.StateTree.CAR); err != nil { if err := examine(tv.Post.StateTree.RootCID); err != nil {
return err return err
} }
} }

View File

@ -57,13 +57,14 @@ func runExecLotus(_ *cli.Context) error {
switch tv.Class { switch tv.Class {
case "message": case "message":
var ( var (
ctx = context.Background() ctx = context.Background()
epoch = tv.Pre.Epoch epoch = tv.Pre.Epoch
preroot = tv.Pre.StateTree.RootCID
) )
bs := blockstore.NewTemporary() bs := blockstore.NewTemporary()
buf := bytes.NewReader(tv.Pre.StateTree.CAR) buf := bytes.NewReader(tv.CAR)
gr, err := gzip.NewReader(buf) gr, err := gzip.NewReader(buf)
if err != nil { if err != nil {
return err return err
@ -86,7 +87,7 @@ func runExecLotus(_ *cli.Context) error {
driver := lotus.NewDriver(ctx) driver := lotus.NewDriver(ctx)
fmt.Println("executing message") fmt.Println("executing message")
spew.Dump(driver.ExecuteMessage(msg, header.Roots[0], bs, epoch)) spew.Dump(driver.ExecuteMessage(msg, preroot, bs, epoch))
return nil return nil

View File

@ -131,29 +131,15 @@ func runExtractMsg(c *cli.Context) error {
return err return err
} }
getZippedCAR := func(root cid.Cid) ([]byte, error) { out := new(bytes.Buffer)
out := new(bytes.Buffer) gw := gzip.NewWriter(out)
gw := gzip.NewWriter(out) if err := g.WriteCAR(gw, preroot, postroot); err != nil {
if err := g.WriteCAR(gw, root); err != nil {
return nil, err
}
if err = gw.Flush(); err != nil {
return nil, err
}
if err = gw.Close(); err != nil {
return nil, err
}
return out.Bytes(), nil
}
pretree, err := getZippedCAR(preroot)
if err != nil {
return err return err
} }
if err = gw.Flush(); err != nil {
posttree, err := getZippedCAR(postroot) return err
if err != nil { }
if err = gw.Close(); err != nil {
return err return err
} }
@ -174,16 +160,17 @@ func runExtractMsg(c *cli.Context) error {
Version: version.String(), Version: version.String(),
}, },
}, },
CAR: out.Bytes(),
Pre: &Preconditions{ Pre: &Preconditions{
Epoch: ts.Height(), Epoch: ts.Height(),
StateTree: &StateTree{ StateTree: &StateTree{
CAR: pretree, RootCID: preroot,
}, },
}, },
ApplyMessage: msgBytes, ApplyMessage: msgBytes,
Post: &Postconditions{ Post: &Postconditions{
StateTree: &StateTree{ StateTree: &StateTree{
CAR: posttree, RootCID: postroot,
}, },
}, },
} }

View File

@ -5,6 +5,7 @@ import (
"encoding/json" "encoding/json"
"github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/abi"
"github.com/ipfs/go-cid"
) )
// Class represents the type of test this instance is. // Class represents the type of test this instance is.
@ -39,8 +40,7 @@ type GenerationData struct {
// StateTree represents a state tree within preconditions and postconditions. // StateTree represents a state tree within preconditions and postconditions.
type StateTree struct { type StateTree struct {
// CAR is the car representation of a state tree RootCID cid.Cid `json:"root_cid"`
CAR HexEncodedBytes `json:"car_hex"`
} }
// HexEncodedBytes is a hex-encoded binary value. // HexEncodedBytes is a hex-encoded binary value.
@ -81,9 +81,15 @@ func (heb *HexEncodedBytes) UnmarshalJSON(v []byte) error {
// TestVector is a single test case // TestVector is a single test case
type TestVector struct { type TestVector struct {
Class `json:"class"` Class `json:"class"`
Selector `json:"selector"` Selector `json:"selector"`
Meta *Metadata `json:"_meta"` Meta *Metadata `json:"_meta"`
// CAR binary data to be loaded into the test environment, usually a CAR
// containing multiple state trees, addressed by root CID from the relevant
// objects.
CAR HexEncodedBytes `json:"car_hex"`
Pre *Preconditions `json:"preconditions"` Pre *Preconditions `json:"preconditions"`
ApplyMessage HexEncodedBytes `json:"apply_message"` ApplyMessage HexEncodedBytes `json:"apply_message"`
Post *Postconditions `json:"postconditions"` Post *Postconditions `json:"postconditions"`

View File

@ -8,6 +8,7 @@ import (
"github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/state"
bs "github.com/filecoin-project/lotus/lib/blockstore" bs "github.com/filecoin-project/lotus/lib/blockstore"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-hamt-ipld" "github.com/ipfs/go-hamt-ipld"
cbor "github.com/ipfs/go-ipld-cbor" cbor "github.com/ipfs/go-ipld-cbor"
"github.com/ipfs/go-ipld-format" "github.com/ipfs/go-ipld-format"
@ -15,7 +16,7 @@ import (
) )
// RecoverStateTree parses a car encoding of a state tree back to a structured format // RecoverStateTree parses a car encoding of a state tree back to a structured format
func RecoverStateTree(ctx context.Context, raw []byte) (*state.StateTree, error) { func RecoverStateTree(ctx context.Context, raw []byte, root cid.Cid) (*state.StateTree, error) {
buf := bytes.NewBuffer(raw) buf := bytes.NewBuffer(raw)
store := bs.NewTemporary() store := bs.NewTemporary()
gr, err := gzip.NewReader(buf) gr, err := gzip.NewReader(buf)
@ -28,14 +29,12 @@ func RecoverStateTree(ctx context.Context, raw []byte) (*state.StateTree, error)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if len(ch.Roots) != 1 {
return nil, fmt.Errorf("car should have 1 root, has %d", len(ch.Roots))
}
cborstore := cbor.NewCborStore(store) cborstore := cbor.NewCborStore(store)
fmt.Printf("root is %s\n", ch.Roots[0]) fmt.Printf("roots are %v\n", ch.Roots)
nd, err := hamt.LoadNode(ctx, cborstore, ch.Roots[0], hamt.UseTreeBitWidth(5)) nd, err := hamt.LoadNode(ctx, cborstore, root, hamt.UseTreeBitWidth(5))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -51,5 +50,5 @@ func RecoverStateTree(ctx context.Context, raw []byte) (*state.StateTree, error)
return nil, err return nil, err
} }
return state.LoadStateTree(cborstore, ch.Roots[0]) return state.LoadStateTree(cborstore, root)
} }

View File

@ -121,7 +121,7 @@ func (sg *Surgeon) GetAccessedActors(ctx context.Context, a api.FullNode, mid ci
// WriteCAR recursively writes the tree referenced by the root as a CAR into the // WriteCAR recursively writes the tree referenced by the root as a CAR into the
// supplied io.Writer. // supplied io.Writer.
func (sg *Surgeon) WriteCAR(w io.Writer, root cid.Cid) error { func (sg *Surgeon) WriteCAR(w io.Writer, roots ...cid.Cid) error {
carWalkFn := func(nd format.Node) (out []*format.Link, err error) { carWalkFn := func(nd format.Node) (out []*format.Link, err error) {
for _, link := range nd.Links() { for _, link := range nd.Links() {
if link.Cid.Prefix().Codec == cid.FilCommitmentSealed || link.Cid.Prefix().Codec == cid.FilCommitmentUnsealed { if link.Cid.Prefix().Codec == cid.FilCommitmentSealed || link.Cid.Prefix().Codec == cid.FilCommitmentUnsealed {
@ -131,7 +131,7 @@ func (sg *Surgeon) WriteCAR(w io.Writer, root cid.Cid) error {
} }
return out, nil return out, nil
} }
return car.WriteCarWithWalker(sg.ctx, sg.stores.DAGService, []cid.Cid{root}, w, carWalkFn) return car.WriteCarWithWalker(sg.ctx, sg.stores.DAGService, roots, w, carWalkFn)
} }
// pluckActorStates plucks the state from the supplied actors at the given // pluckActorStates plucks the state from the supplied actors at the given