[0.13] Create a new HD seed after encrypting the wallet

https://github.com/bitcoin/bitcoin/pull/8389/commits
This commit is contained in:
lateminer
2018-01-02 13:57:39 +03:00
parent 00cb4d52f3
commit 0e02c74800
5 changed files with 55 additions and 12 deletions

View File

@@ -36,6 +36,10 @@ class KeyPoolTest(BitcoinTestFramework):
def run_test(self):
nodes = self.nodes
addr_before_encrypting = nodes[0].getnewaddress()
addr_before_encrypting_data = nodes[0].validateaddress(addr_before_encrypting)
wallet_info_old = nodes[0].getwalletinfo()
assert(addr_before_encrypting_data['hdmasterkeyid'] == wallet_info_old['hdmasterkeyid'])
# Encrypt wallet and wait to terminate
nodes[0].encryptwallet('test')
bitcoind_processes[0].wait()
@@ -43,6 +47,10 @@ class KeyPoolTest(BitcoinTestFramework):
nodes[0] = start_node(0, self.options.tmpdir)
# Keep creating keys
addr = nodes[0].getnewaddress()
addr_data = nodes[0].validateaddress(addr)
wallet_info = nodes[0].getwalletinfo()
assert(addr_before_encrypting_data['hdmasterkeyid'] != wallet_info['hdmasterkeyid'])
assert(addr_data['hdmasterkeyid'] == wallet_info['hdmasterkeyid'])
try:
addr = nodes[0].getnewaddress()
raise AssertionError('Keypool should be exhausted after one address')

View File

@@ -1543,8 +1543,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (GetBoolArg("-usehd", true) && pwalletMain->hdChain.masterKeyID.IsNull() ) {
// generate a new master key
CKey key;
key.MakeNewKey(true);
if (!pwalletMain->SetHDMasterKey(key))
CPubKey masterPubKey = pwalletMain->GenerateNewHDMasterKey();
if (!pwalletMain->SetHDMasterKey(masterPubKey))
throw std::runtime_error("CWallet::GenerateNewKey(): Storing master key failed");
}
CPubKey newDefaultKey;

View File

@@ -2127,7 +2127,7 @@ UniValue encryptwallet(const UniValue& params, bool fHelp)
// slack space in .dat files; that is bad if the old data is
// unencrypted private keys. So:
StartShutdown();
return "wallet encrypted; Bitcoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
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.";
}
UniValue lockunspent(const UniValue& params, bool fHelp)

View File

@@ -946,6 +946,15 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
Lock();
Unlock(strWalletPassphrase);
// if we are using HD, replace the HD master key with a new one
if (!hdChain.masterKeyID.IsNull()) {
CKey key;
key.MakeNewKey(true);
if (!SetHDMasterKey(key))
return false;
}
NewKeyPool();
Lock();
@@ -1378,19 +1387,42 @@ CAmount CWallet::GetChange(const CTxOut& txout) const
return (IsChange(txout) ? txout.nValue : 0);
}
CPubKey CWallet::GenerateNewHDMasterKey()
{
CKey key;
key.MakeNewKey(true);
int64_t nCreationTime = GetTime();
CKeyMetadata metadata(nCreationTime);
// calculate the pubkey
CPubKey pubkey = key.GetPubKey();
assert(key.VerifyPubKey(pubkey));
// set the hd keypath to "m" -> Master, refers the masterkeyid to itself
metadata.hdKeypath = "m";
metadata.hdMasterKeyID = pubkey.GetID();
{
LOCK(cs_wallet);
// mem store the metadata
mapKeyMetadata[pubkey.GetID()] = metadata;
// write the key&metadata to the database
if (!AddKeyPubKey(key, pubkey))
throw std::runtime_error("CWallet::GenerateNewKey(): AddKey failed");
}
return pubkey;
}
bool CWallet::SetHDMasterKey(const CKey& key)
{
LOCK(cs_wallet);
// ensure this wallet.dat can only be opened by clients supporting HD
SetMinVersion(FEATURE_HD);
// store the key as normal "key"/"ckey" object
// in the database
// key metadata is not required
CPubKey pubkey = key.GetPubKey();
if (!AddKeyPubKey(key, pubkey))
throw std::runtime_error("CWallet::GenerateNewKey(): AddKey failed");
// store the keyid (hash160) together with
// the child index counter in the database

View File

@@ -819,10 +819,13 @@ public:
uint64_t GetStakeWeight() const;
/* Set the hd chain model (chain child index counters) */
bool SetHDChain(const CHDChain& chain, bool memonly);
const CHDChain& GetHDChain() { return hdChain; }
/* Generates a new HD master key (will not be activated) */
CPubKey GenerateNewHDMasterKey();
/* Set the current hd master key (will reset the chain child index counters) */
bool SetHDMasterKey(const CKey& key);
const CHDChain& GetHDChain() { return hdChain; }
bool SetHDMasterKey(const CPubKey& key);
};
/** A key allocated from the key pool. */