chain: bisect cmd

This commit is contained in:
Łukasz Magiera 2020-01-30 22:30:21 +01:00
parent b42e481600
commit de5577ca70
2 changed files with 124 additions and 13 deletions

View File

@ -34,31 +34,31 @@ type EPostProof struct {
} }
type BlockHeader struct { type BlockHeader struct {
Miner address.Address Miner address.Address // 0
Ticket *Ticket Ticket *Ticket // 1
EPostProof EPostProof EPostProof EPostProof // 2
Parents []cid.Cid Parents []cid.Cid // 3
ParentWeight BigInt ParentWeight BigInt // 4
Height uint64 Height uint64 // 5
ParentStateRoot cid.Cid ParentStateRoot cid.Cid // 6
ParentMessageReceipts cid.Cid ParentMessageReceipts cid.Cid // 7
Messages cid.Cid Messages cid.Cid // 8
BLSAggregate Signature BLSAggregate Signature // 9
Timestamp uint64 Timestamp uint64 // 10
BlockSig *Signature BlockSig *Signature // 11
ForkSignaling uint64 ForkSignaling uint64 // 12
} }
func (b *BlockHeader) ToStorageBlock() (block.Block, error) { func (b *BlockHeader) ToStorageBlock() (block.Block, error) {

View File

@ -1,10 +1,13 @@
package cli package cli
import ( import (
"bytes"
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"os" "os"
"os/exec"
"strconv"
"strings" "strings"
"time" "time"
@ -28,6 +31,7 @@ var chainCmd = &cli.Command{
chainSetHeadCmd, chainSetHeadCmd,
chainListCmd, chainListCmd,
chainGetCmd, chainGetCmd,
chainBisectCmd,
chainExportCmd, chainExportCmd,
slashConsensusFault, slashConsensusFault,
}, },
@ -394,6 +398,113 @@ func printTipSet(format string, ts *types.TipSet) {
fmt.Println(format) fmt.Println(format)
} }
var chainBisectCmd = &cli.Command{
Name: "bisect",
Usage: "bisect chain for an event",
Description: `Bisect the chain state tree:
lotus chain bisect [min height] [max height] '1/2/3/state/path' 'jq script'
Returns the first tipset in which jq condition is true
v
[start] FFFFFFFTTT [end]
Example: find height at which deal ID 100 000 appeared
- lotus chain bisect 1 32000 '@Ha:t03/1' '.[2] > 100000'
For special path elements see 'chain get' help
`,
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
if cctx.Args().Len() != 4 {
return xerrors.New("need 4 args")
}
start, err := strconv.ParseUint(cctx.Args().Get(0), 10, 64)
if err != nil {
return err
}
end, err := strconv.ParseUint(cctx.Args().Get(1), 10, 64)
if err != nil {
return err
}
subPath := cctx.Args().Get(2)
jqs := cctx.Args().Get(3)
highest, err := api.ChainGetTipSetByHeight(ctx, end, nil)
if err != nil {
return err
}
prev := highest.Height()
for {
mid := (start + end) / 2
if end - start == 1 {
mid = end
start = end
}
midTs, err := api.ChainGetTipSetByHeight(ctx, mid, highest)
if err != nil {
return err
}
path := "/ipld/" + midTs.ParentState().String() + "/" + subPath
fmt.Printf("* Testing %d (%d - %d) (%s): ", mid, start, end, path)
nd, err := api.ChainGetNode(ctx, path)
if err != nil {
return err
}
b, err := json.MarshalIndent(nd, "", "\t")
if err != nil {
return err
}
cmd := exec.CommandContext(ctx, "jq", jqs)
cmd.Stdin = bytes.NewReader(b)
var out bytes.Buffer
cmd.Stdout = &out
if err := cmd.Run(); err != nil {
return err
}
if strings.TrimSpace(out.String()) == "true" {
fmt.Println("true")
// it's lower
end = mid
highest = midTs
} else {
fmt.Println("false")
start = mid
}
if start == end {
if strings.TrimSpace(out.String()) == "true" {
fmt.Println(midTs.Height())
} else {
fmt.Println(prev)
}
return nil
}
prev = mid
}
},
}
var chainExportCmd = &cli.Command{ var chainExportCmd = &cli.Command{
Name: "export", Name: "export",
Usage: "export chain to a car file", Usage: "export chain to a car file",