Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

shed: Commad to decode messages #4565

Merged
merged 1 commit into from
Oct 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cli/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -1291,7 +1291,7 @@ var chainDecodeParamsCmd = &cli.Command{
return xerrors.Errorf("getting actor: %w", err)
}

pstr, err := jsonParams(act.Code, abi.MethodNum(method), params)
pstr, err := JsonParams(act.Code, abi.MethodNum(method), params)
if err != nil {
return err
}
Expand Down
4 changes: 2 additions & 2 deletions cli/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -1211,7 +1211,7 @@ func ComputeStateHTMLTempl(w io.Writer, ts *types.TipSet, o *api.ComputeStateOut
"GetCode": getCode,
"GetMethod": getMethod,
"ToFil": toFil,
"JsonParams": jsonParams,
"JsonParams": JsonParams,
"JsonReturn": jsonReturn,
"IsSlow": isSlow,
"IsVerySlow": isVerySlow,
Expand Down Expand Up @@ -1298,7 +1298,7 @@ func sumGas(changes []*types.GasTrace) types.GasTrace {
return out
}

func jsonParams(code cid.Cid, method abi.MethodNum, params []byte) (string, error) {
func JsonParams(code cid.Cid, method abi.MethodNum, params []byte) (string, error) {
methodMeta, found := stmgr.MethodsMap[code][method]
if !found {
return "", fmt.Errorf("method %d not found on actor %s", method, code)
Expand Down
1 change: 1 addition & 0 deletions cmd/lotus-shed/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ func main() {
datastoreCmd,
ledgerCmd,
sectorsCmd,
msgCmd,
}

app := &cli.App{
Expand Down
280 changes: 280 additions & 0 deletions cmd/lotus-shed/msg.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,280 @@
package main

import (
"bytes"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"

"github.com/fatih/color"

"github.com/ipfs/go-cid"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors"

"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/big"

"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/types"
lcli "github.com/filecoin-project/lotus/cli"
"github.com/filecoin-project/specs-actors/v2/actors/builtin/multisig"
)

var msgCmd = &cli.Command{
Name: "msg",
Usage: "Translate message between various formats",
ArgsUsage: "Message in any form",
Action: func(cctx *cli.Context) error {
if cctx.Args().Len() != 1 {
return xerrors.Errorf("expected 1 argument")
}

msg, err := messageFromString(cctx, cctx.Args().First())
if err != nil {
return err
}

switch msg := msg.(type) {
case *types.SignedMessage:
return printSignedMessage(cctx, msg)
case *types.Message:
return printMessage(cctx, msg)
default:
return xerrors.Errorf("this error message can't be printed")
}
},
}

func printSignedMessage(cctx *cli.Context, smsg *types.SignedMessage) error {
color.Green("Signed:")
color.Blue("CID: %s\n", smsg.Cid())

b, err := smsg.Serialize()
if err != nil {
return err
}
color.Magenta("HEX: %x\n", b)
color.Blue("B64: %s\n", base64.StdEncoding.EncodeToString(b))
jm, err := json.MarshalIndent(smsg, "", " ")
if err != nil {
return xerrors.Errorf("marshaling as json: %w", err)
}

color.Magenta("JSON: %s\n", string(jm))
fmt.Println()
fmt.Println("---")
color.Green("Signed Message Details:")
fmt.Printf("Signature(hex): %x\n", smsg.Signature.Data)
fmt.Printf("Signature(b64): %s\n", base64.StdEncoding.EncodeToString(smsg.Signature.Data))

sigtype, err := smsg.Signature.Type.Name()
if err != nil {
sigtype = err.Error()
}
fmt.Printf("Signature type: %d (%s)\n", smsg.Signature.Type, sigtype)

fmt.Println("-------")
return printMessage(cctx, &smsg.Message)
}

func printMessage(cctx *cli.Context, msg *types.Message) error {
if msg.Version != 0x6d736967 {
color.Green("Unsigned:")
color.Yellow("CID: %s\n", msg.Cid())

b, err := msg.Serialize()
if err != nil {
return err
}
color.Cyan("HEX: %x\n", b)
color.Yellow("B64: %s\n", base64.StdEncoding.EncodeToString(b))

jm, err := json.MarshalIndent(msg, "", " ")
if err != nil {
return xerrors.Errorf("marshaling as json: %w", err)
}

color.Cyan("JSON: %s\n", string(jm))
fmt.Println()
} else {
color.Green("Msig Propose:")
pp := &multisig.ProposeParams{
To: msg.To,
Value: msg.Value,
Method: msg.Method,
Params: msg.Params,
}
var b bytes.Buffer
if err := pp.MarshalCBOR(&b); err != nil {
return err
}

color.Cyan("HEX: %x\n", b.Bytes())
color.Yellow("B64: %s\n", base64.StdEncoding.EncodeToString(b.Bytes()))
jm, err := json.MarshalIndent(pp, "", " ")
if err != nil {
return xerrors.Errorf("marshaling as json: %w", err)
}

color.Cyan("JSON: %s\n", string(jm))
fmt.Println()
}

fmt.Println("---")
color.Green("Message Details:")
fmt.Println("Value:", types.FIL(msg.Value))
fmt.Println("Max Fees:", types.FIL(msg.RequiredFunds()))
fmt.Println("Max Total Cost:", types.FIL(big.Add(msg.RequiredFunds(), msg.Value)))

api, closer, err := lcli.GetFullNodeAPI(cctx)
if err != nil {
return err
}

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

toact, err := api.StateGetActor(ctx, msg.To, types.EmptyTSK)
if err != nil {
return nil
}

fmt.Println("Method:", stmgr.MethodsMap[toact.Code][msg.Method].Name)
p, err := lcli.JsonParams(toact.Code, msg.Method, msg.Params)
if err != nil {
return err
}

fmt.Println("Params:", p)

return nil
}

func messageFromString(cctx *cli.Context, smsg string) (types.ChainMsg, error) {
// a CID is least likely to just decode
if c, err := cid.Parse(smsg); err == nil {
return messageFromCID(cctx, c)
}

// try baseX serializations next
{
// hex first, some hay strings may be decodable as b64
if b, err := hex.DecodeString(smsg); err == nil {
return messageFromBytes(cctx, b)
}

// b64 next
if b, err := base64.StdEncoding.DecodeString(smsg); err == nil {
return messageFromBytes(cctx, b)
}

// b64u??
if b, err := base64.URLEncoding.DecodeString(smsg); err == nil {
return messageFromBytes(cctx, b)
}
}

// maybe it's json?
if _, err := messageFromJson(cctx, []byte(smsg)); err == nil {
return nil, err
}

// declare defeat
return nil, xerrors.Errorf("couldn't decode the message")
}

func messageFromJson(cctx *cli.Context, msgb []byte) (types.ChainMsg, error) {
// Unsigned
{
var msg types.Message
if err := json.Unmarshal(msgb, &msg); err == nil {
if msg.To != address.Undef {
return &msg, nil
}
}
}

// Signed
{
var msg types.SignedMessage
if err := json.Unmarshal(msgb, &msg); err == nil {
if msg.Message.To != address.Undef {
return &msg, nil
}
}
}

return nil, xerrors.New("probably not a json-serialized message")
}

func messageFromBytes(cctx *cli.Context, msgb []byte) (types.ChainMsg, error) {
// Signed
{
var msg types.SignedMessage
if err := msg.UnmarshalCBOR(bytes.NewReader(msgb)); err == nil {
return &msg, nil
}
}

// Unsigned
{
var msg types.Message
if err := msg.UnmarshalCBOR(bytes.NewReader(msgb)); err == nil {
return &msg, nil
}
}

// Multisig propose?
{
var pp multisig.ProposeParams
if err := pp.UnmarshalCBOR(bytes.NewReader(msgb)); err == nil {
i, err := address.NewIDAddress(0)
if err != nil {
return nil, err
}

return &types.Message{
// Hack(-ish)
Version: 0x6d736967,
From: i,

To: pp.To,
Value: pp.Value,

Method: pp.Method,
Params: pp.Params,

GasFeeCap: big.Zero(),
GasPremium: big.Zero(),
}, nil
}
}

// Encoded json???
{
if msg, err := messageFromJson(cctx, msgb); err == nil {
return msg, nil
}
}

return nil, xerrors.New("probably not a cbor-serialized message")
}

func messageFromCID(cctx *cli.Context, c cid.Cid) (types.ChainMsg, error) {
api, closer, err := lcli.GetFullNodeAPI(cctx)
if err != nil {
return nil, err
}

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

msgb, err := api.ChainReadObj(ctx, c)
if err != nil {
return nil, err
}

return messageFromBytes(cctx, msgb)
}