Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F13115587
D6228.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
11 KB
Subscribers
None
D6228.diff
View Options
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
Details
Attached
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)
Attached To
D6228: Store key origin info in key metadata
Event Timeline
Log In to Comment