Skip to content

Commit

Permalink
feat: shed: add a state-tree diff command to lotus shed
Browse files Browse the repository at this point in the history
This makes it easier to debug state mismatches by providing a nice way
to figure out which actors differ between two state-trees and
how (balance, nonce, state, etc.).

It doesn't provide a way to actually _diff_ those state-trees, but one
can use `lotus chain get` to figure that out (although it would be
_nice_ to provide something a bit smarter).
  • Loading branch information
Stebalien committed Feb 11, 2022
1 parent 2e22781 commit 0bd79d8
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 0 deletions.
100 changes: 100 additions & 0 deletions cmd/lotus-shed/diff.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package main

import (
"fmt"

"github.com/urfave/cli/v2"

"github.com/ipfs/go-cid"

lcli "github.com/filecoin-project/lotus/cli"
)

var diffCmd = &cli.Command{
Name: "diff",
Usage: "diff state objects",
Subcommands: []*cli.Command{diffStateTrees},
}

var diffStateTrees = &cli.Command{
Name: "state-trees",
Usage: "diff two state-trees",
ArgsUsage: "<state-tree-a> <state-tree-b>",
Action: func(cctx *cli.Context) error {
api, closer, err := lcli.GetFullNodeAPI(cctx)
if err != nil {
return err
}

defer closer()
ctx := lcli.ReqContext(cctx)

if cctx.NArg() != 2 {
return xerrors.Errorf("expected two state-tree roots")
}

rootA, err := cid.Parse(cctx.Args().Get(0))
if err != nil {
return xerrors.Errorf("first state-tree root (%q) is not a CID: %w", err)
}
rootB, err := cid.Parse(cctx.Args().Get(1))
if err != nil {
return xerrors.Errorf("second state-tree root (%q) is not a CID: %w", err)
}

if rootA == rootB {
fmt.Println("state trees do not differ")
return nil
}

changedB, err := api.StateChangedActors(ctx, rootA, rootB)
if err != nil {
return err
}
changedA, err := api.StateChangedActors(ctx, rootB, rootA)
if err != nil {
return err
}

diff := func(stateA, stateB types.Actor) {
if stateB.Code != stateA.Code {
fmt.Printf(" code: %s != %s\n", stateA.Code, stateB.Code)
}
if stateB.Head != stateA.Head {
fmt.Printf(" state: %s != %s\n", stateA.Head, stateB.Head)
}
if stateB.Nonce != stateA.Nonce {
fmt.Printf(" nonce: %d != %d\n", stateA.Nonce, stateB.Nonce)
}
if !stateB.Balance.Equals(stateA.Balance) {
fmt.Printf(" balance: %s != %s\n", stateA.Balance, stateB.Balance)
}
}

fmt.Printf("state differences between %s (first) and %s (second):\n\n", rootA, rootB)
for addr, stateA := range changedA {
fmt.Println(addr)
stateB, ok := changedB[addr]
if ok {
diff(stateA, stateB)
continue
} else {
fmt.Printf(" actor does not exist in second state-tree (%s)\n", rootB)
}
fmt.Println()
delete(changedB, addr)
}
for addr, stateB := range changedB {
fmt.Println(addr)
stateA, ok := changedA[addr]
if ok {
diff(stateA, stateB)
continue
} else {
fmt.Printf(" actor does not exist in first state-tree (%s)\n", rootA)
}
fmt.Println()
}
return nil
},
}
1 change: 1 addition & 0 deletions cmd/lotus-shed/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ func main() {
sendCsvCmd,
terminationsCmd,
migrationsCmd,
diffCmd,
}

app := &cli.App{
Expand Down

0 comments on commit 0bd79d8

Please sign in to comment.