From d2a682e84ce9cc60c53d5e503a655854c03e1b21 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Wed, 24 Jun 2015 09:53:05 +0200 Subject: [PATCH 1/3] wallet: Add key origin flags An encrypted wallet can still hold keys which where created when the wallet was unencrypted. This PR will add a 8bit-flags-int to the CKeyMetadata class. `listreceivedbyaddress` will report whether the key was generated within a enctypted wallet or if it was imported throught `importprivkey` --- src/wallet/rpcdump.cpp | 1 + src/wallet/rpcwallet.cpp | 17 +++++++++++++++++ src/wallet/wallet.cpp | 7 +++++++ src/wallet/wallet.h | 3 ++- src/wallet/walletdb.h | 14 ++++++++++++++ 5 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index bb5337c4adb..548dd3bc899 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -138,6 +138,7 @@ UniValue importprivkey(const JSONRPCRequest& request) return NullUniValue; pwalletMain->mapKeyMetadata[vchAddress].nCreateTime = 1; + pwalletMain->mapKeyMetadata[vchAddress].keyFlags |= CKeyMetadata::KEY_ORIGIN_IMPORTED; if (!pwalletMain->AddKeyPubKey(key, pubkey)) throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet"); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 5a22e0278da..29bcce69203 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -1196,6 +1196,22 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) fIsWatchonly = (*it).second.fIsWatchonly; } + // convert keyflags into a string + CKeyID keyID; + uint8_t keyFlags = 0; + if (address.GetKeyID(keyID)) + keyFlags = pwalletMain->mapKeyMetadata[keyID].keyFlags; + + std::string keyOrigin; + if (keyFlags & CKeyMetadata::KEY_ORIGIN_UNKNOWN) + keyOrigin = "unknown"; + if (keyFlags & CKeyMetadata::KEY_ORIGIN_ENC_WALLET) + keyOrigin = "encrypted"; + else if (keyFlags & CKeyMetadata::KEY_ORIGIN_UNENC_WALLET) + keyOrigin = "unencrypted"; + if (keyFlags & CKeyMetadata::KEY_ORIGIN_IMPORTED) + keyOrigin = "imported"; + if (fByAccounts) { tallyitem& _item = mapAccountTally[strAccount]; @@ -1211,6 +1227,7 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) obj.push_back(Pair("address", address.ToString())); obj.push_back(Pair("account", strAccount)); obj.push_back(Pair("amount", ValueFromAmount(nAmount))); + obj.push_back(Pair("key_origin", keyOrigin)); obj.push_back(Pair("confirmations", (nConf == std::numeric_limits::max() ? 0 : nConf))); if (!fByAccounts) obj.push_back(Pair("label", strAccount)); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 3e18cb702cd..2092f383823 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -98,6 +98,13 @@ CPubKey CWallet::GenerateNewKey() int64_t nCreationTime = GetTime(); CKeyMetadata metadata(nCreationTime); + //check if the wallet supports keyflags + if (CanSupportFeature(FEATURE_KEYFLAGS)) + { + metadata.nVersion = CKeyMetadata::VERSION_SUPPORT_FLAGS; + metadata.keyFlags |= IsCrypted() ? CKeyMetadata::KEY_ORIGIN_ENC_WALLET : CKeyMetadata::KEY_ORIGIN_UNENC_WALLET; + } + // use HD key derivation if HD was enabled during wallet creation if (IsHDEnabled()) { DeriveNewChildKey(metadata, secret); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 409d8170464..420664619f7 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -81,9 +81,10 @@ enum WalletFeature FEATURE_WALLETCRYPT = 40000, // wallet encryption FEATURE_COMPRPUBKEY = 60000, // compressed public keys + FEATURE_KEYFLAGS = 70000, // key metadata flags for storing informations like key origin FEATURE_HD = 130000, // Hierarchical key derivation after BIP32 (HD Wallet) - FEATURE_LATEST = FEATURE_COMPRPUBKEY // HD is optional, use FEATURE_COMPRPUBKEY as latest version + FEATURE_LATEST = FEATURE_KEYFLAGS // HD is optional, use FEATURE_KEYFLAGS as latest version }; diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index eb25ac613dd..7b222473ecd 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -73,12 +73,21 @@ class CKeyMetadata { public: static const int VERSION_BASIC=1; + static const int VERSION_SUPPORT_FLAGS=2; static const int VERSION_WITH_HDDATA=10; static const int CURRENT_VERSION=VERSION_WITH_HDDATA; + + static const uint8_t KEY_ORIGIN_UNSET = 0x0000; + static const uint8_t KEY_ORIGIN_UNKNOWN = 0x0001; + static const uint8_t KEY_ORIGIN_IMPORTED = 0x0002; + static const uint8_t KEY_ORIGIN_UNENC_WALLET = 0x0004; + static const uint8_t KEY_ORIGIN_ENC_WALLET = 0x0008; + int nVersion; int64_t nCreateTime; // 0 means unknown std::string hdKeypath; //optional HD/bip32 keypath CKeyID hdMasterKeyID; //id of the HD masterkey used to derive this key + uint8_t keyFlags; CKeyMetadata() { @@ -88,6 +97,7 @@ class CKeyMetadata { SetNull(); nCreateTime = nCreateTime_; + keyFlags = KEY_ORIGIN_UNSET; } ADD_SERIALIZE_METHODS; @@ -101,6 +111,9 @@ class CKeyMetadata READWRITE(hdKeypath); READWRITE(hdMasterKeyID); } + else + if (nVersion >= VERSION_SUPPORT_FLAGS) + READWRITE(keyFlags); } void SetNull() @@ -109,6 +122,7 @@ class CKeyMetadata nCreateTime = 0; hdKeypath.clear(); hdMasterKeyID.SetNull(); + keyFlags = KEY_ORIGIN_UNSET; } }; From d275b9416c6225dd20b20453280a3380d6e183fa Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Sat, 6 Aug 2016 04:29:30 +0000 Subject: [PATCH 2/3] wallet: Key origin refactoring --- src/wallet/rpcdump.cpp | 5 +++-- src/wallet/rpcwallet.cpp | 2 +- src/wallet/wallet.cpp | 7 +++---- src/wallet/walletdb.h | 14 ++++++++++++-- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 548dd3bc899..ef7bcb42d45 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -137,8 +137,9 @@ UniValue importprivkey(const JSONRPCRequest& request) if (pwalletMain->HaveKey(vchAddress)) return NullUniValue; - pwalletMain->mapKeyMetadata[vchAddress].nCreateTime = 1; - pwalletMain->mapKeyMetadata[vchAddress].keyFlags |= CKeyMetadata::KEY_ORIGIN_IMPORTED; + CKeyMetadata& metadata = pwalletMain->mapKeyMetadata[vchAddress]; + metadata.nCreateTime = 1; + metadata.SetKeyOrigin(metadata.GetKeyOrigin() | CKeyMetadata::KEY_ORIGIN_IMPORTED); if (!pwalletMain->AddKeyPubKey(key, pubkey)) throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet"); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 29bcce69203..7f4060a89fd 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -1200,7 +1200,7 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) CKeyID keyID; uint8_t keyFlags = 0; if (address.GetKeyID(keyID)) - keyFlags = pwalletMain->mapKeyMetadata[keyID].keyFlags; + keyFlags = pwalletMain->mapKeyMetadata[keyID].GetKeyOrigin(); std::string keyOrigin; if (keyFlags & CKeyMetadata::KEY_ORIGIN_UNKNOWN) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 2092f383823..416e60a87ab 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -99,11 +99,10 @@ CPubKey CWallet::GenerateNewKey() CKeyMetadata metadata(nCreationTime); //check if the wallet supports keyflags - if (CanSupportFeature(FEATURE_KEYFLAGS)) - { - metadata.nVersion = CKeyMetadata::VERSION_SUPPORT_FLAGS; - metadata.keyFlags |= IsCrypted() ? CKeyMetadata::KEY_ORIGIN_ENC_WALLET : CKeyMetadata::KEY_ORIGIN_UNENC_WALLET; + if (CanSupportFeature(FEATURE_KEYFLAGS)) { + metadata.nVersion = CKeyMetadata::VERSION_WITH_FLAGS; } + metadata.SetKeyOrigin(IsCrypted() ? CKeyMetadata::KEY_ORIGIN_ENC_WALLET : CKeyMetadata::KEY_ORIGIN_UNENC_WALLET); // use HD key derivation if HD was enabled during wallet creation if (IsHDEnabled()) { diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index 7b222473ecd..1de998f95a0 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -73,7 +73,7 @@ class CKeyMetadata { public: static const int VERSION_BASIC=1; - static const int VERSION_SUPPORT_FLAGS=2; + static const int VERSION_WITH_FLAGS=2; static const int VERSION_WITH_HDDATA=10; static const int CURRENT_VERSION=VERSION_WITH_HDDATA; @@ -87,7 +87,9 @@ class CKeyMetadata int64_t nCreateTime; // 0 means unknown std::string hdKeypath; //optional HD/bip32 keypath CKeyID hdMasterKeyID; //id of the HD masterkey used to derive this key +private: uint8_t keyFlags; +public: CKeyMetadata() { @@ -112,7 +114,7 @@ class CKeyMetadata READWRITE(hdMasterKeyID); } else - if (nVersion >= VERSION_SUPPORT_FLAGS) + if (nVersion >= VERSION_WITH_FLAGS) READWRITE(keyFlags); } @@ -124,6 +126,14 @@ class CKeyMetadata hdMasterKeyID.SetNull(); keyFlags = KEY_ORIGIN_UNSET; } + + void SetKeyOrigin(const uint8_t n) { + keyFlags = n; + } + + uint8_t GetKeyOrigin() const { + return keyFlags; + } }; /** Access to the wallet database */ From ff448537529a43e1a1cb4d4b0bf45e9b5aee1fcd Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Sat, 6 Aug 2016 04:31:08 +0000 Subject: [PATCH 3/3] wallet: Reimplement key origin as a field in a new CKeyMetadata map --- src/wallet/wallet.cpp | 12 ++++++++++-- src/wallet/wallet.h | 4 +++- src/wallet/walletdb.h | 44 ++++++++++++++++++++++++++++++++++++-------- 3 files changed, 49 insertions(+), 11 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 416e60a87ab..5aaffd47d2e 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -99,8 +99,16 @@ CPubKey CWallet::GenerateNewKey() CKeyMetadata metadata(nCreationTime); //check if the wallet supports keyflags - if (CanSupportFeature(FEATURE_KEYFLAGS)) { - metadata.nVersion = CKeyMetadata::VERSION_WITH_FLAGS; + if (GetVersion() >= FEATURE_HD) { + if (CanSupportFeature(FEATURE_HD_KEYMETA) && SetMinVersion(FEATURE_HD_KEYMETA)) { + metadata.nVersion = CKeyMetadata::VERSION_WITH_META; + } + } else { + if (CanSupportFeature(FEATURE_KEYMETA) && SetMinVersion(FEATURE_KEYMETA)) { + metadata.nVersion = CKeyMetadata::VERSION_WITH_META; + } else if (CanSupportFeature(FEATURE_KEYFLAGS) && SetMinVersion(FEATURE_KEYFLAGS)) { + metadata.nVersion = CKeyMetadata::VERSION_WITH_FLAGS; + } } metadata.SetKeyOrigin(IsCrypted() ? CKeyMetadata::KEY_ORIGIN_ENC_WALLET : CKeyMetadata::KEY_ORIGIN_UNENC_WALLET); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 420664619f7..00704ca06c1 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -82,9 +82,11 @@ enum WalletFeature FEATURE_WALLETCRYPT = 40000, // wallet encryption FEATURE_COMPRPUBKEY = 60000, // compressed public keys FEATURE_KEYFLAGS = 70000, // key metadata flags for storing informations like key origin + FEATURE_KEYMETA = 70001, // key metadata map FEATURE_HD = 130000, // Hierarchical key derivation after BIP32 (HD Wallet) - FEATURE_LATEST = FEATURE_KEYFLAGS // HD is optional, use FEATURE_KEYFLAGS as latest version + FEATURE_HD_KEYMETA = 130001, // HD + key metadata map + FEATURE_LATEST = FEATURE_KEYMETA // HD is optional, use FEATURE_KEYMETA as latest version }; diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index 1de998f95a0..44b47f9cda2 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -75,7 +75,8 @@ class CKeyMetadata static const int VERSION_BASIC=1; static const int VERSION_WITH_FLAGS=2; static const int VERSION_WITH_HDDATA=10; - static const int CURRENT_VERSION=VERSION_WITH_HDDATA; + static const int VERSION_WITH_META=11; + static const int CURRENT_VERSION=VERSION_WITH_META; static const uint8_t KEY_ORIGIN_UNSET = 0x0000; static const uint8_t KEY_ORIGIN_UNKNOWN = 0x0001; @@ -87,9 +88,7 @@ class CKeyMetadata int64_t nCreateTime; // 0 means unknown std::string hdKeypath; //optional HD/bip32 keypath CKeyID hdMasterKeyID; //id of the HD masterkey used to derive this key -private: - uint8_t keyFlags; -public: + std::map mapMeta; CKeyMetadata() { @@ -99,23 +98,37 @@ class CKeyMetadata { SetNull(); nCreateTime = nCreateTime_; - keyFlags = KEY_ORIGIN_UNSET; } ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action) { + if (ser_action.ForRead()) { + SetNull(); + } READWRITE(this->nVersion); READWRITE(nCreateTime); if (this->nVersion >= VERSION_WITH_HDDATA) { READWRITE(hdKeypath); READWRITE(hdMasterKeyID); + if (nVersion >= VERSION_WITH_META) { + READWRITE(mapMeta); + } } else if (nVersion >= VERSION_WITH_FLAGS) + { + uint8_t keyFlags; + if (!ser_action.ForRead()) { + keyFlags = GetKeyOrigin(); + } READWRITE(keyFlags); + if (ser_action.ForRead()) { + SetKeyOrigin(keyFlags); + } + } } void SetNull() @@ -124,15 +137,30 @@ class CKeyMetadata nCreateTime = 0; hdKeypath.clear(); hdMasterKeyID.SetNull(); - keyFlags = KEY_ORIGIN_UNSET; + mapMeta.clear(); } void SetKeyOrigin(const uint8_t n) { - keyFlags = n; + const char * const p = (const char *)&n; + const auto it = mapMeta.find("origin"); + if (it == mapMeta.end()) { + std::string s(p, 1); + mapMeta["origin"] = s; + } else { + // Avoid losing additional bytes, which might be future extension + if (it->second.size() < 1) { + it->second.resize(1); + } + it->second[0] = *p; + } } uint8_t GetKeyOrigin() const { - return keyFlags; + const auto it = mapMeta.find("origin"); + if (it == mapMeta.end() || it->second.size() < 1) { + return KEY_ORIGIN_UNSET; + } + return it->second[0]; } };