Browse Source

Merge #11043: Use std::unique_ptr (C++11) where possible

a357293 Use MakeUnique<Db>(...) (practicalswift)
3e09b39 Use MakeUnique<T>(...) instead of std::unique_ptr<T>(new T(...)) (practicalswift)
8617989 Add MakeUnique (substitute for C++14 std::make_unique) (practicalswift)
d223bc9 Use unique_ptr for pcoinscatcher/pcoinsdbview/pcoinsTip/pblocktree (practicalswift)
b45c597 Use unique_ptr for pdbCopy (Db) and fix potential memory leak (practicalswift)
29ab96d Use unique_ptr for dbenv (DbEnv) (practicalswift)
f72cbf9 Use unique_ptr for pfilter (CBloomFilter) (practicalswift)
8ccf1bb Use unique_ptr for sem{Addnode,Outbound} (CSemaphore) (practicalswift)
73db063 Use unique_ptr for upnp_thread (boost::thread) (practicalswift)
0024531 Use unique_ptr for dbw (CDBWrapper) (practicalswift)
fa6d122 Use unique_ptr:s for {fee,short,long}Stats (TxConfirmStats) (practicalswift)
5a6f768 Use unique_ptr for httpRPCTimerInterface (HTTPRPCTimerInterface) (practicalswift)
860e912 Use unique_ptr for pwalletMain (CWallet) (practicalswift)

Pull request description:

  Use `std::unique_ptr` (C++11) where possible.

  Rationale:
  1. Avoid resource leaks (specifically: forgetting to `delete` an object created using `new`)
  2. Avoid undefined behaviour (specifically: double `delete`:s)

  **Note to reviewers:** Please let me know if I've missed any obvious `std::unique_ptr` candidates. Hopefully this PR should cover all the trivial cases.

Tree-SHA512: 9fbeb47b800ab8ff4e0be9f2a22ab63c23d5c613a0c6716d9183db8d22ddbbce592fb8384a8b7874bf7375c8161efb13ca2197ad6f24b75967148037f0f7b20c
0.16
Wladimir J. van der Laan 7 years ago
parent
commit
5e9be169e4
No known key found for this signature in database
GPG Key ID: 1E4AED62986CD25D
  1. 11
      src/httprpc.cpp
  2. 34
      src/init.cpp
  3. 24
      src/net.cpp
  4. 6
      src/net.h
  5. 10
      src/net_processing.cpp
  6. 24
      src/policy/fees.cpp
  7. 6
      src/policy/fees.h
  8. 3
      src/qt/test/rpcnestedtests.h
  9. 6
      src/rpc/blockchain.cpp
  10. 10
      src/test/dbwrapper_tests.cpp
  11. 12
      src/test/test_bitcoin.cpp
  12. 1
      src/test/test_bitcoin.h
  13. 18
      src/test/txvalidationcache_tests.cpp
  14. 7
      src/util.h
  15. 20
      src/validation.cpp
  16. 6
      src/validation.h
  17. 22
      src/wallet/db.cpp
  18. 2
      src/wallet/db.h
  19. 11
      src/wallet/test/wallet_test_fixture.cpp
  20. 2
      src/wallet/wallet.cpp

11
src/httprpc.cpp

@ -62,7 +62,7 @@ private:
/* Pre-base64-encoded authentication token */ /* Pre-base64-encoded authentication token */
static std::string strRPCUserColonPass; static std::string strRPCUserColonPass;
/* Stored RPC timer interface (for unregistration) */ /* Stored RPC timer interface (for unregistration) */
static HTTPRPCTimerInterface* httpRPCTimerInterface = nullptr; static std::unique_ptr<HTTPRPCTimerInterface> httpRPCTimerInterface;
static void JSONErrorReply(HTTPRequest* req, const UniValue& objError, const UniValue& id) static void JSONErrorReply(HTTPRequest* req, const UniValue& objError, const UniValue& id)
{ {
@ -238,8 +238,8 @@ bool StartHTTPRPC()
RegisterHTTPHandler("/wallet/", false, HTTPReq_JSONRPC); RegisterHTTPHandler("/wallet/", false, HTTPReq_JSONRPC);
#endif #endif
assert(EventBase()); assert(EventBase());
httpRPCTimerInterface = new HTTPRPCTimerInterface(EventBase()); httpRPCTimerInterface = MakeUnique<HTTPRPCTimerInterface>(EventBase());
RPCSetTimerInterface(httpRPCTimerInterface); RPCSetTimerInterface(httpRPCTimerInterface.get());
return true; return true;
} }
@ -253,8 +253,7 @@ void StopHTTPRPC()
LogPrint(BCLog::RPC, "Stopping HTTP RPC server\n"); LogPrint(BCLog::RPC, "Stopping HTTP RPC server\n");
UnregisterHTTPHandler("/", true); UnregisterHTTPHandler("/", true);
if (httpRPCTimerInterface) { if (httpRPCTimerInterface) {
RPCUnsetTimerInterface(httpRPCTimerInterface); RPCUnsetTimerInterface(httpRPCTimerInterface.get());
delete httpRPCTimerInterface; httpRPCTimerInterface.reset();
httpRPCTimerInterface = nullptr;
} }
} }

34
src/init.cpp

