mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-11-12 23:18:14 +01:00
Store key origin info in key metadata
Store the master key fingerprint and derivation path in the key metadata. hdKeypath is kept to indicate the seed and for backwards compatibility, but all key derivation path output uses the key origin info instead of hdKeypath.
This commit is contained in:
@@ -256,16 +256,25 @@ void CWallet::DeriveNewChildKey(WalletBatch &batch, CKeyMetadata& metadata, CKey
|
||||
if (internal) {
|
||||
chainChildKey.Derive(childKey, hdChain.nInternalChainCounter | BIP32_HARDENED_KEY_LIMIT);
|
||||
metadata.hdKeypath = "m/0'/1'/" + std::to_string(hdChain.nInternalChainCounter) + "'";
|
||||
metadata.key_origin.path.push_back(0 | BIP32_HARDENED_KEY_LIMIT);
|
||||
metadata.key_origin.path.push_back(1 | BIP32_HARDENED_KEY_LIMIT);
|
||||
metadata.key_origin.path.push_back(hdChain.nInternalChainCounter | BIP32_HARDENED_KEY_LIMIT);
|
||||
hdChain.nInternalChainCounter++;
|
||||
}
|
||||
else {
|
||||
chainChildKey.Derive(childKey, hdChain.nExternalChainCounter | BIP32_HARDENED_KEY_LIMIT);
|
||||
metadata.hdKeypath = "m/0'/0'/" + std::to_string(hdChain.nExternalChainCounter) + "'";
|
||||
metadata.key_origin.path.push_back(0 | BIP32_HARDENED_KEY_LIMIT);
|
||||
metadata.key_origin.path.push_back(0 | BIP32_HARDENED_KEY_LIMIT);
|
||||
metadata.key_origin.path.push_back(hdChain.nExternalChainCounter | BIP32_HARDENED_KEY_LIMIT);
|
||||
hdChain.nExternalChainCounter++;
|
||||
}
|
||||
} while (HaveKey(childKey.key.GetPubKey().GetID()));
|
||||
secret = childKey.key;
|
||||
metadata.hd_seed_id = hdChain.seed_id;
|
||||
CKeyID master_id = masterKey.key.GetPubKey().GetID();
|
||||
std::copy(master_id.begin(), master_id.begin() + 4, metadata.key_origin.fingerprint);
|
||||
metadata.has_key_origin = true;
|
||||
// update the chain model in the database
|
||||
if (!batch.WriteHDChain(hdChain))
|
||||
throw std::runtime_error(std::string(__func__) + ": Writing HD chain model failed");
|
||||
@@ -355,6 +364,41 @@ bool CWallet::WriteKeyMetadata(const CKeyMetadata& meta, const CPubKey& pubkey,
|
||||
return WalletBatch(*database).WriteKeyMetadata(meta, pubkey, overwrite);
|
||||
}
|
||||
|
||||
void CWallet::UpgradeKeyMetadata()
|
||||
{
|
||||
AssertLockHeld(cs_wallet); // mapKeyMetadata
|
||||
if (IsLocked() || IsWalletFlagSet(WALLET_FLAG_KEY_ORIGIN_METADATA)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& meta_pair : mapKeyMetadata) {
|
||||
CKeyMetadata& meta = meta_pair.second;
|
||||
if (!meta.hd_seed_id.IsNull() && !meta.has_key_origin && meta.hdKeypath != "s") { // If the hdKeypath is "s", that's the seed and it doesn't have a key origin
|
||||
CKey key;
|
||||
GetKey(meta.hd_seed_id, key);
|
||||
CExtKey masterKey;
|
||||
masterKey.SetSeed(key.begin(), key.size());
|
||||
// Add to map
|
||||
CKeyID master_id = masterKey.key.GetPubKey().GetID();
|
||||
std::copy(master_id.begin(), master_id.begin() + 4, meta.key_origin.fingerprint);
|
||||
if (!ParseHDKeypath(meta.hdKeypath, meta.key_origin.path)) {
|
||||
throw std::runtime_error("Invalid stored hdKeypath");
|
||||
}
|
||||
meta.has_key_origin = true;
|
||||
if (meta.nVersion < CKeyMetadata::VERSION_WITH_KEY_ORIGIN) {
|
||||
meta.nVersion = CKeyMetadata::VERSION_WITH_KEY_ORIGIN;
|
||||
}
|
||||
|
||||
// Write meta to wallet
|
||||
CPubKey pubkey;
|
||||
if (GetPubKey(meta_pair.first, pubkey)) {
|
||||
WriteKeyMetadata(meta, pubkey, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
SetWalletFlag(WALLET_FLAG_KEY_ORIGIN_METADATA);
|
||||
}
|
||||
|
||||
bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
|
||||
{
|
||||
return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret);
|
||||
@@ -453,8 +497,11 @@ bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool accept_no_key
|
||||
return false;
|
||||
if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey))
|
||||
continue; // try another master key
|
||||
if (CCryptoKeyStore::Unlock(_vMasterKey, accept_no_keys))
|
||||
if (CCryptoKeyStore::Unlock(_vMasterKey, accept_no_keys)) {
|
||||
// Now that we've unlocked, upgrade the key metadata
|
||||
UpgradeKeyMetadata();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -1414,6 +1461,7 @@ CPubKey CWallet::DeriveNewSeed(const CKey& key)
|
||||
|
||||
// set the hd keypath to "s" -> Seed, refers the seed to itself
|
||||
metadata.hdKeypath = "s";
|
||||
metadata.has_key_origin = false;
|
||||
metadata.hd_seed_id = seed.GetID();
|
||||
|
||||
{
|
||||
@@ -4494,16 +4542,9 @@ bool CWallet::GetKeyOrigin(const CKeyID& keyID, KeyOriginInfo& info) const
|
||||
meta = it->second;
|
||||
}
|
||||
}
|
||||
if (!meta.hdKeypath.empty()) {
|
||||
if (!ParseHDKeypath(meta.hdKeypath, info.path)) return false;
|
||||
// Get the proper master key id
|
||||
CKey key;
|
||||
GetKey(meta.hd_seed_id, key);
|
||||
CExtKey masterKey;
|
||||
masterKey.SetSeed(key.begin(), key.size());
|
||||
// Compute identifier
|
||||
CKeyID masterid = masterKey.key.GetPubKey().GetID();
|
||||
std::copy(masterid.begin(), masterid.begin() + 4, info.fingerprint);
|
||||
if (meta.has_key_origin) {
|
||||
std::copy(meta.key_origin.fingerprint, meta.key_origin.fingerprint + 4, info.fingerprint);
|
||||
info.path = meta.key_origin.path;
|
||||
} else { // Single pubkeys get the master fingerprint of themselves
|
||||
std::copy(keyID.begin(), keyID.begin() + 4, info.fingerprint);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user