Skip to content

Commit 177433a

Browse files
committed
Merge #8694: Basic multiwallet support
c237bd7 wallet: Update formatting (Luke Dashjr) 9cbe8c8 wallet: Forbid -salvagewallet, -zapwallettxes, and -upgradewallet with multiple wallets (Luke Dashjr) a2a5f3f wallet: Base backup filenames on original wallet filename (Luke Dashjr) b823a4c wallet: Include actual backup filename in recovery warning message (Luke Dashjr) 84dcb45 Bugfix: wallet: Fix warningStr, errorStr argument order (Luke Dashjr) 008c360 Wallet: Move multiwallet sanity checks to CWallet::Verify, and do other checks on all wallets (Luke Dashjr) 0f08575 Wallet: Support loading multiple wallets if -wallet used more than once (Luke Dashjr) b124cf0 Wallet: Replace pwalletMain with a vector of wallet pointers (Luke Dashjr) 19b3648 CWalletDB: Store the update counter per wallet (Luke Dashjr) 74e8738 Bugfix: ForceSetArg should replace entr(ies) in mapMultiArgs, not append (Luke Dashjr) 23fb9ad wallet: Move nAccountingEntryNumber from static/global to CWallet (Luke Dashjr) 9d15d55 Bugfix: wallet: Increment "update counter" when modifying account stuff (Luke Dashjr) f28eb80 Bugfix: wallet: Increment "update counter" only after actually making the applicable db changes to avoid potential races (Luke Dashjr) Tree-SHA512: 23f5dda58477307bc07997010740f1dc729164cdddefd2f9a2c9c7a877111eb1516d3e2ad4f9b104621f0b7f17369c69fcef13d28b85cb6c01d35f09a8845f23
2 parents fa1f106 + c237bd7 commit 177433a

File tree

12 files changed

+197
-166
lines changed

12 files changed

+197
-166
lines changed

src/init.cpp

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -197,8 +197,9 @@ void Shutdown()
197197
StopRPC();
198198
StopHTTPServer();
199199
#ifdef ENABLE_WALLET
200-
if (pwalletMain)
201-
pwalletMain->Flush(false);
200+
for (CWalletRef pwallet : vpwallets) {
201+
pwallet->Flush(false);
202+
}
202203
#endif
203204
MapPort(false);
204205
UnregisterValidationInterface(peerLogic.get());
@@ -238,8 +239,9 @@ void Shutdown()
238239
pblocktree = NULL;
239240
}
240241
#ifdef ENABLE_WALLET
241-
if (pwalletMain)
242-
pwalletMain->Flush(true);
242+
for (CWalletRef pwallet : vpwallets) {
243+
pwallet->Flush(true);
244+
}
243245
#endif
244246

245247
#if ENABLE_ZMQ
@@ -259,8 +261,10 @@ void Shutdown()
259261
#endif
260262
UnregisterAllValidationInterfaces();
261263
#ifdef ENABLE_WALLET
262-
delete pwalletMain;
263-
pwalletMain = NULL;
264+
for (CWalletRef pwallet : vpwallets) {
265+
delete pwallet;
266+
}
267+
vpwallets.clear();
264268
#endif
265269
globalVerifyHandle.reset();
266270
ECC_Stop();
@@ -1672,8 +1676,9 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
16721676
uiInterface.InitMessage(_("Done loading"));
16731677

16741678
#ifdef ENABLE_WALLET
1675-
if (pwalletMain)
1676-
pwalletMain->postInitProcess(scheduler);
1679+
for (CWalletRef pwallet : vpwallets) {
1680+
pwallet->postInitProcess(scheduler);
1681+
}
16771682
#endif
16781683

16791684
return !fRequestShutdown;

src/qt/bitcoin.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -474,9 +474,10 @@ void BitcoinApplication::initializeResult(bool success)
474474
window->setClientModel(clientModel);
475475

