Skip to content

Commit 238300b

Browse files
committed
Merge #8323: Add HD keypath to CKeyMetadata, report metadata in validateaddress
7945088 [Wallet] comsetic non-code changes for the HD feature (Jonas Schnelli) 68d7682 [Wallet] ensure CKeyMetadata.hdMasterKeyID will be cleared during SetNull() (Jonas Schnelli) f708085 [QA] extend wallet-hd test to cover HD metadata (Jonas Schnelli) 986c223 [Wallet] print hd masterkeyid in getwalletinfo (Jonas Schnelli) b1c7b24 [Wallet] report optional HDKeypath/HDMasterKeyId in validateaddress (Jonas Schnelli) 5b95dd2 [Wallet] extend CKeyMetadata with HD keypath (Jonas Schnelli)
2 parents 3730393 + 7945088 commit 238300b

File tree

6 files changed

+43
-7
lines changed

6 files changed

+43
-7
lines changed

qa/rpc-tests/wallet-hd.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ def setup_network(self):
3030
def run_test (self):
3131
tmpdir = self.options.tmpdir
3232

33+
# Make sure we use hd, keep masterkeyid
34+
masterkeyid = self.nodes[1].getwalletinfo()['masterkeyid']
35+
assert_equal(len(masterkeyid), 40)
36+
3337
# Import a non-HD private key in the HD wallet
3438
non_hd_add = self.nodes[0].getnewaddress()
3539
self.nodes[1].importprivkey(self.nodes[0].dumpprivkey(non_hd_add))
@@ -43,8 +47,11 @@ def run_test (self):
4347
self.nodes[0].generate(101)
4448
hd_add = None
4549
num_hd_adds = 300
46-
for _ in range(num_hd_adds):
50+
for i in range(num_hd_adds):
4751
hd_add = self.nodes[1].getnewaddress()
52+
hd_info = self.nodes[1].validateaddress(hd_add)
53+
assert_equal(hd_info["hdkeypath"], "m/0'/0'/"+str(i+1)+"'")
54+
assert_equal(hd_info["hdmasterkeyid"], masterkeyid)
4855
self.nodes[0].sendtoaddress(hd_add, 1)
4956
self.nodes[0].generate(1)
5057
self.nodes[0].sendtoaddress(non_hd_add, 1)
@@ -64,6 +71,9 @@ def run_test (self):
6471
hd_add_2 = None
6572
for _ in range(num_hd_adds):
6673
hd_add_2 = self.nodes[1].getnewaddress()
74+
hd_info_2 = self.nodes[1].validateaddress(hd_add_2)
75+
assert_equal(hd_info_2["hdkeypath"], "m/0'/0'/"+str(_+1)+"'")
76+
assert_equal(hd_info_2["hdmasterkeyid"], masterkeyid)
6777
assert_equal(hd_add, hd_add_2)
6878

6979
# Needs rescan

src/rpc/misc.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,8 @@ UniValue validateaddress(const UniValue& params, bool fHelp)
166166
" \"pubkey\" : \"publickeyhex\", (string) The hex value of the raw public key\n"
167167
" \"iscompressed\" : true|false, (boolean) If the address is compressed\n"
168168
" \"account\" : \"account\" (string) DEPRECATED. The account associated with the address, \"\" is the default account\n"
169+
" \"hdkeypath\" : \"keypath\" (string, optional) The HD keypath if the key is HD and available\n"
170+
" \"hdmasterkeyid\" : \"<hash160>\" (string, optional) The Hash160 of the HD master pubkey\n"
169171
"}\n"
170172
"\nExamples:\n"
171173
+ HelpExampleCli("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
@@ -200,6 +202,12 @@ UniValue validateaddress(const UniValue& params, bool fHelp)
200202
ret.pushKVs(detail);
201203
if (pwalletMain && pwalletMain->mapAddressBook.count(dest))
202204
ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest].name));
205+
CKeyID keyID;
206+
if (pwalletMain && address.GetKeyID(keyID) && pwalletMain->mapKeyMetadata.count(keyID) && !pwalletMain->mapKeyMetadata[keyID].hdKeypath.empty())
207+
{
208+
ret.push_back(Pair("hdkeypath", pwalletMain->mapKeyMetadata[keyID].hdKeypath));
209+
ret.push_back(Pair("hdmasterkeyid", pwalletMain->mapKeyMetadata[keyID].hdMasterKeyID.GetHex()));
210+
}
203211
#endif
204212
}
205213
return ret;