@ -152,7 +152,7 @@ public:
// Writes do not need similar protection, as failure to write is handled by the caller. // Writes do not need similar protection, as failure to write is handled by the caller.
}; };
static CCoinsViewErrorCatcher *pcoinscatcher = nullptr; static std::unique_ptr<CCoinsViewErrorCatcher> pcoinscatcher;
static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle; static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle;
void Interrupt(boost::thread_group& threadGroup) void Interrupt(boost::thread_group& threadGroup)
@ -235,14 +235,10 @@ void Shutdown()
if (pcoinsTip != nullptr) { if (pcoinsTip != nullptr) {
FlushStateToDisk(); FlushStateToDisk();
} }
delete pcoinsTip; pcoinsTip.reset();
pcoinsTip = nullptr; pcoinscatcher.reset();
delete pcoinscatcher; pcoinsdbview.reset();
pcoinscatcher = nullptr; pblocktree.reset();
delete pcoinsdbview;
pcoinsdbview = nullptr;
delete pblocktree;
pblocktree = nullptr;
} }
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
StopWallets(); StopWallets();
@ -1406,12 +1402,10 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
do { do {
try { try {
UnloadBlockIndex(); UnloadBlockIndex();
delete pcoinsTip; pcoinsTip.reset();
delete pcoinsdbview; pcoinsdbview.reset();
delete pcoinscatcher; pcoinscatcher.reset();
delete pblocktree; pblocktree.reset(new CBlockTreeDB(nBlockTreeDBCache, false, fReset));
pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReset);
if (fReset) { if (fReset) {
pblocktree->WriteReindexing(true); pblocktree->WriteReindexing(true);
@ -1462,8 +1456,8 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
// At this point we're either in reindex or we've loaded a useful // At this point we're either in reindex or we've loaded a useful
// block tree into mapBlockIndex! // block tree into mapBlockIndex!
pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReset || fReindexChainState); pcoinsdbview.reset(new CCoinsViewDB(nCoinDBCache, false, fReset || fReindexChainState));
pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview); pcoinscatcher.reset(new CCoinsViewErrorCatcher(pcoinsdbview.get()));
// If necessary, upgrade from older database format. // If necessary, upgrade from older database format.
// This is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate // This is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
@ -1473,13 +1467,13 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
} }
// ReplayBlocks is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate // ReplayBlocks is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
if (!ReplayBlocks(chainparams, pcoinsdbview)) { if (!ReplayBlocks(chainparams, pcoinsdbview.get())) {
strLoadError = _("Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate."); strLoadError = _("Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.");
break; break;
} }
// The on-disk coinsdb is now in a good state, create the cache // The on-disk coinsdb is now in a good state, create the cache
pcoinsTip = new CCoinsViewCache(pcoinscatcher); pcoinsTip.reset(new CCoinsViewCache(pcoinscatcher.get()));
bool is_coinsview_empty = fReset || fReindexChainState || pcoinsTip->GetBestBlock().IsNull(); bool is_coinsview_empty = fReset || fReindexChainState || pcoinsTip->GetBestBlock().IsNull();
if (!is_coinsview_empty) { if (!is_coinsview_empty) {
@ -1521,7 +1515,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
} }
} }
if (!CVerifyDB().VerifyDB(chainparams, pcoinsdbview, gArgs.GetArg("-checklevel", DEFAULT_CHECKLEVEL), if (!CVerifyDB().VerifyDB(chainparams, pcoinsdbview.get(), gArgs.GetArg("-checklevel", DEFAULT_CHECKLEVEL),
gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS))) { gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS))) {
strLoadError = _("Corrupted block database detected"); strLoadError = _("Corrupted block database detected");
break; break;

24
src/net.cpp

@ -1534,22 +1534,20 @@ void ThreadMapPort()
void MapPort(bool fUseUPnP) void MapPort(bool fUseUPnP)
{ {
static boost::thread* upnp_thread = nullptr; static std::unique_ptr<boost::thread> upnp_thread;
if (fUseUPnP) if (fUseUPnP)
{ {
if (upnp_thread) { if (upnp_thread) {
upnp_thread->interrupt(); upnp_thread->interrupt();
upnp_thread->join(); upnp_thread->join();
delete upnp_thread;
} }
upnp_thread = new boost::thread(boost::bind(&TraceThread<void (*)()>, "upnp", &ThreadMapPort)); upnp_thread.reset(new boost::thread(boost::bind(&TraceThread<void (*)()>, "upnp", &ThreadMapPort)));
} }
else if (upnp_thread) { else if (upnp_thread) {
upnp_thread->interrupt(); upnp_thread->interrupt();
upnp_thread->join(); upnp_thread->join();
delete upnp_thread; upnp_thread.reset();
upnp_thread = nullptr;
} }
} }
@ -2224,8 +2222,6 @@ CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In) : nSeed0(nSeed0In), nSe
nLastNodeId = 0; nLastNodeId = 0;
nSendBufferMaxSize = 0; nSendBufferMaxSize = 0;
nReceiveFloodSize = 0; nReceiveFloodSize = 0;
semOutbound = nullptr;
semAddnode = nullptr;
flagInterruptMsgProc = false; flagInterruptMsgProc = false;
SetTryNewOutboundPeer(false); SetTryNewOutboundPeer(false);
@ -2331,11 +2327,11 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
if (semOutbound == nullptr) { if (semOutbound == nullptr) {
// initialize semaphore // initialize semaphore
semOutbound = new CSemaphore(std::min((nMaxOutbound + nMaxFeeler), nMaxConnections)); semOutbound = MakeUnique<CSemaphore>(std::min((nMaxOutbound + nMaxFeeler), nMaxConnections));
} }
if (semAddnode == nullptr) { if (semAddnode == nullptr) {
// initialize semaphore // initialize semaphore
semAddnode = new CSemaphore(nMaxAddnode); semAddnode = MakeUnique<CSemaphore>(nMaxAddnode);
} }
// //
@ -2458,10 +2454,8 @@ void CConnman::Stop()
vNodes.clear(); vNodes.clear();
vNodesDisconnected.clear(); vNodesDisconnected.clear();
vhListenSocket.clear(); vhListenSocket.clear();
delete semOutbound; semOutbound.reset();
semOutbound = nullptr; semAddnode.reset();
delete semAddnode;
semAddnode = nullptr;
} }
void CConnman::DeleteNode(CNode* pnode) void CConnman::DeleteNode(CNode* pnode)
@ -2747,7 +2741,7 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn
nNextInvSend = 0; nNextInvSend = 0;
fRelayTxes = false; fRelayTxes = false;
fSentAddr = false; fSentAddr = false;
pfilter = new CBloomFilter(); pfilter = MakeUnique<CBloomFilter>();
timeLastMempoolReq = 0; timeLastMempoolReq = 0;
nLastBlockTime = 0; nLastBlockTime = 0;
nLastTXTime = 0; nLastTXTime = 0;
@ -2777,8 +2771,6 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn
CNode::~CNode() CNode::~CNode()
{ {
CloseSocket(hSocket); CloseSocket(hSocket);
delete pfilter;
} }
void CNode::AskFor(const CInv& inv) void CNode::AskFor(const CInv& inv)

