From fa6dc7fa5fdfd76c6dd5f7ae693a2fb4e37e271f Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Sat, 27 Jul 2019 15:50:36 -0400 Subject: [PATCH 1/2] wallet: Enumerate walletdb keys --- src/wallet/walletdb.cpp | 182 +++++++++++++++++++--------------------- src/wallet/walletdb.h | 25 ++++++ 2 files changed, 113 insertions(+), 94 deletions(-) diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 43dd28b67..f5b90d3a9 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -21,45 +21,70 @@ #include +namespace DBKeys { +const std::string ACENTRY{"acentry"}; +const std::string BESTBLOCK_NOMERKLE{"bestblock_nomerkle"}; +const std::string BESTBLOCK{"bestblock"}; +const std::string CRYPTED_KEY{"ckey"}; +const std::string CSCRIPT{"cscript"}; +const std::string DEFAULTKEY{"defaultkey"}; +const std::string DESTDATA{"destdata"}; +const std::string FLAGS{"flags"}; +const std::string HDCHAIN{"hdchain"}; +const std::string KEYMETA{"keymeta"}; +const std::string KEY{"key"}; +const std::string MASTER_KEY{"mkey"}; +const std::string MINVERSION{"minversion"}; +const std::string NAME{"name"}; +const std::string OLD_KEY{"wkey"}; +const std::string ORDERPOSNEXT{"orderposnext"}; +const std::string POOL{"pool"}; +const std::string PURPOSE{"purpose"}; +const std::string TX{"tx"}; +const std::string VERSION{"version"}; +const std::string WATCHMETA{"watchmeta"}; +const std::string WATCHS{"watchs"}; +} // namespace DBKeys + // // WalletBatch // bool WalletBatch::WriteName(const std::string& strAddress, const std::string& strName) { - return WriteIC(std::make_pair(std::string("name"), strAddress), strName); + return WriteIC(std::make_pair(DBKeys::NAME, strAddress), strName); } bool WalletBatch::EraseName(const std::string& strAddress) { // This should only be used for sending addresses, never for receiving addresses, // receiving addresses must always have an address book entry if they're not change return. - return EraseIC(std::make_pair(std::string("name"), strAddress)); + return EraseIC(std::make_pair(DBKeys::NAME, strAddress)); } bool WalletBatch::WritePurpose(const std::string& strAddress, const std::string& strPurpose) { - return WriteIC(std::make_pair(std::string("purpose"), strAddress), strPurpose); + return WriteIC(std::make_pair(DBKeys::PURPOSE, strAddress), strPurpose); } bool WalletBatch::ErasePurpose(const std::string& strAddress) { - return EraseIC(std::make_pair(std::string("purpose"), strAddress)); + return EraseIC(std::make_pair(DBKeys::PURPOSE, strAddress)); } bool WalletBatch::WriteTx(const CWalletTx& wtx) { - return WriteIC(std::make_pair(std::string("tx"), wtx.GetHash()), wtx); + return WriteIC(std::make_pair(DBKeys::TX, wtx.GetHash()), wtx); } bool WalletBatch::EraseTx(uint256 hash) { - return EraseIC(std::make_pair(std::string("tx"), hash)); + return EraseIC(std::make_pair(DBKeys::TX, hash)); } bool WalletBatch::WriteKeyMetadata(const CKeyMetadata& meta, const CPubKey& pubkey, const bool overwrite) { - return WriteIC(std::make_pair(std::string("keymeta"), pubkey), meta, overwrite); + return WriteIC(std::make_pair(DBKeys::KEYMETA, pubkey), meta, overwrite); } bool WalletBatch::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata& keyMeta) @@ -74,7 +99,7 @@ bool WalletBatch::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end()); vchKey.insert(vchKey.end(), vchPrivKey.begin(), vchPrivKey.end()); - return WriteIC(std::make_pair(std::string("key"), vchPubKey), std::make_pair(vchPrivKey, Hash(vchKey.begin(), vchKey.end())), false); + return WriteIC(std::make_pair(DBKeys::KEY, vchPubKey), std::make_pair(vchPrivKey, Hash(vchKey.begin(), vchKey.end())), false); } bool WalletBatch::WriteCryptedKey(const CPubKey& vchPubKey, @@ -85,75 +110,75 @@ bool WalletBatch::WriteCryptedKey(const CPubKey& vchPubKey, return false; } - if (!WriteIC(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false)) { + if (!WriteIC(std::make_pair(DBKeys::CRYPTED_KEY, vchPubKey), vchCryptedSecret, false)) { return false; } - EraseIC(std::make_pair(std::string("key"), vchPubKey)); - EraseIC(std::make_pair(std::string("wkey"), vchPubKey)); + EraseIC(std::make_pair(DBKeys::KEY, vchPubKey)); + EraseIC(std::make_pair(DBKeys::OLD_KEY, vchPubKey)); return true; } bool WalletBatch::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey) { - return WriteIC(std::make_pair(std::string("mkey"), nID), kMasterKey, true); + return WriteIC(std::make_pair(DBKeys::MASTER_KEY, nID), kMasterKey, true); } bool WalletBatch::WriteCScript(const uint160& hash, const CScript& redeemScript) { - return WriteIC(std::make_pair(std::string("cscript"), hash), redeemScript, false); + return WriteIC(std::make_pair(DBKeys::CSCRIPT, hash), redeemScript, false); } bool WalletBatch::WriteWatchOnly(const CScript &dest, const CKeyMetadata& keyMeta) { - if (!WriteIC(std::make_pair(std::string("watchmeta"), dest), keyMeta)) { + if (!WriteIC(std::make_pair(DBKeys::WATCHMETA, dest), keyMeta)) { return false; } - return WriteIC(std::make_pair(std::string("watchs"), dest), '1'); + return WriteIC(std::make_pair(DBKeys::WATCHS, dest), '1'); } bool WalletBatch::EraseWatchOnly(const CScript &dest) { - if (!EraseIC(std::make_pair(std::string("watchmeta"), dest))) { + if (!EraseIC(std::make_pair(DBKeys::WATCHMETA, dest))) { return false; } - return EraseIC(std::make_pair(std::string("watchs"), dest)); + return EraseIC(std::make_pair(DBKeys::WATCHS, dest)); } bool WalletBatch::WriteBestBlock(const CBlockLocator& locator) { - WriteIC(std::string("bestblock"), CBlockLocator()); // Write empty block locator so versions that require a merkle branch automatically rescan - return WriteIC(std::string("bestblock_nomerkle"), locator); + WriteIC(DBKeys::BESTBLOCK, CBlockLocator()); // Write empty block locator so versions that require a merkle branch automatically rescan + return WriteIC(DBKeys::BESTBLOCK_NOMERKLE, locator); } bool WalletBatch::ReadBestBlock(CBlockLocator& locator) { - if (m_batch.Read(std::string("bestblock"), locator) && !locator.vHave.empty()) return true; - return m_batch.Read(std::string("bestblock_nomerkle"), locator); + if (m_batch.Read(DBKeys::BESTBLOCK, locator) && !locator.vHave.empty()) return true; + return m_batch.Read(DBKeys::BESTBLOCK_NOMERKLE, locator); } bool WalletBatch::WriteOrderPosNext(int64_t nOrderPosNext) { - return WriteIC(std::string("orderposnext"), nOrderPosNext); + return WriteIC(DBKeys::ORDERPOSNEXT, nOrderPosNext); } bool WalletBatch::ReadPool(int64_t nPool, CKeyPool& keypool) { - return m_batch.Read(std::make_pair(std::string("pool"), nPool), keypool); + return m_batch.Read(std::make_pair(DBKeys::POOL, nPool), keypool); } bool WalletBatch::WritePool(int64_t nPool, const CKeyPool& keypool) { - return WriteIC(std::make_pair(std::string("pool"), nPool), keypool); + return WriteIC(std::make_pair(DBKeys::POOL, nPool), keypool); } bool WalletBatch::ErasePool(int64_t nPool) { - return EraseIC(std::make_pair(std::string("pool"), nPool)); + return EraseIC(std::make_pair(DBKeys::POOL, nPool)); } bool WalletBatch::WriteMinVersion(int nVersion) { - return WriteIC(std::string("minversion"), nVersion); + return WriteIC(DBKeys::MINVERSION, nVersion); } class CWalletScanState { @@ -180,20 +205,15 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, // Taking advantage of the fact that pair serialization // is just the two items serialized one after the other ssKey >> strType; - if (strType == "name") - { + if (strType == DBKeys::NAME) { std::string strAddress; ssKey >> strAddress; ssValue >> pwallet->mapAddressBook[DecodeDestination(strAddress)].name; - } - else if (strType == "purpose") - { + } else if (strType == DBKeys::PURPOSE) { std::string strAddress; ssKey >> strAddress; ssValue >> pwallet->mapAddressBook[DecodeDestination(strAddress)].purpose; - } - else if (strType == "tx") - { + } else if (strType == DBKeys::TX) { uint256 hash; ssKey >> hash; CWalletTx wtx(nullptr /* pwallet */, MakeTransactionRef()); @@ -227,9 +247,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, wss.fAnyUnordered = true; pwallet->LoadToWallet(wtx); - } - else if (strType == "watchs") - { + } else if (strType == DBKeys::WATCHS) { wss.nWatchKeys++; CScript script; ssKey >> script; @@ -237,9 +255,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, ssValue >> fYes; if (fYes == '1') pwallet->LoadWatchOnly(script); - } - else if (strType == "key" || strType == "wkey") - { + } else if (strType == DBKeys::KEY || strType == DBKeys::OLD_KEY) { CPubKey vchPubKey; ssKey >> vchPubKey; if (!vchPubKey.IsValid()) @@ -251,8 +267,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, CPrivKey pkey; uint256 hash; - if (strType == "key") - { + if (strType == DBKeys::KEY) { wss.nKeys++; ssValue >> pkey; } else { @@ -261,10 +276,10 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, pkey = wkey.vchPrivKey; } - // Old wallets store keys as "key" [pubkey] => [privkey] + // Old wallets store keys as DBKeys::KEY [pubkey] => [privkey] // ... which was slow for wallets with lots of keys, because the public key is re-derived from the private key // using EC operations as a checksum. - // Newer wallets store keys as "key"[pubkey] => [privkey][hash(pubkey,privkey)], which is much faster while + // Newer wallets store keys as DBKeys::KEY [pubkey] => [privkey][hash(pubkey,privkey)], which is much faster while // remaining backwards-compatible. try { @@ -301,9 +316,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, strErr = "Error reading wallet database: LoadKey failed"; return false; } - } - else if (strType == "mkey") - { + } else if (strType == DBKeys::MASTER_KEY) { unsigned int nID; ssKey >> nID; CMasterKey kMasterKey; @@ -316,9 +329,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, pwallet->mapMasterKeys[nID] = kMasterKey; if (pwallet->nMasterKeyMaxID < nID) pwallet->nMasterKeyMaxID = nID; - } - else if (strType == "ckey") - { + } else if (strType == DBKeys::CRYPTED_KEY) { CPubKey vchPubKey; ssKey >> vchPubKey; if (!vchPubKey.IsValid()) @@ -336,27 +347,21 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, return false; } wss.fIsEncrypted = true; - } - else if (strType == "keymeta") - { + } else if (strType == DBKeys::KEYMETA) { CPubKey vchPubKey; ssKey >> vchPubKey; CKeyMetadata keyMeta; ssValue >> keyMeta; wss.nKeyMeta++; pwallet->LoadKeyMetadata(vchPubKey.GetID(), keyMeta); - } - else if (strType == "watchmeta") - { + } else if (strType == DBKeys::WATCHMETA) { CScript script; ssKey >> script; CKeyMetadata keyMeta; ssValue >> keyMeta; wss.nKeyMeta++; pwallet->LoadScriptMetadata(CScriptID(script), keyMeta); - } - else if (strType == "defaultkey") - { + } else if (strType == DBKeys::DEFAULTKEY) { // We don't want or need the default key, but if there is one set, // we want to make sure that it is valid so that we can detect corruption CPubKey vchPubKey; @@ -365,18 +370,14 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, strErr = "Error reading wallet database: Default Key corrupt"; return false; } - } - else if (strType == "pool") - { + } else if (strType == DBKeys::POOL) { int64_t nIndex; ssKey >> nIndex; CKeyPool keypool; ssValue >> keypool; pwallet->LoadKeyPool(nIndex, keypool); - } - else if (strType == "cscript") - { + } else if (strType == DBKeys::CSCRIPT) { uint160 hash; ssKey >> hash; CScript script; @@ -386,33 +387,27 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, strErr = "Error reading wallet database: LoadCScript failed"; return false; } - } - else if (strType == "orderposnext") - { + } else if (strType == DBKeys::ORDERPOSNEXT) { ssValue >> pwallet->nOrderPosNext; - } - else if (strType == "destdata") - { + } else if (strType == DBKeys::DESTDATA) { std::string strAddress, strKey, strValue; ssKey >> strAddress; ssKey >> strKey; ssValue >> strValue; pwallet->LoadDestData(DecodeDestination(strAddress), strKey, strValue); - } - else if (strType == "hdchain") - { + } else if (strType == DBKeys::HDCHAIN) { CHDChain chain; ssValue >> chain; pwallet->SetHDChain(chain, true); - } else if (strType == "flags") { + } else if (strType == DBKeys::FLAGS) { uint64_t flags; ssValue >> flags; if (!pwallet->SetWalletFlags(flags, true)) { strErr = "Error reading wallet database: Unknown non-tolerable wallet flags found"; return false; } - } else if (strType != "bestblock" && strType != "bestblock_nomerkle" && - strType != "minversion" && strType != "acentry" && strType != "version") { + } else if (strType != DBKeys::BESTBLOCK && strType != DBKeys::BESTBLOCK_NOMERKLE && + strType != DBKeys::MINVERSION && strType != DBKeys::ACENTRY && strType != DBKeys::VERSION) { wss.m_unknown_records++; } } catch (const std::exception& e) { @@ -431,8 +426,8 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, bool WalletBatch::IsKeyType(const std::string& strType) { - return (strType== "key" || strType == "wkey" || - strType == "mkey" || strType == "ckey"); + return (strType == DBKeys::KEY || strType == DBKeys::OLD_KEY || + strType == DBKeys::MASTER_KEY || strType == DBKeys::CRYPTED_KEY); } DBErrors WalletBatch::LoadWallet(CWallet* pwallet) @@ -444,8 +439,7 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet) LOCK(pwallet->cs_wallet); try { int nMinVersion = 0; - if (m_batch.Read((std::string)"minversion", nMinVersion)) - { + if (m_batch.Read(DBKeys::MINVERSION, nMinVersion)) { if (nMinVersion > FEATURE_LATEST) return DBErrors::TOO_NEW; pwallet->LoadMinVersion(nMinVersion); @@ -479,15 +473,15 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet) { // losing keys is considered a catastrophic error, anything else // we assume the user can live with: - if (IsKeyType(strType) || strType == "defaultkey") { + if (IsKeyType(strType) || strType == DBKeys::DEFAULTKEY) { result = DBErrors::CORRUPT; - } else if(strType == "flags") { + } else if (strType == DBKeys::FLAGS) { // reading the wallet flags can only fail if unknown flags are present result = DBErrors::TOO_NEW; } else { // Leave other errors alone, if we try to fix them we might make things worse. fNoncriticalErrors = true; // ... but do warn the user there is something wrong. - if (strType == "tx") + if (strType == DBKeys::TX) // Rescan if there is a bad transaction record: gArgs.SoftSetBoolArg("-rescan", true); } @@ -514,7 +508,7 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet) // Last client version to open this wallet, was previously the file version number int last_client = CLIENT_VERSION; - m_batch.Read(std::string("version"), last_client); + m_batch.Read(DBKeys::VERSION, last_client); int wallet_version = pwallet->GetVersion(); pwallet->WalletLogPrintf("Wallet File Version = %d\n", wallet_version > 0 ? wallet_version : last_client); @@ -534,7 +528,7 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet) return DBErrors::NEED_REWRITE; if (last_client < CLIENT_VERSION) // Update - m_batch.Write(std::string("version"), CLIENT_VERSION); + m_batch.Write(DBKeys::VERSION, CLIENT_VERSION); if (wss.fAnyUnordered) result = pwallet->ReorderTransactions(); @@ -556,8 +550,7 @@ DBErrors WalletBatch::FindWalletTx(std::vector& vTxHash, std::vector FEATURE_LATEST) return DBErrors::TOO_NEW; } @@ -586,7 +579,7 @@ DBErrors WalletBatch::FindWalletTx(std::vector& vTxHash, std::vector> strType; - if (strType == "tx") { + if (strType == DBKeys::TX) { uint256 hash; ssKey >> hash; @@ -721,8 +714,9 @@ bool WalletBatch::RecoverKeysOnlyFilter(void *callbackData, CDataStream ssKey, C fReadOK = ReadKeyValue(dummyWallet, ssKey, ssValue, dummyWss, strType, strErr); } - if (!IsKeyType(strType) && strType != "hdchain") + if (!IsKeyType(strType) && strType != DBKeys::HDCHAIN) { return false; + } if (!fReadOK) { LogPrintf("WARNING: WalletBatch::Recover skipping %s: %s\n", strType, strErr); @@ -744,23 +738,23 @@ bool WalletBatch::VerifyDatabaseFile(const fs::path& wallet_path, std::string& w bool WalletBatch::WriteDestData(const std::string &address, const std::string &key, const std::string &value) { - return WriteIC(std::make_pair(std::string("destdata"), std::make_pair(address, key)), value); + return WriteIC(std::make_pair(DBKeys::DESTDATA, std::make_pair(address, key)), value); } bool WalletBatch::EraseDestData(const std::string &address, const std::string &key) { - return EraseIC(std::make_pair(std::string("destdata"), std::make_pair(address, key))); + return EraseIC(std::make_pair(DBKeys::DESTDATA, std::make_pair(address, key))); } bool WalletBatch::WriteHDChain(const CHDChain& chain) { - return WriteIC(std::string("hdchain"), chain); + return WriteIC(DBKeys::HDCHAIN, chain); } bool WalletBatch::WriteWalletFlags(const uint64_t flags) { - return WriteIC(std::string("flags"), flags); + return WriteIC(DBKeys::FLAGS, flags); } bool WalletBatch::TxnBegin() diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index 90692317e..b78bc49f9 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -55,6 +55,31 @@ enum class DBErrors NEED_REWRITE }; +namespace DBKeys { +extern const std::string ACENTRY; +extern const std::string BESTBLOCK; +extern const std::string BESTBLOCK_NOMERKLE; +extern const std::string CRYPTED_KEY; +extern const std::string CSCRIPT; +extern const std::string DEFAULTKEY; +extern const std::string DESTDATA; +extern const std::string FLAGS; +extern const std::string HDCHAIN; +extern const std::string KEY; +extern const std::string KEYMETA; +extern const std::string MASTER_KEY; +extern const std::string MINVERSION; +extern const std::string NAME; +extern const std::string OLD_KEY; +extern const std::string ORDERPOSNEXT; +extern const std::string POOL; +extern const std::string PURPOSE; +extern const std::string TX; +extern const std::string VERSION; +extern const std::string WATCHMETA; +extern const std::string WATCHS; +} // namespace DBKeys + /* simple HD chain data model */ class CHDChain { From fa6f22bf44c0f741285f27f27ac18e9679802e5e Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Sat, 27 Jul 2019 16:38:16 -0400 Subject: [PATCH 2/2] wallet: Rename CWalletKey to OldKey --- src/wallet/wallet.cpp | 6 ------ src/wallet/wallet.h | 19 +++++++------------ src/wallet/walletdb.cpp | 2 +- 3 files changed, 8 insertions(+), 19 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index b9eb0d3ee..e8cc49b1f 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -4626,12 +4626,6 @@ CKeyPool::CKeyPool(const CPubKey& vchPubKeyIn, bool internalIn) m_pre_split = false; } -CWalletKey::CWalletKey(int64_t nExpires) -{ - nTimeCreated = (nExpires ? GetTime() : 0); - nTimeExpires = nExpires; -} - void CMerkleTx::SetMerkleBranch(const uint256& block_hash, int posInBlock) { // Update the tx's hashBlock diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 8ed27c3cc..243bf9ac3 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -676,23 +676,18 @@ public: } }; -/** Private key that includes an expiration date in case it never gets used. */ -class CWalletKey -{ -public: +/** Private key that was serialized by an old wallet (only used for deserialization) */ +struct OldKey { CPrivKey vchPrivKey; - int64_t nTimeCreated; - int64_t nTimeExpires; - std::string strComment; - // todo: add something to note what created it (user, getnewaddress, change) - // maybe should have a map property map - - explicit CWalletKey(int64_t nExpires=0); - ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action) { + // no longer used by the wallet, thus dropped after deserialization: + int64_t nTimeCreated; + int64_t nTimeExpires; + std::string strComment; + int nVersion = s.GetVersion(); if (!(s.GetType() & SER_GETHASH)) READWRITE(nVersion); diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index f5b90d3a9..987665c9d 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -271,7 +271,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, wss.nKeys++; ssValue >> pkey; } else { - CWalletKey wkey; + OldKey wkey; ssValue >> wkey; pkey = wkey.vchPrivKey; }