Page MenuHomePhabricator

D6228.diff
No OneTemporary

D6228.diff

diff --git a/src/script/sign.h b/src/script/sign.h
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -22,6 +22,7 @@
class CTransaction;
struct KeyOriginInfo {
+ //! First 32 bits of the Hash160 of the public key at the root of the path
uint8_t fingerprint[4];
std::vector<uint32_t> path;
@@ -30,6 +31,18 @@
std::begin(b.fingerprint)) &&
a.path == b.path;
}
+
+ ADD_SERIALIZE_METHODS;
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream &s, Operation ser_action) {
+ READWRITE(fingerprint);
+ READWRITE(path);
+ }
+
+ void clear() {
+ memset(fingerprint, 0, 4);
+ path.clear();
+ }
};
/** An interface to be implemented by keystores that support signing. */
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -14,6 +14,7 @@
#include <script/script.h>
#include <script/standard.h>
#include <sync.h>
+#include <util/bip32.h>
#include <util/system.h>
#include <util/time.h>
#include <util/translation.h>
@@ -1022,8 +1023,10 @@
}
file << strprintf(
" # addr=%s%s\n", strAddr,
- (pwallet->mapKeyMetadata[keyid].hdKeypath.size() > 0
- ? " hdkeypath=" + pwallet->mapKeyMetadata[keyid].hdKeypath
+ (pwallet->mapKeyMetadata[keyid].has_key_origin
+ ? " hdkeypath=" +
+ WriteHDKeypath(
+ pwallet->mapKeyMetadata[keyid].key_origin.path)
: ""));
}
}
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -4153,6 +4153,8 @@
"keypath if the key is HD and available\n"
" \"hdseedid\" : \"<hash160>\" (string, optional) The "
"Hash160 of the HD seed\n"
+ " \"hdmasterfingerprint\" : \"<hash160>\" (string, optional) "
+ "The fingperint of the master key.\n"
" \"labels\" (object) Array of labels "
"associated with the address.\n"
" [\n"
@@ -4221,9 +4223,12 @@
}
if (meta) {
ret.pushKV("timestamp", meta->nCreateTime);
- if (!meta->hdKeypath.empty()) {
- ret.pushKV("hdkeypath", meta->hdKeypath);
+ if (meta->has_key_origin) {
+ ret.pushKV("hdkeypath", WriteHDKeypath(meta->key_origin.path));
ret.pushKV("hdseedid", meta->hd_seed_id.GetHex());
+ ret.pushKV("hdmasterfingerprint",
+ HexStr(meta->key_origin.fingerprint,
+ meta->key_origin.fingerprint + 4));
}
}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -118,6 +118,10 @@
// the wallet if flag is unknown.
// Unknown wallet flags in the lower section <= (1 << 31) will be tolerated.
+ // Indicates that the metadata has already been upgraded to contain key
+ // origins
+ WALLET_FLAG_KEY_ORIGIN_METADATA = (1ULL << 1),
+
// Will enforce the rule that the wallet can't contain any private keys
// (only watch-only/pubkeys).
WALLET_FLAG_DISABLE_PRIVATE_KEYS = (1ULL << 32),
@@ -136,7 +140,8 @@
};
static constexpr uint64_t g_known_wallet_flags =
- WALLET_FLAG_DISABLE_PRIVATE_KEYS | WALLET_FLAG_BLANK_WALLET;
+ WALLET_FLAG_DISABLE_PRIVATE_KEYS | WALLET_FLAG_BLANK_WALLET |
+ WALLET_FLAG_KEY_ORIGIN_METADATA;
/** A key pool entry */
class CKeyPool {
@@ -971,6 +976,9 @@
void LoadScriptMetadata(const CScriptID &script_id,
const CKeyMetadata &metadata)
EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ //! Upgrade stored CKeyMetadata objects to store key origin info as
+ //! KeyOriginInfo
+ void UpgradeKeyMetadata() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool LoadMinVersion(int nVersion) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) {
AssertLockHeld(cs_wallet);
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -317,6 +317,10 @@
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 |
@@ -324,11 +328,19 @@
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__) +
@@ -426,6 +438,45 @@
return WalletBatch(*database).WriteKeyMetadata(meta, pubkey, overwrite);
}
+void CWallet::UpgradeKeyMetadata() {
+ // mapKeyMetadata
+ AssertLockHeld(cs_wallet);
+ if (IsLocked() || IsWalletFlagSet(WALLET_FLAG_KEY_ORIGIN_METADATA)) {
+ return;
+ }
+
+ for (auto &meta_pair : mapKeyMetadata) {
+ CKeyMetadata &meta = meta_pair.second;
+ // If the hdKeypath is "s", that's the seed and it doesn't have a key
+ // origin
+ if (!meta.hd_seed_id.IsNull() && !meta.has_key_origin &&
+ meta.hdKeypath != "s") {
+ 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<uint8_t> &vchCryptedSecret) {
return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret);
@@ -535,6 +586,8 @@
continue;
}
if (CCryptoKeyStore::Unlock(_vMasterKey, accept_no_keys)) {
+ // Now that we've unlocked, upgrade the key metadata
+ UpgradeKeyMetadata();
return true;
}
}
@@ -1566,6 +1619,7 @@
// 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();
LOCK(cs_wallet);
@@ -4912,18 +4966,10 @@
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);
diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h
--- a/src/wallet/walletdb.h
+++ b/src/wallet/walletdb.h
@@ -10,6 +10,7 @@
#include <amount.h>
#include <key.h>
#include <primitives/transaction.h>
+#include <script/sign.h>
#include <script/standard.h> // for CTxDestination
#include <wallet/db.h>
@@ -93,14 +94,20 @@
public:
static const int VERSION_BASIC = 1;
static const int VERSION_WITH_HDDATA = 10;
- static const int CURRENT_VERSION = VERSION_WITH_HDDATA;
+ static const int VERSION_WITH_KEY_ORIGIN = 12;
+ static const int CURRENT_VERSION = VERSION_WITH_KEY_ORIGIN;
int nVersion;
// 0 means unknown.
int64_t nCreateTime;
- // optional HD/bip32 keypath.
+ // optional HD/bip32 keypath. Still used to determine whether a key is a
+ // seed. Also kept for backwards compatibility
std::string hdKeypath;
// Id of the HD seed used to derive this key.
CKeyID hd_seed_id;
+ // Key origin info with path and fingerprint
+ KeyOriginInfo key_origin;
+ //< Whether the key_origin is useful
+ bool has_key_origin = false;
CKeyMetadata() { SetNull(); }
explicit CKeyMetadata(int64_t nCreateTime_) {
@@ -118,6 +125,10 @@
READWRITE(hdKeypath);
READWRITE(hd_seed_id);
}
+ if (this->nVersion >= VERSION_WITH_KEY_ORIGIN) {
+ READWRITE(key_origin);
+ READWRITE(has_key_origin);
+ }
}
void SetNull() {
@@ -125,6 +136,8 @@
nCreateTime = 0;
hdKeypath.clear();
hd_seed_id.SetNull();
+ key_origin.clear();
+ has_key_origin = false;
}
};
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -541,6 +541,15 @@
result = pwallet->ReorderTransactions();
}
+ // Upgrade all of the wallet keymetadata to have the hd master key id
+ // This operation is not atomic, but if it fails, updated entries are still
+ // backwards compatible with older software
+ try {
+ pwallet->UpgradeKeyMetadata();
+ } catch (...) {
+ result = DBErrors::CORRUPT;
+ }
+
return result;
}

File Metadata

Mime Type
text/plain
Expires
Sat, Mar 1, 11:28 (5 h, 31 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5183812
Default Alt Text
D6228.diff (11 KB)

Event Timeline