Wallet: store key creation time. Calculate whole-wallet birthday.
This also encapsulate wallet-read state information into CWalletScanState.
This commit is contained in:
parent
f59530ce6e
commit
3869fb89b6
4 changed files with 135 additions and 38 deletions
|
@ -45,20 +45,33 @@ CPubKey CWallet::GenerateNewKey()
|
|||
return pubkey;
|
||||
}
|
||||
|
||||
bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
|
||||
bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey,
|
||||
int64 nCreateTime)
|
||||
{
|
||||
if (!nCreateTime)
|
||||
nCreateTime = GetTime();
|
||||
if (!nTimeFirstKey || (nCreateTime < nTimeFirstKey))
|
||||
nTimeFirstKey = nCreateTime;
|
||||
if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey))
|
||||
return false;
|
||||
if (!fFileBacked)
|
||||
return true;
|
||||
if (!IsCrypted()) {
|
||||
return CWalletDB(strWalletFile).WriteKey(pubkey, secret.GetPrivKey());
|
||||
return CWalletDB(strWalletFile).WriteKey(pubkey,
|
||||
secret.GetPrivKey(),
|
||||
nCreateTime);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, const vector<unsigned char> &vchCryptedSecret)
|
||||
bool CWallet::AddCryptedKey(const CPubKey &vchPubKey,
|
||||
const vector<unsigned char> &vchCryptedSecret,
|
||||
int64 nCreateTime)
|
||||
{
|
||||
if (!nCreateTime)
|
||||
nCreateTime = GetTime();
|
||||
if (!nTimeFirstKey || (nCreateTime < nTimeFirstKey))
|
||||
nTimeFirstKey = nCreateTime;
|
||||
if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret))
|
||||
return false;
|
||||
if (!fFileBacked)
|
||||
|
@ -66,9 +79,13 @@ bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, const vector<unsigned char
|
|||
{
|
||||
LOCK(cs_wallet);
|
||||
if (pwalletdbEncryption)
|
||||
return pwalletdbEncryption->WriteCryptedKey(vchPubKey, vchCryptedSecret);
|
||||
return pwalletdbEncryption->WriteCryptedKey(vchPubKey,
|
||||
vchCryptedSecret,
|
||||
nCreateTime);
|
||||
else
|
||||
return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey, vchCryptedSecret);
|
||||
return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey,
|
||||
vchCryptedSecret,
|
||||
nCreateTime);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -123,6 +123,8 @@ public:
|
|||
|
||||
std::set<COutPoint> setLockedCoins;
|
||||
|
||||
int64 nTimeFirstKey;
|
||||
|
||||
// check whether we are allowed to upgrade (or already support) to the named feature
|
||||
bool CanSupportFeature(enum WalletFeature wf) { return nWalletMaxVersion >= wf; }
|
||||
|
||||
|
@ -138,14 +140,14 @@ public:
|
|||
// Generate a new key
|
||||
CPubKey GenerateNewKey();
|
||||
// Adds a key to the store, and saves it to disk.
|
||||
bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey);
|
||||
bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey, int64 nCreateTime = 0);
|
||||
// Adds a key to the store, without saving it to disk (used by LoadWallet)
|
||||
bool LoadKey(const CKey& key, const CPubKey &pubkey) { return CCryptoKeyStore::AddKeyPubKey(key, pubkey); }
|
||||
|
||||
bool LoadMinVersion(int nVersion) { nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; }
|
||||
|
||||
// Adds an encrypted key to the store, and saves it to disk.
|
||||
bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
|
||||
bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret, int64 nCreateTime = 0);
|
||||
// Adds an encrypted key to the store, without saving it to disk (used by LoadWallet)
|
||||
bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
|
||||
bool AddCScript(const CScript& redeemScript);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -25,6 +25,37 @@ enum DBErrors
|
|||
DB_NEED_REWRITE
|
||||
};
|
||||
|
||||
class CKeyMetadata
|
||||
{
|
||||
public:
|
||||
static const int CURRENT_VERSION=1;
|
||||
int nVersion;
|
||||
int64 nCreateTime;
|
||||
|
||||
CKeyMetadata()
|
||||
{
|
||||
SetNull();
|
||||
}
|
||||
CKeyMetadata(int64 nCreateTime_)
|
||||
{
|
||||
nVersion = CKeyMetadata::CURRENT_VERSION;
|
||||
nCreateTime = nCreateTime_;
|
||||
}
|
||||
|
||||
IMPLEMENT_SERIALIZE
|
||||
(
|
||||
READWRITE(this->nVersion);
|
||||
nVersion = this->nVersion;
|
||||
READWRITE(nCreateTime);
|
||||
)
|
||||
|
||||
void SetNull()
|
||||
{
|
||||
nVersion = CKeyMetadata::CURRENT_VERSION;
|
||||
nCreateTime = GetTime();
|
||||
}
|
||||
};
|
||||
|
||||
/** Access to the wallet database (wallet.dat) */
|
||||
class CWalletDB : public CDB
|
||||
{
|
||||
|
@ -52,15 +83,31 @@ public:
|
|||
return Erase(std::make_pair(std::string("tx"), hash));
|
||||
}
|
||||
|
||||
bool WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey)
|
||||
bool WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey,
|
||||
int64 nCreateTime)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
|
||||
CKeyMetadata keyMeta(nCreateTime);
|
||||
if (!Write(std::make_pair(std::string("keymeta"), vchPubKey),
|
||||
keyMeta, false))
|
||||
return false;
|
||||
|
||||
return Write(std::make_pair(std::string("key"), vchPubKey), vchPrivKey, false);
|
||||
}
|
||||
|
||||
bool WriteCryptedKey(const CPubKey& vchPubKey, const std::vector<unsigned char>& vchCryptedSecret, bool fEraseUnencryptedKey = true)
|
||||
bool WriteCryptedKey(const CPubKey& vchPubKey,
|
||||
const std::vector<unsigned char>& vchCryptedSecret,
|
||||
int64 nCreateTime)
|
||||
{
|
||||
const bool fEraseUnencryptedKey = true;
|
||||
nWalletDBUpdated++;
|
||||
|
||||
CKeyMetadata keyMeta(nCreateTime);
|
||||
if (!Write(std::make_pair(std::string("keymeta"), vchPubKey),
|
||||
keyMeta, false))
|
||||
return false;
|
||||
|
||||
if (!Write(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false))
|
||||
return false;
|
||||
if (fEraseUnencryptedKey)
|
||||
|
|
Loading…
Reference in a new issue