diff options
Diffstat (limited to 'src/walletdb.cpp')
| -rw-r--r-- | src/walletdb.cpp | 157 |
1 files changed, 90 insertions, 67 deletions
diff --git a/src/walletdb.cpp b/src/walletdb.cpp index 81a21443a..702e219a5 100644 --- a/src/walletdb.cpp +++ b/src/walletdb.cpp @@ -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 @@ -204,7 +220,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, CWalletTx& wtx = pwallet->mapWallet[hash]; ssValue >> wtx; CValidationState state; - if (wtx.CheckTransaction(state) && (wtx.GetHash() == hash) && state.IsValid()) + if (CheckTransaction(wtx, state) && (wtx.GetHash() == hash) && state.IsValid()) wtx.BindWallet(pwallet); else { @@ -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,62 +268,45 @@ 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") { - vector<unsigned char> vchPubKey; + CPubKey vchPubKey; ssKey >> vchPubKey; + if (!vchPubKey.IsValid()) + { + strErr = "Error reading wallet database: CPubKey corrupt"; + return false; + } CKey key; + CPrivKey pkey; if (strType == "key") { - CPrivKey pkey; + wss.nKeys++; ssValue >> pkey; - key.SetPubKey(vchPubKey); - if (!key.SetPrivKey(pkey)) - { - strErr = "Error reading wallet database: CPrivKey corrupt"; - return false; - } - if (key.GetPubKey() != vchPubKey) - { - strErr = "Error reading wallet database: CPrivKey pubkey inconsistency"; - return false; - } - if (!key.IsValid()) - { - strErr = "Error reading wallet database: invalid CPrivKey"; - return false; - } - } - else - { + } else { CWalletKey wkey; ssValue >> wkey; - key.SetPubKey(vchPubKey); - if (!key.SetPrivKey(wkey.vchPrivKey)) - { - strErr = "Error reading wallet database: CPrivKey corrupt"; - return false; - } - if (key.GetPubKey() != vchPubKey) - { - strErr = "Error reading wallet database: CWalletKey pubkey inconsistency"; - return false; - } - if (!key.IsValid()) - { - strErr = "Error reading wallet database: invalid CWalletKey"; - return false; - } + pkey = wkey.vchPrivKey; + } + if (!key.SetPrivKey(pkey, vchPubKey.IsCompressed())) + { + strErr = "Error reading wallet database: CPrivKey corrupt"; + return false; + } + if (key.GetPubKey() != vchPubKey) + { + strErr = "Error reading wallet database: CPrivKey pubkey inconsistency"; + return false; } - if (!pwallet->LoadKey(key)) + if (!pwallet->LoadKey(key, vchPubKey)) { strErr = "Error reading wallet database: LoadKey failed"; return false; @@ -334,12 +333,29 @@ 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") + { + CPubKey vchPubKey; + ssKey >> vchPubKey; + CKeyMetadata keyMeta; + ssValue >> keyMeta; + wss.nKeyMeta++; + + pwallet->LoadKeyMetadata(vchPubKey, keyMeta); + + // find earliest key creation time, as wallet birthday + if (!pwallet->nTimeFirstKey || + (keyMeta.nCreateTime < pwallet->nTimeFirstKey)) + pwallet->nTimeFirstKey = keyMeta.nCreateTime; } else if (strType == "defaultkey") { @@ -349,13 +365,22 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, { int64 nIndex; ssKey >> nIndex; + CKeyPool keypool; + ssValue >> keypool; pwallet->setKeyPool.insert(nIndex); + + // If no metadata exists yet, create a default with the pool key's + // creation time. Note that this may be overwritten by actually + // stored metadata for that key later, which is fine. + CKeyID keyid = keypool.vchPubKey.GetID(); + if (pwallet->mapKeyMetadata.count(keyid) == 0) + pwallet->mapKeyMetadata[keyid] = CKeyMetadata(keypool.nTime); } 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") { @@ -389,10 +414,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; @@ -430,8 +452,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: @@ -466,19 +487,26 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) if (result != DB_LOAD_OK) return result; - printf("nFileVersion = %d\n", nFileVersion); + printf("nFileVersion = %d\n", wss.nFileVersion); + + printf("Keys: %u plaintext, %u encrypted, %u w/ metadata, %u total\n", + wss.nKeys, wss.nCKeys, wss.nKeyMeta, wss.nKeys + wss.nCKeys); - BOOST_FOREACH(uint256 hash, vWalletUpgrade) + // nTimeFirstKey is only reliable if all keys have metadata + if ((wss.nKeys + wss.nCKeys) != wss.nKeyMeta) + pwallet->nTimeFirstKey = 1; // 0 would be considered 'no value' + + 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; @@ -634,10 +662,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) @@ -648,9 +673,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) |