Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/wallet.cpp
Show All 18 Lines | |||||
#include <primitives/transaction.h> | #include <primitives/transaction.h> | ||||
#include <random.h> | #include <random.h> | ||||
#include <script/descriptor.h> | #include <script/descriptor.h> | ||||
#include <script/script.h> | #include <script/script.h> | ||||
#include <script/sighashtype.h> | #include <script/sighashtype.h> | ||||
#include <script/sign.h> | #include <script/sign.h> | ||||
#include <script/signingprovider.h> | #include <script/signingprovider.h> | ||||
#include <txmempool.h> | #include <txmempool.h> | ||||
#include <univalue.h> | |||||
#include <util/bip32.h> | #include <util/bip32.h> | ||||
#include <util/check.h> | #include <util/check.h> | ||||
#include <util/error.h> | #include <util/error.h> | ||||
#include <util/moneystr.h> | #include <util/moneystr.h> | ||||
#include <util/string.h> | #include <util/string.h> | ||||
#include <util/translation.h> | #include <util/translation.h> | ||||
#include <wallet/coincontrol.h> | #include <wallet/coincontrol.h> | ||||
#include <wallet/fees.h> | #include <wallet/fees.h> | ||||
#include <boost/algorithm/string/replace.hpp> | #include <boost/algorithm/string/replace.hpp> | ||||
using interfaces::FoundBlock; | using interfaces::FoundBlock; | ||||
const std::map<uint64_t, std::string> WALLET_FLAG_CAVEATS{ | const std::map<uint64_t, std::string> WALLET_FLAG_CAVEATS{ | ||||
{WALLET_FLAG_AVOID_REUSE, | {WALLET_FLAG_AVOID_REUSE, | ||||
"You need to rescan the blockchain in order to correctly mark used " | "You need to rescan the blockchain in order to correctly mark used " | ||||
"destinations in the past. Until this is done, some destinations may " | "destinations in the past. Until this is done, some destinations may " | ||||
"be considered unused, even if the opposite is the case."}, | "be considered unused, even if the opposite is the case."}, | ||||
}; | }; | ||||
static RecursiveMutex cs_wallets; | static RecursiveMutex cs_wallets; | ||||
static std::vector<std::shared_ptr<CWallet>> vpwallets GUARDED_BY(cs_wallets); | static std::vector<std::shared_ptr<CWallet>> vpwallets GUARDED_BY(cs_wallets); | ||||
static std::list<LoadWalletFn> g_load_wallet_fns GUARDED_BY(cs_wallets); | static std::list<LoadWalletFn> g_load_wallet_fns GUARDED_BY(cs_wallets); | ||||
bool AddWalletSetting(interfaces::Chain &chain, | |||||
const std::string &wallet_name) { | |||||
util::SettingsValue setting_value = chain.getRwSetting("wallet"); | |||||
if (!setting_value.isArray()) { | |||||
setting_value.setArray(); | |||||
} | |||||
for (const util::SettingsValue &value : setting_value.getValues()) { | |||||
if (value.isStr() && value.get_str() == wallet_name) { | |||||
return true; | |||||
} | |||||
} | |||||
setting_value.push_back(wallet_name); | |||||
return chain.updateRwSetting("wallet", setting_value); | |||||
} | |||||
bool RemoveWalletSetting(interfaces::Chain &chain, | |||||
const std::string &wallet_name) { | |||||
util::SettingsValue setting_value = chain.getRwSetting("wallet"); | |||||
if (!setting_value.isArray()) { | |||||
return true; | |||||
} | |||||
util::SettingsValue new_value(util::SettingsValue::VARR); | |||||
for (const util::SettingsValue &value : setting_value.getValues()) { | |||||
if (!value.isStr() || value.get_str() != wallet_name) { | |||||
new_value.push_back(value); | |||||
} | |||||
} | |||||
if (new_value.size() == setting_value.size()) { | |||||
return true; | |||||
} | |||||
return chain.updateRwSetting("wallet", new_value); | |||||
} | |||||
static void UpdateWalletSetting(interfaces::Chain &chain, | |||||
const std::string &wallet_name, | |||||
std::optional<bool> load_on_startup, | |||||
std::vector<bilingual_str> &warnings) { | |||||
if (!load_on_startup) { | |||||
return; | |||||
} | |||||
if (load_on_startup.value() && !AddWalletSetting(chain, wallet_name)) { | |||||
warnings.emplace_back( | |||||
Untranslated("Wallet load on startup setting could not be updated, " | |||||
"so wallet may not be loaded next node startup.")); | |||||
} else if (!load_on_startup.value() && | |||||
!RemoveWalletSetting(chain, wallet_name)) { | |||||
warnings.emplace_back( | |||||
Untranslated("Wallet load on startup setting could not be updated, " | |||||
"so wallet may still be loaded next node startup.")); | |||||
} | |||||
} | |||||
bool AddWallet(const std::shared_ptr<CWallet> &wallet) { | bool AddWallet(const std::shared_ptr<CWallet> &wallet) { | ||||
LOCK(cs_wallets); | LOCK(cs_wallets); | ||||
assert(wallet); | assert(wallet); | ||||
std::vector<std::shared_ptr<CWallet>>::const_iterator i = | std::vector<std::shared_ptr<CWallet>>::const_iterator i = | ||||
std::find(vpwallets.begin(), vpwallets.end(), wallet); | std::find(vpwallets.begin(), vpwallets.end(), wallet); | ||||
if (i != vpwallets.end()) { | if (i != vpwallets.end()) { | ||||
return false; | return false; | ||||
} | } | ||||
vpwallets.push_back(wallet); | vpwallets.push_back(wallet); | ||||
wallet->ConnectScriptPubKeyManNotifiers(); | wallet->ConnectScriptPubKeyManNotifiers(); | ||||
return true; | return true; | ||||
} | } | ||||
bool RemoveWallet(const std::shared_ptr<CWallet> &wallet) { | bool RemoveWallet(const std::shared_ptr<CWallet> &wallet, | ||||
std::optional<bool> load_on_start, | |||||
std::vector<bilingual_str> &warnings) { | |||||
assert(wallet); | assert(wallet); | ||||
interfaces::Chain &chain = wallet->chain(); | |||||
std::string name = wallet->GetName(); | |||||
// Unregister with the validation interface which also drops shared ponters. | // Unregister with the validation interface which also drops shared ponters. | ||||
wallet->m_chain_notifications_handler.reset(); | wallet->m_chain_notifications_handler.reset(); | ||||
LOCK(cs_wallets); | LOCK(cs_wallets); | ||||
std::vector<std::shared_ptr<CWallet>>::iterator i = | std::vector<std::shared_ptr<CWallet>>::iterator i = | ||||
std::find(vpwallets.begin(), vpwallets.end(), wallet); | std::find(vpwallets.begin(), vpwallets.end(), wallet); | ||||
if (i == vpwallets.end()) { | if (i == vpwallets.end()) { | ||||
return false; | return false; | ||||
} | } | ||||
vpwallets.erase(i); | vpwallets.erase(i); | ||||
// Write the wallet setting | |||||
UpdateWalletSetting(chain, name, load_on_start, warnings); | |||||
return true; | return true; | ||||
} | } | ||||
bool RemoveWallet(const std::shared_ptr<CWallet> &wallet, | |||||
std::optional<bool> load_on_start) { | |||||
std::vector<bilingual_str> warnings; | |||||
return RemoveWallet(wallet, load_on_start, warnings); | |||||
} | |||||
std::vector<std::shared_ptr<CWallet>> GetWallets() { | std::vector<std::shared_ptr<CWallet>> GetWallets() { | ||||
LOCK(cs_wallets); | LOCK(cs_wallets); | ||||
return vpwallets; | return vpwallets; | ||||
} | } | ||||
std::shared_ptr<CWallet> GetWallet(const std::string &name) { | std::shared_ptr<CWallet> GetWallet(const std::string &name) { | ||||
LOCK(cs_wallets); | LOCK(cs_wallets); | ||||
for (const std::shared_ptr<CWallet> &wallet : vpwallets) { | for (const std::shared_ptr<CWallet> &wallet : vpwallets) { | ||||
▲ Show 20 Lines • Show All 63 Lines • ▼ Show 20 Lines | void UnloadWallet(std::shared_ptr<CWallet> &&wallet) { | ||||
} | } | ||||
} | } | ||||
static const size_t OUTPUT_GROUP_MAX_ENTRIES = 10; | static const size_t OUTPUT_GROUP_MAX_ENTRIES = 10; | ||||
namespace { | namespace { | ||||
std::shared_ptr<CWallet> | std::shared_ptr<CWallet> | ||||
LoadWalletInternal(const CChainParams &chainParams, interfaces::Chain &chain, | LoadWalletInternal(const CChainParams &chainParams, interfaces::Chain &chain, | ||||
const WalletLocation &location, bilingual_str &error, | const WalletLocation &location, | ||||
std::optional<bool> load_on_start, bilingual_str &error, | |||||
std::vector<bilingual_str> &warnings) { | std::vector<bilingual_str> &warnings) { | ||||
try { | try { | ||||
if (!CWallet::Verify(chainParams, chain, location, error, warnings)) { | if (!CWallet::Verify(chainParams, chain, location, error, warnings)) { | ||||
error = Untranslated("Wallet file verification failed.") + | error = Untranslated("Wallet file verification failed.") + | ||||
Untranslated(" ") + error; | Untranslated(" ") + error; | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
std::shared_ptr<CWallet> wallet = CWallet::CreateWalletFromFile( | std::shared_ptr<CWallet> wallet = CWallet::CreateWalletFromFile( | ||||
chainParams, chain, location, error, warnings); | chainParams, chain, location, error, warnings); | ||||
if (!wallet) { | if (!wallet) { | ||||
error = Untranslated("Wallet loading failed.") + Untranslated(" ") + | error = Untranslated("Wallet loading failed.") + Untranslated(" ") + | ||||
error; | error; | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
AddWallet(wallet); | AddWallet(wallet); | ||||
wallet->postInitProcess(); | wallet->postInitProcess(); | ||||
// Write the wallet setting | |||||
UpdateWalletSetting(chain, location.GetName(), load_on_start, warnings); | |||||
return wallet; | return wallet; | ||||
} catch (const std::runtime_error &e) { | } catch (const std::runtime_error &e) { | ||||
error = Untranslated(e.what()); | error = Untranslated(e.what()); | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
} | } | ||||
} // namespace | } // namespace | ||||
std::shared_ptr<CWallet> LoadWallet(const CChainParams &chainParams, | std::shared_ptr<CWallet> | ||||
interfaces::Chain &chain, | LoadWallet(const CChainParams &chainParams, interfaces::Chain &chain, | ||||
const WalletLocation &location, | const WalletLocation &location, std::optional<bool> load_on_start, | ||||
bilingual_str &error, | bilingual_str &error, std::vector<bilingual_str> &warnings) { | ||||
std::vector<bilingual_str> &warnings) { | |||||
auto result = | auto result = | ||||
WITH_LOCK(g_loading_wallet_mutex, | WITH_LOCK(g_loading_wallet_mutex, | ||||
return g_loading_wallet_set.insert(location.GetName())); | return g_loading_wallet_set.insert(location.GetName())); | ||||
if (!result.second) { | if (!result.second) { | ||||
error = Untranslated("Wallet already being loading."); | error = Untranslated("Wallet already being loading."); | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
auto wallet = | auto wallet = LoadWalletInternal(chainParams, chain, location, | ||||
LoadWalletInternal(chainParams, chain, location, error, warnings); | load_on_start, error, warnings); | ||||
WITH_LOCK(g_loading_wallet_mutex, g_loading_wallet_set.erase(result.first)); | WITH_LOCK(g_loading_wallet_mutex, g_loading_wallet_set.erase(result.first)); | ||||
return wallet; | return wallet; | ||||
} | } | ||||
WalletCreationStatus CreateWallet(const CChainParams ¶ms, | WalletCreationStatus | ||||
interfaces::Chain &chain, | CreateWallet(const CChainParams ¶ms, interfaces::Chain &chain, | ||||
const SecureString &passphrase, | const SecureString &passphrase, uint64_t wallet_creation_flags, | ||||
uint64_t wallet_creation_flags, | const std::string &name, std::optional<bool> load_on_start, | ||||
const std::string &name, bilingual_str &error, | bilingual_str &error, std::vector<bilingual_str> &warnings, | ||||
std::vector<bilingual_str> &warnings, | |||||
std::shared_ptr<CWallet> &result) { | std::shared_ptr<CWallet> &result) { | ||||
// Indicate that the wallet is actually supposed to be blank and not just | // Indicate that the wallet is actually supposed to be blank and not just | ||||
// blank to make it encrypted | // blank to make it encrypted | ||||
bool create_blank = (wallet_creation_flags & WALLET_FLAG_BLANK_WALLET); | bool create_blank = (wallet_creation_flags & WALLET_FLAG_BLANK_WALLET); | ||||
// Born encrypted wallets need to be created blank first. | // Born encrypted wallets need to be created blank first. | ||||
if (!passphrase.empty()) { | if (!passphrase.empty()) { | ||||
wallet_creation_flags |= WALLET_FLAG_BLANK_WALLET; | wallet_creation_flags |= WALLET_FLAG_BLANK_WALLET; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | if (!passphrase.empty() && | ||||
// Relock the wallet | // Relock the wallet | ||||
wallet->Lock(); | wallet->Lock(); | ||||
} | } | ||||
} | } | ||||
AddWallet(wallet); | AddWallet(wallet); | ||||
wallet->postInitProcess(); | wallet->postInitProcess(); | ||||
result = wallet; | result = wallet; | ||||
// Write the wallet settings | |||||
UpdateWalletSetting(chain, name, load_on_start, warnings); | |||||
return WalletCreationStatus::SUCCESS; | return WalletCreationStatus::SUCCESS; | ||||
} | } | ||||
/** @defgroup mapWallet | /** @defgroup mapWallet | ||||
* | * | ||||
* @{ | * @{ | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 4,723 Lines • Show Last 20 Lines |