Merge #16475: wallet: Enumerate walletdb keys

fa6f22bf44 wallet: Rename CWalletKey to OldKey (MarcoFalke)
fa6dc7fa5f wallet: Enumerate walletdb keys (MarcoFalke)

Pull request description:

  It is nice to see all the keys that exists in a single enum

  Also, rename CWalletKey to OldKey and update the outdated documentation

ACKs for top commit:
  laanwj:
    ACK fa6f22bf44, I'm a big fan of this kind of change as it prevents typos, which can happen with 'magic' strings in the code.
  promag:
    ACK fa6f22bf44. @jnewbery suggestions are great followups, I think this is good enough.
  meshcollider:
    utACK fa6f22bf44
  achow101:
    Code review ACK fa6f22bf44
  fanquake:
    ACK fa6f22bf44 - I had a quick look over, definitely prefer this to strings floating around everywhere.

Tree-SHA512: 8ac3abd5a0d22dac1d77b8f97fe1e16c2608d650f3e9d6dd1df2fd5aeb35ef6643dfd4cd5c162404bb0100343c927d66df04dc695507ffc84a6c667e603acc54
This commit is contained in:
fanquake 2019-07-30 11:19:44 +08:00
commit 478fe328a7
No known key found for this signature in database
GPG key ID: 2EEB9F5CC09526C1
4 changed files with 121 additions and 113 deletions

View file

@ -4627,12 +4627,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

View file

@ -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<string, string> property map
explicit CWalletKey(int64_t nExpires=0);
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
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);

View file

@ -21,45 +21,70 @@
#include <boost/thread.hpp>
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,20 +267,19 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
CPrivKey pkey;
uint256 hash;
if (strType == "key")
{
if (strType == DBKeys::KEY) {
wss.nKeys++;
ssValue >> pkey;
} else {
CWalletKey wkey;
OldKey wkey;
ssValue >> wkey;
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<uint256>& vTxHash, std::vector<CW
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;
}
@ -586,7 +579,7 @@ DBErrors WalletBatch::FindWalletTx(std::vector<uint256>& vTxHash, std::vector<CW
std::string strType;
ssKey >> 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()

View file

@ -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
{