lotus/chain/wallet/wallet.go

308 lines
6.2 KiB
Go
Raw Normal View History

2019-07-25 22:15:33 +00:00
package wallet
2019-07-05 14:29:17 +00:00
import (
2019-08-16 04:40:59 +00:00
"context"
2019-11-16 23:41:14 +00:00
"fmt"
2019-07-13 00:41:32 +00:00
"sort"
"strings"
2019-10-08 09:17:03 +00:00
"sync"
2019-07-08 12:51:45 +00:00
bls "github.com/filecoin-project/filecoin-ffi"
2019-07-31 16:58:19 +00:00
2019-10-18 11:39:31 +00:00
logging "github.com/ipfs/go-log"
"github.com/minio/blake2b-simd"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-crypto"
"github.com/filecoin-project/lotus/chain/types"
2019-07-05 14:29:17 +00:00
)
2019-10-18 11:39:31 +00:00
var log = logging.Logger("wallet")
2019-07-05 14:29:17 +00:00
const (
KNamePrefix = "wallet-"
KDefault = "default"
2019-07-05 14:29:17 +00:00
)
type Wallet struct {
keys map[address.Address]*Key
keystore types.KeyStore
2019-10-08 09:17:03 +00:00
lk sync.Mutex
2019-07-05 14:29:17 +00:00
}
func NewWallet(keystore types.KeyStore) (*Wallet, error) {
w := &Wallet{
keys: make(map[address.Address]*Key),
keystore: keystore,
}
return w, nil
2019-07-05 14:29:17 +00:00
}
2019-11-28 22:50:58 +00:00
func KeyWallet(keys ...*Key) *Wallet {
m := make(map[address.Address]*Key)
for _, key := range keys {
m[key.Address] = key
}
return &Wallet{
keys: m,
}
}
2019-08-16 04:40:59 +00:00
func (w *Wallet) Sign(ctx context.Context, addr address.Address, msg []byte) (*types.Signature, error) {
2019-07-05 14:29:17 +00:00
ki, err := w.findKey(addr)
if err != nil {
return nil, err
}
2019-08-06 23:08:34 +00:00
if ki == nil {
return nil, xerrors.Errorf("signing using key '%s': %w", addr.String(), types.ErrKeyInfoNotFound)
2019-08-06 23:08:34 +00:00
}
2019-07-05 14:29:17 +00:00
switch ki.Type {
case types.KTSecp256k1:
2019-07-05 14:29:17 +00:00
b2sum := blake2b.Sum256(msg)
sig, err := crypto.Sign(ki.PrivateKey, b2sum[:])
if err != nil {
return nil, err
}
return &types.Signature{
Type: types.KTSecp256k1,
2019-07-05 14:29:17 +00:00
Data: sig,
}, nil
case types.KTBLS:
2019-07-05 14:29:17 +00:00
var pk bls.PrivateKey
copy(pk[:], ki.PrivateKey)
sig := bls.PrivateKeySign(pk, msg)
return &types.Signature{
Type: types.KTBLS,
2019-07-05 14:29:17 +00:00
Data: sig[:],
}, nil
default:
2019-11-16 23:41:14 +00:00
return nil, fmt.Errorf("cannot sign with unsupported key type: %q", ki.Type)
2019-07-05 14:29:17 +00:00
}
}
func (w *Wallet) findKey(addr address.Address) (*Key, error) {
2019-10-08 09:17:03 +00:00
w.lk.Lock()
defer w.lk.Unlock()
k, ok := w.keys[addr]
if ok {
return k, nil
}
2019-11-28 22:50:58 +00:00
if w.keystore == nil {
log.Warn("findKey didn't find the key in in-memory wallet")
return nil, nil
}
ki, err := w.keystore.Get(KNamePrefix + addr.String())
if err != nil {
if xerrors.Is(err, types.ErrKeyInfoNotFound) {
2019-07-31 16:58:19 +00:00
return nil, 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)
2019-07-05 14:29:17 +00:00
}
w.keys[k.Address] = k
return k, nil
2019-07-05 14:29:17 +00:00
}
2019-10-08 09:46:36 +00:00
func (w *Wallet) Export(addr address.Address) (*types.KeyInfo, error) {
2019-10-08 09:17:03 +00:00
k, err := w.findKey(addr)
if err != nil {
return nil, xerrors.Errorf("failed to find key to export: %w", err)
}
2019-10-08 09:46:36 +00:00
return &k.KeyInfo, nil
2019-07-05 14:29:17 +00:00
}
2019-10-08 09:46:36 +00:00
func (w *Wallet) Import(ki *types.KeyInfo) (address.Address, error) {
w.lk.Lock()
defer w.lk.Unlock()
2019-10-08 09:17:03 +00:00
2019-10-08 09:46:36 +00:00
k, err := NewKey(*ki)
2019-10-08 09:17:03 +00:00
if err != nil {
return address.Undef, xerrors.Errorf("failed to make key: %w", err)
}
2019-10-08 09:46:36 +00:00
if err := w.keystore.Put(KNamePrefix+k.Address.String(), k.KeyInfo); err != nil {
return address.Undef, xerrors.Errorf("saving to keystore: %w", err)
}
2019-10-08 09:17:03 +00:00
return k.Address, nil
2019-07-05 14:29:17 +00:00
}
func (w *Wallet) ListAddrs() ([]address.Address, error) {
all, err := w.keystore.List()
if err != nil {
return nil, xerrors.Errorf("listing keystore: %w", err)
}
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)
}
2019-07-13 00:41:32 +00:00
}
return out, nil
2019-07-13 00:41:32 +00:00
}
func (w *Wallet) GetDefault() (address.Address, error) {
w.lk.Lock()
defer w.lk.Unlock()
ki, err := w.keystore.Get(KDefault)
if err != nil {
return address.Undef, xerrors.Errorf("failed to get default key: %w", err)
}
k, err := NewKey(ki)
if err != nil {
return address.Undef, xerrors.Errorf("failed to read default key from keystore: %w", err)
}
return k.Address, nil
}
func (w *Wallet) SetDefault(a address.Address) error {
w.lk.Lock()
defer w.lk.Unlock()
ki, err := w.keystore.Get(KNamePrefix + a.String())
if err != nil {
return err
}
2019-10-18 11:39:31 +00:00
if err := w.keystore.Delete(KDefault); err != nil {
if !xerrors.Is(err, types.ErrKeyInfoNotFound) {
log.Warnf("failed to unregister current default key: %s", err)
}
}
if err := w.keystore.Put(KDefault, ki); err != nil {
return err
}
return nil
}
func GenerateKey(typ string) (*Key, error) {
2019-07-05 14:29:17 +00:00
switch typ {
case types.KTSecp256k1:
priv, err := crypto.GenerateKey()
2019-07-05 14:29:17 +00:00
if err != nil {
return nil, err
2019-07-05 14:29:17 +00:00
}
ki := types.KeyInfo{
Type: typ,
PrivateKey: priv,
}
2019-07-05 14:29:17 +00:00
return NewKey(ki)
case types.KTBLS:
2019-07-05 14:29:17 +00:00
priv := bls.PrivateKeyGenerate()
ki := types.KeyInfo{
Type: typ,
PrivateKey: priv[:],
}
2019-07-05 14:29:17 +00:00
return NewKey(ki)
2019-07-05 14:29:17 +00:00
default:
return nil, xerrors.Errorf("invalid key type: %s", typ)
}
}
func (w *Wallet) GenerateKey(typ string) (address.Address, error) {
2019-10-08 09:17:03 +00:00
w.lk.Lock()
defer w.lk.Unlock()
k, err := GenerateKey(typ)
if err != nil {
return address.Undef, err
}
if err := w.keystore.Put(KNamePrefix+k.Address.String(), k.KeyInfo); err != nil {
return address.Undef, xerrors.Errorf("saving to keystore: %w", err)
2019-07-05 14:29:17 +00:00
}
w.keys[k.Address] = k
_, err = w.keystore.Get(KDefault)
if err != nil {
if !xerrors.Is(err, types.ErrKeyInfoNotFound) {
return address.Undef, err
}
if err := w.keystore.Put(KDefault, k.KeyInfo); err != nil {
return address.Undef, xerrors.Errorf("failed to set new key as default: %w", err)
}
}
return k.Address, nil
2019-07-05 14:29:17 +00:00
}
func (w *Wallet) HasKey(addr address.Address) (bool, error) {
k, err := w.findKey(addr)
if err != nil {
return false, err
}
return k != nil, nil
}
type Key struct {
types.KeyInfo
2019-07-05 14:29:17 +00:00
PublicKey []byte
Address address.Address
2019-07-05 14:29:17 +00:00
}
func NewKey(keyinfo types.KeyInfo) (*Key, error) {
k := &Key{
KeyInfo: keyinfo,
}
switch k.Type {
case types.KTSecp256k1:
k.PublicKey = crypto.PublicKey(k.PrivateKey)
var err error
k.Address, err = address.NewSecp256k1Address(k.PublicKey)
2019-07-05 14:29:17 +00:00
if err != nil {
return nil, xerrors.Errorf("converting Secp256k1 to address: %w", err)
2019-07-05 14:29:17 +00:00
}
case types.KTBLS:
2019-07-05 14:29:17 +00:00
var pk bls.PrivateKey
copy(pk[:], k.PrivateKey)
2019-07-05 14:29:17 +00:00
pub := bls.PrivateKeyPublicKey(pk)
k.PublicKey = pub[:]
var err error
k.Address, err = address.NewBLSAddress(k.PublicKey)
2019-07-05 14:29:17 +00:00
if err != nil {
return nil, xerrors.Errorf("converting BLS to address: %w", err)
2019-07-05 14:29:17 +00:00
}
2019-07-05 14:29:17 +00:00
default:
return nil, xerrors.Errorf("unknown key type")
2019-07-05 14:29:17 +00:00
}
return k, nil
2019-07-05 14:36:08 +00:00
}