Wallet: store key creation time. Calculate whole-wallet birthday.

This also encapsulate wallet-read state information into CWalletScanState.
This commit is contained in:
Jeff Garzik
2013-06-10 09:36:29 -04:00
parent f59530ce6e
commit 3869fb89b6
4 changed files with 135 additions and 38 deletions

View File

@@ -180,11 +180,27 @@ CWalletDB::ReorderTransactions(CWallet* pwallet)
return DB_LOAD_OK;
}
class CWalletScanState {
public:
unsigned int nKeys;
unsigned int nCKeys;
unsigned int nKeyMeta;
bool fIsEncrypted;
bool fAnyUnordered;
int nFileVersion;
vector<uint256> vWalletUpgrade;
CWalletScanState() {
nKeys = nCKeys = nKeyMeta = 0;
fIsEncrypted = false;
fAnyUnordered = false;
nFileVersion = 0;
}
};
bool
ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
int& nFileVersion, vector<uint256>& vWalletUpgrade,
bool& fIsEncrypted, bool& fAnyUnordered, string& strType, string& strErr)
CWalletScanState &wss, string& strType, string& strErr)
{
try {
// Unserialize
@@ -229,11 +245,11 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
strErr = strprintf("LoadWallet() repairing tx ver=%d %s", wtx.fTimeReceivedIsTxTime, hash.ToString().c_str());
wtx.fTimeReceivedIsTxTime = 0;
}
vWalletUpgrade.push_back(hash);
wss.vWalletUpgrade.push_back(hash);
}
if (wtx.nOrderPos == -1)
fAnyUnordered = true;
wss.fAnyUnordered = true;
//// debug print
//printf("LoadWallet %s\n", wtx.GetHash().ToString().c_str());
@@ -252,12 +268,12 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
if (nNumber > nAccountingEntryNumber)
nAccountingEntryNumber = nNumber;
if (!fAnyUnordered)
if (!wss.fAnyUnordered)
{
CAccountingEntry acentry;
ssValue >> acentry;
if (acentry.nOrderPos == -1)
fAnyUnordered = true;
wss.fAnyUnordered = true;
}
}
else if (strType == "key" || strType == "wkey")
@@ -272,8 +288,10 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
CKey key;
CPrivKey pkey;
if (strType == "key")
{
wss.nKeys++;
ssValue >> pkey;
else {
} else {
CWalletKey wkey;
ssValue >> wkey;
pkey = wkey.vchPrivKey;
@@ -315,12 +333,27 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
ssKey >> vchPubKey;
vector<unsigned char> vchPrivKey;
ssValue >> vchPrivKey;
wss.nCKeys++;
if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey))
{
strErr = "Error reading wallet database: LoadCryptedKey failed";
return false;
}
fIsEncrypted = true;
wss.fIsEncrypted = true;
}
else if (strType == "keymeta")
{
vector<unsigned char> vchPubKey;
ssKey >> vchPubKey;
CKeyMetadata keyMeta;
ssValue >> keyMeta;
wss.nKeyMeta++;
// find earliest key creation time, as wallet birthday
if (!pwallet->nTimeFirstKey ||
(keyMeta.nCreateTime < pwallet->nTimeFirstKey))
pwallet->nTimeFirstKey = keyMeta.nCreateTime;
}
else if (strType == "defaultkey")
{
@@ -334,9 +367,9 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
}
else if (strType == "version")
{
ssValue >> nFileVersion;
if (nFileVersion == 10300)
nFileVersion = 300;
ssValue >> wss.nFileVersion;
if (wss.nFileVersion == 10300)
wss.nFileVersion = 300;
}
else if (strType == "cscript")
{
@@ -370,10 +403,7 @@ static bool IsKeyType(string strType)
DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
{
pwallet->vchDefaultKey = CPubKey();
int nFileVersion = 0;
vector<uint256> vWalletUpgrade;
bool fIsEncrypted = false;
bool fAnyUnordered = false;
CWalletScanState wss;
bool fNoncriticalErrors = false;
DBErrors result = DB_LOAD_OK;
@@ -411,8 +441,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
// Try to be tolerant of single corrupt records:
string strType, strErr;
if (!ReadKeyValue(pwallet, ssKey, ssValue, nFileVersion,
vWalletUpgrade, fIsEncrypted, fAnyUnordered, strType, strErr))
if (!ReadKeyValue(pwallet, ssKey, ssValue, wss, strType, strErr))
{
// losing keys is considered a catastrophic error, anything else
// we assume the user can live with:
@@ -447,19 +476,26 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
if (result != DB_LOAD_OK)
return result;
printf("nFileVersion = %d\n", nFileVersion);
printf("nFileVersion = %d\n", wss.nFileVersion);
BOOST_FOREACH(uint256 hash, vWalletUpgrade)
printf("Keys: %u plaintext, %u encrypted, %u w/ metadata, %u total\n",
wss.nKeys, wss.nCKeys, wss.nKeyMeta, wss.nKeys + wss.nCKeys);
// nTimeFirstKey is only reliable if all keys have metadata
if ((wss.nKeys + wss.nCKeys) != wss.nKeyMeta)
pwallet->nTimeFirstKey = 0;
BOOST_FOREACH(uint256 hash, wss.vWalletUpgrade)
WriteTx(hash, pwallet->mapWallet[hash]);
// Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc:
if (fIsEncrypted && (nFileVersion == 40000 || nFileVersion == 50000))
if (wss.fIsEncrypted && (wss.nFileVersion == 40000 || wss.nFileVersion == 50000))
return DB_NEED_REWRITE;
if (nFileVersion < CLIENT_VERSION) // Update
if (wss.nFileVersion < CLIENT_VERSION) // Update
WriteVersion(CLIENT_VERSION);
if (fAnyUnordered)
if (wss.fAnyUnordered)
result = ReorderTransactions(pwallet);
return result;
@@ -615,10 +651,7 @@ bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys)
return false;
}
CWallet dummyWallet;
int nFileVersion = 0;
vector<uint256> vWalletUpgrade;
bool fIsEncrypted = false;
bool fAnyUnordered = false;
CWalletScanState wss;
DbTxn* ptxn = dbenv.TxnBegin();
BOOST_FOREACH(CDBEnv::KeyValPair& row, salvagedData)
@@ -629,9 +662,7 @@ bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys)
CDataStream ssValue(row.second, SER_DISK, CLIENT_VERSION);
string strType, strErr;
bool fReadOK = ReadKeyValue(&dummyWallet, ssKey, ssValue,
nFileVersion, vWalletUpgrade,
fIsEncrypted, fAnyUnordered,
strType, strErr);
wss, strType, strErr);
if (!IsKeyType(strType))
continue;
if (!fReadOK)