Re: #1290: Add a lotus wallet verify API and CLI command

- The command takes an address, message, and signature, and returns true if the sig is valid
This commit is contained in:
Aayush Rajasekaran 2020-02-25 15:17:15 -08:00
parent f6bda96d5a
commit fe8db295e7
6 changed files with 82 additions and 1 deletions

View File

@ -71,6 +71,7 @@ type FullNode interface {
WalletBalance(context.Context, address.Address) (types.BigInt, error) WalletBalance(context.Context, address.Address) (types.BigInt, error)
WalletSign(context.Context, address.Address, []byte) (*types.Signature, error) WalletSign(context.Context, address.Address, []byte) (*types.Signature, error)
WalletSignMessage(context.Context, address.Address, *types.Message) (*types.SignedMessage, error) WalletSignMessage(context.Context, address.Address, *types.Message) (*types.SignedMessage, error)
WalletVerify(context.Context, address.Address, []byte, *types.Signature) bool
WalletDefaultAddress(context.Context) (address.Address, error) WalletDefaultAddress(context.Context) (address.Address, error)
WalletSetDefault(context.Context, address.Address) error WalletSetDefault(context.Context, address.Address) error
WalletExport(context.Context, address.Address) (*types.KeyInfo, error) WalletExport(context.Context, address.Address) (*types.KeyInfo, error)

View File

@ -83,6 +83,7 @@ type FullNodeStruct struct {
WalletBalance func(context.Context, address.Address) (types.BigInt, error) `perm:"read"` WalletBalance func(context.Context, address.Address) (types.BigInt, error) `perm:"read"`
WalletSign func(context.Context, address.Address, []byte) (*types.Signature, error) `perm:"sign"` WalletSign func(context.Context, address.Address, []byte) (*types.Signature, error) `perm:"sign"`
WalletSignMessage func(context.Context, address.Address, *types.Message) (*types.SignedMessage, error) `perm:"sign"` WalletSignMessage func(context.Context, address.Address, *types.Message) (*types.SignedMessage, error) `perm:"sign"`
WalletVerify func(context.Context, address.Address, []byte, *types.Signature) bool `perm:"read"`
WalletDefaultAddress func(context.Context) (address.Address, error) `perm:"write"` WalletDefaultAddress func(context.Context) (address.Address, error) `perm:"write"`
WalletSetDefault func(context.Context, address.Address) error `perm:"admin"` WalletSetDefault func(context.Context, address.Address) error `perm:"admin"`
WalletExport func(context.Context, address.Address) (*types.KeyInfo, error) `perm:"admin"` WalletExport func(context.Context, address.Address) (*types.KeyInfo, error) `perm:"admin"`
@ -311,6 +312,10 @@ func (c *FullNodeStruct) WalletSignMessage(ctx context.Context, k address.Addres
return c.Internal.WalletSignMessage(ctx, k, msg) return c.Internal.WalletSignMessage(ctx, k, msg)
} }
func (c *FullNodeStruct) WalletVerify(ctx context.Context, k address.Address, msg []byte, sig *types.Signature) bool {
return c.Internal.WalletVerify(ctx, k, msg, sig)
}
func (c *FullNodeStruct) WalletDefaultAddress(ctx context.Context) (address.Address, error) { func (c *FullNodeStruct) WalletDefaultAddress(ctx context.Context) (address.Address, error) {
return c.Internal.WalletDefaultAddress(ctx) return c.Internal.WalletDefaultAddress(ctx)
} }

View File

@ -28,6 +28,20 @@ const (
metadataTraceConetxt = "traceContext" metadataTraceConetxt = "traceContext"
) )
// custom CLI error
type ErrCmdFailed struct {
msg string
}
func (e *ErrCmdFailed) Error() string {
return e.msg
}
func NewCliError(s string) error {
return &ErrCmdFailed{s}
}
// ApiConnector returns API instance // ApiConnector returns API instance
type ApiConnector func() api.FullNode type ApiConnector func() api.FullNode

View File

@ -25,6 +25,7 @@ var walletCmd = &cli.Command{
walletGetDefault, walletGetDefault,
walletSetDefault, walletSetDefault,
walletSign, walletSign,
walletVerify,
}, },
} }
@ -277,3 +278,53 @@ var walletSign = &cli.Command{
return nil return nil
}, },
} }
var walletVerify = &cli.Command{
Name: "verify",
Usage: "verify the signature of a message",
ArgsUsage: "<signing address> <hexMessage> <signature>",
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() || cctx.NArg() != 3 {
return fmt.Errorf("must specify signing address, message, and signature to verify")
}
addr, err := address.NewFromString(cctx.Args().First())
if err != nil {
return err
}
msg, err := hex.DecodeString(cctx.Args().Get(1))
if err != nil {
return err
}
sigBytes, err := hex.DecodeString(cctx.Args().Get(2))
if err != nil {
return err
}
sig, err := types.SignatureFromBytes(sigBytes)
if err != nil {
return err
}
if api.WalletVerify(ctx, addr, msg, &sig) {
fmt.Println("valid")
return nil
} else {
fmt.Println("invalid")
return NewCliError("CLI Verify called with invalid signature")
}
},
}

View File

@ -73,7 +73,12 @@ func main() {
Code: trace.StatusCodeFailedPrecondition, Code: trace.StatusCodeFailedPrecondition,
Message: err.Error(), Message: err.Error(),
}) })
_, ok := err.(*lcli.ErrCmdFailed)
if ok {
log.Debugf("%+v", err)
} else {
log.Warnf("%+v", err) log.Warnf("%+v", err)
}
os.Exit(1) os.Exit(1)
} }
} }

View File

@ -2,6 +2,7 @@ package full
import ( import (
"context" "context"
"github.com/filecoin-project/lotus/lib/sigs"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/stmgr"
@ -53,6 +54,10 @@ func (a *WalletAPI) WalletSignMessage(ctx context.Context, k address.Address, ms
}, nil }, nil
} }
func (a *WalletAPI) WalletVerify(ctx context.Context, k address.Address, msg []byte, sig *types.Signature) bool {
return sigs.Verify(sig, k, msg) == nil
}
func (a *WalletAPI) WalletDefaultAddress(ctx context.Context) (address.Address, error) { func (a *WalletAPI) WalletDefaultAddress(ctx context.Context) (address.Address, error) {
return a.Wallet.GetDefault() return a.Wallet.GetDefault()
} }