6
src/net.h

@ -399,8 +399,8 @@ private:
/** Services this instance offers */ /** Services this instance offers */
ServiceFlags nLocalServices; ServiceFlags nLocalServices;
CSemaphore *semOutbound; std::unique_ptr<CSemaphore> semOutbound;
CSemaphore *semAddnode; std::unique_ptr<CSemaphore> semAddnode;
int nMaxConnections; int nMaxConnections;
int nMaxOutbound; int nMaxOutbound;
int nMaxAddnode; int nMaxAddnode;
@ -648,7 +648,7 @@ public:
bool fSentAddr; bool fSentAddr;
CSemaphoreGrant grantOutbound; CSemaphoreGrant grantOutbound;
CCriticalSection cs_filter; CCriticalSection cs_filter;
CBloomFilter* pfilter; std::unique_ptr<CBloomFilter> pfilter;
std::atomic<int> nRefCount; std::atomic<int> nRefCount;
const uint64_t nKeyedNetGroup; const uint64_t nKeyedNetGroup;

10
src/net_processing.cpp

@ -2102,7 +2102,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (!AlreadyHave(inv) && if (!AlreadyHave(inv) &&
AcceptToMemoryPool(mempool, state, ptx, &fMissingInputs, &lRemovedTxn, false /* bypass_limits */, 0 /* nAbsurdFee */)) { AcceptToMemoryPool(mempool, state, ptx, &fMissingInputs, &lRemovedTxn, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
mempool.check(pcoinsTip); mempool.check(pcoinsTip.get());
RelayTransaction(tx, connman); RelayTransaction(tx, connman);
for (unsigned int i = 0; i < tx.vout.size(); i++) { for (unsigned int i = 0; i < tx.vout.size(); i++) {
vWorkQueue.emplace_back(inv.hash, i); vWorkQueue.emplace_back(inv.hash, i);
@ -2169,7 +2169,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
recentRejects->insert(orphanHash); recentRejects->insert(orphanHash);
} }
} }
mempool.check(pcoinsTip); mempool.check(pcoinsTip.get());
} }
} }
@ -2751,8 +2751,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
else else
{ {
LOCK(pfrom->cs_filter); LOCK(pfrom->cs_filter);
delete pfrom->pfilter; pfrom->pfilter.reset(new CBloomFilter(filter));
pfrom->pfilter = new CBloomFilter(filter);
pfrom->pfilter->UpdateEmptyFull(); pfrom->pfilter->UpdateEmptyFull();
pfrom->fRelayTxes = true; pfrom->fRelayTxes = true;
} }
@ -2788,8 +2787,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
{ {
LOCK(pfrom->cs_filter); LOCK(pfrom->cs_filter);
if (pfrom->GetLocalServices() & NODE_BLOOM) { if (pfrom->GetLocalServices() & NODE_BLOOM) {
delete pfrom->pfilter; pfrom->pfilter.reset(new CBloomFilter());
pfrom->pfilter = new CBloomFilter();
} }
pfrom->fRelayTxes = true; pfrom->fRelayTxes = true;
} }

24
src/policy/fees.cpp

