diff --git a/doc/release-notes.md b/doc/release-notes.md --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -10,3 +10,10 @@ - It is now possible to unload wallets dynamically at runtime. This feature is currently only available through the RPC interface. - Wallets dynamically unloaded will now be reflected in the gui. + - `hdmasterkeyid` in `getwalletinfo` has been deprecated in favor of + `hdseedid`. `hdmasterkeyid` will be removed in V0.21. + - `hdmasterkeyid` in `getaddressinfo` has been deprecated in favor of + `hdseedid`. `hdmasterkeyid` will be removed in V0.21. + - The `inactivehdmaster` property in the `dumpwallet` output has been + deprecated in favor of `inactivehdseed`. `inactivehdmaster` will be removed + in V0.21. diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -894,10 +894,10 @@ // add the base58check encoded extended master if the wallet uses HD CKeyID seed_id = pwallet->GetHDChain().seed_id; if (!seed_id.IsNull()) { - CKey key; - if (pwallet->GetKey(seed_id, key)) { + CKey seed; + if (pwallet->GetKey(seed_id, seed)) { CExtKey masterKey; - masterKey.SetSeed(key.begin(), key.size()); + masterKey.SetSeed(seed.begin(), seed.size()); file << "# extended private masterkey: " << EncodeExtKey(masterKey) << "\n\n"; @@ -917,11 +917,11 @@ strLabel)) { file << strprintf("label=%s", strLabel); } else if (keyid == seed_id) { - file << "hdmaster=1"; + file << "hdseed=1"; } else if (mapKeyPool.count(keyid)) { file << "reserve=1"; - } else if (pwallet->mapKeyMetadata[keyid].hdKeypath == "m") { - file << "inactivehdmaster=1"; + } else if (pwallet->mapKeyMetadata[keyid].hdKeypath == "s") { + file << "inactivehdseed=1"; } else { file << "change=1"; } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3289,9 +3289,11 @@ "fee configuration, set in " + CURRENCY_UNIT + "/kB\n" - " \"hdmasterkeyid\": \"\" (string, optional) the " - "Hash160 of the HD master pubkey (only present when HD is " - "enabled)\n" + " \"hdseedid\": \"\" (string, optional) the " + "Hash160 of the HD seed (only present when HD is enabled)\n" + " \"hdmasterkeyid\": \"\" (string, optional) alias " + "for hdseedid retained for backwards-compatibility. Will be " + "removed in V0.21.\n" "}\n" "\nExamples:\n" + HelpExampleCli("getwalletinfo", "") + @@ -3327,6 +3329,7 @@ } obj.pushKV("paytxfee", ValueFromAmount(pwallet->m_pay_tx_fee.GetFeePerK())); if (!seed_id.IsNull()) { + obj.pushKV("hdseedid", seed_id.GetHex()); obj.pushKV("hdmasterkeyid", seed_id.GetHex()); } return obj; @@ -4420,7 +4423,7 @@ "about the address embedded in P2SH or P2WSH, if relevant and " "known. It includes all getaddressinfo output fields for the " "embedded address, excluding metadata (\"timestamp\", " - "\"hdkeypath\", \"hdmasterkeyid\") and relation to the wallet " + "\"hdkeypath\", \"hdseedid\") and relation to the wallet " "(\"ismine\", \"iswatchonly\", \"account\").\n" " \"iscompressed\" : true|false, (boolean) If the address is " "compressed\n" @@ -4431,8 +4434,11 @@ "GMT)\n" " \"hdkeypath\" : \"keypath\" (string, optional) The HD " "keypath if the key is HD and available\n" - " \"hdmasterkeyid\" : \"\" (string, optional) The " - "Hash160 of the HD master pubkey\n" + " \"hdseedid\" : \"\" (string, optional) The " + "Hash160 of the HD seed\n" + " \"hdmasterkeyid\" : \"\" (string, optional) alias for " + "hdseedid maintained for backwards compatibility. Will be removed " + "in V0.21.\n" "}\n" "\nExamples:\n" + HelpExampleCli("getaddressinfo", @@ -4485,6 +4491,7 @@ ret.pushKV("timestamp", meta->nCreateTime); if (!meta->hdKeypath.empty()) { ret.pushKV("hdkeypath", meta->hdKeypath); + ret.pushKV("hdseedid", meta->hd_seed_id.GetHex()); ret.pushKV("hdmasterkeyid", meta->hd_seed_id.GetHex()); } } @@ -4526,7 +4533,7 @@ "used.\n" " The seed value can be retrieved " "using the dumpwallet command. It is the private key marked " - "hdmaster=1\n" + "hdseed=1\n" "\nExamples:\n" + HelpExampleCli("sethdseed", "") + HelpExampleCli("sethdseed", "false") + diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1296,19 +1296,19 @@ /* Returns true if HD is enabled */ bool IsHDEnabled() const; - /* Generates a new HD master key (will not be activated) */ + /* Generates a new HD seed (will not be activated) */ CPubKey GenerateNewSeed(); /** - * Derives a new HD master key (will not be activated) + * Derives a new HD seed (will not be activated) */ CPubKey DeriveNewSeed(const CKey &key); /** - * Set the current HD master key (will reset the chain child index counters) - * Sets the master key's version based on the current wallet version (so the + * Set the current HD seed (will reset the chain child index counters) + * Sets the seed's version based on the current wallet version (so the * caller must ensure the current wallet version is correct before calling - * this function). + * this function). */ void SetHDSeed(const CPubKey &key); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -202,8 +202,8 @@ void CWallet::DeriveNewChildKey(WalletBatch &batch, CKeyMetadata &metadata, CKey &secret, bool internal) { // for now we use a fixed keypath scheme of m/0'/0'/k - // master key seed (256bit) - CKey key; + // seed (256bit) + CKey seed; // hd master key CExtKey masterKey; // key at m/0' @@ -213,13 +213,12 @@ // key at m/0'/0'/' CExtKey childKey; - // try to get the master key - if (!GetKey(hdChain.seed_id, key)) { - throw std::runtime_error(std::string(__func__) + - ": Master key not found"); + // try to get the seed + if (!GetKey(hdChain.seed_id, seed)) { + throw std::runtime_error(std::string(__func__) + ": seed not found"); } - masterKey.SetSeed(key.begin(), key.size()); + masterKey.SetSeed(seed.begin(), seed.size()); // derive m/0' // use hardened derivation (child keys >= 0x80000000 are hardened after @@ -787,7 +786,7 @@ Lock(); Unlock(strWalletPassphrase); - // If we are using HD, replace the HD master key (seed) with a new one. + // If we are using HD, replace the HD seed with a new one if (IsHDEnabled()) { SetHDSeed(GenerateNewSeed()); } @@ -1558,26 +1557,26 @@ int64_t nCreationTime = GetTime(); CKeyMetadata metadata(nCreationTime); - // Calculate the pubkey. - CPubKey pubkey = key.GetPubKey(); - assert(key.VerifyPubKey(pubkey)); + // Calculate the seed + CPubKey seed = key.GetPubKey(); + assert(key.VerifyPubKey(seed)); - // Set the hd keypath to "m" -> Master, refers the masterkeyid to itself. - metadata.hdKeypath = "m"; - metadata.hd_seed_id = pubkey.GetID(); + // Set the hd keypath to "s" -> Seed, refers the seed to itself + metadata.hdKeypath = "s"; + metadata.hd_seed_id = seed.GetID(); LOCK(cs_wallet); // mem store the metadata - mapKeyMetadata[pubkey.GetID()] = metadata; + mapKeyMetadata[seed.GetID()] = metadata; - // Write the key&metadata to the database. - if (!AddKeyPubKey(key, pubkey)) { + // Write the key&metadata to the database + if (!AddKeyPubKey(key, seed)) { throw std::runtime_error(std::string(__func__) + ": AddKeyPubKey failed"); } - return pubkey; + return seed; } void CWallet::SetHDSeed(const CPubKey &seed) { @@ -4488,9 +4487,9 @@ } walletInstance->SetMinVersion(FEATURE_LATEST); - // Generate a new master key. - CPubKey masterPubKey = walletInstance->GenerateNewSeed(); - walletInstance->SetHDSeed(masterPubKey); + // Generate a new seed + CPubKey seed = walletInstance->GenerateNewSeed(); + walletInstance->SetHDSeed(seed); // Top up the keypool if (!walletInstance->TopUpKeyPool()) { diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -63,7 +63,7 @@ public: uint32_t nExternalChainCounter; uint32_t nInternalChainCounter; - //!< master key hash160 + //!< seed hash160 CKeyID seed_id; static const int VERSION_HD_BASE = 1; @@ -101,7 +101,7 @@ int64_t nCreateTime; // optional HD/bip32 keypath. std::string hdKeypath; - // Id of the HD masterkey used to derive this key. + // Id of the HD seed used to derive this key. CKeyID hd_seed_id; CKeyMetadata() { SetNull(); } diff --git a/test/functional/wallet_dump.py b/test/functional/wallet_dump.py --- a/test/functional/wallet_dump.py +++ b/test/functional/wallet_dump.py @@ -32,10 +32,10 @@ addr_keypath = comment.split(" addr=")[1] addr = addr_keypath.split(" ")[0] keypath = None - if keytype == "inactivehdmaster=1": + if keytype == "inactivehdseed=1": # ensure the old master is still available assert(hd_master_addr_old == addr) - elif keytype == "hdmaster=1": + elif keytype == "hdseed=1": # ensure we have generated a new hd master key assert(hd_master_addr_old != addr) hd_master_addr_ret = addr diff --git a/test/functional/wallet_hd.py b/test/functional/wallet_hd.py --- a/test/functional/wallet_hd.py +++ b/test/functional/wallet_hd.py @@ -30,7 +30,9 @@ connect_nodes_bi(self.nodes[0], self.nodes[1]) # Make sure we use hd, keep masterkeyid - masterkeyid = self.nodes[1].getwalletinfo()['hdmasterkeyid'] + masterkeyid = self.nodes[1].getwalletinfo()['hdseedid'] + assert_equal(masterkeyid, self.nodes[1].getwalletinfo()[ + 'hdmasterkeyid']) assert_equal(len(masterkeyid), 40) # create an internal key @@ -57,6 +59,7 @@ hd_add = self.nodes[1].getnewaddress() hd_info = self.nodes[1].getaddressinfo(hd_add) assert_equal(hd_info["hdkeypath"], "m/0'/0'/" + str(i) + "'") + assert_equal(hd_info["hdseedid"], masterkeyid) assert_equal(hd_info["hdmasterkeyid"], masterkeyid) self.nodes[0].sendtoaddress(hd_add, 1) self.nodes[0].generate(1) @@ -89,6 +92,7 @@ hd_add_2 = self.nodes[1].getnewaddress() hd_info_2 = self.nodes[1].getaddressinfo(hd_add_2) assert_equal(hd_info_2["hdkeypath"], "m/0'/0'/" + str(i) + "'") + assert_equal(hd_info_2["hdseedid"], masterkeyid) assert_equal(hd_info_2["hdmasterkeyid"], masterkeyid) assert_equal(hd_add, hd_add_2) connect_nodes_bi(self.nodes[0], self.nodes[1]) @@ -138,9 +142,9 @@ assert_equal(keypath[0:7], "m/0'/1'") # Generate a new HD seed on node 1 and make sure it is set - orig_masterkeyid = self.nodes[1].getwalletinfo()['hdmasterkeyid'] + orig_masterkeyid = self.nodes[1].getwalletinfo()['hdseedid'] self.nodes[1].sethdseed() - new_masterkeyid = self.nodes[1].getwalletinfo()['hdmasterkeyid'] + new_masterkeyid = self.nodes[1].getwalletinfo()['hdseedid'] assert orig_masterkeyid != new_masterkeyid addr = self.nodes[1].getnewaddress() # Make sure the new address is the first from the keypool @@ -152,11 +156,11 @@ new_seed = self.nodes[0].dumpprivkey(self.nodes[0].getnewaddress()) orig_masterkeyid = new_masterkeyid self.nodes[1].sethdseed(False, new_seed) - new_masterkeyid = self.nodes[1].getwalletinfo()['hdmasterkeyid'] + new_masterkeyid = self.nodes[1].getwalletinfo()['hdseedid'] assert orig_masterkeyid != new_masterkeyid addr = self.nodes[1].getnewaddress() assert_equal(orig_masterkeyid, self.nodes[1].getaddressinfo( - addr)['hdmasterkeyid']) + addr)['hdseedid']) # Make sure the new address continues previous keypool assert_equal(self.nodes[1].getaddressinfo( addr)['hdkeypath'], 'm/0\'/0\'/1\'') @@ -165,7 +169,7 @@ self.nodes[1].keypoolrefill(1) next_addr = self.nodes[1].getnewaddress() assert_equal(new_masterkeyid, self.nodes[1].getaddressinfo( - next_addr)['hdmasterkeyid']) + next_addr)['hdseedid']) # Make sure the new address is not from previous keypool assert_equal(self.nodes[1].getaddressinfo( next_addr)['hdkeypath'], 'm/0\'/0\'/0\'') diff --git a/test/functional/wallet_keypool.py b/test/functional/wallet_keypool.py --- a/test/functional/wallet_keypool.py +++ b/test/functional/wallet_keypool.py @@ -19,8 +19,10 @@ addr_before_encrypting_data = nodes[ 0].getaddressinfo(addr_before_encrypting) wallet_info_old = nodes[0].getwalletinfo() + assert_equal(wallet_info_old['hdseedid'], + wallet_info_old['hdmasterkeyid']) assert(addr_before_encrypting_data[ - 'hdmasterkeyid'] == wallet_info_old['hdmasterkeyid']) + 'hdseedid'] == wallet_info_old['hdseedid']) # Encrypt wallet and wait to terminate nodes[0].node_encrypt_wallet('test') @@ -30,9 +32,10 @@ addr = nodes[0].getnewaddress() addr_data = nodes[0].getaddressinfo(addr) wallet_info = nodes[0].getwalletinfo() + assert_equal(wallet_info['hdseedid'], wallet_info['hdmasterkeyid']) assert(addr_before_encrypting_data[ - 'hdmasterkeyid'] != wallet_info['hdmasterkeyid']) - assert(addr_data['hdmasterkeyid'] == wallet_info['hdmasterkeyid']) + 'hdseedid'] != wallet_info['hdseedid']) + assert(addr_data['hdseedid'] == wallet_info['hdseedid']) assert_raises_rpc_error( -12, "Error: Keypool ran out, please call keypoolrefill first", nodes[0].getnewaddress)