476476
#ifdef ENABLE_WALLET
477-
if(pwalletMain)
477+
// TODO: Expose secondary wallets
478+
if (!vpwallets.empty())
478479
{
479-
walletModel = new WalletModel(platformStyle, pwalletMain, optionsModel);
480+
walletModel = new WalletModel(platformStyle, vpwallets[0], optionsModel);
480481

481482
window->addWallet(BitcoinGUI::DEFAULT_WALLET, walletModel);
482483
window->setCurrentWallet(BitcoinGUI::DEFAULT_WALLET);

src/util.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,7 @@ void ArgsManager::ForceSetArg(const std::string& strArg, const std::string& strV
474474
{
475475
LOCK(cs_args);
476476
mapArgs[strArg] = strValue;
477+
mapMultiArgs[strArg].clear();
477478
mapMultiArgs[strArg].push_back(strValue);
478479
}
479480

src/wallet/db.cpp

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ void CDBEnv::MakeMock()
142142
fMockDb = true;
143143
}
144144

145-
CDBEnv::VerifyResult CDBEnv::Verify(const std::string& strFile, bool (*recoverFunc)(const std::string& strFile))
145+
CDBEnv::VerifyResult CDBEnv::Verify(const std::string& strFile, recoverFunc_type recoverFunc, std::string& out_backup_filename)
146146
{
147147
LOCK(cs_db);
148148
assert(mapFileUseCount.count(strFile) == 0);
@@ -155,21 +155,21 @@ CDBEnv::VerifyResult CDBEnv::Verify(const std::string& strFile, bool (*recoverFu
155155
return RECOVER_FAIL;
156156

157157
// Try to recover:
158-
bool fRecovered = (*recoverFunc)(strFile);
158+
bool fRecovered = (*recoverFunc)(strFile, out_backup_filename);
159159
return (fRecovered ? RECOVER_OK : RECOVER_FAIL);
160160
}
161161

162-
bool CDB::Recover(const std::string& filename, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue))
162+
bool CDB::Recover(const std::string& filename, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue), std::string& newFilename)
163163
{
164164
// Recovery procedure:
165-
// move wallet file to wallet.timestamp.bak
165+
// move wallet file to walletfilename.timestamp.bak
166166
// Call Salvage with fAggressive=true to
167167
// get as much data as possible.
168168
// Rewrite salvaged data to fresh wallet file
169169
// Set -rescan so any missing transactions will be
170170
// found.
171171
int64_t now = GetTime();
172-
std::string newFilename = strprintf("wallet.%d.bak", now);
172+
newFilename = strprintf("%s.%d.bak", filename, now);
173173

174174
int result = bitdb.dbenv->dbrename(NULL, filename.c_str(), NULL,
175175
newFilename.c_str(), DB_AUTO_COMMIT);
@@ -259,18 +259,19 @@ bool CDB::VerifyEnvironment(const std::string& walletFile, const fs::path& dataD
259259
return true;
260260
}
261261

262-
bool CDB::VerifyDatabaseFile(const std::string& walletFile, const fs::path& dataDir, std::string& warningStr, std::string& errorStr, bool (*recoverFunc)(const std::string& strFile))
262+
bool CDB::VerifyDatabaseFile(const std::string& walletFile, const fs::path& dataDir, std::string& warningStr, std::string& errorStr, CDBEnv::recoverFunc_type recoverFunc)
263263
{
264264
if (fs::exists(dataDir / walletFile))
265265
{
266-
CDBEnv::VerifyResult r = bitdb.Verify(walletFile, recoverFunc);
266+
std::string backup_filename;
267+
CDBEnv::VerifyResult r = bitdb.Verify(walletFile, recoverFunc, backup_filename);
267268
if (r == CDBEnv::RECOVER_OK)
268269
{
269270
warningStr = strprintf(_("Warning: Wallet file corrupt, data salvaged!"
270271
" Original %s saved as %s in %s; if"
271272
" your balance or transactions are incorrect you should"
272273
" restore from a backup."),
273-
walletFile, "wallet.{timestamp}.bak", dataDir);
274+
walletFile, backup_filename, dataDir);
274275
}
275276
if (r == CDBEnv::RECOVER_FAIL)
276277
{
@@ -432,6 +433,11 @@ void CDB::Flush()
432433
env->dbenv->txn_checkpoint(nMinutes ? GetArg("-dblogsize", DEFAULT_WALLET_DBLOGSIZE) * 1024 : 0, nMinutes, 0);
433434
}
434435

436+
void CWalletDBWrapper::IncrementUpdateCounter()
437+
{
438+
++nUpdateCounter;
439+
}
440+
435441
void CDB::Close()
436442
{
437443
if (!pdb)

src/wallet/db.h

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ class CDBEnv
5555
enum VerifyResult { VERIFY_OK,
5656
RECOVER_OK,
5757
RECOVER_FAIL };
58-
VerifyResult Verify(const std::string& strFile, bool (*recoverFunc)(const std::string& strFile));
58+
typedef bool (*recoverFunc_type)(const std::string& strFile, std::string& out_backup_filename);
59+
VerifyResult Verify(const std::string& strFile, recoverFunc_type recoverFunc, std::string& out_backup_filename);
5960
/**
6061
* Salvage data from a file that Verify says is bad.
6162
* fAggressive sets the DB_AGGRESSIVE flag (see berkeley DB->verify() method documentation).
@@ -93,13 +94,13 @@ class CWalletDBWrapper
9394
friend class CDB;
9495
public:
9596
/** Create dummy DB handle */
96-
CWalletDBWrapper(): env(nullptr)
97+
CWalletDBWrapper() : nLastSeen(0), nLastFlushed(0), nLastWalletUpdate(0), env(nullptr)
9798
{
9899
}
99100

100101
/** Create DB handle to real database */
101-
CWalletDBWrapper(CDBEnv *env_in, const std::string &strFile_in):
102-
env(env_in), strFile(strFile_in)
102+
CWalletDBWrapper(CDBEnv *env_in, const std::string &strFile_in) :
103+
nLastSeen(0), nLastFlushed(0), nLastWalletUpdate(0), env(env_in), strFile(strFile_in)
103104
{
104105
}
105106

@@ -119,6 +120,13 @@ class CWalletDBWrapper
119120
*/
120121
void Flush(bool shutdown);
121122

123+
void IncrementUpdateCounter();
124+
125+
std::atomic<unsigned int> nUpdateCounter;
126+
unsigned int nLastSeen;
127+
unsigned int nLastFlushed;
128+
int64_t nLastWalletUpdate;
129+
122130
private:
123131
/** BerkeleyDB specific */
124132
CDBEnv *env;
@@ -149,15 +157,15 @@ class CDB
149157

150158
void Flush();
151159
void Close();
152-
static bool Recover(const std::string& filename, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue));
160+
static bool Recover(const std::string& filename, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue), std::string& out_backup_filename);
153161

154162
/* flush the wallet passively (TRY_LOCK)
155163
ideal to be called periodically */
156164
static bool PeriodicFlush(CWalletDBWrapper& dbw);
157165
/* verifies the database environment */
158166
static bool VerifyEnvironment(const std::string& walletFile, const fs::path& dataDir, std::string& errorStr);
159167
/* verifies the database file */
160-
static bool VerifyDatabaseFile(const std::string& walletFile, const fs::path& dataDir, std::string& warningStr, std::string& errorStr, bool (*recoverFunc)(const std::string& strFile));
168+
static bool VerifyDatabaseFile(const std::string& walletFile, const fs::path& dataDir, std::string& warningStr, std::string& errorStr, CDBEnv::recoverFunc_type recoverFunc);
161169

162170
private:
163171
CDB(const CDB&);

src/wallet/rpcwallet.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@
3131

3232
CWallet *GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
3333
{
34-
return pwalletMain;
34+
// TODO: Some way to access secondary wallets
35+
return vpwallets.empty() ? nullptr : vpwallets[0];
3536
}
3637

3738
std::string HelpRequiringPassphrase(CWallet * const pwallet)

src/wallet/test/wallet_test_fixture.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#include "wallet/db.h"
99
#include "wallet/wallet.h"
1010

11+
CWallet *pwalletMain;
12+
1113
WalletTestingSetup::WalletTestingSetup(const std::string& chainName):
1214
TestingSetup(chainName)
1315
{

src/wallet/test/wallet_tests.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#include <boost/test/unit_test.hpp>
1919
#include <univalue.h>
2020

21+
extern CWallet* pwalletMain;
22+
2123
extern UniValue importmulti(const JSONRPCRequest& request);
2224
extern UniValue dumpwallet(const JSONRPCRequest& request);
2325
extern UniValue importwallet(const JSONRPCRequest& request);
@@ -401,8 +403,7 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
401403
// after.
402404
{
403405
CWallet wallet;
404-
CWallet *backup = ::pwalletMain;
405-
::pwalletMain = &wallet;
406+
vpwallets.insert(vpwallets.begin(), &wallet);
406407
UniValue keys;
407408
keys.setArray();
408409
UniValue key;
@@ -433,7 +434,7 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
433434
"downloading and rescanning the relevant blocks (see -reindex and -rescan "
434435
"options).\"}},{\"success\":true}]",
435436
0, oldTip->GetBlockTimeMax(), TIMESTAMP_WINDOW));
436-
::pwalletMain = backup;
437+
vpwallets.erase(vpwallets.begin());
437438
}
438439
}
439440

