diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index bb5337c4adb..ef7bcb42d45 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -137,7 +137,9 @@ UniValue importprivkey(const JSONRPCRequest& request) if (pwalletMain->HaveKey(vchAddress)) return NullUniValue; - pwalletMain->mapKeyMetadata[vchAddress].nCreateTime = 1; + 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 5a22e0278da..7f4060a89fd 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].GetKeyOrigin(); + + 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..5aaffd47d2e 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -98,6 +98,20 @@ CPubKey CWallet::GenerateNewKey() int64_t nCreationTime = GetTime(); CKeyMetadata metadata(nCreationTime); + //check if the wallet supports keyflags + 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); + // 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..00704ca06c1 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -81,9 +81,12 @@ 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_COMPRPUBKEY // HD is optional, use FEATURE_COMPRPUBKEY 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 eb25ac613dd..44b47f9cda2 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -73,12 +73,22 @@ class CKeyMetadata { public: 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; + 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 + std::map mapMeta; CKeyMetadata() { @@ -94,12 +104,30 @@ class CKeyMetadata 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); + } } } @@ -109,6 +137,30 @@ class CKeyMetadata nCreateTime = 0; hdKeypath.clear(); hdMasterKeyID.SetNull(); + mapMeta.clear(); + } + + void SetKeyOrigin(const uint8_t 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 { + const auto it = mapMeta.find("origin"); + if (it == mapMeta.end() || it->second.size() < 1) { + return KEY_ORIGIN_UNSET; + } + return it->second[0]; } };