@ -548,16 +548,13 @@ CBlockPolicyEstimator::CBlockPolicyEstimator()
bucketMap[INF_FEERATE] = bucketIndex; bucketMap[INF_FEERATE] = bucketIndex;
assert(bucketMap.size() == buckets.size()); assert(bucketMap.size() == buckets.size());
feeStats = new TxConfirmStats(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE); feeStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE));
shortStats = new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE); shortStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE));
longStats = new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE); longStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE));
} }
CBlockPolicyEstimator::~CBlockPolicyEstimator() CBlockPolicyEstimator::~CBlockPolicyEstimator()
{ {
delete feeStats;
delete shortStats;
delete longStats;
} }
void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, bool validFeeEstimate) void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, bool validFeeEstimate)
@ -690,16 +687,16 @@ CFeeRate CBlockPolicyEstimator::estimateRawFee(int confTarget, double successThr
double sufficientTxs = SUFFICIENT_FEETXS; double sufficientTxs = SUFFICIENT_FEETXS;
switch (horizon) { switch (horizon) {
case FeeEstimateHorizon::SHORT_HALFLIFE: { case FeeEstimateHorizon::SHORT_HALFLIFE: {
stats = shortStats; stats = shortStats.get();
sufficientTxs = SUFFICIENT_TXS_SHORT; sufficientTxs = SUFFICIENT_TXS_SHORT;
break; break;
} }
case FeeEstimateHorizon::MED_HALFLIFE: { case FeeEstimateHorizon::MED_HALFLIFE: {
stats = feeStats; stats = feeStats.get();
break; break;
} }
case FeeEstimateHorizon::LONG_HALFLIFE: { case FeeEstimateHorizon::LONG_HALFLIFE: {
stats = longStats; stats = longStats.get();
break; break;
} }
default: { default: {
@ -1002,12 +999,9 @@ bool CBlockPolicyEstimator::Read(CAutoFile& filein)
} }
// Destroy old TxConfirmStats and point to new ones that already reference buckets and bucketMap // Destroy old TxConfirmStats and point to new ones that already reference buckets and bucketMap
delete feeStats; feeStats = std::move(fileFeeStats);
delete shortStats; shortStats = std::move(fileShortStats);
delete longStats; longStats = std::move(fileLongStats);
feeStats = fileFeeStats.release();
shortStats = fileShortStats.release();
longStats = fileLongStats.release();
nBestSeenHeight = nFileBestSeenHeight; nBestSeenHeight = nFileBestSeenHeight;
historicalFirst = nFileHistoricalFirst; historicalFirst = nFileHistoricalFirst;

6
src/policy/fees.h

@ -245,9 +245,9 @@ private:
std::map<uint256, TxStatsInfo> mapMemPoolTxs; std::map<uint256, TxStatsInfo> mapMemPoolTxs;
/** Classes to track historical data on transaction confirmations */ /** Classes to track historical data on transaction confirmations */
TxConfirmStats* feeStats; std::unique_ptr<TxConfirmStats> feeStats;
TxConfirmStats* shortStats; std::unique_ptr<TxConfirmStats> shortStats;
TxConfirmStats* longStats; std::unique_ptr<TxConfirmStats> longStats;
unsigned int trackedTxs; unsigned int trackedTxs;
unsigned int untrackedTxs; unsigned int untrackedTxs;

3
src/qt/test/rpcnestedtests.h

@ -17,9 +17,6 @@ class RPCNestedTests : public QObject
private Q_SLOTS: private Q_SLOTS:
void rpcNestedTests(); void rpcNestedTests();
private:
CCoinsViewDB *pcoinsdbview;
}; };
#endif // BITCOIN_QT_TEST_RPC_NESTED_TESTS_H #endif // BITCOIN_QT_TEST_RPC_NESTED_TESTS_H

6
src/rpc/blockchain.cpp

@ -928,7 +928,7 @@ UniValue gettxoutsetinfo(const JSONRPCRequest& request)
CCoinsStats stats; CCoinsStats stats;
FlushStateToDisk(); FlushStateToDisk();
if (GetUTXOStats(pcoinsdbview, stats)) { if (GetUTXOStats(pcoinsdbview.get(), stats)) {
ret.push_back(Pair("height", (int64_t)stats.nHeight)); ret.push_back(Pair("height", (int64_t)stats.nHeight));
ret.push_back(Pair("bestblock", stats.hashBlock.GetHex())); ret.push_back(Pair("bestblock", stats.hashBlock.GetHex()));
ret.push_back(Pair("transactions", (int64_t)stats.nTransactions)); ret.push_back(Pair("transactions", (int64_t)stats.nTransactions));
@ -996,7 +996,7 @@ UniValue gettxout(const JSONRPCRequest& request)
Coin coin; Coin coin;
if (fMempool) { if (fMempool) {
LOCK(mempool.cs); LOCK(mempool.cs);
CCoinsViewMemPool view(pcoinsTip, mempool); CCoinsViewMemPool view(pcoinsTip.get(), mempool);
if (!view.GetCoin(out, coin) || mempool.isSpent(out)) { if (!view.GetCoin(out, coin) || mempool.isSpent(out)) {
return NullUniValue; return NullUniValue;
} }
@ -1048,7 +1048,7 @@ UniValue verifychain(const JSONRPCRequest& request)
if (!request.params[1].isNull()) if (!request.params[1].isNull())
nCheckDepth = request.params[1].get_int(); nCheckDepth = request.params[1].get_int();
return CVerifyDB().VerifyDB(Params(), pcoinsTip, nCheckLevel, nCheckDepth); return CVerifyDB().VerifyDB(Params(), pcoinsTip.get(), nCheckLevel, nCheckDepth);
} }
/** Implementation of IsSuperMajority with better feedback */ /** Implementation of IsSuperMajority with better feedback */

10
src/test/dbwrapper_tests.cpp

@ -125,7 +125,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)
create_directories(ph); create_directories(ph);
// Set up a non-obfuscated wrapper to write some initial data. // Set up a non-obfuscated wrapper to write some initial data.
CDBWrapper* dbw = new CDBWrapper(ph, (1 << 10), false, false, false); std::unique_ptr<CDBWrapper> dbw = MakeUnique<CDBWrapper>(ph, (1 << 10), false, false, false);
char key = 'k'; char key = 'k';
uint256 in = InsecureRand256(); uint256 in = InsecureRand256();
uint256 res; uint256 res;
@ -135,8 +135,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)
BOOST_CHECK_EQUAL(res.ToString(), in.ToString()); BOOST_CHECK_EQUAL(res.ToString(), in.ToString());
// Call the destructor to free leveldb LOCK // Call the destructor to free leveldb LOCK
delete dbw; dbw.reset();
dbw = nullptr;
// Now, set up another wrapper that wants to obfuscate the same directory // Now, set up another wrapper that wants to obfuscate the same directory
CDBWrapper odbw(ph, (1 << 10), false, false, true); CDBWrapper odbw(ph, (1 << 10), false, false, true);
@ -167,7 +166,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex)
create_directories(ph); create_directories(ph);
// Set up a non-obfuscated wrapper to write some initial data. // Set up a non-obfuscated wrapper to write some initial data.
CDBWrapper* dbw = new CDBWrapper(ph, (1 << 10), false, false, false); std::unique_ptr<CDBWrapper> dbw = MakeUnique<CDBWrapper>(ph, (1 << 10), false, false, false);
char key = 'k'; char key = 'k';
uint256 in = InsecureRand256(); uint256 in = InsecureRand256();
uint256 res; uint256 res;
@ -177,8 +176,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex)
BOOST_CHECK_EQUAL(res.ToString(), in.ToString()); BOOST_CHECK_EQUAL(res.ToString(), in.ToString());
// Call the destructor to free leveldb LOCK // Call the destructor to free leveldb LOCK
delete dbw; dbw.reset();
dbw = nullptr;
// Simulate a -reindex by wiping the existing data store // Simulate a -reindex by wiping the existing data store
CDBWrapper odbw(ph, (1 << 10), false, true, true); CDBWrapper odbw(ph, (1 << 10), false, true, true);

