Skip to content

Commit 2266b43

Browse files
jonasschnellilaanwj
authored andcommitted
Port from 0.13: Create a new HD seed after encrypting the wallet
Forward-ports two commits from 0.13: - [0.13] Create a new HD seed after encrypting the wallet - [Wallet] Add CKeyMetadata record for HDMasterKey(s), factor out HD key generation Github-Pull: #8389 Rebased-From: f142c11 de45c06
1 parent 806b9e7 commit 2266b43

File tree

4 files changed

+57
-12
lines changed

4 files changed

+57
-12
lines changed

qa/rpc-tests/keypool.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,23 @@ class KeyPoolTest(BitcoinTestFramework):
1212

1313
def run_test(self):
1414
nodes = self.nodes
15+
addr_before_encrypting = nodes[0].getnewaddress()
16+
addr_before_encrypting_data = nodes[0].validateaddress(addr_before_encrypting)
17+
wallet_info_old = nodes[0].getwalletinfo()
18+
assert(addr_before_encrypting_data['hdmasterkeyid'] == wallet_info_old['hdmasterkeyid'])
19+
1520
# Encrypt wallet and wait to terminate
1621
nodes[0].encryptwallet('test')
1722
bitcoind_processes[0].wait()
1823
# Restart node 0
1924
nodes[0] = start_node(0, self.options.tmpdir)
2025
# Keep creating keys
2126
addr = nodes[0].getnewaddress()
27+
addr_data = nodes[0].validateaddress(addr)
28+
wallet_info = nodes[0].getwalletinfo()
29+
assert(addr_before_encrypting_data['hdmasterkeyid'] != wallet_info['hdmasterkeyid'])
30+
assert(addr_data['hdmasterkeyid'] == wallet_info['hdmasterkeyid'])
31+
2232
try:
2333
addr = nodes[0].getnewaddress()
2434
raise AssertionError('Keypool should be exhausted after one address')

src/wallet/rpcwallet.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2081,7 +2081,7 @@ UniValue encryptwallet(const UniValue& params, bool fHelp)
20812081
// slack space in .dat files; that is bad if the old data is
20822082
// unencrypted private keys. So:
20832083
StartShutdown();
2084-
return "wallet encrypted; Bitcoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
2084+
return "wallet encrypted; Bitcoin server stopping, restart to run with encrypted wallet. The keypool has been flushed and a new HD seed was generated (if you are using HD). You need to make a new backup.";
20852085
}
20862086

20872087
UniValue lockunspent(const UniValue& params, bool fHelp)

src/wallet/wallet.cpp

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,15 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
626626

627627
Lock();
628628
Unlock(strWalletPassphrase);
629+
630+
// if we are using HD, replace the HD master key (seed) with a new one
631+
if (!hdChain.masterKeyID.IsNull()) {
632+
CKey key;
633+
CPubKey masterPubKey = GenerateNewHDMasterKey();
634+
if (!SetHDMasterKey(masterPubKey))
635+
return false;
636+
}
637+
629638
NewKeyPool();
630639
Lock();
631640

@@ -1166,20 +1175,43 @@ CAmount CWallet::GetChange(const CTransaction& tx) const
11661175
return nChange;
11671176
}
11681177

1169-
bool CWallet::SetHDMasterKey(const CKey& key)
1178+
CPubKey CWallet::GenerateNewHDMasterKey()
1179+
{
1180+
CKey key;
1181+
key.MakeNewKey(true);
1182+
1183+
int64_t nCreationTime = GetTime();
1184+
CKeyMetadata metadata(nCreationTime);
1185+
1186+
// calculate the pubkey
1187+
CPubKey pubkey = key.GetPubKey();
1188+
assert(key.VerifyPubKey(pubkey));
1189+
1190+
// set the hd keypath to "m" -> Master, refers the masterkeyid to itself
1191+
metadata.hdKeypath = "m";
1192+
metadata.hdMasterKeyID = pubkey.GetID();
1193+
1194+
{
1195+
LOCK(cs_wallet);
1196+
1197+
// mem store the metadata
1198+
mapKeyMetadata[pubkey.GetID()] = metadata;
1199+
1200+
// write the key&metadata to the database
1201+
if (!AddKeyPubKey(key, pubkey))
1202+
throw std::runtime_error("CWallet::GenerateNewKey(): AddKey failed");
1203+
}
1204+
1205+
return pubkey;
1206+
}
1207+
1208+
bool CWallet::SetHDMasterKey(const CPubKey& pubkey)
11701209
{
11711210
LOCK(cs_wallet);
11721211

11731212
// ensure this wallet.dat can only be opened by clients supporting HD
11741213
SetMinVersion(FEATURE_HD);
11751214

1176-
// store the key as normal "key"/"ckey" object
1177-
// in the database
1178-
// key metadata is not required
1179-
CPubKey pubkey = key.GetPubKey();
1180-
if (!AddKeyPubKey(key, pubkey))
1181-
throw std::runtime_error("CWallet::GenerateNewKey(): AddKey failed");
1182-
11831215
// store the keyid (hash160) together with
11841216
// the child index counter in the database
11851217
// as a hdchain object
@@ -3299,8 +3331,8 @@ bool CWallet::InitLoadWallet()
32993331
if (GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET) && walletInstance->hdChain.masterKeyID.IsNull()) {
33003332
// generate a new master key
33013333
CKey key;
3302-
key.MakeNewKey(true);
3303-
if (!walletInstance->SetHDMasterKey(key))
3334+
CPubKey masterPubKey = walletInstance->GenerateNewHDMasterKey();
3335+
if (!walletInstance->SetHDMasterKey(masterPubKey))
33043336
throw std::runtime_error("CWallet::GenerateNewKey(): Storing master key failed");
33053337
}
33063338
CPubKey newDefaultKey;

src/wallet/wallet.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -901,8 +901,11 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
901901
bool SetHDChain(const CHDChain& chain, bool memonly);
902902
const CHDChain& GetHDChain() { return hdChain; }
903903

904+
/* Generates a new HD master key (will not be activated) */
905+
CPubKey GenerateNewHDMasterKey();
906+
904907
/* Set the current HD master key (will reset the chain child index counters) */
905-
bool SetHDMasterKey(const CKey& key);
908+
bool SetHDMasterKey(const CPubKey& key);
906909
};
907910

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

0 commit comments

Comments
 (0)