-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: shed: add a state-tree diff command to lotus shed
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
Showing
2 changed files
with
101 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -68,6 +68,7 @@ func main() { | |
sendCsvCmd, | ||
terminationsCmd, | ||
migrationsCmd, | ||
diffCmd, | ||
} | ||
|
||
app := &cli.App{ | ||
|