12
src/test/test_bitcoin.cpp

@ -81,9 +81,9 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
GetMainSignals().RegisterBackgroundSignalScheduler(scheduler); GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
mempool.setSanityCheck(1.0); mempool.setSanityCheck(1.0);
pblocktree = new CBlockTreeDB(1 << 20, true); pblocktree.reset(new CBlockTreeDB(1 << 20, true));
pcoinsdbview = new CCoinsViewDB(1 << 23, true); pcoinsdbview.reset(new CCoinsViewDB(1 << 23, true));
pcoinsTip = new CCoinsViewCache(pcoinsdbview); pcoinsTip.reset(new CCoinsViewCache(pcoinsdbview.get()));
if (!LoadGenesisBlock(chainparams)) { if (!LoadGenesisBlock(chainparams)) {
throw std::runtime_error("LoadGenesisBlock failed."); throw std::runtime_error("LoadGenesisBlock failed.");
} }
@ -110,9 +110,9 @@ TestingSetup::~TestingSetup()
g_connman.reset(); g_connman.reset();
peerLogic.reset(); peerLogic.reset();
UnloadBlockIndex(); UnloadBlockIndex();
delete pcoinsTip; pcoinsTip.reset();
delete pcoinsdbview; pcoinsdbview.reset();
delete pblocktree; pblocktree.reset();
fs::remove_all(pathTemp); fs::remove_all(pathTemp);
} }

1
src/test/test_bitcoin.h

@ -57,7 +57,6 @@ struct CConnmanTest {
class PeerLogicValidation; class PeerLogicValidation;
struct TestingSetup: public BasicTestingSetup { struct TestingSetup: public BasicTestingSetup {
CCoinsViewDB *pcoinsdbview;
fs::path pathTemp; fs::path pathTemp;
boost::thread_group threadGroup; boost::thread_group threadGroup;
CConnman* connman; CConnman* connman;

18
src/test/txvalidationcache_tests.cpp

@ -119,7 +119,7 @@ void ValidateCheckInputsForAllFlags(CMutableTransaction &tx, uint32_t failing_fl
// WITNESS requires P2SH // WITNESS requires P2SH
test_flags |= SCRIPT_VERIFY_P2SH; test_flags |= SCRIPT_VERIFY_P2SH;
} }
bool ret = CheckInputs(tx, state, pcoinsTip, true, test_flags, true, add_to_cache, txdata, nullptr); bool ret = CheckInputs(tx, state, pcoinsTip.get(), true, test_flags, true, add_to_cache, txdata, nullptr);
// CheckInputs should succeed iff test_flags doesn't intersect with // CheckInputs should succeed iff test_flags doesn't intersect with
// failing_flags // failing_flags
bool expected_return_value = !(test_flags & failing_flags); bool expected_return_value = !(test_flags & failing_flags);
@ -135,13 +135,13 @@ void ValidateCheckInputsForAllFlags(CMutableTransaction &tx, uint32_t failing_fl
if (ret && add_to_cache) { if (ret && add_to_cache) {
// Check that we get a cache hit if the tx was valid // Check that we get a cache hit if the tx was valid
std::vector<CScriptCheck> scriptchecks; std::vector<CScriptCheck> scriptchecks;
BOOST_CHECK(CheckInputs(tx, state, pcoinsTip, true, test_flags, true, add_to_cache, txdata, &scriptchecks)); BOOST_CHECK(CheckInputs(tx, state, pcoinsTip.get(), true, test_flags, true, add_to_cache, txdata, &scriptchecks));
BOOST_CHECK(scriptchecks.empty()); BOOST_CHECK(scriptchecks.empty());
} else { } else {
// Check that we get script executions to check, if the transaction // Check that we get script executions to check, if the transaction
// was invalid, or we didn't add to cache. // was invalid, or we didn't add to cache.
std::vector<CScriptCheck> scriptchecks; std::vector<CScriptCheck> scriptchecks;
BOOST_CHECK(CheckInputs(tx, state, pcoinsTip, true, test_flags, true, add_to_cache, txdata, &scriptchecks)); BOOST_CHECK(CheckInputs(tx, state, pcoinsTip.get(), true, test_flags, true, add_to_cache, txdata, &scriptchecks));
BOOST_CHECK_EQUAL(scriptchecks.size(), tx.vin.size()); BOOST_CHECK_EQUAL(scriptchecks.size(), tx.vin.size());
} }
} }
@ -201,13 +201,13 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
CValidationState state; CValidationState state;
PrecomputedTransactionData ptd_spend_tx(spend_tx); PrecomputedTransactionData ptd_spend_tx(spend_tx);
BOOST_CHECK(!CheckInputs(spend_tx, state, pcoinsTip, true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, nullptr)); BOOST_CHECK(!CheckInputs(spend_tx, state, pcoinsTip.get(), true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, nullptr));
// If we call again asking for scriptchecks (as happens in // If we call again asking for scriptchecks (as happens in
// ConnectBlock), we should add a script check object for this -- we're // ConnectBlock), we should add a script check object for this -- we're
// not caching invalidity (if that changes, delete this test case). // not caching invalidity (if that changes, delete this test case).
std::vector<CScriptCheck> scriptchecks; std::vector<CScriptCheck> scriptchecks;
BOOST_CHECK(CheckInputs(spend_tx, state, pcoinsTip, true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, &scriptchecks)); BOOST_CHECK(CheckInputs(spend_tx, state, pcoinsTip.get(), true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, &scriptchecks));
BOOST_CHECK_EQUAL(scriptchecks.size(), 1); BOOST_CHECK_EQUAL(scriptchecks.size(), 1);
// Test that CheckInputs returns true iff DERSIG-enforcing flags are // Test that CheckInputs returns true iff DERSIG-enforcing flags are
@ -268,7 +268,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 100; invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
CValidationState state; CValidationState state;
PrecomputedTransactionData txdata(invalid_with_cltv_tx); PrecomputedTransactionData txdata(invalid_with_cltv_tx);
BOOST_CHECK(CheckInputs(invalid_with_cltv_tx, state, pcoinsTip, true, SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true, txdata, nullptr)); BOOST_CHECK(CheckInputs(invalid_with_cltv_tx, state, pcoinsTip.get(), true, SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true, txdata, nullptr));
} }
// TEST CHECKSEQUENCEVERIFY // TEST CHECKSEQUENCEVERIFY
@ -296,7 +296,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 100; invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
CValidationState state; CValidationState state;
PrecomputedTransactionData txdata(invalid_with_csv_tx); PrecomputedTransactionData txdata(invalid_with_csv_tx);
BOOST_CHECK(CheckInputs(invalid_with_csv_tx, state, pcoinsTip, true, SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true, txdata, nullptr)); BOOST_CHECK(CheckInputs(invalid_with_csv_tx, state, pcoinsTip.get(), true, SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true, txdata, nullptr));
} }
// TODO: add tests for remaining script flags // TODO: add tests for remaining script flags
@ -358,12 +358,12 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
CValidationState state; CValidationState state;
PrecomputedTransactionData txdata(tx); PrecomputedTransactionData txdata(tx);
// This transaction is now invalid under segwit, because of the second input. // This transaction is now invalid under segwit, because of the second input.
BOOST_CHECK(!CheckInputs(tx, state, pcoinsTip, true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, nullptr)); BOOST_CHECK(!CheckInputs(tx, state, pcoinsTip.get(), true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, nullptr));
std::vector<CScriptCheck> scriptchecks; std::vector<CScriptCheck> scriptchecks;
// Make sure this transaction was not cached (ie because the first // Make sure this transaction was not cached (ie because the first
// input was valid) // input was valid)
BOOST_CHECK(CheckInputs(tx, state, pcoinsTip, true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, &scriptchecks)); BOOST_CHECK(CheckInputs(tx, state, pcoinsTip.get(), true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, &scriptchecks));
// Should get 2 script checks back -- caching is on a whole-transaction basis. // Should get 2 script checks back -- caching is on a whole-transaction basis.
BOOST_CHECK_EQUAL(scriptchecks.size(), 2); BOOST_CHECK_EQUAL(scriptchecks.size(), 2);
} }

