aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet')
-rw-r--r--src/wallet/coincontrol.h2
-rw-r--r--src/wallet/db.cpp10
-rw-r--r--src/wallet/feebumper.cpp4
-rw-r--r--src/wallet/init.cpp147
-rw-r--r--src/wallet/rpcdump.cpp56
-rw-r--r--src/wallet/rpcwallet.cpp335
-rw-r--r--src/wallet/rpcwallet.h2
-rw-r--r--src/wallet/test/coinselector_tests.cpp15
-rw-r--r--src/wallet/test/wallet_tests.cpp30
-rw-r--r--src/wallet/wallet.cpp306
-rw-r--r--src/wallet/wallet.h127
-rw-r--r--src/wallet/walletdb.cpp4
-rw-r--r--src/wallet/walletdb.h12
13 files changed, 702 insertions, 348 deletions
diff --git a/src/wallet/coincontrol.h b/src/wallet/coincontrol.h
index 2f08162ee4..98b4298507 100644
--- a/src/wallet/coincontrol.h
+++ b/src/wallet/coincontrol.h
@@ -22,7 +22,7 @@ public:
boost::optional<OutputType> m_change_type;
//! 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 are solvable
bool fAllowWatchOnly;
//! Override automatic min/max checks on fee, m_feerate must be set if true
bool fOverrideFeeRate;
diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp
index 10a06e4b9a..410dd5009f 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -53,7 +53,7 @@ void CheckUniqueFileid(const BerkeleyEnvironment& env, const std::string& filena
}
CCriticalSection cs_db;
-std::map<std::string, BerkeleyEnvironment> g_dbenvs; //!< Map from directory name to open db environment.
+std::map<std::string, BerkeleyEnvironment> g_dbenvs GUARDED_BY(cs_db); //!< Map from directory name to open db environment.
} // namespace
BerkeleyEnvironment* GetWalletEnv(const fs::path& wallet_path, std::string& database_filename)
@@ -102,7 +102,7 @@ void BerkeleyEnvironment::Close()
int ret = dbenv->close(0);
if (ret != 0)
- LogPrintf("BerkeleyEnvironment::EnvShutdown: Error %d shutting down database environment: %s\n", ret, DbEnv::strerror(ret));
+ LogPrintf("BerkeleyEnvironment::Close: Error %d closing database environment: %s\n", ret, DbEnv::strerror(ret));
if (!fMockDb)
DbEnv((u_int32_t)0).remove(strPath.c_str(), 0);
}
@@ -168,8 +168,12 @@ bool BerkeleyEnvironment::Open(bool retry)
nEnvFlags,
S_IRUSR | S_IWUSR);
if (ret != 0) {
- dbenv->close(0);
LogPrintf("BerkeleyEnvironment::Open: Error %d opening database environment: %s\n", ret, DbEnv::strerror(ret));
+ int ret2 = dbenv->close(0);
+ if (ret2 != 0) {
+ LogPrintf("BerkeleyEnvironment::Open: Error %d closing failed database environment: %s\n", ret2, DbEnv::strerror(ret2));
+ }
+ Reset();
if (retry) {
// try moving the database env out of the way
fs::path pathDatabaseBak = pathIn / strprintf("database.%d.bak", GetTime());
diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp
index 4d70dde72a..0eb85a6e5c 100644
--- a/src/wallet/feebumper.cpp
+++ b/src/wallet/feebumper.cpp
@@ -18,7 +18,7 @@
//! Check whether transaction has descendant in wallet or mempool, or has been
//! mined, or conflicts with a mined transaction. Return a feebumper::Result.
-static feebumper::Result PreconditionChecks(const CWallet* wallet, const CWalletTx& wtx, std::vector<std::string>& errors)
+static feebumper::Result PreconditionChecks(const CWallet* wallet, const CWalletTx& wtx, std::vector<std::string>& errors) EXCLUSIVE_LOCKS_REQUIRED(wallet->cs_wallet)
{
if (wallet->HasWalletSpend(wtx.GetHash())) {
errors.push_back("Transaction has descendants in the wallet");
@@ -185,7 +185,7 @@ Result CreateTransaction(const CWallet* wallet, const uint256& txid, const CCoin
// If the output is not large enough to pay the fee, fail.
CAmount nDelta = new_fee - old_fee;
assert(nDelta > 0);
- mtx = *wtx.tx;
+ mtx = CMutableTransaction{*wtx.tx};
CTxOut* poutput = &(mtx.vout[nOutput]);
if (poutput->nValue < nDelta) {
errors.push_back("Change output is too small to bump the fee");
diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp
index 06f9c730c0..daeff1d0e8 100644
--- a/src/wallet/init.cpp
+++ b/src/wallet/init.cpp
@@ -6,6 +6,7 @@
#include <chainparams.h>
#include <init.h>
#include <net.h>
+#include <scheduler.h>
#include <util.h>
#include <utilmoneystr.h>
#include <validation.h>
@@ -18,7 +19,7 @@ class WalletInit : public WalletInitInterface {
public:
//! Return the wallets help message.
- std::string GetHelpString(bool showDebug) const override;
+ void AddWalletOptions() const override;
//! Wallets parameter interaction
bool ParameterInteraction() const override;
@@ -49,46 +50,38 @@ public:
const WalletInitInterface& g_wallet_init_interface = WalletInit();
-std::string WalletInit::GetHelpString(bool showDebug) const
+void WalletInit::AddWalletOptions() const
{
- std::string strUsage = HelpMessageGroup(_("Wallet options:"));
- strUsage += HelpMessageOpt("-addresstype", strprintf("What type of addresses to use (\"legacy\", \"p2sh-segwit\", or \"bech32\", default: \"%s\")", FormatOutputType(DEFAULT_ADDRESS_TYPE)));
- strUsage += HelpMessageOpt("-changetype", "What type of change to use (\"legacy\", \"p2sh-segwit\", or \"bech32\"). Default is same as -addresstype, except when -addresstype=p2sh-segwit a native segwit output is used when sending to a native segwit address)");
- strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls"));
- strUsage += HelpMessageOpt("-discardfee=<amt>", strprintf(_("The fee rate (in %s/kB) that indicates your tolerance for discarding change by adding it to the fee (default: %s). "
- "Note: An output is discarded if it is dust at this rate, but we will always discard up to the dust relay fee and a discard fee above that is limited by the fee estimate for the longest target"),
- CURRENCY_UNIT, FormatMoney(DEFAULT_DISCARD_FEE)));
- strUsage += HelpMessageOpt("-fallbackfee=<amt>", strprintf(_("A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)"),
- CURRENCY_UNIT, FormatMoney(DEFAULT_FALLBACK_FEE)));
- strUsage += HelpMessageOpt("-keypool=<n>", strprintf(_("Set key pool size to <n> (default: %u)"), DEFAULT_KEYPOOL_SIZE));
- strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)"),
- CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE)));
- strUsage += HelpMessageOpt("-paytxfee=<amt>", strprintf(_("Fee (in %s/kB) to add to transactions you send (default: %s)"),
- CURRENCY_UNIT, FormatMoney(CFeeRate{DEFAULT_PAY_TX_FEE}.GetFeePerK())));
- strUsage += HelpMessageOpt("-rescan", _("Rescan the block chain for missing wallet transactions on startup"));
- strUsage += HelpMessageOpt("-salvagewallet", _("Attempt to recover private keys from a corrupt wallet on startup"));
- strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), DEFAULT_SPEND_ZEROCONF_CHANGE));
- strUsage += HelpMessageOpt("-txconfirmtarget=<n>", strprintf(_("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)"), DEFAULT_TX_CONFIRM_TARGET));
- strUsage += HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format on startup"));
- strUsage += HelpMessageOpt("-wallet=<path>", _("Specify wallet database path. Can be specified multiple times to load multiple wallets. Path is interpreted relative to <walletdir> if it is not absolute, and will be created if it does not exist (as a directory containing a wallet.dat file and log files). For backwards compatibility this will also accept names of existing data files in <walletdir>.)"));
- strUsage += HelpMessageOpt("-walletbroadcast", _("Make the wallet broadcast transactions") + " " + strprintf(_("(default: %u)"), DEFAULT_WALLETBROADCAST));
- strUsage += HelpMessageOpt("-walletdir=<dir>", _("Specify directory to hold wallets (default: <datadir>/wallets if it exists, otherwise <datadir>)"));
- strUsage += HelpMessageOpt("-walletnotify=<cmd>", _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)"));
- strUsage += HelpMessageOpt("-walletrbf", strprintf(_("Send transactions with full-RBF opt-in enabled (RPC only, default: %u)"), DEFAULT_WALLET_RBF));
- strUsage += HelpMessageOpt("-zapwallettxes=<mode>", _("Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup") +
- " " + _("(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)"));
-
- if (showDebug)
- {
- strUsage += HelpMessageGroup(_("Wallet debugging/testing options:"));
-
- strUsage += HelpMessageOpt("-dblogsize=<n>", strprintf("Flush wallet database activity from memory to disk log every <n> megabytes (default: %u)", DEFAULT_WALLET_DBLOGSIZE));
- strUsage += HelpMessageOpt("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", DEFAULT_FLUSHWALLET));
- strUsage += HelpMessageOpt("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", DEFAULT_WALLET_PRIVDB));
- strUsage += HelpMessageOpt("-walletrejectlongchains", strprintf(_("Wallet will not create transactions that violate mempool chain limits (default: %u)"), DEFAULT_WALLET_REJECT_LONG_CHAINS));
- }
-
- return strUsage;
+ gArgs.AddArg("-addresstype", strprintf("What type of addresses to use (\"legacy\", \"p2sh-segwit\", or \"bech32\", default: \"%s\")", FormatOutputType(DEFAULT_ADDRESS_TYPE)), false, OptionsCategory::WALLET);
+ gArgs.AddArg("-changetype", "What type of change to use (\"legacy\", \"p2sh-segwit\", or \"bech32\"). Default is same as -addresstype, except when -addresstype=p2sh-segwit a native segwit output is used when sending to a native segwit address)", false, OptionsCategory::WALLET);
+ gArgs.AddArg("-disablewallet", "Do not load the wallet and disable wallet RPC calls", false, OptionsCategory::WALLET);
+ gArgs.AddArg("-discardfee=<amt>", strprintf("The fee rate (in %s/kB) that indicates your tolerance for discarding change by adding it to the fee (default: %s). "
+ "Note: An output is discarded if it is dust at this rate, but we will always discard up to the dust relay fee and a discard fee above that is limited by the fee estimate for the longest target",
+ CURRENCY_UNIT, FormatMoney(DEFAULT_DISCARD_FEE)), false, OptionsCategory::WALLET);
+ gArgs.AddArg("-fallbackfee=<amt>", strprintf("A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)",
+ CURRENCY_UNIT, FormatMoney(DEFAULT_FALLBACK_FEE)), false, OptionsCategory::WALLET);
+ gArgs.AddArg("-keypool=<n>", strprintf("Set key pool size to <n> (default: %u)", DEFAULT_KEYPOOL_SIZE), false, OptionsCategory::WALLET);
+ gArgs.AddArg("-mintxfee=<amt>", strprintf("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)",
+ CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE)), false, OptionsCategory::WALLET);
+ gArgs.AddArg("-paytxfee=<amt>", strprintf("Fee (in %s/kB) to add to transactions you send (default: %s)",
+ CURRENCY_UNIT, FormatMoney(CFeeRate{DEFAULT_PAY_TX_FEE}.GetFeePerK())), false, OptionsCategory::WALLET);
+ gArgs.AddArg("-rescan", "Rescan the block chain for missing wallet transactions on startup", false, OptionsCategory::WALLET);
+ gArgs.AddArg("-salvagewallet", "Attempt to recover private keys from a corrupt wallet on startup", false, OptionsCategory::WALLET);
+ gArgs.AddArg("-spendzeroconfchange", strprintf("Spend unconfirmed change when sending transactions (default: %u)", DEFAULT_SPEND_ZEROCONF_CHANGE), false, OptionsCategory::WALLET);
+ gArgs.AddArg("-txconfirmtarget=<n>", strprintf("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)", DEFAULT_TX_CONFIRM_TARGET), false, OptionsCategory::WALLET);
+ gArgs.AddArg("-upgradewallet", "Upgrade wallet to latest format on startup", false, OptionsCategory::WALLET);
+ gArgs.AddArg("-wallet=<path>", "Specify wallet database path. Can be specified multiple times to load multiple wallets. Path is interpreted relative to <walletdir> if it is not absolute, and will be created if it does not exist (as a directory containing a wallet.dat file and log files). For backwards compatibility this will also accept names of existing data files in <walletdir>.)", false, OptionsCategory::WALLET);
+ gArgs.AddArg("-walletbroadcast", strprintf("Make the wallet broadcast transactions (default: %u)", DEFAULT_WALLETBROADCAST), false, OptionsCategory::WALLET);
+ gArgs.AddArg("-walletdir=<dir>", "Specify directory to hold wallets (default: <datadir>/wallets if it exists, otherwise <datadir>)", false, OptionsCategory::WALLET);
+ gArgs.AddArg("-walletnotify=<cmd>", "Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)", false, OptionsCategory::WALLET);
+ gArgs.AddArg("-walletrbf", strprintf("Send transactions with full-RBF opt-in enabled (RPC only, default: %u)", DEFAULT_WALLET_RBF), false, OptionsCategory::WALLET);
+ gArgs.AddArg("-zapwallettxes=<mode>", "Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup"
+ " (1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)", false, OptionsCategory::WALLET);
+
+ gArgs.AddArg("-dblogsize=<n>", strprintf("Flush wallet database activity from memory to disk log every <n> megabytes (default: %u)", DEFAULT_WALLET_DBLOGSIZE), true, OptionsCategory::WALLET_DEBUG_TEST);
+ gArgs.AddArg("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", DEFAULT_FLUSHWALLET), true, OptionsCategory::WALLET_DEBUG_TEST);
+ gArgs.AddArg("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", DEFAULT_WALLET_PRIVDB), true, OptionsCategory::WALLET_DEBUG_TEST);
+ gArgs.AddArg("-walletrejectlongchains", strprintf("Wallet will not create transactions that violate mempool chain limits (default: %u)", DEFAULT_WALLET_REJECT_LONG_CHAINS), true, OptionsCategory::WALLET_DEBUG_TEST);
}
bool WalletInit::ParameterInteraction() const
@@ -197,55 +190,29 @@ bool WalletInit::Verify() const
uiInterface.InitMessage(_("Verifying wallet(s)..."));
+ std::vector<std::string> wallet_files = gArgs.GetArgs("-wallet");
+
+ // Parameter interaction code should have thrown an error if -salvagewallet
+ // was enabled with more than wallet file, so the wallet_files size check
+ // here should have no effect.
+ bool salvage_wallet = gArgs.GetBoolArg("-salvagewallet", false) && wallet_files.size() <= 1;
+
// Keep track of each wallet absolute path to detect duplicates.
std::set<fs::path> wallet_paths;
- for (const std::string& walletFile : gArgs.GetArgs("-wallet")) {
- // Do some checking on wallet path. It should be either a:
- //
- // 1. Path where a directory can be created.
- // 2. Path to an existing directory.
- // 3. Path to a symlink to a directory.
- // 4. For backwards compatibility, the name of a data file in -walletdir.
- fs::path wallet_path = fs::absolute(walletFile, GetWalletDir());
- fs::file_type path_type = fs::symlink_status(wallet_path).type();
- if (!(path_type == fs::file_not_found || path_type == fs::directory_file ||
- (path_type == fs::symlink_file && fs::is_directory(wallet_path)) ||
- (path_type == fs::regular_file && fs::path(walletFile).filename() == walletFile))) {
- return InitError(strprintf(
- _("Invalid -wallet path '%s'. -wallet path should point to a directory where wallet.dat and "
- "database/log.?????????? files can be stored, a location where such a directory could be created, "
- "or (for backwards compatibility) the name of an existing data file in -walletdir (%s)"),
- walletFile, GetWalletDir()));
- }
+ for (const auto wallet_file : wallet_files) {
+ fs::path wallet_path = fs::absolute(wallet_file, GetWalletDir());
if (!wallet_paths.insert(wallet_path).second) {
- return InitError(strprintf(_("Error loading wallet %s. Duplicate -wallet filename specified."), walletFile));
+ return InitError(strprintf(_("Error loading wallet %s. Duplicate -wallet filename specified."), wallet_file));
}
- std::string strError;
- if (!WalletBatch::VerifyEnvironment(wallet_path, strError)) {
- return InitError(strError);
- }
-
- if (gArgs.GetBoolArg("-salvagewallet", false)) {
- // Recover readable keypairs:
- CWallet dummyWallet("dummy", WalletDatabase::CreateDummy());
- std::string backup_filename;
- if (!WalletBatch::Recover(wallet_path, (void *)&dummyWallet, WalletBatch::RecoverKeysOnlyFilter, backup_filename)) {
- return false;
- }
- }
-
- std::string strWarning;
- bool dbV = WalletBatch::VerifyDatabaseFile(wallet_path, strWarning, strError);
- if (!strWarning.empty()) {
- InitWarning(strWarning);
- }
- if (!dbV) {
- InitError(strError);
- return false;
- }
+ std::string error_string;
+ std::string warning_string;
+ bool verify_success = CWallet::Verify(wallet_file, salvage_wallet, error_string, warning_string);
+ if (!error_string.empty()) InitError(error_string);
+ if (!warning_string.empty()) InitWarning(warning_string);
+ if (!verify_success) return false;
}
return true;
@@ -259,7 +226,7 @@ bool WalletInit::Open() const
}
for (const std::string& walletFile : gArgs.GetArgs("-wallet")) {
- CWallet * const pwallet = CWallet::CreateWalletFromFile(walletFile, fs::absolute(walletFile, GetWalletDir()));
+ std::shared_ptr<CWallet> pwallet = CWallet::CreateWalletFromFile(walletFile, fs::absolute(walletFile, GetWalletDir()));
if (!pwallet) {
return false;
}
@@ -271,29 +238,31 @@ bool WalletInit::Open() const
void WalletInit::Start(CScheduler& scheduler) const
{
- for (CWallet* pwallet : GetWallets()) {
- pwallet->postInitProcess(scheduler);
+ for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
+ pwallet->postInitProcess();
}
+
+ // Run a thread to flush wallet periodically
+ scheduler.scheduleEvery(MaybeCompactWalletDB, 500);
}
void WalletInit::Flush() const
{
- for (CWallet* pwallet : GetWallets()) {
+ for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
pwallet->Flush(false);
}
}
void WalletInit::Stop() const
{
- for (CWallet* pwallet : GetWallets()) {
+ for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
pwallet->Flush(true);
}
}
void WalletInit::Close() const
{
- for (CWallet* pwallet : GetWallets()) {
+ for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
RemoveWallet(pwallet);
- delete pwallet;
}
}
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 2cb07fb932..d09af1dbd1 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -56,7 +56,7 @@ static std::string DecodeDumpString(const std::string &str) {
for (unsigned int pos = 0; pos < str.length(); pos++) {
unsigned char c = str[pos];
if (c == '%' && pos+2 < str.length()) {
- c = (((str[pos+1]>>6)*9+((str[pos+1]-'0')&15)) << 4) |
+ c = (((str[pos+1]>>6)*9+((str[pos+1]-'0')&15)) << 4) |
((str[pos+2]>>6)*9+((str[pos+2]-'0')&15));
pos += 2;
}
@@ -89,7 +89,8 @@ static bool GetWalletAddressesForKey(CWallet * const pwallet, const CKeyID &keyi
UniValue importprivkey(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -185,7 +186,8 @@ UniValue importprivkey(const JSONRPCRequest& request)
UniValue abortrescan(const JSONRPCRequest& request)
{
- CWallet* const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -209,7 +211,7 @@ UniValue abortrescan(const JSONRPCRequest& request)
}
static void ImportAddress(CWallet*, const CTxDestination& dest, const std::string& strLabel);
-static void ImportScript(CWallet* const pwallet, const CScript& script, const std::string& strLabel, bool isRedeemScript)
+static void ImportScript(CWallet* const pwallet, const CScript& script, const std::string& strLabel, bool isRedeemScript) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
{
if (!isRedeemScript && ::IsMine(*pwallet, script) == ISMINE_SPENDABLE) {
throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
@@ -235,7 +237,7 @@ static void ImportScript(CWallet* const pwallet, const CScript& script, const st
}
}
-static void ImportAddress(CWallet* const pwallet, const CTxDestination& dest, const std::string& strLabel)
+static void ImportAddress(CWallet* const pwallet, const CTxDestination& dest, const std::string& strLabel) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
{
CScript script = GetScriptForDestination(dest);
ImportScript(pwallet, script, strLabel, false);
@@ -246,7 +248,8 @@ static void ImportAddress(CWallet* const pwallet, const CTxDestination& dest, co
UniValue importaddress(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -330,7 +333,8 @@ UniValue importaddress(const JSONRPCRequest& request)
UniValue importprunedfunds(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -392,7 +396,8 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
UniValue removeprunedfunds(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -430,7 +435,8 @@ UniValue removeprunedfunds(const JSONRPCRequest& request)
UniValue importpubkey(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -506,7 +512,8 @@ UniValue importpubkey(const JSONRPCRequest& request)
UniValue importwallet(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -640,7 +647,8 @@ UniValue importwallet(const JSONRPCRequest& request)
UniValue dumpprivkey(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -683,7 +691,8 @@ UniValue dumpprivkey(const JSONRPCRequest& request)
UniValue dumpwallet(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -752,13 +761,13 @@ UniValue dumpwallet(const JSONRPCRequest& request)
file << "\n";
// add the base58check encoded extended master if the wallet uses HD
- CKeyID masterKeyID = pwallet->GetHDChain().masterKeyID;
- if (!masterKeyID.IsNull())
+ CKeyID seed_id = pwallet->GetHDChain().seed_id;
+ if (!seed_id.IsNull())
{
- CKey key;
- if (pwallet->GetKey(masterKeyID, key)) {
+ CKey seed;
+ if (pwallet->GetKey(seed_id, seed)) {
CExtKey masterKey;
- masterKey.SetMaster(key.begin(), key.size());
+ masterKey.SetSeed(seed.begin(), seed.size());
file << "# extended private masterkey: " << EncodeExtKey(masterKey) << "\n\n";
}
@@ -773,12 +782,12 @@ UniValue dumpwallet(const JSONRPCRequest& request)
file << strprintf("%s %s ", EncodeSecret(key), strTime);
if (GetWalletAddressesForKey(pwallet, keyid, strAddr, strLabel)) {
file << strprintf("label=%s", strLabel);
- } else if (keyid == masterKeyID) {
- file << "hdmaster=1";
+ } else if (keyid == seed_id) {
+ file << "hdseed=1";
} else if (mapKeyPool.count(keyid)) {
file << "reserve=1";
- } else if (pwallet->mapKeyMetadata[keyid].hdKeypath == "m") {
- file << "inactivehdmaster=1";
+ } else if (pwallet->mapKeyMetadata[keyid].hdKeypath == "s") {
+ file << "inactivehdseed=1";
} else {
file << "change=1";
}
@@ -811,7 +820,7 @@ UniValue dumpwallet(const JSONRPCRequest& request)
}
-static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int64_t timestamp)
+static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
{
try {
bool success = false;
@@ -1127,7 +1136,8 @@ static int64_t GetImportTimestamp(const UniValue& data, int64_t now)
UniValue importmulti(const JSONRPCRequest& mainRequest)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(mainRequest);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(mainRequest);
+ CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, mainRequest.fHelp)) {
return NullUniValue;
}
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 94e61aa20e..3809eb3dd7 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -40,17 +40,17 @@
static const std::string WALLET_ENDPOINT_BASE = "/wallet/";
-CWallet *GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
+std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
{
if (request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) == WALLET_ENDPOINT_BASE) {
// wallet endpoint was used
std::string requestedWallet = urlDecode(request.URI.substr(WALLET_ENDPOINT_BASE.size()));
- CWallet* pwallet = GetWallet(requestedWallet);
+ std::shared_ptr<CWallet> pwallet = GetWallet(requestedWallet);
if (!pwallet) throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
return pwallet;
}
- std::vector<CWallet*> wallets = GetWallets();
+ std::vector<std::shared_ptr<CWallet>> wallets = GetWallets();
return wallets.size() == 1 || (request.fHelp && wallets.size() > 0) ? wallets[0] : nullptr;
}
@@ -134,7 +134,9 @@ static std::string LabelFromValue(const UniValue& value)
static UniValue getnewaddress(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -198,7 +200,9 @@ CTxDestination GetLabelDestination(CWallet* const pwallet, const std::string& la
static UniValue getlabeladdress(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -256,7 +260,9 @@ static UniValue getlabeladdress(const JSONRPCRequest& request)
static UniValue getrawchangeaddress(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -304,7 +310,9 @@ static UniValue getrawchangeaddress(const JSONRPCRequest& request)
static UniValue setlabel(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -358,7 +366,9 @@ static UniValue setlabel(const JSONRPCRequest& request)
static UniValue getaccount(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -401,7 +411,9 @@ static UniValue getaccount(const JSONRPCRequest& request)
static UniValue getaddressesbyaccount(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -487,7 +499,9 @@ static CTransactionRef SendMoney(CWallet * const pwallet, const CTxDestination &
static UniValue sendtoaddress(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -574,7 +588,9 @@ static UniValue sendtoaddress(const JSONRPCRequest& request)
static UniValue listaddressgroupings(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -631,7 +647,9 @@ static UniValue listaddressgroupings(const JSONRPCRequest& request)
static UniValue signmessage(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -692,7 +710,9 @@ static UniValue signmessage(const JSONRPCRequest& request)
static UniValue getreceivedbyaddress(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -757,7 +777,9 @@ static UniValue getreceivedbyaddress(const JSONRPCRequest& request)
static UniValue getreceivedbylabel(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -827,7 +849,9 @@ static UniValue getreceivedbylabel(const JSONRPCRequest& request)
static UniValue getbalance(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -910,7 +934,9 @@ static UniValue getbalance(const JSONRPCRequest& request)
static UniValue getunconfirmedbalance(const JSONRPCRequest &request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -932,7 +958,9 @@ static UniValue getunconfirmedbalance(const JSONRPCRequest &request)
static UniValue movecmd(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -989,7 +1017,9 @@ static UniValue movecmd(const JSONRPCRequest& request)
static UniValue sendfrom(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -1062,7 +1092,9 @@ static UniValue sendfrom(const JSONRPCRequest& request)
static UniValue sendmany(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -1257,7 +1289,9 @@ static UniValue sendmany(const JSONRPCRequest& request)
static UniValue addmultisigaddress(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -1392,7 +1426,9 @@ public:
static UniValue addwitnessaddress(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -1624,7 +1660,9 @@ static UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bo
static UniValue listreceivedbyaddress(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -1673,7 +1711,9 @@ static UniValue listreceivedbyaddress(const JSONRPCRequest& request)
static UniValue listreceivedbylabel(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -1838,7 +1878,9 @@ static void AcentryToJSON(const CAccountingEntry& acentry, const std::string& st
UniValue listtransactions(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -2026,7 +2068,9 @@ UniValue listtransactions(const JSONRPCRequest& request)
static UniValue listaccounts(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -2119,7 +2163,9 @@ static UniValue listaccounts(const JSONRPCRequest& request)
static UniValue listsinceblock(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -2258,7 +2304,9 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
static UniValue gettransaction(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -2352,7 +2400,9 @@ static UniValue gettransaction(const JSONRPCRequest& request)
static UniValue abandontransaction(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -2396,7 +2446,9 @@ static UniValue abandontransaction(const JSONRPCRequest& request)
static UniValue backupwallet(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -2429,7 +2481,9 @@ static UniValue backupwallet(const JSONRPCRequest& request)
static UniValue keypoolrefill(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -2476,7 +2530,9 @@ static void LockWallet(CWallet* pWallet)
static UniValue walletpassphrase(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -2549,7 +2605,9 @@ static UniValue walletpassphrase(const JSONRPCRequest& request)
static UniValue walletpassphrasechange(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -2598,7 +2656,9 @@ static UniValue walletpassphrasechange(const JSONRPCRequest& request)
static UniValue walletlock(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -2636,7 +2696,9 @@ static UniValue walletlock(const JSONRPCRequest& request)
static UniValue encryptwallet(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -2696,7 +2758,9 @@ static UniValue encryptwallet(const JSONRPCRequest& request)
static UniValue lockunspent(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -2823,7 +2887,9 @@ static UniValue lockunspent(const JSONRPCRequest& request)
static UniValue listlockunspent(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -2874,7 +2940,9 @@ static UniValue listlockunspent(const JSONRPCRequest& request)
static UniValue settxfee(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -2903,7 +2971,9 @@ static UniValue settxfee(const JSONRPCRequest& request)
static UniValue getwalletinfo(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -2925,7 +2995,8 @@ static UniValue getwalletinfo(const JSONRPCRequest& request)
" \"keypoolsize_hd_internal\": xxxx, (numeric) how many new keys are pre-generated for internal use (used for change outputs, only appears if the wallet is using this feature, otherwise external keys are used)\n"
" \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n"
" \"paytxfee\": x.xxxx, (numeric) the transaction fee configuration, set in " + CURRENCY_UNIT + "/kB\n"
- " \"hdmasterkeyid\": \"<hash160>\" (string, optional) the Hash160 of the HD master pubkey (only present when HD is enabled)\n"
+ " \"hdseedid\": \"<hash160>\" (string, optional) the Hash160 of the HD seed (only present when HD is enabled)\n"
+ " \"hdmasterkeyid\": \"<hash160>\" (string, optional) alias for hdseedid retained for backwards-compatibility. Will be removed in V0.18.\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getwalletinfo", "")
@@ -2949,16 +3020,18 @@ static UniValue getwalletinfo(const JSONRPCRequest& request)
obj.pushKV("txcount", (int)pwallet->mapWallet.size());
obj.pushKV("keypoololdest", pwallet->GetOldestKeyPoolTime());
obj.pushKV("keypoolsize", (int64_t)kpExternalSize);
- CKeyID masterKeyID = pwallet->GetHDChain().masterKeyID;
- if (!masterKeyID.IsNull() && pwallet->CanSupportFeature(FEATURE_HD_SPLIT)) {
+ CKeyID seed_id = pwallet->GetHDChain().seed_id;
+ if (!seed_id.IsNull() && pwallet->CanSupportFeature(FEATURE_HD_SPLIT)) {
obj.pushKV("keypoolsize_hd_internal", (int64_t)(pwallet->GetKeyPoolSize() - kpExternalSize));
}
if (pwallet->IsCrypted()) {
obj.pushKV("unlocked_until", pwallet->nRelockTime);
}
obj.pushKV("paytxfee", ValueFromAmount(pwallet->m_pay_tx_fee.GetFeePerK()));
- if (!masterKeyID.IsNull())
- obj.pushKV("hdmasterkeyid", masterKeyID.GetHex());
+ if (!seed_id.IsNull()) {
+ obj.pushKV("hdseedid", seed_id.GetHex());
+ obj.pushKV("hdmasterkeyid", seed_id.GetHex());
+ }
return obj;
}
@@ -2981,22 +3054,71 @@ static UniValue listwallets(const JSONRPCRequest& request)
UniValue obj(UniValue::VARR);
- for (CWallet* pwallet : GetWallets()) {
- if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
+ for (const std::shared_ptr<CWallet>& wallet : GetWallets()) {
+ if (!EnsureWalletIsAvailable(wallet.get(), request.fHelp)) {
return NullUniValue;
}
- LOCK(pwallet->cs_wallet);
+ LOCK(wallet->cs_wallet);
- obj.push_back(pwallet->GetName());
+ obj.push_back(wallet->GetName());
}
return obj;
}
+UniValue loadwallet(const JSONRPCRequest& request)
+{
+ if (request.fHelp || request.params.size() != 1)
+ throw std::runtime_error(
+ "loadwallet \"filename\"\n"
+ "\nLoads a wallet from a wallet file or directory."
+ "\nNote that all wallet command-line options used when starting bitcoind will be"
+ "\napplied to the new wallet (eg -zapwallettxes, upgradewallet, rescan, etc).\n"
+ "\nArguments:\n"
+ "1. \"filename\" (string, required) The wallet directory or .dat file.\n"
+ "\nResult:\n"
+ "{\n"
+ " \"name\" : <wallet_name>, (string) The wallet name if loaded successfully.\n"
+ " \"warning\" : <warning>, (string) Warning message if wallet was not loaded cleanly.\n"
+ "}\n"
+ "\nExamples:\n"
+ + HelpExampleCli("loadwallet", "\"test.dat\"")
+ + HelpExampleRpc("loadwallet", "\"test.dat\"")
+ );
+ std::string wallet_file = request.params[0].get_str();
+ std::string error;
+
+ fs::path wallet_path = fs::absolute(wallet_file, GetWalletDir());
+ if (fs::symlink_status(wallet_path).type() == fs::file_not_found) {
+ throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Wallet " + wallet_file + " not found.");
+ }
+
+ std::string warning;
+ if (!CWallet::Verify(wallet_file, false, error, warning)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Wallet file verification failed: " + error);
+ }
+
+ std::shared_ptr<CWallet> const wallet = CWallet::CreateWalletFromFile(wallet_file, fs::absolute(wallet_file, GetWalletDir()));
+ if (!wallet) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Wallet loading failed.");
+ }
+ AddWallet(wallet);
+
+ wallet->postInitProcess();
+
+ UniValue obj(UniValue::VOBJ);
+ obj.pushKV("name", wallet->GetName());
+ obj.pushKV("warning", warning);
+
+ return obj;
+}
+
static UniValue resendwallettransactions(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -3031,7 +3153,9 @@ static UniValue resendwallettransactions(const JSONRPCRequest& request)
static UniValue listunspent(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -3202,7 +3326,9 @@ static UniValue listunspent(const JSONRPCRequest& request)
static UniValue fundrawtransaction(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -3402,7 +3528,9 @@ static UniValue fundrawtransaction(const JSONRPCRequest& request)
UniValue signrawtransactionwithwallet(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -3471,7 +3599,9 @@ UniValue signrawtransactionwithwallet(const JSONRPCRequest& request)
static UniValue bumpfee(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
return NullUniValue;
@@ -3620,7 +3750,9 @@ static UniValue bumpfee(const JSONRPCRequest& request)
UniValue generate(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
@@ -3665,7 +3797,9 @@ UniValue generate(const JSONRPCRequest& request)
UniValue rescanblockchain(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -3870,7 +4004,9 @@ static UniValue AddressBookDataToJSON(const CAddressBookData& data, const bool v
UniValue getaddressinfo(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -3901,13 +4037,14 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
" ]\n"
" \"sigsrequired\" : xxxxx (numeric, optional) Number of signatures required to spend multisig output (only if \"script\" is \"multisig\")\n"
" \"pubkey\" : \"publickeyhex\", (string, optional) The hex value of the raw public key, for single-key addresses (possibly embedded in P2SH or P2WSH)\n"
- " \"embedded\" : {...}, (object, optional) Information about the address embedded in P2SH or P2WSH, if relevant and known. It includes all getaddressinfo output fields for the embedded address, excluding metadata (\"timestamp\", \"hdkeypath\", \"hdmasterkeyid\") and relation to the wallet (\"ismine\", \"iswatchonly\", \"account\").\n"
+ " \"embedded\" : {...}, (object, optional) Information about the address embedded in P2SH or P2WSH, if relevant and known. It includes all getaddressinfo output fields for the embedded address, excluding metadata (\"timestamp\", \"hdkeypath\", \"hdseedid\") and relation to the wallet (\"ismine\", \"iswatchonly\", \"account\").\n"
" \"iscompressed\" : true|false, (boolean) If the address is compressed\n"
" \"label\" : \"label\" (string) The label associated with the address, \"\" is the default account\n"
" \"account\" : \"account\" (string) DEPRECATED. This field will be removed in V0.18. To see this deprecated field, start bitcoind with -deprecatedrpc=accounts. The account associated with the address, \"\" is the default account\n"
" \"timestamp\" : timestamp, (number, optional) The creation time of the key if available in seconds since epoch (Jan 1 1970 GMT)\n"
" \"hdkeypath\" : \"keypath\" (string, optional) The HD keypath if the key is HD and available\n"
- " \"hdmasterkeyid\" : \"<hash160>\" (string, optional) The Hash160 of the HD master pubkey\n"
+ " \"hdseedid\" : \"<hash160>\" (string, optional) The Hash160 of the HD seed\n"
+ " \"hdmasterkeyid\" : \"<hash160>\" (string, optional) alias for hdseedid maintained for backwards compatibility. Will be removed in V0.18.\n"
" \"labels\" (object) Array of labels associated with the address.\n"
" [\n"
" { (json object of label data)\n"
@@ -3967,7 +4104,8 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
ret.pushKV("timestamp", meta->nCreateTime);
if (!meta->hdKeypath.empty()) {
ret.pushKV("hdkeypath", meta->hdKeypath);
- ret.pushKV("hdmasterkeyid", meta->hdMasterKeyID.GetHex());
+ ret.pushKV("hdseedid", meta->hd_seed_id.GetHex());
+ ret.pushKV("hdmasterkeyid", meta->hd_seed_id.GetHex());
}
}
@@ -3986,7 +4124,9 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
static UniValue getaddressesbylabel(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -4029,7 +4169,9 @@ static UniValue getaddressesbylabel(const JSONRPCRequest& request)
static UniValue listlabels(const JSONRPCRequest& request)
{
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
@@ -4079,6 +4221,77 @@ static UniValue listlabels(const JSONRPCRequest& request)
return ret;
}
+UniValue sethdseed(const JSONRPCRequest& request)
+{
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
+ return NullUniValue;
+ }
+
+ if (request.fHelp || request.params.size() > 2) {
+ throw std::runtime_error(
+ "sethdseed ( \"newkeypool\" \"seed\" )\n"
+ "\nSet or generate a new HD wallet seed. Non-HD wallets will not be upgraded to being a HD wallet. Wallets that are already\n"
+ "HD will have a new HD seed set so that new keys added to the keypool will be derived from this new seed.\n"
+ "\nNote that you will need to MAKE A NEW BACKUP of your wallet after setting the HD wallet seed.\n"
+ + HelpRequiringPassphrase(pwallet) +
+ "\nArguments:\n"
+ "1. \"newkeypool\" (boolean, optional, default=true) Whether to flush old unused addresses, including change addresses, from the keypool and regenerate it.\n"
+ " If true, the next address from getnewaddress and change address from getrawchangeaddress will be from this new seed.\n"
+ " If false, addresses (including change addresses if the wallet already had HD Chain Split enabled) from the existing\n"
+ " keypool will be used until it has been depleted.\n"
+ "2. \"seed\" (string, optional) The WIF private key to use as the new HD seed; if not provided a random seed will be used.\n"
+ " The seed value can be retrieved using the dumpwallet command. It is the private key marked hdseed=1\n"
+ "\nExamples:\n"
+ + HelpExampleCli("sethdseed", "")
+ + HelpExampleCli("sethdseed", "false")
+ + HelpExampleCli("sethdseed", "true \"wifkey\"")
+ + HelpExampleRpc("sethdseed", "true, \"wifkey\"")
+ );
+ }
+
+ if (IsInitialBlockDownload()) {
+ throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Cannot set a new HD seed while still in Initial Block Download");
+ }
+
+ LOCK2(cs_main, pwallet->cs_wallet);
+
+ // Do not do anything to non-HD wallets
+ if (!pwallet->IsHDEnabled()) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Cannot set a HD seed on a non-HD wallet. Start with -upgradewallet in order to upgrade a non-HD wallet to HD");
+ }
+
+ EnsureWalletIsUnlocked(pwallet);
+
+ bool flush_key_pool = true;
+ if (!request.params[0].isNull()) {
+ flush_key_pool = request.params[0].get_bool();
+ }
+
+ CPubKey master_pub_key;
+ if (request.params[1].isNull()) {
+ master_pub_key = pwallet->GenerateNewSeed();
+ } else {
+ CKey key = DecodeSecret(request.params[1].get_str());
+ if (!key.IsValid()) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
+ }
+
+ if (HaveKey(*pwallet, key)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Already have this key (either as an HD seed or as a loose private key)");
+ }
+
+ master_pub_key = pwallet->DeriveNewSeed(key);
+ }
+
+ pwallet->SetHDSeed(master_pub_key);
+ if (flush_key_pool) pwallet->NewKeyPool();
+
+ return NullUniValue;
+}
+
extern UniValue abortrescan(const JSONRPCRequest& request); // in rpcdump.cpp
extern UniValue dumpprivkey(const JSONRPCRequest& request); // in rpcdump.cpp
extern UniValue importprivkey(const JSONRPCRequest& request);
@@ -4127,6 +4340,7 @@ static const CRPCCommand commands[] =
{ "wallet", "listtransactions", &listtransactions, {"account|dummy","count","skip","include_watchonly"} },
{ "wallet", "listunspent", &listunspent, {"minconf","maxconf","addresses","include_unsafe","query_options"} },
{ "wallet", "listwallets", &listwallets, {} },
+ { "wallet", "loadwallet", &loadwallet, {"filename"} },
{ "wallet", "lockunspent", &lockunspent, {"unlock","transactions"} },
{ "wallet", "sendfrom", &sendfrom, {"fromaccount","toaddress","amount","minconf","comment","comment_to"} },
{ "wallet", "sendmany", &sendmany, {"fromaccount|dummy","amounts","minconf","comment","subtractfeefrom","replaceable","conf_target","estimate_mode"} },
@@ -4139,6 +4353,7 @@ static const CRPCCommand commands[] =
{ "wallet", "walletpassphrase", &walletpassphrase, {"passphrase","timeout"} },
{ "wallet", "removeprunedfunds", &removeprunedfunds, {"txid"} },
{ "wallet", "rescanblockchain", &rescanblockchain, {"start_height", "stop_height"} },
+ { "wallet", "sethdseed", &sethdseed, {"newkeypool","seed"} },
/** Account functions (deprecated) */
{ "wallet", "getaccountaddress", &getlabeladdress, {"account"} },
diff --git a/src/wallet/rpcwallet.h b/src/wallet/rpcwallet.h
index 84f161abb5..b841f3e424 100644
--- a/src/wallet/rpcwallet.h
+++ b/src/wallet/rpcwallet.h
@@ -20,7 +20,7 @@ void RegisterWalletRPCCommands(CRPCTable &t);
* @param[in] request JSONRPCRequest that wishes to access a wallet
* @return nullptr if no wallet should be used, or a pointer to the CWallet
*/
-CWallet *GetWalletForJSONRPCRequest(const JSONRPCRequest& request);
+std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request);
std::string HelpRequiringPassphrase(CWallet *);
void EnsureWalletIsUnlocked(CWallet *);
diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp
index ac47d4448a..e90370cf06 100644
--- a/src/wallet/test/coinselector_tests.cpp
+++ b/src/wallet/test/coinselector_tests.cpp
@@ -536,19 +536,9 @@ BOOST_AUTO_TEST_CASE(SelectCoins_test)
std::exponential_distribution<double> distribution (100);
FastRandomContext rand;
- // Output stuff
- CAmount out_value = 0;
- CoinSet out_set;
- CAmount target = 0;
- bool bnb_used;
-
// Run this test 100 times
for (int i = 0; i < 100; ++i)
{
- // Reset
- out_value = 0;
- target = 0;
- out_set.clear();
empty_wallet();
// Make a wallet with 1000 exponentially distributed random inputs
@@ -561,11 +551,14 @@ BOOST_AUTO_TEST_CASE(SelectCoins_test)
CFeeRate rate(rand.randrange(300) + 100);
// Generate a random target value between 1000 and wallet balance
- target = rand.randrange(balance - 1000) + 1000;
+ CAmount target = rand.randrange(balance - 1000) + 1000;
// Perform selection
CoinSelectionParams coin_selection_params_knapsack(false, 34, 148, CFeeRate(0), 0);
CoinSelectionParams coin_selection_params_bnb(true, 34, 148, CFeeRate(0), 0);
+ CoinSet out_set;
+ CAmount out_value = 0;
+ bool bnb_used = false;
BOOST_CHECK(testWallet.SelectCoinsMinConf(target, filter_standard, vCoins, out_set, out_value, coin_selection_params_bnb, bnb_used) ||
testWallet.SelectCoinsMinConf(target, filter_standard, vCoins, out_set, out_value, coin_selection_params_knapsack, bnb_used));
BOOST_CHECK_GE(out_value, target);
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 99c963a348..03754154fc 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -73,8 +73,8 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
// before the missing block, and success for a key whose creation time is
// after.
{
- CWallet wallet("dummy", WalletDatabase::CreateDummy());
- AddWallet(&wallet);
+ std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>("dummy", WalletDatabase::CreateDummy());
+ AddWallet(wallet);
UniValue keys;
keys.setArray();
UniValue key;
@@ -105,7 +105,7 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
"downloading and rescanning the relevant blocks (see -reindex and -rescan "
"options).\"}},{\"success\":true}]",
0, oldTip->GetBlockTimeMax(), TIMESTAMP_WINDOW));
- RemoveWallet(&wallet);
+ RemoveWallet(wallet);
}
}
@@ -132,36 +132,36 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
// Import key into wallet and call dumpwallet to create backup file.
{
- CWallet wallet("dummy", WalletDatabase::CreateDummy());
- LOCK(wallet.cs_wallet);
- wallet.mapKeyMetadata[coinbaseKey.GetPubKey().GetID()].nCreateTime = KEY_TIME;
- wallet.AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey());
+ std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>("dummy", WalletDatabase::CreateDummy());
+ LOCK(wallet->cs_wallet);
+ wallet->mapKeyMetadata[coinbaseKey.GetPubKey().GetID()].nCreateTime = KEY_TIME;
+ wallet->AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey());
JSONRPCRequest request;
request.params.setArray();
request.params.push_back((pathTemp / "wallet.backup").string());
- AddWallet(&wallet);
+ AddWallet(wallet);
::dumpwallet(request);
- RemoveWallet(&wallet);
+ RemoveWallet(wallet);
}
// Call importwallet RPC and verify all blocks with timestamps >= BLOCK_TIME
// were scanned, and no prior blocks were scanned.
{
- CWallet wallet("dummy", WalletDatabase::CreateDummy());
+ std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>("dummy", WalletDatabase::CreateDummy());
JSONRPCRequest request;
request.params.setArray();
request.params.push_back((pathTemp / "wallet.backup").string());
- AddWallet(&wallet);
+ AddWallet(wallet);
::importwallet(request);
- RemoveWallet(&wallet);
+ RemoveWallet(wallet);
- LOCK(wallet.cs_wallet);
- BOOST_CHECK_EQUAL(wallet.mapWallet.size(), 3U);
+ LOCK(wallet->cs_wallet);
+ BOOST_CHECK_EQUAL(wallet->mapWallet.size(), 3U);
BOOST_CHECK_EQUAL(m_coinbase_txns.size(), 103U);
for (size_t i = 0; i < m_coinbase_txns.size(); ++i) {
- bool found = wallet.GetWalletTx(m_coinbase_txns[i]->GetHash());
+ bool found = wallet->GetWalletTx(m_coinbase_txns[i]->GetHash());
bool expected = i >= 100;
BOOST_CHECK_EQUAL(found, expected);
}
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 9533e6ff56..36c5f2c5de 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -23,11 +23,11 @@
#include <primitives/block.h>
#include <primitives/transaction.h>
#include <script/script.h>
-#include <scheduler.h>
#include <timedata.h>
#include <txmempool.h>
#include <utilmoneystr.h>
#include <wallet/fees.h>
+#include <wallet/walletutil.h>
#include <algorithm>
#include <assert.h>
@@ -36,23 +36,23 @@
#include <boost/algorithm/string/replace.hpp>
static CCriticalSection cs_wallets;
-static std::vector<CWallet*> vpwallets GUARDED_BY(cs_wallets);
+static std::vector<std::shared_ptr<CWallet>> vpwallets GUARDED_BY(cs_wallets);
-bool AddWallet(CWallet* wallet)
+bool AddWallet(const std::shared_ptr<CWallet>& wallet)
{
LOCK(cs_wallets);
assert(wallet);
- std::vector<CWallet*>::const_iterator i = std::find(vpwallets.begin(), vpwallets.end(), wallet);
+ std::vector<std::shared_ptr<CWallet>>::const_iterator i = std::find(vpwallets.begin(), vpwallets.end(), wallet);
if (i != vpwallets.end()) return false;
vpwallets.push_back(wallet);
return true;
}
-bool RemoveWallet(CWallet* wallet)
+bool RemoveWallet(const std::shared_ptr<CWallet>& wallet)
{
LOCK(cs_wallets);
assert(wallet);
- std::vector<CWallet*>::iterator i = std::find(vpwallets.begin(), vpwallets.end(), wallet);
+ std::vector<std::shared_ptr<CWallet>>::iterator i = std::find(vpwallets.begin(), vpwallets.end(), wallet);
if (i == vpwallets.end()) return false;
vpwallets.erase(i);
return true;
@@ -64,16 +64,16 @@ bool HasWallets()
return !vpwallets.empty();
}
-std::vector<CWallet*> GetWallets()
+std::vector<std::shared_ptr<CWallet>> GetWallets()
{
LOCK(cs_wallets);
return vpwallets;
}
-CWallet* GetWallet(const std::string& name)
+std::shared_ptr<CWallet> GetWallet(const std::string& name)
{
LOCK(cs_wallets);
- for (CWallet* wallet : vpwallets) {
+ for (const std::shared_ptr<CWallet>& wallet : vpwallets) {
if (wallet->GetName() == name) return wallet;
}
return nullptr;
@@ -191,17 +191,17 @@ CPubKey CWallet::GenerateNewKey(WalletBatch &batch, bool internal)
void CWallet::DeriveNewChildKey(WalletBatch &batch, CKeyMetadata& metadata, CKey& secret, bool internal)
{
// for now we use a fixed keypath scheme of m/0'/0'/k
- CKey key; //master key seed (256bit)
+ CKey seed; //seed (256bit)
CExtKey masterKey; //hd master key
CExtKey accountKey; //key at m/0'
CExtKey chainChildKey; //key at m/0'/0' (external) or m/0'/1' (internal)
CExtKey childKey; //key at m/0'/0'/<n>'
- // try to get the master key
- if (!GetKey(hdChain.masterKeyID, key))
- throw std::runtime_error(std::string(__func__) + ": Master key not found");
+ // try to get the seed
+ if (!GetKey(hdChain.seed_id, seed))
+ throw std::runtime_error(std::string(__func__) + ": seed not found");
- masterKey.SetMaster(key.begin(), key.size());
+ masterKey.SetSeed(seed.begin(), seed.size());
// derive m/0'
// use hardened derivation (child keys >= 0x80000000 are hardened after bip32)
@@ -228,7 +228,7 @@ void CWallet::DeriveNewChildKey(WalletBatch &batch, CKeyMetadata& metadata, CKey
}
} while (HaveKey(childKey.key.GetPubKey().GetID()));
secret = childKey.key;
- metadata.hdMasterKeyID = hdChain.masterKeyID;
+ metadata.hd_seed_id = hdChain.seed_id;
// update the chain model in the database
if (!batch.WriteHDChain(hdChain))
throw std::runtime_error(std::string(__func__) + ": Writing HD chain model failed");
@@ -549,7 +549,9 @@ void CWallet::SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator> ran
}
}
- assert(copyFrom);
+ if (!copyFrom) {
+ return;
+ }
// Now copy data from copyFrom to rest:
for (TxSpends::iterator it = range.first; it != range.second; ++it)
@@ -687,9 +689,9 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
Lock();
Unlock(strWalletPassphrase);
- // if we are using HD, replace the HD master key (seed) with a new one
+ // if we are using HD, replace the HD seed with a new one
if (IsHDEnabled()) {
- if (!SetHDMasterKey(GenerateNewHDMasterKey())) {
+ if (!SetHDSeed(GenerateNewSeed())) {
return false;
}
}
@@ -1448,37 +1450,41 @@ CAmount CWallet::GetChange(const CTransaction& tx) const
return nChange;
}
-CPubKey CWallet::GenerateNewHDMasterKey()
+CPubKey CWallet::GenerateNewSeed()
{
CKey key;
key.MakeNewKey(true);
+ return DeriveNewSeed(key);
+}
+CPubKey CWallet::DeriveNewSeed(const CKey& key)
+{
int64_t nCreationTime = GetTime();
CKeyMetadata metadata(nCreationTime);
- // calculate the pubkey
- CPubKey pubkey = key.GetPubKey();
- assert(key.VerifyPubKey(pubkey));
+ // calculate the seed
+ CPubKey seed = key.GetPubKey();
+ assert(key.VerifyPubKey(seed));
- // set the hd keypath to "m" -> Master, refers the masterkeyid to itself
- metadata.hdKeypath = "m";
- metadata.hdMasterKeyID = pubkey.GetID();
+ // set the hd keypath to "s" -> Seed, refers the seed to itself
+ metadata.hdKeypath = "s";
+ metadata.hd_seed_id = seed.GetID();
{
LOCK(cs_wallet);
// mem store the metadata
- mapKeyMetadata[pubkey.GetID()] = metadata;
+ mapKeyMetadata[seed.GetID()] = metadata;
// write the key&metadata to the database
- if (!AddKeyPubKey(key, pubkey))
+ if (!AddKeyPubKey(key, seed))
throw std::runtime_error(std::string(__func__) + ": AddKeyPubKey failed");
}
- return pubkey;
+ return seed;
}
-bool CWallet::SetHDMasterKey(const CPubKey& pubkey)
+bool CWallet::SetHDSeed(const CPubKey& seed)
{
LOCK(cs_wallet);
// store the keyid (hash160) together with
@@ -1486,7 +1492,7 @@ bool CWallet::SetHDMasterKey(const CPubKey& pubkey)
// as a hdchain object
CHDChain newHdChain;
newHdChain.nVersion = CanSupportFeature(FEATURE_HD_SPLIT) ? CHDChain::VERSION_HD_CHAIN_SPLIT : CHDChain::VERSION_HD_BASE;
- newHdChain.masterKeyID = pubkey.GetID();
+ newHdChain.seed_id = seed.GetID();
SetHDChain(newHdChain, false);
return true;
@@ -1504,7 +1510,7 @@ bool CWallet::SetHDChain(const CHDChain& chain, bool memonly)
bool CWallet::IsHDEnabled() const
{
- return !hdChain.masterKeyID.IsNull();
+ return !hdChain.seed_id.IsNull();
}
int64_t CWalletTx::GetTxTime() const
@@ -1745,23 +1751,27 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, CBlock
fAbortRescan = false;
ShowProgress(_("Rescanning..."), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup
CBlockIndex* tip = nullptr;
- double dProgressStart;
- double dProgressTip;
+ double progress_begin;
+ double progress_end;
{
LOCK(cs_main);
- tip = chainActive.Tip();
- dProgressStart = GuessVerificationProgress(chainParams.TxData(), pindex);
- dProgressTip = GuessVerificationProgress(chainParams.TxData(), tip);
+ progress_begin = GuessVerificationProgress(chainParams.TxData(), pindex);
+ if (pindexStop == nullptr) {
+ tip = chainActive.Tip();
+ progress_end = GuessVerificationProgress(chainParams.TxData(), tip);
+ } else {
+ progress_end = GuessVerificationProgress(chainParams.TxData(), pindexStop);
+ }
}
- double gvp = dProgressStart;
+ double progress_current = progress_begin;
while (pindex && !fAbortRescan && !ShutdownRequested())
{
- if (pindex->nHeight % 100 == 0 && dProgressTip - dProgressStart > 0.0) {
- ShowProgress(_("Rescanning..."), std::max(1, std::min(99, (int)((gvp - dProgressStart) / (dProgressTip - dProgressStart) * 100))));
+ if (pindex->nHeight % 100 == 0 && progress_end - progress_begin > 0.0) {
+ ShowProgress(_("Rescanning..."), std::max(1, std::min(99, (int)((progress_current - progress_begin) / (progress_end - progress_begin) * 100))));
}
if (GetTime() >= nNow + 60) {
nNow = GetTime();
- LogPrintf("Still rescanning. At block %d. Progress=%f\n", pindex->nHeight, gvp);
+ LogPrintf("Still rescanning. At block %d. Progress=%f\n", pindex->nHeight, progress_current);
}
CBlock block;
@@ -1785,18 +1795,18 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, CBlock
{
LOCK(cs_main);
pindex = chainActive.Next(pindex);
- gvp = GuessVerificationProgress(chainParams.TxData(), pindex);
- if (tip != chainActive.Tip()) {
+ progress_current = GuessVerificationProgress(chainParams.TxData(), pindex);
+ if (pindexStop == nullptr && tip != chainActive.Tip()) {
tip = chainActive.Tip();
// in case the tip has changed, update progress max
- dProgressTip = GuessVerificationProgress(chainParams.TxData(), tip);
+ progress_end = GuessVerificationProgress(chainParams.TxData(), tip);
}
}
}
if (pindex && fAbortRescan) {
- LogPrintf("Rescan aborted at block %d. Progress=%f\n", pindex->nHeight, gvp);
+ LogPrintf("Rescan aborted at block %d. Progress=%f\n", pindex->nHeight, progress_current);
} else if (pindex && ShutdownRequested()) {
- LogPrintf("Rescan interrupted by shutdown request at block %d. Progress=%f\n", pindex->nHeight, gvp);
+ LogPrintf("Rescan interrupted by shutdown request at block %d. Progress=%f\n", pindex->nHeight, progress_current);
}
ShowProgress(_("Rescanning..."), 100); // hide progress dialog in GUI
}
@@ -2065,8 +2075,8 @@ bool CWalletTx::IsTrusted() const
bool CWalletTx::IsEquivalentTo(const CWalletTx& _tx) const
{
- CMutableTransaction tx1 = *this->tx;
- CMutableTransaction tx2 = *_tx.tx;
+ CMutableTransaction tx1 {*this->tx};
+ CMutableTransaction tx2 {*_tx.tx};
for (auto& txin : tx1.vin) txin.scriptSig = CScript();
for (auto& txin : tx2.vin) txin.scriptSig = CScript();
return CTransaction(tx1) == CTransaction(tx2);
@@ -2366,10 +2376,10 @@ void CWallet::AvailableCoins(std::vector<COutput> &vCoins, bool fOnlySafe, const
continue;
}
- bool fSpendableIn = ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || (coinControl && coinControl->fAllowWatchOnly && (mine & ISMINE_WATCH_SOLVABLE) != ISMINE_NO);
- bool fSolvableIn = (mine & (ISMINE_SPENDABLE | ISMINE_WATCH_SOLVABLE)) != ISMINE_NO;
+ bool solvable = IsSolvable(*this, pcoin->tx->vout[i].scriptPubKey);
+ bool spendable = ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || (((mine & ISMINE_WATCH_ONLY) != ISMINE_NO) && (coinControl && coinControl->fAllowWatchOnly && solvable));
- vCoins.push_back(COutput(pcoin, i, nDepth, fSpendableIn, fSolvableIn, safeTx));
+ vCoins.push_back(COutput(pcoin, i, nDepth, spendable, solvable, safeTx));
// Checks the sum amount of all UTXO's.
if (nMinimumSumAmount != MAX_MONEY) {
@@ -3191,8 +3201,6 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
if (nLoadWalletRet != DBErrors::LOAD_OK)
return nLoadWalletRet;
- uiInterface.LoadWallet(this);
-
return DBErrors::LOAD_OK;
}
@@ -3322,6 +3330,11 @@ bool CWallet::NewKeyPool()
}
setExternalKeyPool.clear();
+ for (int64_t nIndex : set_pre_split_keypool) {
+ batch.ErasePool(nIndex);
+ }
+ set_pre_split_keypool.clear();
+
m_pool_key_to_index.clear();
if (!TopUpKeyPool()) {
@@ -3335,13 +3348,15 @@ bool CWallet::NewKeyPool()
size_t CWallet::KeypoolCountExternalKeys()
{
AssertLockHeld(cs_wallet); // setExternalKeyPool
- return setExternalKeyPool.size();
+ return setExternalKeyPool.size() + set_pre_split_keypool.size();
}
void CWallet::LoadKeyPool(int64_t nIndex, const CKeyPool &keypool)
{
AssertLockHeld(cs_wallet);
- if (keypool.fInternal) {
+ if (keypool.m_pre_split) {
+ set_pre_split_keypool.insert(nIndex);
+ } else if (keypool.fInternal) {
setInternalKeyPool.insert(nIndex);
} else {
setExternalKeyPool.insert(nIndex);
@@ -3406,13 +3421,13 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
m_pool_key_to_index[pubkey.GetID()] = index;
}
if (missingInternal + missingExternal > 0) {
- LogPrintf("keypool added %d keys (%d internal), size=%u (%u internal)\n", missingInternal + missingExternal, missingInternal, setInternalKeyPool.size() + setExternalKeyPool.size(), setInternalKeyPool.size());
+ LogPrintf("keypool added %d keys (%d internal), size=%u (%u internal)\n", missingInternal + missingExternal, missingInternal, setInternalKeyPool.size() + setExternalKeyPool.size() + set_pre_split_keypool.size(), setInternalKeyPool.size());
}
}
return true;
}
-void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRequestedInternal)
+bool CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRequestedInternal)
{
nIndex = -1;
keypool.vchPubKey = CPubKey();
@@ -3423,11 +3438,13 @@ void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRe
TopUpKeyPool();
bool fReturningInternal = IsHDEnabled() && CanSupportFeature(FEATURE_HD_SPLIT) && fRequestedInternal;
- std::set<int64_t>& setKeyPool = fReturningInternal ? setInternalKeyPool : setExternalKeyPool;
+ bool use_split_keypool = set_pre_split_keypool.empty();
+ std::set<int64_t>& setKeyPool = use_split_keypool ? (fReturningInternal ? setInternalKeyPool : setExternalKeyPool) : set_pre_split_keypool;
// Get the oldest key
- if(setKeyPool.empty())
- return;
+ if (setKeyPool.empty()) {
+ return false;
+ }
WalletBatch batch(*database);
@@ -3440,14 +3457,18 @@ void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRe
if (!HaveKey(keypool.vchPubKey.GetID())) {
throw std::runtime_error(std::string(__func__) + ": unknown key in key pool");
}
- if (keypool.fInternal != fReturningInternal) {
+ // If the key was pre-split keypool, we don't care about what type it is
+ if (use_split_keypool && keypool.fInternal != fReturningInternal) {
throw std::runtime_error(std::string(__func__) + ": keypool entry misclassified");
}
+ if (!keypool.vchPubKey.IsValid()) {
+ throw std::runtime_error(std::string(__func__) + ": keypool entry invalid");
+ }
- assert(keypool.vchPubKey.IsValid());
m_pool_key_to_index.erase(keypool.vchPubKey.GetID());
LogPrintf("keypool reserve %d\n", nIndex);
}
+ return true;
}
void CWallet::KeepKey(int64_t nIndex)
@@ -3465,6 +3486,8 @@ void CWallet::ReturnKey(int64_t nIndex, bool fInternal, const CPubKey& pubkey)
LOCK(cs_wallet);
if (fInternal) {
setInternalKeyPool.insert(nIndex);
+ } else if (!set_pre_split_keypool.empty()) {
+ set_pre_split_keypool.insert(nIndex);
} else {
setExternalKeyPool.insert(nIndex);
}
@@ -3478,10 +3501,8 @@ bool CWallet::GetKeyFromPool(CPubKey& result, bool internal)
CKeyPool keypool;
{
LOCK(cs_wallet);
- int64_t nIndex = 0;
- ReserveKeyFromKeyPool(nIndex, keypool, internal);
- if (nIndex == -1)
- {
+ int64_t nIndex;
+ if (!ReserveKeyFromKeyPool(nIndex, keypool, internal)) {
if (IsLocked()) return false;
WalletBatch batch(*database);
result = GenerateNewKey(batch, internal);
@@ -3517,6 +3538,9 @@ int64_t CWallet::GetOldestKeyPoolTime()
int64_t oldestKey = GetOldestKeyTimeInPool(setExternalKeyPool, batch);
if (IsHDEnabled() && CanSupportFeature(FEATURE_HD_SPLIT)) {
oldestKey = std::max(GetOldestKeyTimeInPool(setInternalKeyPool, batch), oldestKey);
+ if (!set_pre_split_keypool.empty()) {
+ oldestKey = std::max(GetOldestKeyTimeInPool(set_pre_split_keypool, batch), oldestKey);
+ }
}
return oldestKey;
@@ -3680,12 +3704,10 @@ bool CReserveKey::GetReservedKey(CPubKey& pubkey, bool internal)
if (nIndex == -1)
{
CKeyPool keypool;
- pwallet->ReserveKeyFromKeyPool(nIndex, keypool, internal);
- if (nIndex != -1)
- vchPubKey = keypool.vchPubKey;
- else {
+ if (!pwallet->ReserveKeyFromKeyPool(nIndex, keypool, internal)) {
return false;
}
+ vchPubKey = keypool.vchPubKey;
fInternal = keypool.fInternal;
}
assert(vchPubKey.IsValid());
@@ -3714,8 +3736,8 @@ void CWallet::MarkReserveKeysAsUsed(int64_t keypool_id)
{
AssertLockHeld(cs_wallet);
bool internal = setInternalKeyPool.count(keypool_id);
- if (!internal) assert(setExternalKeyPool.count(keypool_id));
- std::set<int64_t> *setKeyPool = internal ? &setInternalKeyPool : &setExternalKeyPool;
+ if (!internal) assert(setExternalKeyPool.count(keypool_id) || set_pre_split_keypool.count(keypool_id));
+ std::set<int64_t> *setKeyPool = internal ? &setInternalKeyPool : (set_pre_split_keypool.empty() ? &setExternalKeyPool : &set_pre_split_keypool);
auto it = setKeyPool->begin();
WalletBatch batch(*database);
@@ -3951,7 +3973,71 @@ std::vector<std::string> CWallet::GetDestValues(const std::string& prefix) const
return values;
}
-CWallet* CWallet::CreateWalletFromFile(const std::string& name, const fs::path& path)
+void CWallet::MarkPreSplitKeys()
+{
+ WalletBatch batch(*database);
+ for (auto it = setExternalKeyPool.begin(); it != setExternalKeyPool.end();) {
+ int64_t index = *it;
+ CKeyPool keypool;
+ if (!batch.ReadPool(index, keypool)) {
+ throw std::runtime_error(std::string(__func__) + ": read keypool entry failed");
+ }
+ keypool.m_pre_split = true;
+ if (!batch.WritePool(index, keypool)) {
+ throw std::runtime_error(std::string(__func__) + ": writing modified keypool entry failed");
+ }
+ set_pre_split_keypool.insert(index);
+ it = setExternalKeyPool.erase(it);
+ }
+}
+
+bool CWallet::Verify(std::string wallet_file, bool salvage_wallet, std::string& error_string, std::string& warning_string)
+{
+ // Do some checking on wallet path. It should be either a:
+ //
+ // 1. Path where a directory can be created.
+ // 2. Path to an existing directory.
+ // 3. Path to a symlink to a directory.
+ // 4. For backwards compatibility, the name of a data file in -walletdir.
+ LOCK(cs_wallets);
+ fs::path wallet_path = fs::absolute(wallet_file, GetWalletDir());
+ fs::file_type path_type = fs::symlink_status(wallet_path).type();
+ if (!(path_type == fs::file_not_found || path_type == fs::directory_file ||
+ (path_type == fs::symlink_file && fs::is_directory(wallet_path)) ||
+ (path_type == fs::regular_file && fs::path(wallet_file).filename() == wallet_file))) {
+ error_string = strprintf(
+ "Invalid -wallet path '%s'. -wallet path should point to a directory where wallet.dat and "
+ "database/log.?????????? files can be stored, a location where such a directory could be created, "
+ "or (for backwards compatibility) the name of an existing data file in -walletdir (%s)",
+ wallet_file, GetWalletDir());
+ return false;
+ }
+
+ // Make sure that the wallet path doesn't clash with an existing wallet path
+ for (auto wallet : GetWallets()) {
+ if (fs::absolute(wallet->GetName(), GetWalletDir()) == wallet_path) {
+ error_string = strprintf("Error loading wallet %s. Duplicate -wallet filename specified.", wallet_file);
+ return false;
+ }
+ }
+
+ if (!WalletBatch::VerifyEnvironment(wallet_path, error_string)) {
+ return false;
+ }
+
+ if (salvage_wallet) {
+ // Recover readable keypairs:
+ CWallet dummyWallet("dummy", WalletDatabase::CreateDummy());
+ std::string backup_filename;
+ if (!WalletBatch::Recover(wallet_path, (void *)&dummyWallet, WalletBatch::RecoverKeysOnlyFilter, backup_filename)) {
+ return false;
+ }
+ }
+
+ return WalletBatch::VerifyDatabaseFile(wallet_path, warning_string, error_string);
+}
+
+std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(const std::string& name, const fs::path& path)
{
const std::string& walletFile = name;
@@ -3973,7 +4059,7 @@ CWallet* CWallet::CreateWalletFromFile(const std::string& name, const fs::path&
int64_t nStart = GetTimeMillis();
bool fFirstRun = true;
- CWallet *walletInstance = new CWallet(name, WalletDatabase::Create(path));
+ std::shared_ptr<CWallet> walletInstance = std::make_shared<CWallet>(name, WalletDatabase::Create(path));
DBErrors nLoadWalletRet = walletInstance->LoadWallet(fFirstRun);
if (nLoadWalletRet != DBErrors::LOAD_OK)
{
@@ -4002,6 +4088,9 @@ CWallet* CWallet::CreateWalletFromFile(const std::string& name, const fs::path&
}
}
+ uiInterface.LoadWallet(walletInstance);
+
+ int prev_version = walletInstance->nWalletVersion;
if (gArgs.GetBoolArg("-upgradewallet", fFirstRun))
{
int nMaxVersion = gArgs.GetArg("-upgradewallet", 0);
@@ -4021,6 +4110,49 @@ CWallet* CWallet::CreateWalletFromFile(const std::string& name, const fs::path&
walletInstance->SetMaxVersion(nMaxVersion);
}
+ // Upgrade to HD if explicit upgrade
+ if (gArgs.GetBoolArg("-upgradewallet", false)) {
+ LOCK(walletInstance->cs_wallet);
+
+ // Do not upgrade versions to any version between HD_SPLIT and FEATURE_PRE_SPLIT_KEYPOOL unless already supporting HD_SPLIT
+ int max_version = walletInstance->nWalletVersion;
+ if (!walletInstance->CanSupportFeature(FEATURE_HD_SPLIT) && max_version >=FEATURE_HD_SPLIT && max_version < FEATURE_PRE_SPLIT_KEYPOOL) {
+ InitError(_("Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use -upgradewallet=169900 or -upgradewallet with no version specified."));
+ return nullptr;
+ }
+
+ bool hd_upgrade = false;
+ bool split_upgrade = false;
+ if (walletInstance->CanSupportFeature(FEATURE_HD) && !walletInstance->IsHDEnabled()) {
+ LogPrintf("Upgrading wallet to HD\n");
+ walletInstance->SetMinVersion(FEATURE_HD);
+
+ // generate a new master key
+ CPubKey masterPubKey = walletInstance->GenerateNewSeed();
+ if (!walletInstance->SetHDSeed(masterPubKey)) {
+ throw std::runtime_error(std::string(__func__) + ": Storing master key failed");
+ }
+ hd_upgrade = true;
+ }
+ // Upgrade to HD chain split if necessary
+ if (walletInstance->CanSupportFeature(FEATURE_HD_SPLIT)) {
+ LogPrintf("Upgrading wallet to use HD chain split\n");
+ walletInstance->SetMinVersion(FEATURE_PRE_SPLIT_KEYPOOL);
+ split_upgrade = FEATURE_HD_SPLIT > prev_version;
+ }
+ // Mark all keys currently in the keypool as pre-split
+ if (split_upgrade) {
+ walletInstance->MarkPreSplitKeys();
+ }
+ // Regenerate the keypool if upgraded to HD
+ if (hd_upgrade) {
+ if (!walletInstance->TopUpKeyPool()) {
+ InitError(_("Unable to generate keys") += "\n");
+ return nullptr;
+ }
+ }
+ }
+
if (fFirstRun)
{
// ensure this wallet.dat can only be opened by clients supporting HD with chain split and expects no default key
@@ -4028,12 +4160,12 @@ CWallet* CWallet::CreateWalletFromFile(const std::string& name, const fs::path&
InitError(strprintf(_("Error creating %s: You can't create non-HD wallets with this version."), walletFile));
return nullptr;
}
- walletInstance->SetMinVersion(FEATURE_NO_DEFAULT_KEY);
+ walletInstance->SetMinVersion(FEATURE_LATEST);
- // generate a new master key
- CPubKey masterPubKey = walletInstance->GenerateNewHDMasterKey();
- if (!walletInstance->SetHDMasterKey(masterPubKey))
- throw std::runtime_error(std::string(__func__) + ": Storing master key failed");
+ // generate a new seed
+ CPubKey seed = walletInstance->GenerateNewSeed();
+ if (!walletInstance->SetHDSeed(seed))
+ throw std::runtime_error(std::string(__func__) + ": Storing HD seed failed");
// Top up the keypool
if (!walletInstance->TopUpKeyPool()) {
@@ -4141,7 +4273,6 @@ CWallet* CWallet::CreateWalletFromFile(const std::string& name, const fs::path&
}
walletInstance->m_last_block_processed = chainActive.Tip();
- RegisterValidationInterface(walletInstance);
if (chainActive.Tip() && chainActive.Tip() != pindexRescan)
{
@@ -4171,7 +4302,7 @@ CWallet* CWallet::CreateWalletFromFile(const std::string& name, const fs::path&
nStart = GetTimeMillis();
{
- WalletRescanReserver reserver(walletInstance);
+ WalletRescanReserver reserver(walletInstance.get());
if (!reserver.reserve()) {
InitError(_("Failed to rescan the wallet during initialization"));
return nullptr;
@@ -4207,6 +4338,10 @@ CWallet* CWallet::CreateWalletFromFile(const std::string& name, const fs::path&
}
}
}
+
+ // Register with the validation interface. It's ok to do this after rescan since we're still holding cs_main.
+ RegisterValidationInterface(walletInstance.get());
+
walletInstance->SetBroadcastTransactions(gArgs.GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST));
{
@@ -4219,18 +4354,11 @@ CWallet* CWallet::CreateWalletFromFile(const std::string& name, const fs::path&
return walletInstance;
}
-std::atomic<bool> CWallet::fFlushScheduled(false);
-
-void CWallet::postInitProcess(CScheduler& scheduler)
+void CWallet::postInitProcess()
{
// Add wallet transactions that aren't already in a block to mempool
// Do this here as mempool requires genesis block to be loaded
ReacceptWalletTransactions();
-
- // Run a thread to flush wallet periodically
- if (!CWallet::fFlushScheduled.exchange(true)) {
- scheduler.scheduleEvery(MaybeCompactWalletDB, 500);
- }
}
bool CWallet::BackupWallet(const std::string& strDest)
@@ -4242,6 +4370,7 @@ CKeyPool::CKeyPool()
{
nTime = GetTime();
fInternal = false;
+ m_pre_split = false;
}
CKeyPool::CKeyPool(const CPubKey& vchPubKeyIn, bool internalIn)
@@ -4249,6 +4378,7 @@ CKeyPool::CKeyPool(const CPubKey& vchPubKeyIn, bool internalIn)
nTime = GetTime();
vchPubKey = vchPubKeyIn;
fInternal = internalIn;
+ m_pre_split = false;
}
CWalletKey::CWalletKey(int64_t nExpires)
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 3208a20f0f..f1761b0fcf 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -32,11 +32,11 @@
#include <utility>
#include <vector>
-bool AddWallet(CWallet* wallet);
-bool RemoveWallet(CWallet* wallet);
+bool AddWallet(const std::shared_ptr<CWallet>& wallet);
+bool RemoveWallet(const std::shared_ptr<CWallet>& wallet);
bool HasWallets();
-std::vector<CWallet*> GetWallets();
-CWallet* GetWallet(const std::string& name);
+std::vector<std::shared_ptr<CWallet>> GetWallets();
+std::shared_ptr<CWallet> GetWallet(const std::string& name);
//! Default for -keypool
static const unsigned int DEFAULT_KEYPOOL_SIZE = 1000;
@@ -68,7 +68,6 @@ class CCoinControl;
class COutput;
class CReserveKey;
class CScript;
-class CScheduler;
class CTxMemPool;
class CBlockPolicyEstimator;
class CWalletTx;
@@ -89,7 +88,9 @@ enum WalletFeature
FEATURE_NO_DEFAULT_KEY = 159900, // Wallet without a default key written
- FEATURE_LATEST = FEATURE_COMPRPUBKEY // HD is optional, use FEATURE_COMPRPUBKEY as latest version
+ FEATURE_PRE_SPLIT_KEYPOOL = 169900, // Upgraded to HD SPLIT and can have a pre-split keypool
+
+ FEATURE_LATEST = FEATURE_PRE_SPLIT_KEYPOOL
};
enum class OutputType {
@@ -119,6 +120,7 @@ public:
int64_t nTime;
CPubKey vchPubKey;
bool fInternal; // for change outputs
+ bool m_pre_split; // For keys generated before keypool split upgrade
CKeyPool();
CKeyPool(const CPubKey& vchPubKeyIn, bool internalIn);
@@ -141,9 +143,18 @@ public:
(this will be the case for any wallet before the HD chain split version) */
fInternal = false;
}
+ try {
+ READWRITE(m_pre_split);
+ }
+ catch (std::ios_base::failure&) {
+ /* flag as postsplit address if we can't read the m_pre_split boolean
+ (this will be the case for any wallet that upgrades to HD chain split)*/
+ m_pre_split = false;
+ }
}
else {
READWRITE(fInternal);
+ READWRITE(m_pre_split);
}
}
};
@@ -663,7 +674,6 @@ class WalletRescanReserver; //forward declarations for ScanForWalletTransactions
class CWallet final : public CCryptoKeyStore, public CValidationInterface
{
private:
- static std::atomic<bool> fFlushScheduled;
std::atomic<bool> fAbortRescan{false};
std::atomic<bool> fScanningWallet{false}; // controlled by WalletRescanReserver
std::mutex mutexScanning;
@@ -698,16 +708,17 @@ private:
/* Used by TransactionAddedToMemorypool/BlockConnected/Disconnected.
* Should be called with pindexBlock and posInBlock if this is for a transaction that is included in a block. */
- void SyncTransaction(const CTransactionRef& tx, const CBlockIndex *pindex = nullptr, int posInBlock = 0);
+ void SyncTransaction(const CTransactionRef& tx, const CBlockIndex *pindex = nullptr, int posInBlock = 0) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/* the HD chain data model (external chain counters) */
CHDChain hdChain;
/* HD derive new child key (on internal or external chain) */
- void DeriveNewChildKey(WalletBatch &batch, CKeyMetadata& metadata, CKey& secret, bool internal = false);
+ void DeriveNewChildKey(WalletBatch &batch, CKeyMetadata& metadata, CKey& secret, bool internal = false) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
std::set<int64_t> setInternalKeyPool;
std::set<int64_t> setExternalKeyPool;
+ std::set<int64_t> set_pre_split_keypool;
int64_t m_max_keypool_index = 0;
std::map<CKeyID, int64_t> m_pool_key_to_index;
@@ -722,7 +733,7 @@ private:
* of the other AddWatchOnly which accepts a timestamp and sets
* nTimeFirstKey more intelligently for more efficient rescans.
*/
- bool AddWatchOnly(const CScript& dest) override;
+ bool AddWatchOnly(const CScript& dest) override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/**
* Wallet filename from wallet=<path> command line or config option.
@@ -773,7 +784,8 @@ public:
*/
const std::string& GetName() const { return m_name; }
- void LoadKeyPool(int64_t nIndex, const CKeyPool &keypool);
+ void LoadKeyPool(int64_t nIndex, const CKeyPool &keypool) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ void MarkPreSplitKeys();
// Map from Key ID to key metadata.
std::map<CKeyID, CKeyMetadata> mapKeyMetadata;
@@ -814,12 +826,12 @@ public:
const CWalletTx* GetWalletTx(const uint256& hash) const;
//! check whether we are allowed to upgrade (or already support) to the named feature
- bool CanSupportFeature(enum WalletFeature wf) const { AssertLockHeld(cs_wallet); return nWalletMaxVersion >= wf; }
+ bool CanSupportFeature(enum WalletFeature wf) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) { AssertLockHeld(cs_wallet); return nWalletMaxVersion >= wf; }
/**
* populate vCoins with vector of available COutputs.
*/
- void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlySafe=true, const CCoinControl *coinControl = nullptr, const CAmount& nMinimumAmount = 1, const CAmount& nMaximumAmount = MAX_MONEY, const CAmount& nMinimumSumAmount = MAX_MONEY, const uint64_t nMaximumCount = 0, const int nMinDepth = 0, const int nMaxDepth = 9999999) const;
+ void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlySafe=true, const CCoinControl *coinControl = nullptr, const CAmount& nMinimumAmount = 1, const CAmount& nMaximumAmount = MAX_MONEY, const CAmount& nMinimumSumAmount = MAX_MONEY, const uint64_t nMaximumCount = 0, const int nMinDepth = 0, const int nMaxDepth = 9999999) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/**
* Return list of available coins and locked coins grouped by non-change output address.
@@ -842,11 +854,11 @@ public:
bool IsSpent(const uint256& hash, unsigned int n) const;
- bool IsLockedCoin(uint256 hash, unsigned int n) const;
- void LockCoin(const COutPoint& output);
- void UnlockCoin(const COutPoint& output);
- void UnlockAllCoins();
- void ListLockedCoins(std::vector<COutPoint>& vOutpts) const;
+ bool IsLockedCoin(uint256 hash, unsigned int n) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ void LockCoin(const COutPoint& output) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ void UnlockCoin(const COutPoint& output) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ void UnlockAllCoins() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ void ListLockedCoins(std::vector<COutPoint>& vOutpts) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/*
* Rescan abort properties
@@ -859,18 +871,18 @@ public:
* keystore implementation
* Generate a new key
*/
- CPubKey GenerateNewKey(WalletBatch& batch, bool internal = false);
+ CPubKey GenerateNewKey(WalletBatch& batch, bool internal = false) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! Adds a key to the store, and saves it to disk.
- bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override;
- bool AddKeyPubKeyWithDB(WalletBatch &batch,const CKey& key, const CPubKey &pubkey);
+ bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ bool AddKeyPubKeyWithDB(WalletBatch &batch,const CKey& key, const CPubKey &pubkey) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! Adds a key to the store, without saving it to disk (used by LoadWallet)
bool LoadKey(const CKey& key, const CPubKey &pubkey) { return CCryptoKeyStore::AddKeyPubKey(key, pubkey); }
//! Load metadata (used by LoadWallet)
- bool LoadKeyMetadata(const CKeyID& keyID, const CKeyMetadata &metadata);
- bool LoadScriptMetadata(const CScriptID& script_id, const CKeyMetadata &metadata);
+ bool LoadKeyMetadata(const CKeyID& keyID, const CKeyMetadata &metadata) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ bool LoadScriptMetadata(const CScriptID& script_id, const CKeyMetadata &metadata) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
- bool LoadMinVersion(int nVersion) { AssertLockHeld(cs_wallet); nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; }
- void UpdateTimeFirstKey(int64_t nCreateTime);
+ bool LoadMinVersion(int nVersion) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) { AssertLockHeld(cs_wallet); nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; }
+ void UpdateTimeFirstKey(int64_t nCreateTime) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! Adds an encrypted key to the store, and saves it to disk.
bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret) override;
@@ -891,8 +903,8 @@ public:
std::vector<std::string> GetDestValues(const std::string& prefix) const;
//! Adds a watch-only address to the store, and saves it to disk.
- bool AddWatchOnly(const CScript& dest, int64_t nCreateTime);
- bool RemoveWatchOnly(const CScript &dest) override;
+ bool AddWatchOnly(const CScript& dest, int64_t nCreateTime) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ bool RemoveWatchOnly(const CScript &dest) override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! Adds a watch-only address to the store, without saving it to disk (used by LoadWallet)
bool LoadWatchOnly(const CScript &dest);
@@ -903,16 +915,16 @@ public:
bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase);
bool EncryptWallet(const SecureString& strWalletPassphrase);
- void GetKeyBirthTimes(std::map<CTxDestination, int64_t> &mapKeyBirth) const;
+ void GetKeyBirthTimes(std::map<CTxDestination, int64_t> &mapKeyBirth) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
unsigned int ComputeTimeSmart(const CWalletTx& wtx) const;
/**
* Increment the next transaction order id
* @return next transaction order id
*/
- int64_t IncOrderPosNext(WalletBatch *batch = nullptr);
+ int64_t IncOrderPosNext(WalletBatch *batch = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
DBErrors ReorderTransactions();
- bool AccountMove(std::string strFrom, std::string strTo, CAmount nAmount, std::string strComment = "");
+ bool AccountMove(std::string strFrom, std::string strTo, CAmount nAmount, std::string strComment = "") EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool GetLabelDestination(CTxDestination &dest, const std::string& label, bool bForceNew = false);
void MarkDirty();
@@ -921,7 +933,7 @@ public:
void TransactionAddedToMempool(const CTransactionRef& tx) override;
void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex *pindex, const std::vector<CTransactionRef>& vtxConflicted) override;
void BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) override;
- bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate);
+ bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver& reserver, bool update);
CBlockIndex* ScanForWalletTransactions(CBlockIndex* pindexStart, CBlockIndex* pindexStop, const WalletRescanReserver& reserver, bool fUpdate = false);
void TransactionRemovedFromMempool(const CTransactionRef &ptx) override;
@@ -945,7 +957,7 @@ public:
* calling CreateTransaction();
*/
bool FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosInOut, std::string& strFailReason, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, CCoinControl);
- bool SignTransaction(CMutableTransaction& tx);
+ bool SignTransaction(CMutableTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/**
* Create a new transaction paying the recipients with a set of coins
@@ -985,9 +997,24 @@ public:
OutputType m_default_change_type{DEFAULT_CHANGE_TYPE};
bool NewKeyPool();
- size_t KeypoolCountExternalKeys();
+ size_t KeypoolCountExternalKeys() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool TopUpKeyPool(unsigned int kpSize = 0);
- void ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRequestedInternal);
+
+ /**
+ * Reserves a key from the keypool and sets nIndex to its index
+ *
+ * @param[out] nIndex the index of the key in keypool
+ * @param[out] keypool the keypool the key was drawn from, which could be the
+ * the pre-split pool if present, or the internal or external pool
+ * @param fRequestedInternal true if the caller would like the key drawn
+ * from the internal keypool, false if external is preferred
+ *
+ * @return true if succeeded, false if failed due to empty keypool
+ * @throws std::runtime_error if keypool read failed, key was invalid,
+ * was not found in the wallet, or was misclassified in the internal
+ * or external keypool
+ */
+ bool ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRequestedInternal);
void KeepKey(int64_t nIndex);
void ReturnKey(int64_t nIndex, bool fInternal, const CPubKey& pubkey);
bool GetKeyFromPool(CPubKey &key, bool internal = false);
@@ -995,10 +1022,10 @@ public:
/**
* Marks all keys in the keypool up to and including reserve_key as used.
*/
- void MarkReserveKeysAsUsed(int64_t keypool_id);
+ void MarkReserveKeysAsUsed(int64_t keypool_id) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
const std::map<CKeyID, int64_t>& GetAllReserveKeys() const { return m_pool_key_to_index; }
- std::set< std::set<CTxDestination> > GetAddressGroupings();
+ std::set<std::set<CTxDestination>> GetAddressGroupings() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
std::map<CTxDestination, CAmount> GetAddressBalances();
std::set<CTxDestination> GetLabelAddresses(const std::string& label) const;
@@ -1026,7 +1053,7 @@ public:
DBErrors LoadWallet(bool& fFirstRunRet);
DBErrors ZapWalletTx(std::vector<CWalletTx>& vWtx);
- DBErrors ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut);
+ DBErrors ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool SetAddressBook(const CTxDestination& address, const std::string& strName, const std::string& purpose);
@@ -1046,7 +1073,7 @@ public:
void GetScriptForMining(std::shared_ptr<CReserveScript> &script);
- unsigned int GetKeyPoolSize()
+ unsigned int GetKeyPoolSize() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
{
AssertLockHeld(cs_wallet); // set{Ex,In}ternalKeyPool
return setInternalKeyPool.size() + setExternalKeyPool.size();
@@ -1065,7 +1092,7 @@ public:
std::set<uint256> GetConflicts(const uint256& txid) const;
//! Check if a given transaction has any of its outputs spent by another transaction in the wallet
- bool HasWalletSpend(const uint256& txid) const;
+ bool HasWalletSpend(const uint256& txid) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! Flush wallet (bitdb flush)
void Flush(bool shutdown=false);
@@ -1106,14 +1133,17 @@ public:
/** Mark a transaction as replaced by another transaction (e.g., BIP 125). */
bool MarkReplaced(const uint256& originalHash, const uint256& newHash);
+ //! Verify wallet naming and perform salvage on the wallet if required
+ static bool Verify(std::string wallet_file, bool salvage_wallet, std::string& error_string, std::string& warning_string);
+
/* Initializes the wallet, returns a new CWallet instance or a null pointer in case of an error */
- static CWallet* CreateWalletFromFile(const std::string& name, const fs::path& path);
+ static std::shared_ptr<CWallet> CreateWalletFromFile(const std::string& name, const fs::path& path);
/**
* Wallet post-init setup
* Gives the wallet a chance to register repetitive tasks and complete post-init tasks
*/
- void postInitProcess(CScheduler& scheduler);
+ void postInitProcess();
bool BackupWallet(const std::string& strDest);
@@ -1124,14 +1154,17 @@ public:
/* Returns true if HD is enabled */
bool IsHDEnabled() const;
- /* Generates a new HD master key (will not be activated) */
- CPubKey GenerateNewHDMasterKey();
+ /* Generates a new HD seed (will not be activated) */
+ CPubKey GenerateNewSeed();
+
+ /* Derives a new HD seed (will not be activated) */
+ CPubKey DeriveNewSeed(const CKey& key);
- /* Set the current HD master key (will reset the chain child index counters)
- Sets the master key's version based on the current wallet version (so the
+ /* Set the current HD seed (will reset the chain child index counters)
+ Sets the seed's version based on the current wallet version (so the
caller must ensure the current wallet version is correct before calling
this function). */
- bool SetHDMasterKey(const CPubKey& key);
+ bool SetHDSeed(const CPubKey& key);
/**
* Blocks until the wallet state is up-to-date to /at least/ the current
@@ -1139,7 +1172,7 @@ public:
* Obviously holding cs_main/cs_wallet when going into this call may cause
* deadlock
*/
- void BlockUntilSyncedToCurrentChain();
+ void BlockUntilSyncedToCurrentChain() LOCKS_EXCLUDED(cs_wallet);
/**
* Explicitly make the wallet learn the related scripts for outputs to the
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 4d1a6d48d0..4b4460a794 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -248,7 +248,7 @@ public:
static bool
ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
- CWalletScanState &wss, std::string& strType, std::string& strErr)
+ CWalletScanState &wss, std::string& strType, std::string& strErr) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
{
try {
// Unserialize
@@ -756,7 +756,7 @@ void MaybeCompactWalletDB()
return;
}
- for (CWallet* pwallet : GetWallets()) {
+ for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
WalletDatabase& dbh = pwallet->GetDBHandle();
unsigned int nUpdateCounter = dbh.nUpdateCounter;
diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h
index a73d727c0c..3237376f63 100644
--- a/src/wallet/walletdb.h
+++ b/src/wallet/walletdb.h
@@ -62,7 +62,7 @@ class CHDChain
public:
uint32_t nExternalChainCounter;
uint32_t nInternalChainCounter;
- CKeyID masterKeyID; //!< master key hash160
+ CKeyID seed_id; //!< seed hash160
static const int VERSION_HD_BASE = 1;
static const int VERSION_HD_CHAIN_SPLIT = 2;
@@ -76,7 +76,7 @@ public:
{
READWRITE(this->nVersion);
READWRITE(nExternalChainCounter);
- READWRITE(masterKeyID);
+ READWRITE(seed_id);
if (this->nVersion >= VERSION_HD_CHAIN_SPLIT)
READWRITE(nInternalChainCounter);
}
@@ -86,7 +86,7 @@ public:
nVersion = CHDChain::CURRENT_VERSION;
nExternalChainCounter = 0;
nInternalChainCounter = 0;
- masterKeyID.SetNull();
+ seed_id.SetNull();
}
};
@@ -99,7 +99,7 @@ public:
int nVersion;
int64_t nCreateTime; // 0 means unknown
std::string hdKeypath; //optional HD/bip32 keypath
- CKeyID hdMasterKeyID; //id of the HD masterkey used to derive this key
+ CKeyID hd_seed_id; //id of the HD seed used to derive this key
CKeyMetadata()
{
@@ -120,7 +120,7 @@ public:
if (this->nVersion >= VERSION_WITH_HDDATA)
{
READWRITE(hdKeypath);
- READWRITE(hdMasterKeyID);
+ READWRITE(hd_seed_id);
}
}
@@ -129,7 +129,7 @@ public:
nVersion = CKeyMetadata::CURRENT_VERSION;
nCreateTime = 0;
hdKeypath.clear();
- hdMasterKeyID.SetNull();
+ hd_seed_id.SetNull();
}
};