src/wallet/rpcwallet.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2269,6 +2269,7 @@ UniValue getwalletinfo(const UniValue& params, bool fHelp)
22692269
" \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n"
22702270
" \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n"
22712271
" \"paytxfee\": x.xxxx, (numeric) the transaction fee configuration, set in " + CURRENCY_UNIT + "/kB\n"
2272+
" \"masterkeyid\": \"<hash160>\", (string) the Hash160 of the HD master pubkey\n"
22722273
"}\n"
22732274
"\nExamples:\n"
22742275
+ HelpExampleCli("getwalletinfo", "")
@@ -2288,6 +2289,9 @@ UniValue getwalletinfo(const UniValue& params, bool fHelp)
22882289
if (pwalletMain->IsCrypted())
22892290
obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
22902291
obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK())));
2292+
CKeyID masterKeyID = pwalletMain->GetHDChain().masterKeyID;
2293+
if (!masterKeyID.IsNull())
2294+
obj.push_back(Pair("masterkeyid", masterKeyID.GetHex()));
22912295
return obj;
22922296
}
22932297

src/wallet/wallet.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ CPubKey CWallet::GenerateNewKey()
126126
// childIndex | BIP32_HARDENED_KEY_LIMIT = derive childIndex in hardened child-index-range
127127
// example: 1 | BIP32_HARDENED_KEY_LIMIT == 0x80000001 == 2147483649
128128
externalChainChildKey.Derive(childKey, hdChain.nExternalChainCounter | BIP32_HARDENED_KEY_LIMIT);
129+
metadata.hdKeypath = "m/0'/0'/"+std::to_string(hdChain.nExternalChainCounter)+"'";
130+
metadata.hdMasterKeyID = hdChain.masterKeyID;
129131
// increment childkey index
130132
hdChain.nExternalChainCounter++;
131133
} while(HaveKey(childKey.key.GetPubKey().GetID()));

src/wallet/wallet.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -577,7 +577,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
577577

578578
void SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator>);
579579

580-
/* the hd chain data model (external chain counters) */
580+
/* the HD chain data model (external chain counters) */
581581
CHDChain hdChain;
582582

583583
public:
@@ -896,11 +896,12 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
896896

897897
bool BackupWallet(const std::string& strDest);
898898

899-
/* Set the hd chain model (chain child index counters) */
899+
/* Set the HD chain model (chain child index counters) */
900900
bool SetHDChain(const CHDChain& chain, bool memonly);
901901

902-
/* Set the current hd master key (will reset the chain child index counters) */
902+
/* Set the current HD master key (will reset the chain child index counters) */
903903
bool SetHDMasterKey(const CKey& key);
904+
const CHDChain& GetHDChain() { return hdChain; }
904905
};
905906

906907
/** A key allocated from the key pool. */

src/wallet/walletdb.h

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ enum DBErrors
4141
DB_NEED_REWRITE
4242
};
4343

44-
/* simple hd chain data model */
44+
/* simple HD chain data model */
4545
class CHDChain
4646
{
4747
public:
@@ -73,17 +73,21 @@ class CHDChain
7373
class CKeyMetadata
7474
{
7575
public:
76-
static const int CURRENT_VERSION=1;
76+
static const int VERSION_BASIC=1;
77+
static const int VERSION_WITH_HDDATA=10;
78+
static const int CURRENT_VERSION=VERSION_WITH_HDDATA;
7779
int nVersion;
7880
int64_t nCreateTime; // 0 means unknown
81+
std::string hdKeypath; //optional HD/bip32 keypath
82+
CKeyID hdMasterKeyID; //id of the HD masterkey used to derive this key
7983

8084
CKeyMetadata()
8185
{
8286
SetNull();
8387
}
8488
CKeyMetadata(int64_t nCreateTime_)
8589
{
86-
nVersion = CKeyMetadata::CURRENT_VERSION;
90+
SetNull();
8791
nCreateTime = nCreateTime_;
8892
}
8993

@@ -94,12 +98,19 @@ class CKeyMetadata
9498
READWRITE(this->nVersion);
9599
nVersion = this->nVersion;
96100
READWRITE(nCreateTime);
101+
if (this->nVersion >= VERSION_WITH_HDDATA)
102+
{
103+
READWRITE(hdKeypath);
104+
READWRITE(hdMasterKeyID);
105+
}
97106
}
98107

99108
void SetNull()
100109
{
101110
nVersion = CKeyMetadata::CURRENT_VERSION;
102111
nCreateTime = 0;
112+
hdKeypath.clear();
113+
hdMasterKeyID.SetNull();
103114
}
104115
};
105116

0 commit comments

Comments
 (0)