lotus/cli/chain.go

255 lines
5.0 KiB
Go
Raw Normal View History

2019-07-09 15:19:27 +00:00
package cli
import (
2019-10-10 03:50:50 +00:00
"context"
2019-07-23 00:54:27 +00:00
"encoding/json"
2019-07-09 15:19:27 +00:00
"fmt"
cid "github.com/ipfs/go-cid"
"golang.org/x/xerrors"
2019-07-09 15:19:27 +00:00
"gopkg.in/urfave/cli.v2"
2019-07-23 00:54:27 +00:00
"github.com/filecoin-project/go-lotus/api"
types "github.com/filecoin-project/go-lotus/chain/types"
2019-07-09 15:19:27 +00:00
)
var chainCmd = &cli.Command{
Name: "chain",
Usage: "Interact with filecoin blockchain",
Subcommands: []*cli.Command{
chainHeadCmd,
2019-07-23 00:54:27 +00:00
chainGetBlock,
chainReadObjCmd,
chainGetMsgCmd,
2019-07-09 15:19:27 +00:00
},
}
var chainHeadCmd = &cli.Command{
Name: "head",
Usage: "Print chain head",
Action: func(cctx *cli.Context) error {
2019-10-03 18:12:30 +00:00
api, closer, err := GetFullNodeAPI(cctx)
2019-07-10 17:28:49 +00:00
if err != nil {
return err
}
2019-10-03 18:12:30 +00:00
defer closer()
2019-07-18 23:16:23 +00:00
ctx := ReqContext(cctx)
2019-07-09 15:19:27 +00:00
head, err := api.ChainHead(ctx)
if err != nil {
return err
}
2019-07-11 02:36:43 +00:00
for _, c := range head.Cids() {
2019-07-09 15:19:27 +00:00
fmt.Println(c)
}
return nil
},
}
2019-07-23 00:54:27 +00:00
var chainGetBlock = &cli.Command{
Name: "getblock",
Usage: "Get a block and print its details",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "raw",
Usage: "print just the raw block header",
},
},
Action: func(cctx *cli.Context) error {
2019-10-03 18:12:30 +00:00
api, closer, err := GetFullNodeAPI(cctx)
2019-07-23 00:54:27 +00:00
if err != nil {
return err
}
2019-10-03 18:12:30 +00:00
defer closer()
2019-07-18 23:16:23 +00:00
ctx := ReqContext(cctx)
2019-07-23 00:54:27 +00:00
if !cctx.Args().Present() {
return fmt.Errorf("must pass cid of block to print")
}
bcid, err := cid.Decode(cctx.Args().First())
if err != nil {
return err
}
blk, err := api.ChainGetBlock(ctx, bcid)
if err != nil {
return xerrors.Errorf("get block failed: %w", err)
2019-07-23 00:54:27 +00:00
}
if cctx.Bool("raw") {
out, err := json.MarshalIndent(blk, "", " ")
if err != nil {
return err
}
fmt.Println(string(out))
return nil
}
msgs, err := api.ChainGetBlockMessages(ctx, bcid)
if err != nil {
return xerrors.Errorf("failed to get messages: %w", err)
2019-07-23 00:54:27 +00:00
}
pmsgs, err := api.ChainGetParentMessages(ctx, bcid)
if err != nil {
return xerrors.Errorf("failed to get parent messages: %w", err)
}
recpts, err := api.ChainGetParentReceipts(ctx, bcid)
if err != nil {
log.Warn(err)
//return xerrors.Errorf("failed to get receipts: %w", err)
}
2019-07-23 00:54:27 +00:00
cblock := struct {
types.BlockHeader
BlsMessages []*types.Message
SecpkMessages []*types.SignedMessage
ParentReceipts []*types.MessageReceipt
ParentMessages []cid.Cid
2019-07-23 00:54:27 +00:00
}{}
cblock.BlockHeader = *blk
2019-08-02 03:51:34 +00:00
cblock.BlsMessages = msgs.BlsMessages
cblock.SecpkMessages = msgs.SecpkMessages
cblock.ParentReceipts = recpts
cblock.ParentMessages = apiMsgCids(pmsgs)
2019-07-23 00:54:27 +00:00
out, err := json.MarshalIndent(cblock, "", " ")
if err != nil {
return err
}
fmt.Println(string(out))
return nil
},
}
func apiMsgCids(in []api.Message) []cid.Cid {
out := make([]cid.Cid, len(in))
for k, v := range in {
out[k] = v.Cid
}
return out
}
var chainReadObjCmd = &cli.Command{
Name: "read-obj",
Usage: "Read the raw bytes of an object",
Action: func(cctx *cli.Context) error {
2019-10-03 18:12:30 +00:00
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
2019-10-03 18:12:30 +00:00
defer closer()
ctx := ReqContext(cctx)
c, err := cid.Decode(cctx.Args().First())
if err != nil {
return fmt.Errorf("failed to parse cid input: %s", err)
}
obj, err := api.ChainReadObj(ctx, c)
if err != nil {
return err
}
fmt.Printf("%x\n", obj)
return nil
},
}
var chainGetMsgCmd = &cli.Command{
Name: "getmessage",
Usage: "Get and print a message by its cid",
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
c, err := cid.Decode(cctx.Args().First())
if err != nil {
return xerrors.Errorf("failed to parse cid input: %w", err)
}
mb, err := api.ChainReadObj(ctx, c)
if err != nil {
return xerrors.Errorf("failed to read object: %w", err)
}
var i interface{}
m, err := types.DecodeMessage(mb)
if err != nil {
sm, err := types.DecodeSignedMessage(mb)
if err != nil {
return xerrors.Errorf("failed to decode object as a message: %w", err)
}
i = sm
} else {
i = m
}
enc, err := json.MarshalIndent(i, "", " ")
if err != nil {
return err
}
fmt.Println(string(enc))
return nil
},
}
2019-10-10 03:50:50 +00:00
var chainSetHead = &cli.Command{
Name: "sethead",
Usage: "manually set the local nodes head tipset (Caution: normally only used for recovery)",
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
if !cctx.Args().Present() {
return fmt.Errorf("must pass cids for tipset to set as head")
}
ts, err := parseTipSet(api, ctx, cctx.Args().Slice())
if err != nil {
return err
}
if err := api.ChainSetHead(ctx, ts); err != nil {
return err
}
return nil
},
}
func parseTipSet(api api.FullNode, ctx context.Context, vals []string) (*types.TipSet, error) {
var headers []*types.BlockHeader
for _, c := range vals {
blkc, err := cid.Decode(c)
if err != nil {
return nil, err
}
bh, err := api.ChainGetBlock(ctx, blkc)
if err != nil {
return nil, err
}
headers = append(headers, bh)
}
return types.NewTipSet(headers)
}