Integrate keystore with chain/wallet

License: MIT
Signed-off-by: Jakub Sztandera <kubuxu@protonmail.ch>
This commit is contained in:
Jakub Sztandera 2019-07-18 17:41:30 +02:00
parent cb9bf4200c
commit 710f87fdf4
4 changed files with 109 additions and 56 deletions

View File

@ -4,25 +4,36 @@ import (
"encoding/binary"
"fmt"
"sort"
"strings"
"github.com/filecoin-project/go-lotus/chain/address"
"github.com/filecoin-project/go-lotus/chain/types"
"github.com/filecoin-project/go-lotus/lib/bls-signatures"
"github.com/filecoin-project/go-lotus/lib/crypto"
"github.com/minio/blake2b-simd"
"golang.org/x/xerrors"
)
const (
KNamePrefix = "wallet-"
KTSecp256k1 = "secp256k1"
KTBLS = "bls"
)
type Wallet struct {
keys map[address.Address]*KeyInfo
keys map[address.Address]*Key
keystore types.KeyStore
}
func NewWallet() *Wallet {
return &Wallet{keys: make(map[address.Address]*KeyInfo)}
func NewWallet(keystore types.KeyStore) (*Wallet, error) {
w := &Wallet{
keys: make(map[address.Address]*Key),
keystore: keystore,
}
return w, nil
}
type Signature struct {
@ -118,12 +129,21 @@ func (w *Wallet) Sign(addr address.Address, msg []byte) (*Signature, error) {
}
}
func (w *Wallet) findKey(addr address.Address) (*KeyInfo, error) {
ki, ok := w.keys[addr]
if !ok {
return nil, fmt.Errorf("key not for given address not found in wallet")
func (w *Wallet) findKey(addr address.Address) (*Key, error) {
k, ok := w.keys[addr]
if ok {
return k, nil
}
return ki, nil
ki, err := w.keystore.Get(KNamePrefix + addr.String())
if err != nil {
return nil, xerrors.Errorf("getting from keystore: %w", err)
}
k, err = NewKey(ki)
if err != nil {
return nil, xerrors.Errorf("decoding from keystore: %w", err)
}
w.keys[k.Address] = k
return k, nil
}
func (w *Wallet) Export(addr address.Address) ([]byte, error) {
@ -134,74 +154,99 @@ func (w *Wallet) Import(kdata []byte) (address.Address, error) {
panic("nyi")
}
func (w *Wallet) ListAddrs() []address.Address {
var out []address.Address
for a := range w.keys {
out = append(out, a)
func (w *Wallet) ListAddrs() ([]address.Address, error) {
all, err := w.keystore.List()
if err != nil {
return nil, xerrors.Errorf("listing keystore: %w", err)
}
sort.Slice(out, func(i, j int) bool {
return out[i].String() < out[j].String()
})
return out
sort.Strings(all)
out := make([]address.Address, 0, len(all))
for _, a := range all {
if strings.HasPrefix(a, KNamePrefix) {
name := strings.TrimPrefix(a, KNamePrefix)
addr, err := address.NewFromString(name)
if err != nil {
return nil, xerrors.Errorf("converting name to address: %w", err)
}
out = append(out, addr)
}
}
return out, nil
}
func (w *Wallet) GenerateKey(typ string) (address.Address, error) {
var k *Key
switch typ {
case KTSecp256k1:
k, err := crypto.GenerateKey()
priv, err := crypto.GenerateKey()
if err != nil {
return address.Undef, err
}
ki := &KeyInfo{
PrivateKey: k,
Type: typ,
}
addr := ki.Address()
w.keys[addr] = ki
return addr, nil
k, err = NewKey(types.KeyInfo{typ, priv})
if err != nil {
return address.Undef, err
}
case KTBLS:
priv := bls.PrivateKeyGenerate()
ki := &KeyInfo{
PrivateKey: priv[:],
Type: KTBLS,
}
addr := ki.Address()
w.keys[addr] = ki
return addr, nil
default:
return address.Undef, fmt.Errorf("invalid key type: %s", typ)
}
}
type KeyInfo struct {
PrivateKey []byte
Type string
}
func (ki *KeyInfo) Address() address.Address {
switch ki.Type {
case KTSecp256k1:
pub := crypto.PublicKey(ki.PrivateKey)
addr, err := address.NewSecp256k1Address(pub)
var err error
k, err = NewKey(types.KeyInfo{typ, priv[:]})
if err != nil {
panic(err)
return address.Undef, err
}
default:
return address.Undef, xerrors.Errorf("invalid key type: %s", typ)
}
err := w.keystore.Put(KNamePrefix+k.Address.String(), k.KeyInfo)
if err != nil {
return address.Undef, xerrors.Errorf("saving to keystore: %w", err)
}
w.keys[k.Address] = k
return k.Address, nil
}
type Key struct {
types.KeyInfo
PublicKey []byte
Address address.Address
}
func NewKey(keyinfo types.KeyInfo) (*Key, error) {
k := &Key{
KeyInfo: keyinfo,
}
switch k.Type {
case KTSecp256k1:
k.PublicKey = crypto.PublicKey(k.PrivateKey)
var err error
k.Address, err = address.NewSecp256k1Address(k.PublicKey)
if err != nil {
return nil, xerrors.Errorf("converting Secp256k1 to address: %w", err)
}
return addr
case KTBLS:
var pk bls.PrivateKey
copy(pk[:], ki.PrivateKey)
copy(pk[:], k.PrivateKey)
pub := bls.PrivateKeyPublicKey(pk)
a, err := address.NewBLSAddress(pub[:])
k.PublicKey = pub[:]
var err error
k.Address, err = address.NewBLSAddress(k.PublicKey)
if err != nil {
panic(err)
return nil, xerrors.Errorf("converting BLS to address: %w", err)
}
return a
default:
panic("unsupported key type")
return nil, xerrors.Errorf("unknown key type")
}
return k, nil
}

1
go.mod
View File

@ -66,6 +66,7 @@ require (
go4.org v0.0.0-20190313082347-94abd6928b1d // indirect
golang.org/x/sync v0.0.0-20190423024810-112230192c58 // indirect
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522
google.golang.org/appengine v1.4.0 // indirect
gopkg.in/urfave/cli.v2 v2.0.0-20180128182452-d3ae77c26ac8
launchpad.net/gocheck v0.0.0-20140225173054-000000000087 // indirect
)

View File

@ -110,7 +110,7 @@ func (a *API) WalletNew(ctx context.Context, typ string) (address.Address, error
}
func (a *API) WalletList(ctx context.Context) ([]address.Address, error) {
return a.Wallet.ListAddrs(), nil
return a.Wallet.ListAddrs()
}
func (a *API) NetConnect(ctx context.Context, p peer.AddrInfo) error {

View File

@ -24,6 +24,7 @@ import (
"github.com/filecoin-project/go-lotus/api"
"github.com/filecoin-project/go-lotus/chain"
"github.com/filecoin-project/go-lotus/chain/types"
"github.com/filecoin-project/go-lotus/node/config"
"github.com/filecoin-project/go-lotus/node/hello"
"github.com/filecoin-project/go-lotus/node/modules"
@ -213,6 +214,10 @@ func Repo(r repo.Repo) Option {
if err != nil {
return Error(err)
}
kstore, err := lr.KeyStore()
if err != nil {
return Error(err)
}
return Options(
Config(cfg),
@ -227,6 +232,8 @@ func Repo(r repo.Repo) Option {
Override(new(ci.PrivKey), pk),
Override(new(ci.PubKey), ci.PrivKey.GetPublic),
Override(new(peer.ID), peer.IDFromPublicKey),
Override(new(types.KeyStore), kstore),
)
}