WIP: adding in ledger support
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
This commit is contained in:
parent
40b2e2d0c1
commit
b35f9b56b4
@ -1249,6 +1249,9 @@ func (mp *MessagePool) Updates(ctx context.Context) (<-chan api.MpoolUpdate, err
|
||||
}
|
||||
|
||||
func (mp *MessagePool) loadLocal() error {
|
||||
return nil
|
||||
// TODO: this causes super slow startup...
|
||||
|
||||
res, err := mp.localMsgs.Query(query.Query{})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("query local messages: %w", err)
|
||||
|
139
chain/wallet/ledger/ledger.go
Normal file
139
chain/wallet/ledger/ledger.go
Normal file
@ -0,0 +1,139 @@
|
||||
package ledgerwallet
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/ipfs/go-datastore"
|
||||
"github.com/ipfs/go-datastore/query"
|
||||
ledgerfil "github.com/whyrusleeping/ledger-filecoin-go"
|
||||
)
|
||||
|
||||
type LedgerWallet struct {
|
||||
ds datastore.Datastore
|
||||
}
|
||||
|
||||
func NewWallet(ds datastore.Datastore) *LedgerWallet {
|
||||
return &LedgerWallet{ds}
|
||||
}
|
||||
|
||||
type LedgerKeyInfo struct {
|
||||
Address address.Address
|
||||
Path []uint32
|
||||
}
|
||||
|
||||
var _ (api.WalletAPI) = (*LedgerWallet)(nil)
|
||||
|
||||
func (lw LedgerWallet) WalletSign(ctx context.Context, signer address.Address, toSign []byte, meta api.MsgMeta) (*crypto.Signature, error) {
|
||||
ki, err := lw.getKeyInfo(signer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fl, err := ledgerfil.FindLedgerFilecoinApp()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer fl.Close()
|
||||
if meta.Type != api.MTChainMsg {
|
||||
return nil, fmt.Errorf("ledger can only sign chain messages")
|
||||
}
|
||||
|
||||
// TODO: assert meta matches the 'toSign' bits
|
||||
|
||||
sig, err := fl.SignSECP256K1(ki.Path, meta.Extra)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &crypto.Signature{
|
||||
Type: crypto.SigTypeSecp256k1,
|
||||
Data: sig.SignatureBytes(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (lw LedgerWallet) getKeyInfo(addr address.Address) (*LedgerKeyInfo, error) {
|
||||
kib, err := lw.ds.Get(keyForAddr(addr))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var out LedgerKeyInfo
|
||||
if err := json.Unmarshal(kib, &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
func (lw LedgerWallet) WalletDelete(ctx context.Context, k address.Address) error {
|
||||
return lw.ds.Delete(keyForAddr(k))
|
||||
}
|
||||
|
||||
func (lw LedgerWallet) WalletExport(ctx context.Context, k address.Address) (*types.KeyInfo, error) {
|
||||
return nil, fmt.Errorf("cannot export keys from ledger wallets")
|
||||
}
|
||||
|
||||
func (lw LedgerWallet) WalletHas(ctx context.Context, k address.Address) (bool, error) {
|
||||
_, err := lw.ds.Get(keyForAddr(k))
|
||||
if err == nil {
|
||||
return true, nil
|
||||
}
|
||||
if err == datastore.ErrNotFound {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
|
||||
func (lw LedgerWallet) WalletImport(ctx context.Context, kinfo *types.KeyInfo) (address.Address, error) {
|
||||
var ki LedgerKeyInfo
|
||||
if err := json.Unmarshal(kinfo.PrivateKey, &ki); err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
if ki.Address == address.Undef {
|
||||
return address.Undef, fmt.Errorf("no address given in imported key info")
|
||||
}
|
||||
|
||||
if err := lw.ds.Put(keyForAddr(ki.Address), kinfo.PrivateKey); err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
return ki.Address, nil
|
||||
}
|
||||
|
||||
func (lw LedgerWallet) WalletList(ctx context.Context) ([]address.Address, error) {
|
||||
res, err := lw.ds.Query(query.Query{Prefix: "ledgerkey/"})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var out []address.Address
|
||||
for {
|
||||
res, ok := res.NextSync()
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
|
||||
var ki LedgerKeyInfo
|
||||
if err := json.Unmarshal(res.Value, &ki); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out = append(out, ki.Address)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (lw LedgerWallet) WalletNew(ctx context.Context, t crypto.SigType) (address.Address, error) {
|
||||
return address.Undef, fmt.Errorf("cannot create new address on ledger")
|
||||
}
|
||||
|
||||
func keyForAddr(addr address.Address) datastore.Key {
|
||||
return datastore.NewKey("ledgerkey/" + addr.String())
|
||||
}
|
205
cmd/lotus-shed/ledger.go
Normal file
205
cmd/lotus-shed/ledger.go
Normal file
@ -0,0 +1,205 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
ledgerwallet "github.com/filecoin-project/lotus/chain/wallet/ledger"
|
||||
"github.com/urfave/cli/v2"
|
||||
ledgerfil "github.com/whyrusleeping/ledger-filecoin-go"
|
||||
)
|
||||
|
||||
var ledgerCmd = &cli.Command{
|
||||
Name: "ledger",
|
||||
Usage: "Ledger interactions",
|
||||
Flags: []cli.Flag{},
|
||||
Subcommands: []*cli.Command{
|
||||
ledgerListAddressesCmd,
|
||||
ledgerKeyInfoCmd,
|
||||
ledgerSignTestCmd,
|
||||
},
|
||||
}
|
||||
|
||||
var ledgerListAddressesCmd = &cli.Command{
|
||||
Name: "list",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
|
||||
fl, err := ledgerfil.FindLedgerFilecoinApp()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < 20; i++ {
|
||||
p := []uint32{0x80000000 + 44, 0x80000000 + 461, 0x80000000, 0, uint32(i)}
|
||||
pubk, err := fl.GetPublicKeySECP256K1(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
addr, err := address.NewSecp256k1Address(pubk)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("%s: %s\n", addr, printHDPath(p))
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func parseHDPath(s string) ([]uint32, error) {
|
||||
parts := strings.Split(s, "/")
|
||||
if parts[0] != "m" {
|
||||
return nil, fmt.Errorf("expected HD path to start with 'm'")
|
||||
}
|
||||
|
||||
var out []uint32
|
||||
for _, p := range parts[1:] {
|
||||
var hard bool
|
||||
if strings.HasSuffix(p, "'") {
|
||||
p = p[:len(p)-1]
|
||||
hard = true
|
||||
}
|
||||
|
||||
v, err := strconv.ParseUint(p, 10, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v >= 0x80000000 {
|
||||
return nil, fmt.Errorf("path element %s too large", p)
|
||||
}
|
||||
|
||||
if hard {
|
||||
v += 0x80000000
|
||||
}
|
||||
out = append(out, uint32(v))
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func printHDPath(pth []uint32) string {
|
||||
s := "m/"
|
||||
for _, p := range pth {
|
||||
var hard bool
|
||||
if p >= 0x80000000 {
|
||||
p -= 0x80000000
|
||||
}
|
||||
s += fmt.Sprint(p)
|
||||
if hard {
|
||||
s += "'"
|
||||
}
|
||||
s += "/"
|
||||
}
|
||||
|
||||
return strings.TrimRight(s, "/")
|
||||
}
|
||||
|
||||
func numlist(p []uint32) string {
|
||||
var out []string
|
||||
for _, v := range p {
|
||||
out = append(out, fmt.Sprint(v))
|
||||
}
|
||||
return strings.Join(out, ",")
|
||||
}
|
||||
|
||||
var ledgerKeyInfoCmd = &cli.Command{
|
||||
Name: "key-info",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if !cctx.Args().Present() {
|
||||
return cli.ShowCommandHelp(cctx, cctx.Command.Name)
|
||||
}
|
||||
|
||||
fl, err := ledgerfil.FindLedgerFilecoinApp()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p, err := parseHDPath(cctx.Args().First())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pubk, _, addr, err := fl.GetAddressPubKeySECP256K1(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(addr)
|
||||
fmt.Println(pubk)
|
||||
|
||||
a, err := address.NewFromString(addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var pd ledgerwallet.LedgerKeyInfo
|
||||
pd.Address = a
|
||||
pd.Path = p
|
||||
|
||||
b, err := json.Marshal(pd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var ki types.KeyInfo
|
||||
ki.Type = wallet.KTSecp256k1
|
||||
ki.PrivateKey = b
|
||||
|
||||
out, err := json.Marshal(ki)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(string(out))
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var ledgerSignTestCmd = &cli.Command{
|
||||
Name: "sign",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if !cctx.Args().Present() {
|
||||
return cli.ShowCommandHelp(cctx, cctx.Command.Name)
|
||||
}
|
||||
|
||||
fl, err := ledgerfil.FindLedgerFilecoinApp()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p, err := parseHDPath(cctx.Args().First())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
addr, err := address.NewFromString("f1xc3hws5n6y5m3m44gzb3gyjzhups6wzmhe663ji")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m := &types.Message{
|
||||
To: addr,
|
||||
From: addr,
|
||||
}
|
||||
|
||||
b, err := m.ToStorageBlock()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sig, err := fl.SignSECP256K1(p, b.RawData())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(sig.SignatureBytes())
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
@ -41,6 +41,7 @@ func main() {
|
||||
syncCmd,
|
||||
stateTreePruneCmd,
|
||||
datastoreCmd,
|
||||
ledgerCmd,
|
||||
}
|
||||
|
||||
app := &cli.App{
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
"github.com/filecoin-project/go-jsonrpc"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
ledgerwallet "github.com/filecoin-project/lotus/chain/wallet/ledger"
|
||||
lcli "github.com/filecoin-project/lotus/cli"
|
||||
"github.com/filecoin-project/lotus/lib/lotuslog"
|
||||
"github.com/filecoin-project/lotus/node/repo"
|
||||
@ -98,6 +99,14 @@ var runCmd = &cli.Command{
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_ = w
|
||||
|
||||
ds, err := lr.Datastore("/metadata")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lw := ledgerwallet.NewWallet(ds)
|
||||
|
||||
address := cctx.String("listen")
|
||||
mux := mux.NewRouter()
|
||||
@ -105,7 +114,7 @@ var runCmd = &cli.Command{
|
||||
log.Info("Setting up API endpoint at " + address)
|
||||
|
||||
rpcServer := jsonrpc.NewServer()
|
||||
rpcServer.Register("Filecoin", &LoggedWallet{under: w})
|
||||
rpcServer.Register("Filecoin", &LoggedWallet{under: lw})
|
||||
|
||||
mux.Handle("/rpc/v0", rpcServer)
|
||||
mux.PathPrefix("/").Handler(http.DefaultServeMux) // pprof
|
||||
|
1
go.mod
1
go.mod
@ -120,6 +120,7 @@ require (
|
||||
github.com/urfave/cli/v2 v2.2.0
|
||||
github.com/whyrusleeping/bencher v0.0.0-20190829221104-bb6607aa8bba
|
||||
github.com/whyrusleeping/cbor-gen v0.0.0-20200826160007-0b9f6c5fb163
|
||||
github.com/whyrusleeping/ledger-filecoin-go v0.9.1-0.20201010031517-c3dcc1bddce4
|
||||
github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7
|
||||
github.com/whyrusleeping/pubsub v0.0.0-20131020042734-02de8aa2db3d
|
||||
github.com/xorcare/golden v0.6.1-0.20191112154924-b87f686d7542
|
||||
|
7
go.sum
7
go.sum
@ -1422,6 +1422,8 @@ github.com/whyrusleeping/go-smux-multiplex v3.0.16+incompatible/go.mod h1:34LEDb
|
||||
github.com/whyrusleeping/go-smux-multistream v2.0.2+incompatible/go.mod h1:dRWHHvc4HDQSHh9gbKEBbUZ+f2Q8iZTPG3UOGYODxSQ=
|
||||
github.com/whyrusleeping/go-smux-yamux v2.0.8+incompatible/go.mod h1:6qHUzBXUbB9MXmw3AUdB52L8sEb/hScCqOdW2kj/wuI=
|
||||
github.com/whyrusleeping/go-smux-yamux v2.0.9+incompatible/go.mod h1:6qHUzBXUbB9MXmw3AUdB52L8sEb/hScCqOdW2kj/wuI=
|
||||
github.com/whyrusleeping/ledger-filecoin-go v0.9.1-0.20201010031517-c3dcc1bddce4 h1:NwiwjQDB3CzQ5XH0rdMh1oQqzJH7O2PSLWxif/w3zsY=
|
||||
github.com/whyrusleeping/ledger-filecoin-go v0.9.1-0.20201010031517-c3dcc1bddce4/go.mod h1:K+EVq8d5QcQ2At5VECsA+SNZvWefyBXh8TnIsxo1OvQ=
|
||||
github.com/whyrusleeping/mafmt v1.2.8/go.mod h1:faQJFPbLSxzD9xpA02ttW/tS9vZykNvXwGvqIpk20FA=
|
||||
github.com/whyrusleeping/mdns v0.0.0-20180901202407-ef14215e6b30/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4=
|
||||
github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4=
|
||||
@ -1443,6 +1445,10 @@ github.com/xorcare/golden v0.6.1-0.20191112154924-b87f686d7542 h1:oWgZJmC1DorFZD
|
||||
github.com/xorcare/golden v0.6.1-0.20191112154924-b87f686d7542/go.mod h1:7T39/ZMvaSEZlBPoYfVFmsBLmUl3uz9IuzWj/U6FtvQ=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/zondax/hid v0.9.0 h1:eiT3P6vNxAEVxXMw66eZUAAnU2zD33JBkfG/EnfAKl8=
|
||||
github.com/zondax/hid v0.9.0/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM=
|
||||
github.com/zondax/ledger-go v0.12.1 h1:hYRcyznPRJp+5mzF2sazTLP2nGvGjYDD2VzhHhFomLU=
|
||||
github.com/zondax/ledger-go v0.12.1/go.mod h1:KatxXrVDzgWwbssUWsF5+cOJHXPvzQ09YSlzGNuhOEo=
|
||||
go.dedis.ch/fixbuf v1.0.3 h1:hGcV9Cd/znUxlusJ64eAlExS+5cJDIyTyEG+otu5wQs=
|
||||
go.dedis.ch/fixbuf v1.0.3/go.mod h1:yzJMt34Wa5xD37V5RTdmp38cz3QhMagdGoem9anUalw=
|
||||
go.dedis.ch/kyber/v3 v3.0.4/go.mod h1:OzvaEnPvKlyrWyp3kGXlFdp7ap1VC6RkZDTaPikqhsQ=
|
||||
@ -1515,6 +1521,7 @@ golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
|
Loading…
Reference in New Issue
Block a user