7
src/util.h

@ -326,4 +326,11 @@ template <typename Callable> void TraceThread(const char* name, Callable func)
std::string CopyrightHolders(const std::string& strPrefix); std::string CopyrightHolders(const std::string& strPrefix);
//! Substitute for C++14 std::make_unique.
template <typename T, typename... Args>
std::unique_ptr<T> MakeUnique(Args&&... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
#endif // BITCOIN_UTIL_H #endif // BITCOIN_UTIL_H

20
src/validation.cpp

@ -201,9 +201,9 @@ CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& loc
return chain.Genesis(); return chain.Genesis();
} }
CCoinsViewDB *pcoinsdbview = nullptr; std::unique_ptr<CCoinsViewDB> pcoinsdbview;
CCoinsViewCache *pcoinsTip = nullptr; std::unique_ptr<CCoinsViewCache> pcoinsTip;
CBlockTreeDB *pblocktree = nullptr; std::unique_ptr<CBlockTreeDB> pblocktree;
enum FlushStateMode { enum FlushStateMode {
FLUSH_STATE_NONE, FLUSH_STATE_NONE,
@ -295,7 +295,7 @@ bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool
} }
else { else {
// pcoinsTip contains the UTXO set for chainActive.Tip() // pcoinsTip contains the UTXO set for chainActive.Tip()
CCoinsViewMemPool viewMemPool(pcoinsTip, mempool); CCoinsViewMemPool viewMemPool(pcoinsTip.get(), mempool);
std::vector<int> prevheights; std::vector<int> prevheights;
prevheights.resize(tx.vin.size()); prevheights.resize(tx.vin.size());
for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) { for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) {
@ -424,7 +424,7 @@ void UpdateMempoolForReorg(DisconnectedBlockTransactions &disconnectpool, bool f
mempool.UpdateTransactionsFromBlock(vHashUpdate); mempool.UpdateTransactionsFromBlock(vHashUpdate);
// We also need to remove any now-immature transactions // We also need to remove any now-immature transactions
mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); mempool.removeForReorg(pcoinsTip.get(), chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS);
// Re-limit mempool size, in case we added any transactions // Re-limit mempool size, in case we added any transactions
LimitMempoolSize(mempool, gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60); LimitMempoolSize(mempool, gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60);
} }
@ -557,7 +557,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
LockPoints lp; LockPoints lp;
{ {
LOCK(pool.cs); LOCK(pool.cs);
CCoinsViewMemPool viewMemPool(pcoinsTip, pool); CCoinsViewMemPool viewMemPool(pcoinsTip.get(), pool);
view.SetBackend(viewMemPool); view.SetBackend(viewMemPool);
// do all inputs exist? // do all inputs exist?
@ -2105,7 +2105,7 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara
// Apply the block atomically to the chain state. // Apply the block atomically to the chain state.
int64_t nStart = GetTimeMicros(); int64_t nStart = GetTimeMicros();
{ {
CCoinsViewCache view(pcoinsTip); CCoinsViewCache view(pcoinsTip.get());
assert(view.GetBestBlock() == pindexDelete->GetBlockHash()); assert(view.GetBestBlock() == pindexDelete->GetBlockHash());
if (DisconnectBlock(block, pindexDelete, view) != DISCONNECT_OK) if (DisconnectBlock(block, pindexDelete, view) != DISCONNECT_OK)
return error("DisconnectTip(): DisconnectBlock %s failed", pindexDelete->GetBlockHash().ToString()); return error("DisconnectTip(): DisconnectBlock %s failed", pindexDelete->GetBlockHash().ToString());
@ -2235,7 +2235,7 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams,
int64_t nTime3; int64_t nTime3;
LogPrint(BCLog::BENCH, " - Load block from disk: %.2fms [%.2fs]\n", (nTime2 - nTime1) * MILLI, nTimeReadFromDisk * MICRO); LogPrint(BCLog::BENCH, " - Load block from disk: %.2fms [%.2fs]\n", (nTime2 - nTime1) * MILLI, nTimeReadFromDisk * MICRO);
{ {
CCoinsViewCache view(pcoinsTip); CCoinsViewCache view(pcoinsTip.get());
bool rv = ConnectBlock(blockConnecting, state, pindexNew, view, chainparams); bool rv = ConnectBlock(blockConnecting, state, pindexNew, view, chainparams);
GetMainSignals().BlockChecked(blockConnecting, state); GetMainSignals().BlockChecked(blockConnecting, state);
if (!rv) { if (!rv) {
@ -2413,7 +2413,7 @@ static bool ActivateBestChainStep(CValidationState& state, const CChainParams& c
// any disconnected transactions back to the mempool. // any disconnected transactions back to the mempool.
UpdateMempoolForReorg(disconnectpool, true); UpdateMempoolForReorg(disconnectpool, true);
} }
mempool.check(pcoinsTip); mempool.check(pcoinsTip.get());
// Callbacks/notifications for a new best chain. // Callbacks/notifications for a new best chain.
if (fInvalidFound) if (fInvalidFound)
@ -3275,7 +3275,7 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams,
{ {
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
assert(pindexPrev && pindexPrev == chainActive.Tip()); assert(pindexPrev && pindexPrev == chainActive.Tip());
CCoinsViewCache viewNew(pcoinsTip); CCoinsViewCache viewNew(pcoinsTip.get());
CBlockIndex indexDummy(block); CBlockIndex indexDummy(block);
indexDummy.pprev = pindexPrev; indexDummy.pprev = pindexPrev;
indexDummy.nHeight = pindexPrev->nHeight + 1; indexDummy.nHeight = pindexPrev->nHeight + 1;

6
src/validation.h

@ -444,13 +444,13 @@ bool ResetBlockFailureFlags(CBlockIndex *pindex);
extern CChain chainActive; extern CChain chainActive;
/** Global variable that points to the coins database (protected by cs_main) */ /** Global variable that points to the coins database (protected by cs_main) */
extern CCoinsViewDB *pcoinsdbview; extern std::unique_ptr<CCoinsViewDB> pcoinsdbview;
/** Global variable that points to the active CCoinsView (protected by cs_main) */ /** Global variable that points to the active CCoinsView (protected by cs_main) */
extern CCoinsViewCache *pcoinsTip; extern std::unique_ptr<CCoinsViewCache> pcoinsTip;
/** Global variable that points to the active block tree (protected by cs_main) */ /** Global variable that points to the active block tree (protected by cs_main) */
extern CBlockTreeDB *pblocktree; extern std::unique_ptr<CBlockTreeDB> pblocktree;
/** /**
* Return the spend height, which is one more than the inputs.GetBestBlock(). * Return the spend height, which is one more than the inputs.GetBestBlock().

22
src/wallet/db.cpp

@ -75,13 +75,12 @@ void CDBEnv::EnvShutdown()
void CDBEnv::Reset() void CDBEnv::Reset()
{ {
delete dbenv; dbenv.reset(new DbEnv(DB_CXX_NO_EXCEPTIONS));
dbenv = new DbEnv(DB_CXX_NO_EXCEPTIONS);
fDbEnvInit = false; fDbEnvInit = false;
fMockDb = false; fMockDb = false;
} }
CDBEnv::CDBEnv() : dbenv(nullptr) CDBEnv::CDBEnv()
{ {
Reset(); Reset();
} }
@ -89,8 +88,6 @@ CDBEnv::CDBEnv() : dbenv(nullptr)
CDBEnv::~CDBEnv() CDBEnv::~CDBEnv()
{ {
EnvShutdown(); EnvShutdown();
delete dbenv;
dbenv = nullptr;
} }
void CDBEnv::Close() void CDBEnv::Close()
@ -182,7 +179,7 @@ CDBEnv::VerifyResult CDBEnv::Verify(const std::string& strFile, recoverFunc_type
LOCK(cs_db); LOCK(cs_db);
assert(mapFileUseCount.count(strFile) == 0); assert(mapFileUseCount.count(strFile) == 0);
Db db(dbenv, 0); Db db(dbenv.get(), 0);
int result = db.verify(strFile.c_str(), nullptr, nullptr, 0); int result = db.verify(strFile.c_str(), nullptr, nullptr, 0);
if (result == 0) if (result == 0)
return VERIFY_OK; return VERIFY_OK;
@ -225,7 +222,7 @@ bool CDB::Recover(const std::string& filename, void *callbackDataIn, bool (*reco
} }
LogPrintf("Salvage(aggressive) found %u records\n", salvagedData.size()); LogPrintf("Salvage(aggressive) found %u records\n", salvagedData.size());
std::unique_ptr<Db> pdbCopy(new Db(bitdb.dbenv, 0)); std::unique_ptr<Db> pdbCopy = MakeUnique<Db>(bitdb.dbenv.get(), 0);
int ret = pdbCopy->open(nullptr, // Txn pointer int ret = pdbCopy->open(nullptr, // Txn pointer
filename.c_str(), // Filename filename.c_str(), // Filename
"main", // Logical db name "main", // Logical db name
@ -334,7 +331,7 @@ bool CDBEnv::Salvage(const std::string& strFile, bool fAggressive, std::vector<C
std::stringstream strDump; std::stringstream strDump;
Db db(dbenv, 0); Db db(dbenv.get(), 0);
int result = db.verify(strFile.c_str(), nullptr, &strDump, flags); int result = db.verify(strFile.c_str(), nullptr, &strDump, flags);
if (result == DB_VERIFY_BAD) { 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");
@ -416,7 +413,7 @@ CDB::CDB(CWalletDBWrapper& dbw, const char* pszMode, bool fFlushOnCloseIn) : pdb
pdb = env->mapDb[strFilename]; pdb = env->mapDb[strFilename];
if (pdb == nullptr) { if (pdb == nullptr) {
int ret; int ret;
std::unique_ptr<Db> pdb_temp(new Db(env->dbenv, 0)); std::unique_ptr<Db> pdb_temp = MakeUnique<Db>(env->dbenv.get(), 0);
bool fMockDb = env->IsMock(); bool fMockDb = env->IsMock();
if (fMockDb) { if (fMockDb) {
@ -525,7 +522,7 @@ bool CDB::Rewrite(CWalletDBWrapper& dbw, const char* pszSkip)
std::string strFileRes = strFile + ".rewrite"; std::string strFileRes = strFile + ".rewrite";
{ // surround usage of db with extra {} { // surround usage of db with extra {}
CDB db(dbw, "r"); CDB db(dbw, "r");
Db* pdbCopy = new Db(env->dbenv, 0); std::unique_ptr<Db> pdbCopy = MakeUnique<Db>(env->dbenv.get(), 0);
int ret = pdbCopy->open(nullptr, // Txn pointer int ret = pdbCopy->open(nullptr, // Txn pointer
strFileRes.c_str(), // Filename strFileRes.c_str(), // Filename
@ -574,13 +571,12 @@ bool CDB::Rewrite(CWalletDBWrapper& dbw, const char* pszSkip)
} else { } else {
pdbCopy->close(0); pdbCopy->close(0);
} }
delete pdbCopy;
} }
if (fSuccess) { if (fSuccess) {
Db dbA(env->dbenv, 0); Db dbA(env->dbenv.get(), 0);
if (dbA.remove(strFile.c_str(), nullptr, 0)) if (dbA.remove(strFile.c_str(), nullptr, 0))
fSuccess = false; fSuccess = false;
Db dbB(env->dbenv, 0); Db dbB(env->dbenv.get(), 0);
if (dbB.rename(strFileRes.c_str(), nullptr, strFile.c_str(), 0)) if (dbB.rename(strFileRes.c_str(), nullptr, strFile.c_str(), 0))
fSuccess = false; fSuccess = false;
} }

2
src/wallet/db.h

@ -36,7 +36,7 @@ private:
public: public:
mutable CCriticalSection cs_db; mutable CCriticalSection cs_db;
DbEnv *dbenv; std::unique_ptr<DbEnv> dbenv;
std::map<std::string, int> mapFileUseCount; std::map<std::string, int> mapFileUseCount;
std::map<std::string, Db*> mapDb; std::map<std::string, Db*> mapDb;

11
src/wallet/test/wallet_test_fixture.cpp

@ -8,7 +8,7 @@
#include "wallet/db.h" #include "wallet/db.h"
#include "wallet/wallet.h" #include "wallet/wallet.h"
CWallet *pwalletMain; std::unique_ptr<CWallet> pwalletMain;
WalletTestingSetup::WalletTestingSetup(const std::string& chainName): WalletTestingSetup::WalletTestingSetup(const std::string& chainName):
TestingSetup(chainName) TestingSetup(chainName)
@ -17,18 +17,17 @@ WalletTestingSetup::WalletTestingSetup(const std::string& chainName):
bool fFirstRun; bool fFirstRun;
std::unique_ptr<CWalletDBWrapper> dbw(new CWalletDBWrapper(&bitdb, "wallet_test.dat")); std::unique_ptr<CWalletDBWrapper> dbw(new CWalletDBWrapper(&bitdb, "wallet_test.dat"));
pwalletMain = new CWallet(std::move(dbw)); pwalletMain = MakeUnique<CWallet>(std::move(dbw));
pwalletMain->LoadWallet(fFirstRun); pwalletMain->LoadWallet(fFirstRun);
RegisterValidationInterface(pwalletMain); RegisterValidationInterface(pwalletMain.get());
RegisterWalletRPCCommands(tableRPC); RegisterWalletRPCCommands(tableRPC);
} }
WalletTestingSetup::~WalletTestingSetup() WalletTestingSetup::~WalletTestingSetup()
{ {
UnregisterValidationInterface(pwalletMain); UnregisterValidationInterface(pwalletMain.get());
delete pwalletMain; pwalletMain.reset();
pwalletMain = nullptr;
bitdb.Flush(true); bitdb.Flush(true);
bitdb.Reset(); bitdb.Reset();

2
src/wallet/wallet.cpp

@ -3806,7 +3806,7 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
uiInterface.InitMessage(_("Zapping all transactions from wallet...")); uiInterface.InitMessage(_("Zapping all transactions from wallet..."));
std::unique_ptr<CWalletDBWrapper> dbw(new CWalletDBWrapper(&bitdb, walletFile)); std::unique_ptr<CWalletDBWrapper> dbw(new CWalletDBWrapper(&bitdb, walletFile));
std::unique_ptr<CWallet> tempWallet(new CWallet(std::move(dbw))); std::unique_ptr<CWallet> tempWallet = MakeUnique<CWallet>(std::move(dbw));
DBErrors nZapWalletRet = tempWallet->ZapWalletTx(vWtx); DBErrors nZapWalletRet = tempWallet->ZapWalletTx(vWtx);
if (nZapWalletRet != DB_LOAD_OK) { if (nZapWalletRet != DB_LOAD_OK) {
InitError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile)); InitError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile));

Loading…
Cancel
Save