@@ -443,7 +444,6 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
443444
// than or equal to key birthday.
444445
BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
445446
{
446-
CWallet *pwalletMainBackup = ::pwalletMain;
447447
LOCK(cs_main);
448448

449449
// Create two blocks with same timestamp to verify that importwallet rescan
@@ -469,7 +469,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
469469
JSONRPCRequest request;
470470
request.params.setArray();
471471
request.params.push_back("wallet.backup");
472-
::pwalletMain = &wallet;
472+
vpwallets.insert(vpwallets.begin(), &wallet);
473473
::dumpwallet(request);
474474
}
475475

@@ -481,7 +481,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
481481
JSONRPCRequest request;
482482
request.params.setArray();
483483
request.params.push_back("wallet.backup");
484-
::pwalletMain = &wallet;
484+
vpwallets[0] = &wallet;
485485
::importwallet(request);
486486

487487
BOOST_CHECK_EQUAL(wallet.mapWallet.size(), 3);
@@ -494,7 +494,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
494494
}
495495

496496
SetMockTime(0);
497-
::pwalletMain = pwalletMainBackup;
497+
vpwallets.erase(vpwallets.begin());
498498
}
499499

500500
// Check that GetImmatureCredit() returns a newly calculated value instead of

0 commit comments

Comments
 (0)