walletrpc: use bytes to represent master key fingerprint

The integer representation is not common and using bytes allows users to
easily confirm whether their master key fingerprint is correct.
This commit is contained in:
Wilmer Paulino 2021-05-04 16:08:57 -07:00
parent f7b130b5ca
commit e079a9583c
No known key found for this signature in database
GPG Key ID: 6DF57B9F9514972F
5 changed files with 54 additions and 30 deletions

@ -4,7 +4,6 @@ package main
import (
"encoding/base64"
"encoding/binary"
"encoding/hex"
"encoding/json"
"errors"
@ -988,13 +987,14 @@ func importAccount(ctx *cli.Context) error {
return err
}
var masterKeyFingerprint uint32
var mkfpBytes []byte
if ctx.IsSet("master_key_fingerprint") {
mkfp, err := hex.DecodeString(ctx.String("master_key_fingerprint"))
mkfpBytes, err = hex.DecodeString(
ctx.String("master_key_fingerprint"),
)
if err != nil {
return fmt.Errorf("invalid master key fingerprint: %v", err)
}
masterKeyFingerprint = binary.LittleEndian.Uint32(mkfp)
}
walletClient, cleanUp := getWalletClient(ctx)
@ -1004,7 +1004,7 @@ func importAccount(ctx *cli.Context) error {
req := &walletrpc.ImportAccountRequest{
Name: ctx.Args().Get(1),
ExtendedPublicKey: ctx.Args().Get(0),
MasterKeyFingerprint: masterKeyFingerprint,
MasterKeyFingerprint: mkfpBytes,
AddressType: addrType,
DryRun: dryRun,
}

@ -723,8 +723,9 @@ type Account struct {
//
//The fingerprint of the root key from which the account public key was
//derived from. This will always be zero for the default imported account in
//which single public keys are imported into.
MasterKeyFingerprint uint32 `protobuf:"varint,4,opt,name=master_key_fingerprint,json=masterKeyFingerprint,proto3" json:"master_key_fingerprint,omitempty"`
//which single public keys are imported into. The bytes are in big-endian
//order.
MasterKeyFingerprint []byte `protobuf:"bytes,4,opt,name=master_key_fingerprint,json=masterKeyFingerprint,proto3" json:"master_key_fingerprint,omitempty"`
//
//The derivation path corresponding to the account public key. This will
//always be empty for the default imported account in which single public keys
@ -797,11 +798,11 @@ func (x *Account) GetExtendedPublicKey() string {
return ""
}
func (x *Account) GetMasterKeyFingerprint() uint32 {
func (x *Account) GetMasterKeyFingerprint() []byte {
if x != nil {
return x.MasterKeyFingerprint
}
return 0
return nil
}
func (x *Account) GetDerivationPath() string {
@ -951,8 +952,9 @@ type ImportAccountRequest struct {
//
//The fingerprint of the root key (also known as the key with derivation path
//m/) from which the account public key was derived from. This may be required
//by some hardware wallets for proper identification and signing.
MasterKeyFingerprint uint32 `protobuf:"varint,3,opt,name=master_key_fingerprint,json=masterKeyFingerprint,proto3" json:"master_key_fingerprint,omitempty"`
//by some hardware wallets for proper identification and signing. The bytes
//must be in big-endian order.
MasterKeyFingerprint []byte `protobuf:"bytes,3,opt,name=master_key_fingerprint,json=masterKeyFingerprint,proto3" json:"master_key_fingerprint,omitempty"`
//
//An address type is only required when the extended account public key has a
//legacy version (xpub, tpub, etc.), such that the wallet cannot detect what
@ -1013,11 +1015,11 @@ func (x *ImportAccountRequest) GetExtendedPublicKey() string {
return ""
}
func (x *ImportAccountRequest) GetMasterKeyFingerprint() uint32 {
func (x *ImportAccountRequest) GetMasterKeyFingerprint() []byte {
if x != nil {
return x.MasterKeyFingerprint
}
return 0
return nil
}
func (x *ImportAccountRequest) GetAddressType() AddressType {
@ -2841,7 +2843,7 @@ var file_walletrpc_walletkit_proto_rawDesc = []byte{
0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x65, 0x78, 0x74,
0x65, 0x6e, 0x64, 0x65, 0x64, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x34,
0x0a, 0x16, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x66, 0x69, 0x6e,
0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x14,
0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x14,
0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70,
0x72, 0x69, 0x6e, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x65, 0x72, 0x69, 0x76, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64,
@ -2872,7 +2874,7 @@ var file_walletrpc_walletkit_proto_rawDesc = []byte{
0x52, 0x11, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63,
0x4b, 0x65, 0x79, 0x12, 0x34, 0x0a, 0x16, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x6b, 0x65,
0x79, 0x5f, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x18, 0x03, 0x20,
0x01, 0x28, 0x0d, 0x52, 0x14, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x46, 0x69,
0x01, 0x28, 0x0c, 0x52, 0x14, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x46, 0x69,
0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x12, 0x39, 0x0a, 0x0c, 0x61, 0x64, 0x64,
0x72, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32,
0x16, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x72,

@ -324,9 +324,10 @@ message Account {
/*
The fingerprint of the root key from which the account public key was
derived from. This will always be zero for the default imported account in
which single public keys are imported into.
which single public keys are imported into. The bytes are in big-endian
order.
*/
uint32 master_key_fingerprint = 4;
bytes master_key_fingerprint = 4;
/*
The derivation path corresponding to the account public key. This will
@ -377,9 +378,10 @@ message ImportAccountRequest {
/*
The fingerprint of the root key (also known as the key with derivation path
m/) from which the account public key was derived from. This may be required
by some hardware wallets for proper identification and signing.
by some hardware wallets for proper identification and signing. The bytes
must be in big-endian order.
*/
uint32 master_key_fingerprint = 3;
bytes master_key_fingerprint = 3;
/*
An address type is only required when the extended account public key has a

@ -861,9 +861,9 @@
"description": "The public key backing the account that all keys are derived from\nrepresented as an extended key. This will always be empty for the default\nimported account in which single public keys are imported into."
},
"master_key_fingerprint": {
"type": "integer",
"format": "int64",
"description": "The fingerprint of the root key from which the account public key was\nderived from. This will always be zero for the default imported account in\nwhich single public keys are imported into."
"type": "string",
"format": "byte",
"description": "The fingerprint of the root key from which the account public key was\nderived from. This will always be zero for the default imported account in\nwhich single public keys are imported into. The bytes are in big-endian\norder."
},
"derivation_path": {
"type": "string",
@ -1057,9 +1057,9 @@
"description": "A public key that corresponds to a wallet account represented as an extended\nkey. It must conform to a derivation path of the form\nm/purpose'/coin_type'/account'."
},
"master_key_fingerprint": {
"type": "integer",
"format": "int64",
"description": "The fingerprint of the root key (also known as the key with derivation path\nm/) from which the account public key was derived from. This may be required\nby some hardware wallets for proper identification and signing."
"type": "string",
"format": "byte",
"description": "The fingerprint of the root key (also known as the key with derivation path\nm/) from which the account public key was derived from. This may be required\nby some hardware wallets for proper identification and signing. The bytes\nmust be in big-endian order."
},
"address_type": {
"$ref": "#/definitions/walletrpcAddressType",

@ -5,6 +5,7 @@ package walletrpc
import (
"bytes"
"context"
"encoding/binary"
"errors"
"fmt"
"io/ioutil"
@ -1253,8 +1254,8 @@ func marshalWalletAccount(account *waddrmgr.AccountProperties) (*Account, error)
break
}
switch account.AddrSchema {
case &waddrmgr.KeyScopeBIP0049AddrSchema:
switch *account.AddrSchema {
case waddrmgr.KeyScopeBIP0049AddrSchema:
addrType = AddressType_NESTED_WITNESS_PUBKEY_HASH
default:
return nil, fmt.Errorf("unsupported address schema %v",
@ -1283,7 +1284,13 @@ func marshalWalletAccount(account *waddrmgr.AccountProperties) (*Account, error)
nonHardenedIndex := account.AccountPubKey.ChildIndex() -
hdkeychain.HardenedKeyStart
rpcAccount.ExtendedPublicKey = account.AccountPubKey.String()
rpcAccount.MasterKeyFingerprint = account.MasterKeyFingerprint
if account.MasterKeyFingerprint != 0 {
var mkfp [4]byte
binary.BigEndian.PutUint32(
mkfp[:], account.MasterKeyFingerprint,
)
rpcAccount.MasterKeyFingerprint = mkfp[:]
}
rpcAccount.DerivationPath = fmt.Sprintf("%v/%v'",
account.KeyScope, nonHardenedIndex)
}
@ -1396,14 +1403,27 @@ func (w *WalletKit) ImportAccount(ctx context.Context,
if err != nil {
return nil, err
}
var mkfp uint32
switch len(req.MasterKeyFingerprint) {
// No master key fingerprint provided, which is fine as it's not
// required.
case 0:
// Expected length.
case 4:
mkfp = binary.BigEndian.Uint32(req.MasterKeyFingerprint)
default:
return nil, errors.New("invalid length for master key " +
"fingerprint, expected 4 bytes in big-endian")
}
addrType, err := parseAddrType(req.AddressType, false)
if err != nil {
return nil, err
}
accountProps, extAddrs, intAddrs, err := w.cfg.Wallet.ImportAccount(
req.Name, accountPubKey, req.MasterKeyFingerprint, addrType,
req.DryRun,
req.Name, accountPubKey, mkfp, addrType, req.DryRun,
)
if err != nil {
return nil, err