diff --git a/src/wallet/coincontrol.h b/src/wallet/coincontrol.h index eaf4ff806..587e61ec4 100644 --- a/src/wallet/coincontrol.h +++ b/src/wallet/coincontrol.h @@ -1,79 +1,62 @@ // Copyright (c) 2011-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_WALLET_COINCONTROL_H #define BITCOIN_WALLET_COINCONTROL_H #include "primitives/transaction.h" /** Coin Control Features. */ -class CCoinControl -{ +class CCoinControl { public: CTxDestination destChange; - //! If false, allows unselected inputs, but requires all selected inputs be used + //! If false, allows unselected inputs, but requires all selected inputs be + //! used bool fAllowOtherInputs; - //! Includes watch only addresses which match the ISMINE_WATCH_SOLVABLE criteria + //! Includes watch only addresses which match the ISMINE_WATCH_SOLVABLE + //! criteria bool fAllowWatchOnly; //! Minimum absolute fee (not per kilobyte) CAmount nMinimumTotalFee; //! Override estimated feerate bool fOverrideFeeRate; //! Feerate to use if overrideFeeRate is true CFeeRate nFeeRate; //! Override the default confirmation target, 0 = use default int nConfirmTarget; - CCoinControl() - { - SetNull(); - } + CCoinControl() { SetNull(); } - void SetNull() - { + void SetNull() { destChange = CNoDestination(); fAllowOtherInputs = false; fAllowWatchOnly = false; setSelected.clear(); nMinimumTotalFee = 0; nFeeRate = CFeeRate(0); fOverrideFeeRate = false; nConfirmTarget = 0; } - bool HasSelected() const - { - return (setSelected.size() > 0); - } + bool HasSelected() const { return (setSelected.size() > 0); } - bool IsSelected(const COutPoint& output) const - { + bool IsSelected(const COutPoint &output) const { return (setSelected.count(output) > 0); } - void Select(const COutPoint& output) - { - setSelected.insert(output); - } + void Select(const COutPoint &output) { setSelected.insert(output); } - void UnSelect(const COutPoint& output) - { - setSelected.erase(output); - } + void UnSelect(const COutPoint &output) { setSelected.erase(output); } - void UnSelectAll() - { - setSelected.clear(); - } + void UnSelectAll() { setSelected.clear(); } - void ListSelected(std::vector& vOutpoints) const - { + void ListSelected(std::vector &vOutpoints) const { vOutpoints.assign(setSelected.begin(), setSelected.end()); } private: std::set setSelected; }; #endif // BITCOIN_WALLET_COINCONTROL_H diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index 7d1b429b3..7f5504ab4 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -1,475 +1,465 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "db.h" #include "addrman.h" #include "hash.h" #include "protocol.h" #include "util.h" #include "utilstrencodings.h" #include #ifndef WIN32 #include #endif #include #include #include using namespace std; - // // CDB // CDBEnv bitdb; -void CDBEnv::EnvShutdown() -{ - if (!fDbEnvInit) - return; +void CDBEnv::EnvShutdown() { + if (!fDbEnvInit) return; fDbEnvInit = false; int ret = dbenv->close(0); if (ret != 0) - LogPrintf("CDBEnv::EnvShutdown: Error %d shutting down database environment: %s\n", ret, DbEnv::strerror(ret)); - if (!fMockDb) - DbEnv((u_int32_t)0).remove(strPath.c_str(), 0); + LogPrintf("CDBEnv::EnvShutdown: Error %d shutting down database " + "environment: %s\n", + ret, DbEnv::strerror(ret)); + if (!fMockDb) DbEnv((u_int32_t)0).remove(strPath.c_str(), 0); } -void CDBEnv::Reset() -{ +void CDBEnv::Reset() { delete dbenv; dbenv = new DbEnv(DB_CXX_NO_EXCEPTIONS); fDbEnvInit = false; fMockDb = false; } -CDBEnv::CDBEnv() : dbenv(NULL) -{ +CDBEnv::CDBEnv() : dbenv(NULL) { Reset(); } -CDBEnv::~CDBEnv() -{ +CDBEnv::~CDBEnv() { EnvShutdown(); delete dbenv; dbenv = NULL; } -void CDBEnv::Close() -{ +void CDBEnv::Close() { EnvShutdown(); } -bool CDBEnv::Open(const boost::filesystem::path& pathIn) -{ - if (fDbEnvInit) - return true; +bool CDBEnv::Open(const boost::filesystem::path &pathIn) { + if (fDbEnvInit) return true; boost::this_thread::interruption_point(); strPath = pathIn.string(); boost::filesystem::path pathLogDir = pathIn / "database"; TryCreateDirectory(pathLogDir); boost::filesystem::path pathErrorFile = pathIn / "db.log"; - LogPrintf("CDBEnv::Open: LogDir=%s ErrorFile=%s\n", pathLogDir.string(), pathErrorFile.string()); + LogPrintf("CDBEnv::Open: LogDir=%s ErrorFile=%s\n", pathLogDir.string(), + pathErrorFile.string()); unsigned int nEnvFlags = 0; - if (GetBoolArg("-privdb", DEFAULT_WALLET_PRIVDB)) - nEnvFlags |= DB_PRIVATE; + if (GetBoolArg("-privdb", DEFAULT_WALLET_PRIVDB)) nEnvFlags |= DB_PRIVATE; dbenv->set_lg_dir(pathLogDir.string().c_str()); - dbenv->set_cachesize(0, 0x100000, 1); // 1 MiB should be enough for just the wallet + // 1 MiB should be enough for just the wallet + dbenv->set_cachesize(0, 0x100000, 1); dbenv->set_lg_bsize(0x10000); dbenv->set_lg_max(1048576); dbenv->set_lk_max_locks(40000); dbenv->set_lk_max_objects(40000); - dbenv->set_errfile(fopen(pathErrorFile.string().c_str(), "a")); /// debug + /// debug + dbenv->set_errfile(fopen(pathErrorFile.string().c_str(), "a")); dbenv->set_flags(DB_AUTO_COMMIT, 1); dbenv->set_flags(DB_TXN_WRITE_NOSYNC, 1); dbenv->log_set_config(DB_LOG_AUTO_REMOVE, 1); - int ret = dbenv->open(strPath.c_str(), - DB_CREATE | - DB_INIT_LOCK | - DB_INIT_LOG | - DB_INIT_MPOOL | - DB_INIT_TXN | - DB_THREAD | - DB_RECOVER | - nEnvFlags, - S_IRUSR | S_IWUSR); + int ret = + dbenv->open(strPath.c_str(), + DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | + DB_INIT_TXN | DB_THREAD | DB_RECOVER | nEnvFlags, + S_IRUSR | S_IWUSR); if (ret != 0) - return error("CDBEnv::Open: Error %d opening database environment: %s\n", ret, DbEnv::strerror(ret)); + return error( + "CDBEnv::Open: Error %d opening database environment: %s\n", ret, + DbEnv::strerror(ret)); fDbEnvInit = true; fMockDb = false; return true; } -void CDBEnv::MakeMock() -{ +void CDBEnv::MakeMock() { if (fDbEnvInit) throw runtime_error("CDBEnv::MakeMock: Already initialized"); boost::this_thread::interruption_point(); LogPrint("db", "CDBEnv::MakeMock\n"); dbenv->set_cachesize(1, 0, 1); dbenv->set_lg_bsize(10485760 * 4); dbenv->set_lg_max(10485760); dbenv->set_lk_max_locks(10000); dbenv->set_lk_max_objects(10000); dbenv->set_flags(DB_AUTO_COMMIT, 1); dbenv->log_set_config(DB_LOG_IN_MEMORY, 1); - int ret = dbenv->open(NULL, - DB_CREATE | - DB_INIT_LOCK | - DB_INIT_LOG | - DB_INIT_MPOOL | - DB_INIT_TXN | - DB_THREAD | - DB_PRIVATE, - S_IRUSR | S_IWUSR); + int ret = dbenv->open(NULL, DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | + DB_INIT_MPOOL | DB_INIT_TXN | DB_THREAD | + DB_PRIVATE, + S_IRUSR | S_IWUSR); if (ret > 0) - throw runtime_error(strprintf("CDBEnv::MakeMock: Error %d opening database environment.", ret)); + throw runtime_error(strprintf( + "CDBEnv::MakeMock: Error %d opening database environment.", ret)); fDbEnvInit = true; fMockDb = true; } -CDBEnv::VerifyResult CDBEnv::Verify(const std::string& strFile, bool (*recoverFunc)(CDBEnv& dbenv, const std::string& strFile)) -{ +CDBEnv::VerifyResult +CDBEnv::Verify(const std::string &strFile, + bool (*recoverFunc)(CDBEnv &dbenv, const std::string &strFile)) { LOCK(cs_db); assert(mapFileUseCount.count(strFile) == 0); Db db(dbenv, 0); int result = db.verify(strFile.c_str(), NULL, NULL, 0); if (result == 0) return VERIFY_OK; else if (recoverFunc == NULL) return RECOVER_FAIL; // Try to recover: bool fRecovered = (*recoverFunc)(*this, strFile); return (fRecovered ? RECOVER_OK : RECOVER_FAIL); } /* End of headers, beginning of key/value data */ static const char *HEADER_END = "HEADER=END"; /* End of key/value data */ static const char *DATA_END = "DATA=END"; -bool CDBEnv::Salvage(const std::string& strFile, bool fAggressive, std::vector& vResult) -{ +bool CDBEnv::Salvage(const std::string &strFile, bool fAggressive, + std::vector &vResult) { LOCK(cs_db); assert(mapFileUseCount.count(strFile) == 0); u_int32_t flags = DB_SALVAGE; - if (fAggressive) - flags |= DB_AGGRESSIVE; + if (fAggressive) flags |= DB_AGGRESSIVE; stringstream strDump; Db db(dbenv, 0); int result = db.verify(strFile.c_str(), NULL, &strDump, flags); if (result == DB_VERIFY_BAD) { - LogPrintf("CDBEnv::Salvage: Database salvage found errors, all data may not be recoverable.\n"); + LogPrintf("CDBEnv::Salvage: Database salvage found errors, all data " + "may not be recoverable.\n"); if (!fAggressive) { - LogPrintf("CDBEnv::Salvage: Rerun with aggressive mode to ignore errors and continue.\n"); + LogPrintf("CDBEnv::Salvage: Rerun with aggressive mode to ignore " + "errors and continue.\n"); return false; } } if (result != 0 && result != DB_VERIFY_BAD) { - LogPrintf("CDBEnv::Salvage: Database salvage failed with result %d.\n", result); + LogPrintf("CDBEnv::Salvage: Database salvage failed with result %d.\n", + result); return false; } // Format of bdb dump is ascii lines: // header lines... // HEADER=END // hexadecimal key // hexadecimal value // ... repeated // DATA=END string strLine; - while (!strDump.eof() && strLine != HEADER_END) - getline(strDump, strLine); // Skip past header + while (!strDump.eof() && strLine != HEADER_END) { + // Skip past header + getline(strDump, strLine); + } std::string keyHex, valueHex; while (!strDump.eof() && keyHex != DATA_END) { getline(strDump, keyHex); if (keyHex != DATA_END) { - if (strDump.eof()) - break; + if (strDump.eof()) break; getline(strDump, valueHex); if (valueHex == DATA_END) { - LogPrintf("CDBEnv::Salvage: WARNING: Number of keys in data does not match number of values.\n"); + LogPrintf("CDBEnv::Salvage: WARNING: Number of keys in data " + "does not match number of values.\n"); break; } vResult.push_back(make_pair(ParseHex(keyHex), ParseHex(valueHex))); } } if (keyHex != DATA_END) { - LogPrintf("CDBEnv::Salvage: WARNING: Unexpected end of file while reading salvage output.\n"); + LogPrintf("CDBEnv::Salvage: WARNING: Unexpected end of file while " + "reading salvage output.\n"); return false; } return (result == 0); } - -void CDBEnv::CheckpointLSN(const std::string& strFile) -{ +void CDBEnv::CheckpointLSN(const std::string &strFile) { dbenv->txn_checkpoint(0, 0, 0); - if (fMockDb) - return; + if (fMockDb) return; dbenv->lsn_reset(strFile.c_str(), 0); } - -CDB::CDB(const std::string& strFilename, const char* pszMode, bool fFlushOnCloseIn) : pdb(NULL), activeTxn(NULL) -{ +CDB::CDB(const std::string &strFilename, const char *pszMode, + bool fFlushOnCloseIn) + : pdb(NULL), activeTxn(NULL) { int ret; fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w')); fFlushOnClose = fFlushOnCloseIn; - if (strFilename.empty()) - return; + if (strFilename.empty()) return; bool fCreate = strchr(pszMode, 'c') != NULL; unsigned int nFlags = DB_THREAD; - if (fCreate) - nFlags |= DB_CREATE; + if (fCreate) nFlags |= DB_CREATE; { LOCK(bitdb.cs_db); if (!bitdb.Open(GetDataDir())) throw runtime_error("CDB: Failed to open database environment."); strFile = strFilename; ++bitdb.mapFileUseCount[strFile]; pdb = bitdb.mapDb[strFile]; if (pdb == NULL) { pdb = new Db(bitdb.dbenv, 0); bool fMockDb = bitdb.IsMock(); if (fMockDb) { - DbMpoolFile* mpf = pdb->get_mpf(); + DbMpoolFile *mpf = pdb->get_mpf(); ret = mpf->set_flags(DB_MPOOL_NOFILE, 1); if (ret != 0) - throw runtime_error(strprintf("CDB: Failed to configure for no temp file backing for database %s", strFile)); + throw runtime_error( + strprintf("CDB: Failed to configure for no temp file " + "backing for database %s", + strFile)); } - ret = pdb->open(NULL, // Txn pointer - fMockDb ? NULL : strFile.c_str(), // Filename - fMockDb ? strFile.c_str() : "main", // Logical db name - DB_BTREE, // Database type - nFlags, // Flags - 0); + ret = + pdb->open(NULL, // Txn pointer + fMockDb ? NULL : strFile.c_str(), // Filename + fMockDb ? strFile.c_str() : "main", // Logical db name + DB_BTREE, // Database type + nFlags, // Flags + 0); if (ret != 0) { delete pdb; pdb = NULL; --bitdb.mapFileUseCount[strFile]; strFile = ""; - throw runtime_error(strprintf("CDB: Error %d, can't open database %s", ret, strFilename)); + throw runtime_error(strprintf( + "CDB: Error %d, can't open database %s", ret, strFilename)); } if (fCreate && !Exists(string("version"))) { bool fTmp = fReadOnly; fReadOnly = false; WriteVersion(CLIENT_VERSION); fReadOnly = fTmp; } bitdb.mapDb[strFile] = pdb; } } } -void CDB::Flush() -{ - if (activeTxn) - return; +void CDB::Flush() { + if (activeTxn) return; // Flush database activity from memory pool to disk log unsigned int nMinutes = 0; - if (fReadOnly) - nMinutes = 1; + if (fReadOnly) nMinutes = 1; - bitdb.dbenv->txn_checkpoint(nMinutes ? GetArg("-dblogsize", DEFAULT_WALLET_DBLOGSIZE) * 1024 : 0, nMinutes, 0); + bitdb.dbenv->txn_checkpoint( + nMinutes ? GetArg("-dblogsize", DEFAULT_WALLET_DBLOGSIZE) * 1024 : 0, + nMinutes, 0); } -void CDB::Close() -{ - if (!pdb) - return; - if (activeTxn) - activeTxn->abort(); +void CDB::Close() { + if (!pdb) return; + if (activeTxn) activeTxn->abort(); activeTxn = NULL; pdb = NULL; - if (fFlushOnClose) - Flush(); + if (fFlushOnClose) Flush(); { LOCK(bitdb.cs_db); --bitdb.mapFileUseCount[strFile]; } } -void CDBEnv::CloseDb(const string& strFile) -{ - { - LOCK(cs_db); - if (mapDb[strFile] != NULL) { - // Close the database handle - Db* pdb = mapDb[strFile]; - pdb->close(0); - delete pdb; - mapDb[strFile] = NULL; - } +void CDBEnv::CloseDb(const string &strFile) { + LOCK(cs_db); + if (mapDb[strFile] != NULL) { + // Close the database handle + Db *pdb = mapDb[strFile]; + pdb->close(0); + delete pdb; + mapDb[strFile] = NULL; } } -bool CDBEnv::RemoveDb(const string& strFile) -{ +bool CDBEnv::RemoveDb(const string &strFile) { this->CloseDb(strFile); LOCK(cs_db); int rc = dbenv->dbremove(NULL, strFile.c_str(), NULL, DB_AUTO_COMMIT); return (rc == 0); } -bool CDB::Rewrite(const string& strFile, const char* pszSkip) -{ +bool CDB::Rewrite(const string &strFile, const char *pszSkip) { while (true) { { LOCK(bitdb.cs_db); - if (!bitdb.mapFileUseCount.count(strFile) || bitdb.mapFileUseCount[strFile] == 0) { + if (!bitdb.mapFileUseCount.count(strFile) || + bitdb.mapFileUseCount[strFile] == 0) { // Flush log data to the dat file bitdb.CloseDb(strFile); bitdb.CheckpointLSN(strFile); bitdb.mapFileUseCount.erase(strFile); bool fSuccess = true; LogPrintf("CDB::Rewrite: Rewriting %s...\n", strFile); string strFileRes = strFile + ".rewrite"; { // surround usage of db with extra {} CDB db(strFile.c_str(), "r"); - Db* pdbCopy = new Db(bitdb.dbenv, 0); + Db *pdbCopy = new Db(bitdb.dbenv, 0); int ret = pdbCopy->open(NULL, // Txn pointer strFileRes.c_str(), // Filename - "main", // Logical db name - DB_BTREE, // Database type - DB_CREATE, // Flags + "main", // Logical db name + DB_BTREE, // Database type + DB_CREATE, // Flags 0); if (ret > 0) { - LogPrintf("CDB::Rewrite: Can't create database file %s\n", strFileRes); + LogPrintf( + "CDB::Rewrite: Can't create database file %s\n", + strFileRes); fSuccess = false; } - Dbc* pcursor = db.GetCursor(); + Dbc *pcursor = db.GetCursor(); if (pcursor) while (fSuccess) { CDataStream ssKey(SER_DISK, CLIENT_VERSION); CDataStream ssValue(SER_DISK, CLIENT_VERSION); int ret1 = db.ReadAtCursor(pcursor, ssKey, ssValue); if (ret1 == DB_NOTFOUND) { pcursor->close(); break; } else if (ret1 != 0) { pcursor->close(); fSuccess = false; break; } if (pszSkip && - strncmp(ssKey.data(), pszSkip, std::min(ssKey.size(), strlen(pszSkip))) == 0) + strncmp(ssKey.data(), pszSkip, + std::min(ssKey.size(), + strlen(pszSkip))) == 0) continue; if (strncmp(ssKey.data(), "\x07version", 8) == 0) { // Update version: ssValue.clear(); ssValue << CLIENT_VERSION; } Dbt datKey(ssKey.data(), ssKey.size()); Dbt datValue(ssValue.data(), ssValue.size()); - int ret2 = pdbCopy->put(NULL, &datKey, &datValue, DB_NOOVERWRITE); - if (ret2 > 0) - fSuccess = false; + int ret2 = pdbCopy->put(NULL, &datKey, &datValue, + DB_NOOVERWRITE); + if (ret2 > 0) fSuccess = false; } if (fSuccess) { db.Close(); bitdb.CloseDb(strFile); - if (pdbCopy->close(0)) - fSuccess = false; + if (pdbCopy->close(0)) fSuccess = false; delete pdbCopy; } } if (fSuccess) { Db dbA(bitdb.dbenv, 0); - if (dbA.remove(strFile.c_str(), NULL, 0)) - fSuccess = false; + if (dbA.remove(strFile.c_str(), NULL, 0)) fSuccess = false; Db dbB(bitdb.dbenv, 0); - if (dbB.rename(strFileRes.c_str(), NULL, strFile.c_str(), 0)) + if (dbB.rename(strFileRes.c_str(), NULL, strFile.c_str(), + 0)) fSuccess = false; } if (!fSuccess) - LogPrintf("CDB::Rewrite: Failed to rewrite database file %s\n", strFileRes); + LogPrintf( + "CDB::Rewrite: Failed to rewrite database file %s\n", + strFileRes); return fSuccess; } } MilliSleep(100); } return false; } - -void CDBEnv::Flush(bool fShutdown) -{ +void CDBEnv::Flush(bool fShutdown) { int64_t nStart = GetTimeMillis(); // Flush log data to the actual data file on all files that are not in use - LogPrint("db", "CDBEnv::Flush: Flush(%s)%s\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started"); - if (!fDbEnvInit) - return; + LogPrint("db", "CDBEnv::Flush: Flush(%s)%s\n", fShutdown ? "true" : "false", + fDbEnvInit ? "" : " database not started"); + if (!fDbEnvInit) return; { LOCK(cs_db); map::iterator mi = mapFileUseCount.begin(); while (mi != mapFileUseCount.end()) { string strFile = (*mi).first; int nRefCount = (*mi).second; - LogPrint("db", "CDBEnv::Flush: Flushing %s (refcount = %d)...\n", strFile, nRefCount); + LogPrint("db", "CDBEnv::Flush: Flushing %s (refcount = %d)...\n", + strFile, nRefCount); if (nRefCount == 0) { // Move log data to the dat file CloseDb(strFile); LogPrint("db", "CDBEnv::Flush: %s checkpoint\n", strFile); dbenv->txn_checkpoint(0, 0, 0); LogPrint("db", "CDBEnv::Flush: %s detach\n", strFile); - if (!fMockDb) - dbenv->lsn_reset(strFile.c_str(), 0); + if (!fMockDb) dbenv->lsn_reset(strFile.c_str(), 0); LogPrint("db", "CDBEnv::Flush: %s closed\n", strFile); mapFileUseCount.erase(mi++); } else mi++; } - LogPrint("db", "CDBEnv::Flush: Flush(%s)%s took %15dms\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started", GetTimeMillis() - nStart); + LogPrint("db", "CDBEnv::Flush: Flush(%s)%s took %15dms\n", + fShutdown ? "true" : "false", + fDbEnvInit ? "" : " database not started", + GetTimeMillis() - nStart); if (fShutdown) { - char** listp; + char **listp; if (mapFileUseCount.empty()) { dbenv->log_archive(&listp, DB_ARCH_REMOVE); Close(); if (!fMockDb) - boost::filesystem::remove_all(boost::filesystem::path(strPath) / "database"); + boost::filesystem::remove_all( + boost::filesystem::path(strPath) / "database"); } } } } diff --git a/src/wallet/db.h b/src/wallet/db.h index b4ce044e7..2474fc715 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -1,308 +1,286 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_WALLET_DB_H #define BITCOIN_WALLET_DB_H #include "clientversion.h" #include "serialize.h" #include "streams.h" #include "sync.h" #include "version.h" #include #include #include #include #include static const unsigned int DEFAULT_WALLET_DBLOGSIZE = 100; static const bool DEFAULT_WALLET_PRIVDB = true; -class CDBEnv -{ +class CDBEnv { private: bool fDbEnvInit; bool fMockDb; // Don't change into boost::filesystem::path, as that can result in - // shutdown problems/crashes caused by a static initialized internal pointer. + // shutdown problems/crashes caused by a static initialized internal + // pointer. std::string strPath; void EnvShutdown(); public: mutable CCriticalSection cs_db; DbEnv *dbenv; std::map mapFileUseCount; - std::map mapDb; + std::map mapDb; CDBEnv(); ~CDBEnv(); void Reset(); void MakeMock(); bool IsMock() { return fMockDb; } /** - * Verify that database file strFile is OK. If it is not, - * call the callback to try to recover. + * Verify that database file strFile is OK. If it is not, call the callback + * to try to recover. * This must be called BEFORE strFile is opened. * Returns true if strFile is OK. */ - enum VerifyResult { VERIFY_OK, - RECOVER_OK, - RECOVER_FAIL }; - VerifyResult Verify(const std::string& strFile, bool (*recoverFunc)(CDBEnv& dbenv, const std::string& strFile)); + enum VerifyResult { VERIFY_OK, RECOVER_OK, RECOVER_FAIL }; + VerifyResult Verify(const std::string &strFile, + bool (*recoverFunc)(CDBEnv &dbenv, + const std::string &strFile)); /** * Salvage data from a file that Verify says is bad. - * fAggressive sets the DB_AGGRESSIVE flag (see berkeley DB->verify() method documentation). + * fAggressive sets the DB_AGGRESSIVE flag (see berkeley DB->verify() method + * documentation). * Appends binary key/value pairs to vResult, returns true if successful. * NOTE: reads the entire database into memory, so cannot be used * for huge databases. */ - typedef std::pair, std::vector > KeyValPair; - bool Salvage(const std::string& strFile, bool fAggressive, std::vector& vResult); + typedef std::pair, std::vector> + KeyValPair; + bool Salvage(const std::string &strFile, bool fAggressive, + std::vector &vResult); - bool Open(const boost::filesystem::path& path); + bool Open(const boost::filesystem::path &path); void Close(); void Flush(bool fShutdown); - void CheckpointLSN(const std::string& strFile); + void CheckpointLSN(const std::string &strFile); - void CloseDb(const std::string& strFile); - bool RemoveDb(const std::string& strFile); + void CloseDb(const std::string &strFile); + bool RemoveDb(const std::string &strFile); - DbTxn* TxnBegin(int flags = DB_TXN_WRITE_NOSYNC) - { - DbTxn* ptxn = NULL; + DbTxn *TxnBegin(int flags = DB_TXN_WRITE_NOSYNC) { + DbTxn *ptxn = NULL; int ret = dbenv->txn_begin(NULL, &ptxn, flags); - if (!ptxn || ret != 0) - return NULL; + if (!ptxn || ret != 0) return NULL; return ptxn; } }; extern CDBEnv bitdb; - /** RAII class that provides access to a Berkeley database */ -class CDB -{ +class CDB { protected: - Db* pdb; + Db *pdb; std::string strFile; - DbTxn* activeTxn; + DbTxn *activeTxn; bool fReadOnly; bool fFlushOnClose; - explicit CDB(const std::string& strFilename, const char* pszMode = "r+", bool fFlushOnCloseIn=true); + explicit CDB(const std::string &strFilename, const char *pszMode = "r+", + bool fFlushOnCloseIn = true); ~CDB() { Close(); } public: void Flush(); void Close(); private: - CDB(const CDB&); - void operator=(const CDB&); + CDB(const CDB &); + void operator=(const CDB &); protected: - template - bool Read(const K& key, T& value) - { - if (!pdb) - return false; + template bool Read(const K &key, T &value) { + if (!pdb) return false; // Key CDataStream ssKey(SER_DISK, CLIENT_VERSION); ssKey.reserve(1000); ssKey << key; Dbt datKey(ssKey.data(), ssKey.size()); // Read Dbt datValue; datValue.set_flags(DB_DBT_MALLOC); int ret = pdb->get(activeTxn, &datKey, &datValue, 0); memset(datKey.get_data(), 0, datKey.get_size()); - if (datValue.get_data() == NULL) - return false; + if (datValue.get_data() == NULL) return false; // Unserialize value try { - CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION); + CDataStream ssValue((char *)datValue.get_data(), + (char *)datValue.get_data() + + datValue.get_size(), + SER_DISK, CLIENT_VERSION); ssValue >> value; - } catch (const std::exception&) { + } catch (const std::exception &) { return false; } // Clear and free memory memset(datValue.get_data(), 0, datValue.get_size()); free(datValue.get_data()); return (ret == 0); } template - bool Write(const K& key, const T& value, bool fOverwrite = true) - { - if (!pdb) - return false; - if (fReadOnly) - assert(!"Write called on database in read-only mode"); + bool Write(const K &key, const T &value, bool fOverwrite = true) { + if (!pdb) return false; + if (fReadOnly) assert(!"Write called on database in read-only mode"); // Key CDataStream ssKey(SER_DISK, CLIENT_VERSION); ssKey.reserve(1000); ssKey << key; Dbt datKey(ssKey.data(), ssKey.size()); // Value CDataStream ssValue(SER_DISK, CLIENT_VERSION); ssValue.reserve(10000); ssValue << value; Dbt datValue(ssValue.data(), ssValue.size()); // Write - int ret = pdb->put(activeTxn, &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE)); + int ret = pdb->put(activeTxn, &datKey, &datValue, + (fOverwrite ? 0 : DB_NOOVERWRITE)); // Clear memory in case it was a private key memset(datKey.get_data(), 0, datKey.get_size()); memset(datValue.get_data(), 0, datValue.get_size()); return (ret == 0); } - template - bool Erase(const K& key) - { - if (!pdb) - return false; - if (fReadOnly) - assert(!"Erase called on database in read-only mode"); + template bool Erase(const K &key) { + if (!pdb) return false; + if (fReadOnly) assert(!"Erase called on database in read-only mode"); // Key CDataStream ssKey(SER_DISK, CLIENT_VERSION); ssKey.reserve(1000); ssKey << key; Dbt datKey(ssKey.data(), ssKey.size()); // Erase int ret = pdb->del(activeTxn, &datKey, 0); // Clear memory memset(datKey.get_data(), 0, datKey.get_size()); return (ret == 0 || ret == DB_NOTFOUND); } - template - bool Exists(const K& key) - { - if (!pdb) - return false; + template bool Exists(const K &key) { + if (!pdb) return false; // Key CDataStream ssKey(SER_DISK, CLIENT_VERSION); ssKey.reserve(1000); ssKey << key; Dbt datKey(ssKey.data(), ssKey.size()); // Exists int ret = pdb->exists(activeTxn, &datKey, 0); // Clear memory memset(datKey.get_data(), 0, datKey.get_size()); return (ret == 0); } - Dbc* GetCursor() - { - if (!pdb) - return NULL; - Dbc* pcursor = NULL; + Dbc *GetCursor() { + if (!pdb) return NULL; + Dbc *pcursor = NULL; int ret = pdb->cursor(NULL, &pcursor, 0); - if (ret != 0) - return NULL; + if (ret != 0) return NULL; return pcursor; } - int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, bool setRange = false) - { + int ReadAtCursor(Dbc *pcursor, CDataStream &ssKey, CDataStream &ssValue, + bool setRange = false) { // Read at cursor Dbt datKey; unsigned int fFlags = DB_NEXT; if (setRange) { datKey.set_data(ssKey.data()); datKey.set_size(ssKey.size()); fFlags = DB_SET_RANGE; } Dbt datValue; datKey.set_flags(DB_DBT_MALLOC); datValue.set_flags(DB_DBT_MALLOC); int ret = pcursor->get(&datKey, &datValue, fFlags); if (ret != 0) return ret; else if (datKey.get_data() == NULL || datValue.get_data() == NULL) return 99999; // Convert to streams ssKey.SetType(SER_DISK); ssKey.clear(); - ssKey.write((char*)datKey.get_data(), datKey.get_size()); + ssKey.write((char *)datKey.get_data(), datKey.get_size()); ssValue.SetType(SER_DISK); ssValue.clear(); - ssValue.write((char*)datValue.get_data(), datValue.get_size()); + ssValue.write((char *)datValue.get_data(), datValue.get_size()); // Clear and free memory memset(datKey.get_data(), 0, datKey.get_size()); memset(datValue.get_data(), 0, datValue.get_size()); free(datKey.get_data()); free(datValue.get_data()); return 0; } public: - bool TxnBegin() - { - if (!pdb || activeTxn) - return false; - DbTxn* ptxn = bitdb.TxnBegin(); - if (!ptxn) - return false; + bool TxnBegin() { + if (!pdb || activeTxn) return false; + DbTxn *ptxn = bitdb.TxnBegin(); + if (!ptxn) return false; activeTxn = ptxn; return true; } - bool TxnCommit() - { - if (!pdb || !activeTxn) - return false; + bool TxnCommit() { + if (!pdb || !activeTxn) return false; int ret = activeTxn->commit(0); activeTxn = NULL; return (ret == 0); } - bool TxnAbort() - { - if (!pdb || !activeTxn) - return false; + bool TxnAbort() { + if (!pdb || !activeTxn) return false; int ret = activeTxn->abort(); activeTxn = NULL; return (ret == 0); } - bool ReadVersion(int& nVersion) - { + bool ReadVersion(int &nVersion) { nVersion = 0; return Read(std::string("version"), nVersion); } - bool WriteVersion(int nVersion) - { + bool WriteVersion(int nVersion) { return Write(std::string("version"), nVersion); } - bool static Rewrite(const std::string& strFile, const char* pszSkip = NULL); + bool static Rewrite(const std::string &strFile, const char *pszSkip = NULL); }; #endif // BITCOIN_WALLET_DB_H diff --git a/src/wallet/test/crypto_tests.cpp b/src/wallet/test/crypto_tests.cpp index 0d012daca..73e2c5832 100644 --- a/src/wallet/test/crypto_tests.cpp +++ b/src/wallet/test/crypto_tests.cpp @@ -1,238 +1,300 @@ // Copyright (c) 2014-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "test/test_bitcoin.h" #include "test/test_random.h" #include "utilstrencodings.h" -#include "test/test_bitcoin.h" #include "wallet/crypter.h" #include #include #include #include BOOST_FIXTURE_TEST_SUITE(wallet_crypto, BasicTestingSetup) -bool OldSetKeyFromPassphrase(const SecureString& strKeyData, const std::vector& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod, unsigned char* chKey, unsigned char* chIV) -{ - if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE) - return false; +bool OldSetKeyFromPassphrase(const SecureString &strKeyData, + const std::vector &chSalt, + const unsigned int nRounds, + const unsigned int nDerivationMethod, + unsigned char *chKey, unsigned char *chIV) { + if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE) return false; int i = 0; if (nDerivationMethod == 0) i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(), &chSalt[0], - (unsigned char *)&strKeyData[0], strKeyData.size(), nRounds, chKey, chIV); + (unsigned char *)&strKeyData[0], strKeyData.size(), + nRounds, chKey, chIV); - if (i != (int)WALLET_CRYPTO_KEY_SIZE) - { + if (i != (int)WALLET_CRYPTO_KEY_SIZE) { memory_cleanse(chKey, sizeof(chKey)); memory_cleanse(chIV, sizeof(chIV)); return false; } return true; } -bool OldEncrypt(const CKeyingMaterial& vchPlaintext, std::vector &vchCiphertext, const unsigned char chKey[32], const unsigned char chIV[16]) -{ +bool OldEncrypt(const CKeyingMaterial &vchPlaintext, + std::vector &vchCiphertext, + const unsigned char chKey[32], const unsigned char chIV[16]) { // max ciphertext len for a n bytes of plaintext is // n + AES_BLOCK_SIZE - 1 bytes int nLen = vchPlaintext.size(); int nCLen = nLen + AES_BLOCK_SIZE, nFLen = 0; - vchCiphertext = std::vector (nCLen); + vchCiphertext = std::vector(nCLen); EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); if (!ctx) return false; bool fOk = true; EVP_CIPHER_CTX_init(ctx); - if (fOk) fOk = EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0; - if (fOk) fOk = EVP_EncryptUpdate(ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen) != 0; - if (fOk) fOk = EVP_EncryptFinal_ex(ctx, (&vchCiphertext[0]) + nCLen, &nFLen) != 0; + if (fOk) + fOk = + EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0; + if (fOk) + fOk = EVP_EncryptUpdate(ctx, &vchCiphertext[0], &nCLen, + &vchPlaintext[0], nLen) != 0; + if (fOk) + fOk = + EVP_EncryptFinal_ex(ctx, (&vchCiphertext[0]) + nCLen, &nFLen) != 0; EVP_CIPHER_CTX_cleanup(ctx); EVP_CIPHER_CTX_free(ctx); if (!fOk) return false; vchCiphertext.resize(nCLen + nFLen); return true; } -bool OldDecrypt(const std::vector& vchCiphertext, CKeyingMaterial& vchPlaintext, const unsigned char chKey[32], const unsigned char chIV[16]) -{ +bool OldDecrypt(const std::vector &vchCiphertext, + CKeyingMaterial &vchPlaintext, const unsigned char chKey[32], + const unsigned char chIV[16]) { // plaintext will always be equal to or lesser than length of ciphertext int nLen = vchCiphertext.size(); int nPLen = nLen, nFLen = 0; vchPlaintext = CKeyingMaterial(nPLen); EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); if (!ctx) return false; bool fOk = true; EVP_CIPHER_CTX_init(ctx); - if (fOk) fOk = EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0; - if (fOk) fOk = EVP_DecryptUpdate(ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen) != 0; - if (fOk) fOk = EVP_DecryptFinal_ex(ctx, (&vchPlaintext[0]) + nPLen, &nFLen) != 0; + if (fOk) + fOk = + EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0; + if (fOk) + fOk = EVP_DecryptUpdate(ctx, &vchPlaintext[0], &nPLen, + &vchCiphertext[0], nLen) != 0; + if (fOk) + fOk = EVP_DecryptFinal_ex(ctx, (&vchPlaintext[0]) + nPLen, &nFLen) != 0; EVP_CIPHER_CTX_cleanup(ctx); EVP_CIPHER_CTX_free(ctx); if (!fOk) return false; vchPlaintext.resize(nPLen + nFLen); return true; } -class TestCrypter -{ +class TestCrypter { public: -static void TestPassphraseSingle(const std::vector& vchSalt, const SecureString& passphrase, uint32_t rounds, - const std::vector& correctKey = std::vector(), - const std::vector& correctIV=std::vector()) -{ - unsigned char chKey[WALLET_CRYPTO_KEY_SIZE]; - unsigned char chIV[WALLET_CRYPTO_IV_SIZE]; - - CCrypter crypt; - crypt.SetKeyFromPassphrase(passphrase, vchSalt, rounds, 0); - - OldSetKeyFromPassphrase(passphrase, vchSalt, rounds, 0, chKey, chIV); - - BOOST_CHECK_MESSAGE(memcmp(chKey, crypt.vchKey.data(), crypt.vchKey.size()) == 0, \ - HexStr(chKey, chKey+sizeof(chKey)) + std::string(" != ") + HexStr(crypt.vchKey)); - BOOST_CHECK_MESSAGE(memcmp(chIV, crypt.vchIV.data(), crypt.vchIV.size()) == 0, \ - HexStr(chIV, chIV+sizeof(chIV)) + std::string(" != ") + HexStr(crypt.vchIV)); - - if(!correctKey.empty()) - BOOST_CHECK_MESSAGE(memcmp(chKey, &correctKey[0], sizeof(chKey)) == 0, \ - HexStr(chKey, chKey+sizeof(chKey)) + std::string(" != ") + HexStr(correctKey.begin(), correctKey.end())); - if(!correctIV.empty()) - BOOST_CHECK_MESSAGE(memcmp(chIV, &correctIV[0], sizeof(chIV)) == 0, - HexStr(chIV, chIV+sizeof(chIV)) + std::string(" != ") + HexStr(correctIV.begin(), correctIV.end())); -} - -static void TestPassphrase(const std::vector& vchSalt, const SecureString& passphrase, uint32_t rounds, - const std::vector& correctKey = std::vector(), - const std::vector& correctIV=std::vector()) -{ - TestPassphraseSingle(vchSalt, passphrase, rounds, correctKey, correctIV); - for(SecureString::const_iterator i(passphrase.begin()); i != passphrase.end(); ++i) - TestPassphraseSingle(vchSalt, SecureString(i, passphrase.end()), rounds); -} - - -static void TestDecrypt(const CCrypter& crypt, const std::vector& vchCiphertext, \ - const std::vector& vchPlaintext = std::vector()) -{ - CKeyingMaterial vchDecrypted1; - CKeyingMaterial vchDecrypted2; - int result1, result2; - result1 = crypt.Decrypt(vchCiphertext, vchDecrypted1); - result2 = OldDecrypt(vchCiphertext, vchDecrypted2, crypt.vchKey.data(), crypt.vchIV.data()); - BOOST_CHECK(result1 == result2); - - // These two should be equal. However, OpenSSL 1.0.1j introduced a change - // that would zero all padding except for the last byte for failed decrypts. - // This behavior was reverted for 1.0.1k. - if (vchDecrypted1 != vchDecrypted2 && vchDecrypted1.size() >= AES_BLOCK_SIZE && SSLeay() == 0x100010afL) - { - for(CKeyingMaterial::iterator it = vchDecrypted1.end() - AES_BLOCK_SIZE; it != vchDecrypted1.end() - 1; it++) - *it = 0; + static void + TestPassphraseSingle(const std::vector &vchSalt, + const SecureString &passphrase, uint32_t rounds, + const std::vector &correctKey = + std::vector(), + const std::vector &correctIV = + std::vector()) { + unsigned char chKey[WALLET_CRYPTO_KEY_SIZE]; + unsigned char chIV[WALLET_CRYPTO_IV_SIZE]; + + CCrypter crypt; + crypt.SetKeyFromPassphrase(passphrase, vchSalt, rounds, 0); + + OldSetKeyFromPassphrase(passphrase, vchSalt, rounds, 0, chKey, chIV); + + BOOST_CHECK_MESSAGE( + memcmp(chKey, crypt.vchKey.data(), crypt.vchKey.size()) == 0, + HexStr(chKey, chKey + sizeof(chKey)) + std::string(" != ") + + HexStr(crypt.vchKey)); + BOOST_CHECK_MESSAGE( + memcmp(chIV, crypt.vchIV.data(), crypt.vchIV.size()) == 0, + HexStr(chIV, chIV + sizeof(chIV)) + std::string(" != ") + + HexStr(crypt.vchIV)); + + if (!correctKey.empty()) + BOOST_CHECK_MESSAGE( + memcmp(chKey, &correctKey[0], sizeof(chKey)) == 0, + HexStr(chKey, chKey + sizeof(chKey)) + std::string(" != ") + + HexStr(correctKey.begin(), correctKey.end())); + if (!correctIV.empty()) + BOOST_CHECK_MESSAGE(memcmp(chIV, &correctIV[0], sizeof(chIV)) == 0, + HexStr(chIV, chIV + sizeof(chIV)) + + std::string(" != ") + + HexStr(correctIV.begin(), correctIV.end())); } - BOOST_CHECK_MESSAGE(vchDecrypted1 == vchDecrypted2, HexStr(vchDecrypted1.begin(), vchDecrypted1.end()) + " != " + HexStr(vchDecrypted2.begin(), vchDecrypted2.end())); + static void TestPassphrase(const std::vector &vchSalt, + const SecureString &passphrase, uint32_t rounds, + const std::vector &correctKey = + std::vector(), + const std::vector &correctIV = + std::vector()) { + TestPassphraseSingle(vchSalt, passphrase, rounds, correctKey, + correctIV); + for (SecureString::const_iterator i(passphrase.begin()); + i != passphrase.end(); ++i) + TestPassphraseSingle(vchSalt, SecureString(i, passphrase.end()), + rounds); + } - if (vchPlaintext.size()) - BOOST_CHECK(CKeyingMaterial(vchPlaintext.begin(), vchPlaintext.end()) == vchDecrypted2); -} + static void TestDecrypt(const CCrypter &crypt, + const std::vector &vchCiphertext, + const std::vector &vchPlaintext = + std::vector()) { + CKeyingMaterial vchDecrypted1; + CKeyingMaterial vchDecrypted2; + int result1, result2; + result1 = crypt.Decrypt(vchCiphertext, vchDecrypted1); + result2 = OldDecrypt(vchCiphertext, vchDecrypted2, crypt.vchKey.data(), + crypt.vchIV.data()); + BOOST_CHECK(result1 == result2); + + // These two should be equal. However, OpenSSL 1.0.1j introduced a + // change that would zero all padding except for the last byte for + // failed decrypts. + // This behavior was reverted for 1.0.1k. + if (vchDecrypted1 != vchDecrypted2 && + vchDecrypted1.size() >= AES_BLOCK_SIZE && SSLeay() == 0x100010afL) { + for (CKeyingMaterial::iterator it = + vchDecrypted1.end() - AES_BLOCK_SIZE; + it != vchDecrypted1.end() - 1; it++) + *it = 0; + } + + BOOST_CHECK_MESSAGE( + vchDecrypted1 == vchDecrypted2, + HexStr(vchDecrypted1.begin(), vchDecrypted1.end()) + " != " + + HexStr(vchDecrypted2.begin(), vchDecrypted2.end())); + + if (vchPlaintext.size()) + BOOST_CHECK(CKeyingMaterial(vchPlaintext.begin(), + vchPlaintext.end()) == vchDecrypted2); + } -static void TestEncryptSingle(const CCrypter& crypt, const CKeyingMaterial& vchPlaintext, - const std::vector& vchCiphertextCorrect = std::vector()) -{ - std::vector vchCiphertext1; - std::vector vchCiphertext2; - int result1 = crypt.Encrypt(vchPlaintext, vchCiphertext1); + static void + TestEncryptSingle(const CCrypter &crypt, + const CKeyingMaterial &vchPlaintext, + const std::vector &vchCiphertextCorrect = + std::vector()) { + std::vector vchCiphertext1; + std::vector vchCiphertext2; + int result1 = crypt.Encrypt(vchPlaintext, vchCiphertext1); - int result2 = OldEncrypt(vchPlaintext, vchCiphertext2, crypt.vchKey.data(), crypt.vchIV.data()); - BOOST_CHECK(result1 == result2); - BOOST_CHECK(vchCiphertext1 == vchCiphertext2); + int result2 = OldEncrypt(vchPlaintext, vchCiphertext2, + crypt.vchKey.data(), crypt.vchIV.data()); + BOOST_CHECK(result1 == result2); + BOOST_CHECK(vchCiphertext1 == vchCiphertext2); - if (!vchCiphertextCorrect.empty()) - BOOST_CHECK(vchCiphertext2 == vchCiphertextCorrect); + if (!vchCiphertextCorrect.empty()) + BOOST_CHECK(vchCiphertext2 == vchCiphertextCorrect); - const std::vector vchPlaintext2(vchPlaintext.begin(), vchPlaintext.end()); + const std::vector vchPlaintext2(vchPlaintext.begin(), + vchPlaintext.end()); - if(vchCiphertext1 == vchCiphertext2) - TestDecrypt(crypt, vchCiphertext1, vchPlaintext2); -} - -static void TestEncrypt(const CCrypter& crypt, const std::vector& vchPlaintextIn, \ - const std::vector& vchCiphertextCorrect = std::vector()) -{ - TestEncryptSingle(crypt, CKeyingMaterial(vchPlaintextIn.begin(), vchPlaintextIn.end()), vchCiphertextCorrect); - for(std::vector::const_iterator i(vchPlaintextIn.begin()); i != vchPlaintextIn.end(); ++i) - TestEncryptSingle(crypt, CKeyingMaterial(i, vchPlaintextIn.end())); -} + if (vchCiphertext1 == vchCiphertext2) + TestDecrypt(crypt, vchCiphertext1, vchPlaintext2); + } + static void + TestEncrypt(const CCrypter &crypt, + const std::vector &vchPlaintextIn, + const std::vector &vchCiphertextCorrect = + std::vector()) { + TestEncryptSingle(crypt, CKeyingMaterial(vchPlaintextIn.begin(), + vchPlaintextIn.end()), + vchCiphertextCorrect); + for (std::vector::const_iterator i( + vchPlaintextIn.begin()); + i != vchPlaintextIn.end(); ++i) + TestEncryptSingle(crypt, CKeyingMaterial(i, vchPlaintextIn.end())); + } }; BOOST_AUTO_TEST_CASE(passphrase) { // These are expensive. - TestCrypter::TestPassphrase(ParseHex("0000deadbeef0000"), "test", 25000, \ - ParseHex("fc7aba077ad5f4c3a0988d8daa4810d0d4a0e3bcb53af662998898f33df0556a"), \ - ParseHex("cf2f2691526dd1aa220896fb8bf7c369")); + TestCrypter::TestPassphrase( + ParseHex("0000deadbeef0000"), "test", 25000, + ParseHex( + "fc7aba077ad5f4c3a0988d8daa4810d0d4a0e3bcb53af662998898f33df0556a"), + ParseHex("cf2f2691526dd1aa220896fb8bf7c369")); std::string hash(GetRandHash().ToString()); std::vector vchSalt(8); GetRandBytes(&vchSalt[0], vchSalt.size()); uint32_t rounds = insecure_rand(); - if (rounds > 30000) - rounds = 30000; - TestCrypter::TestPassphrase(vchSalt, SecureString(hash.begin(), hash.end()), rounds); + if (rounds > 30000) rounds = 30000; + TestCrypter::TestPassphrase(vchSalt, SecureString(hash.begin(), hash.end()), + rounds); } BOOST_AUTO_TEST_CASE(encrypt) { std::vector vchSalt = ParseHex("0000deadbeef0000"); BOOST_CHECK(vchSalt.size() == WALLET_CRYPTO_SALT_SIZE); CCrypter crypt; crypt.SetKeyFromPassphrase("passphrase", vchSalt, 25000, 0); - TestCrypter::TestEncrypt(crypt, ParseHex("22bcade09ac03ff6386914359cfe885cfeb5f77ff0d670f102f619687453b29d")); + TestCrypter::TestEncrypt(crypt, + ParseHex("22bcade09ac03ff6386914359cfe885cfeb5f77f" + "f0d670f102f619687453b29d")); - for (int i = 0; i != 100; i++) - { + for (int i = 0; i != 100; i++) { uint256 hash(GetRandHash()); - TestCrypter::TestEncrypt(crypt, std::vector(hash.begin(), hash.end())); + TestCrypter::TestEncrypt( + crypt, std::vector(hash.begin(), hash.end())); } - } BOOST_AUTO_TEST_CASE(decrypt) { std::vector vchSalt = ParseHex("0000deadbeef0000"); BOOST_CHECK(vchSalt.size() == WALLET_CRYPTO_SALT_SIZE); CCrypter crypt; crypt.SetKeyFromPassphrase("passphrase", vchSalt, 25000, 0); // Some corner cases the came up while testing - TestCrypter::TestDecrypt(crypt,ParseHex("795643ce39d736088367822cdc50535ec6f103715e3e48f4f3b1a60a08ef59ca")); - TestCrypter::TestDecrypt(crypt,ParseHex("de096f4a8f9bd97db012aa9d90d74de8cdea779c3ee8bc7633d8b5d6da703486")); - TestCrypter::TestDecrypt(crypt,ParseHex("32d0a8974e3afd9c6c3ebf4d66aa4e6419f8c173de25947f98cf8b7ace49449c")); - TestCrypter::TestDecrypt(crypt,ParseHex("e7c055cca2faa78cb9ac22c9357a90b4778ded9b2cc220a14cea49f931e596ea")); - TestCrypter::TestDecrypt(crypt,ParseHex("b88efddd668a6801d19516d6830da4ae9811988ccbaf40df8fbb72f3f4d335fd")); - TestCrypter::TestDecrypt(crypt,ParseHex("8cae76aa6a43694e961ebcb28c8ca8f8540b84153d72865e8561ddd93fa7bfa9")); - - for (int i = 0; i != 100; i++) - { + TestCrypter::TestDecrypt(crypt, + ParseHex("795643ce39d736088367822cdc50535ec6f10371" + "5e3e48f4f3b1a60a08ef59ca")); + TestCrypter::TestDecrypt(crypt, + ParseHex("de096f4a8f9bd97db012aa9d90d74de8cdea779c" + "3ee8bc7633d8b5d6da703486")); + TestCrypter::TestDecrypt(crypt, + ParseHex("32d0a8974e3afd9c6c3ebf4d66aa4e6419f8c173" + "de25947f98cf8b7ace49449c")); + TestCrypter::TestDecrypt(crypt, + ParseHex("e7c055cca2faa78cb9ac22c9357a90b4778ded9b" + "2cc220a14cea49f931e596ea")); + TestCrypter::TestDecrypt(crypt, + ParseHex("b88efddd668a6801d19516d6830da4ae9811988c" + "cbaf40df8fbb72f3f4d335fd")); + TestCrypter::TestDecrypt(crypt, + ParseHex("8cae76aa6a43694e961ebcb28c8ca8f8540b8415" + "3d72865e8561ddd93fa7bfa9")); + + for (int i = 0; i != 100; i++) { uint256 hash(GetRandHash()); - TestCrypter::TestDecrypt(crypt, std::vector(hash.begin(), hash.end())); + TestCrypter::TestDecrypt( + crypt, std::vector(hash.begin(), hash.end())); } } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/wallet/test/wallet_test_fixture.h b/src/wallet/test/wallet_test_fixture.h index 97a6d9839..dc0204d78 100644 --- a/src/wallet/test/wallet_test_fixture.h +++ b/src/wallet/test/wallet_test_fixture.h @@ -1,18 +1,17 @@ // Copyright (c) 2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_WALLET_TEST_FIXTURE_H #define BITCOIN_WALLET_TEST_FIXTURE_H #include "test/test_bitcoin.h" /** Testing setup and teardown for wallet. */ -struct WalletTestingSetup: public TestingSetup { - WalletTestingSetup(const std::string& chainName = CBaseChainParams::MAIN); +struct WalletTestingSetup : public TestingSetup { + WalletTestingSetup(const std::string &chainName = CBaseChainParams::MAIN); ~WalletTestingSetup(); }; #endif -