refactor: Split out wallet argument loading

This section is necessarily repetitive, makes CWallet::Create() easier
to read, and splits out functionality that will be useful when wallet
creation and loading are separated.

Review with `-color-moved=dimmed-zebra`
This commit is contained in:
David Gumberg
2025-05-22 18:49:00 -07:00
parent a02c4a82d8
commit b15a94a618
2 changed files with 144 additions and 130 deletions

View File

@@ -2881,6 +2881,146 @@ std::unique_ptr<WalletDatabase> MakeWalletDatabase(const std::string& name, cons
return MakeDatabase(*wallet_path, options, status, error_string);
}
bool CWallet::LoadWalletArgs(std::shared_ptr<CWallet> wallet, const WalletContext& context, bilingual_str& error, std::vector<bilingual_str>& warnings)
{
interfaces::Chain* chain = context.chain;
const ArgsManager& args = *Assert(context.args);
if (!args.GetArg("-addresstype", "").empty()) {
std::optional<OutputType> parsed = ParseOutputType(args.GetArg("-addresstype", ""));
if (!parsed) {
error = strprintf(_("Unknown address type '%s'"), args.GetArg("-addresstype", ""));
return false;
}
wallet->m_default_address_type = parsed.value();
}
if (!args.GetArg("-changetype", "").empty()) {
std::optional<OutputType> parsed = ParseOutputType(args.GetArg("-changetype", ""));
if (!parsed) {
error = strprintf(_("Unknown change type '%s'"), args.GetArg("-changetype", ""));
return false;
}
wallet->m_default_change_type = parsed.value();
}
if (const auto arg{args.GetArg("-mintxfee")}) {
std::optional<CAmount> min_tx_fee = ParseMoney(*arg);
if (!min_tx_fee) {
error = AmountErrMsg("mintxfee", *arg);
return false;
} else if (min_tx_fee.value() > HIGH_TX_FEE_PER_KB) {
warnings.push_back(AmountHighWarn("-mintxfee") + Untranslated(" ") +
_("This is the minimum transaction fee you pay on every transaction."));
}
wallet->m_min_fee = CFeeRate{min_tx_fee.value()};
}
if (const auto arg{args.GetArg("-maxapsfee")}) {
const std::string& max_aps_fee{*arg};
if (max_aps_fee == "-1") {
wallet->m_max_aps_fee = -1;
} else if (std::optional<CAmount> max_fee = ParseMoney(max_aps_fee)) {
if (max_fee.value() > HIGH_APS_FEE) {
warnings.push_back(AmountHighWarn("-maxapsfee") + Untranslated(" ") +
_("This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection."));
}
wallet->m_max_aps_fee = max_fee.value();
} else {
error = AmountErrMsg("maxapsfee", max_aps_fee);
return false;
}
}
if (const auto arg{args.GetArg("-fallbackfee")}) {
std::optional<CAmount> fallback_fee = ParseMoney(*arg);
if (!fallback_fee) {
error = strprintf(_("Invalid amount for %s=<amount>: '%s'"), "-fallbackfee", *arg);
return false;
} else if (fallback_fee.value() > HIGH_TX_FEE_PER_KB) {
warnings.push_back(AmountHighWarn("-fallbackfee") + Untranslated(" ") +
_("This is the transaction fee you may pay when fee estimates are not available."));
}
wallet->m_fallback_fee = CFeeRate{fallback_fee.value()};
}
// Disable fallback fee in case value was set to 0, enable if non-null value
wallet->m_allow_fallback_fee = wallet->m_fallback_fee.GetFeePerK() != 0;
if (const auto arg{args.GetArg("-discardfee")}) {
std::optional<CAmount> discard_fee = ParseMoney(*arg);
if (!discard_fee) {
error = strprintf(_("Invalid amount for %s=<amount>: '%s'"), "-discardfee", *arg);
return false;
} else if (discard_fee.value() > HIGH_TX_FEE_PER_KB) {
warnings.push_back(AmountHighWarn("-discardfee") + Untranslated(" ") +
_("This is the transaction fee you may discard if change is smaller than dust at this level"));
}
wallet->m_discard_rate = CFeeRate{discard_fee.value()};
}
if (const auto arg{args.GetArg("-paytxfee")}) {
warnings.push_back(_("-paytxfee is deprecated and will be fully removed in v31.0."));
std::optional<CAmount> pay_tx_fee = ParseMoney(*arg);
if (!pay_tx_fee) {
error = AmountErrMsg("paytxfee", *arg);
return false;
} else if (pay_tx_fee.value() > HIGH_TX_FEE_PER_KB) {
warnings.push_back(AmountHighWarn("-paytxfee") + Untranslated(" ") +
_("This is the transaction fee you will pay if you send a transaction."));
}
wallet->m_pay_tx_fee = CFeeRate{pay_tx_fee.value(), 1000};
if (chain && wallet->m_pay_tx_fee < chain->relayMinFee()) {
error = strprintf(_("Invalid amount for %s=<amount>: '%s' (must be at least %s)"),
"-paytxfee", *arg, chain->relayMinFee().ToString());
return false;
}
}
if (const auto arg{args.GetArg("-maxtxfee")}) {
std::optional<CAmount> max_fee = ParseMoney(*arg);
if (!max_fee) {
error = AmountErrMsg("maxtxfee", *arg);
return false;
} else if (max_fee.value() > HIGH_MAX_TX_FEE) {
warnings.push_back(strprintf(_("%s is set very high! Fees this large could be paid on a single transaction."), "-maxtxfee"));
}
if (chain && CFeeRate{max_fee.value(), 1000} < chain->relayMinFee()) {
error = strprintf(_("Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
"-maxtxfee", *arg, chain->relayMinFee().ToString());
return false;
}
wallet->m_default_max_tx_fee = max_fee.value();
}
if (const auto arg{args.GetArg("-consolidatefeerate")}) {
if (std::optional<CAmount> consolidate_feerate = ParseMoney(*arg)) {
wallet->m_consolidate_feerate = CFeeRate(*consolidate_feerate);
} else {
error = AmountErrMsg("consolidatefeerate", *arg);
return false;
}
}
if (chain && chain->relayMinFee().GetFeePerK() > HIGH_TX_FEE_PER_KB) {
warnings.push_back(AmountHighWarn("-minrelaytxfee") + Untranslated(" ") +
_("The wallet will avoid paying less than the minimum relay fee."));
}
wallet->m_confirm_target = args.GetIntArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET);
wallet->m_spend_zero_conf_change = args.GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE);
wallet->m_signal_rbf = args.GetBoolArg("-walletrbf", DEFAULT_WALLET_RBF);
wallet->SetBroadcastTransactions(args.GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST));
return true;
}
std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::string& name, std::unique_ptr<WalletDatabase> database, uint64_t wallet_creation_flags, bilingual_str& error, std::vector<bilingual_str>& warnings)
{
interfaces::Chain* chain = context.chain;
@@ -2939,137 +3079,9 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri
}
}
if (!args.GetArg("-addresstype", "").empty()) {
std::optional<OutputType> parsed = ParseOutputType(args.GetArg("-addresstype", ""));
if (!parsed) {
error = strprintf(_("Unknown address type '%s'"), args.GetArg("-addresstype", ""));
if (!LoadWalletArgs(walletInstance, context, error, warnings)) {
return nullptr;
}
walletInstance->m_default_address_type = parsed.value();
}
if (!args.GetArg("-changetype", "").empty()) {
std::optional<OutputType> parsed = ParseOutputType(args.GetArg("-changetype", ""));
if (!parsed) {
error = strprintf(_("Unknown change type '%s'"), args.GetArg("-changetype", ""));
return nullptr;
}
walletInstance->m_default_change_type = parsed.value();
}
if (const auto arg{args.GetArg("-mintxfee")}) {
std::optional<CAmount> min_tx_fee = ParseMoney(*arg);
if (!min_tx_fee) {
error = AmountErrMsg("mintxfee", *arg);
return nullptr;
} else if (min_tx_fee.value() > HIGH_TX_FEE_PER_KB) {
warnings.push_back(AmountHighWarn("-mintxfee") + Untranslated(" ") +
_("This is the minimum transaction fee you pay on every transaction."));
}
walletInstance->m_min_fee = CFeeRate{min_tx_fee.value()};
}
if (const auto arg{args.GetArg("-maxapsfee")}) {
const std::string& max_aps_fee{*arg};
if (max_aps_fee == "-1") {
walletInstance->m_max_aps_fee = -1;
} else if (std::optional<CAmount> max_fee = ParseMoney(max_aps_fee)) {
if (max_fee.value() > HIGH_APS_FEE) {
warnings.push_back(AmountHighWarn("-maxapsfee") + Untranslated(" ") +
_("This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection."));
}
walletInstance->m_max_aps_fee = max_fee.value();
} else {
error = AmountErrMsg("maxapsfee", max_aps_fee);
return nullptr;
}
}
if (const auto arg{args.GetArg("-fallbackfee")}) {
std::optional<CAmount> fallback_fee = ParseMoney(*arg);
if (!fallback_fee) {
error = strprintf(_("Invalid amount for %s=<amount>: '%s'"), "-fallbackfee", *arg);
return nullptr;
} else if (fallback_fee.value() > HIGH_TX_FEE_PER_KB) {
warnings.push_back(AmountHighWarn("-fallbackfee") + Untranslated(" ") +
_("This is the transaction fee you may pay when fee estimates are not available."));
}
walletInstance->m_fallback_fee = CFeeRate{fallback_fee.value()};
}
// Disable fallback fee in case value was set to 0, enable if non-null value
walletInstance->m_allow_fallback_fee = walletInstance->m_fallback_fee.GetFeePerK() != 0;
if (const auto arg{args.GetArg("-discardfee")}) {
std::optional<CAmount> discard_fee = ParseMoney(*arg);
if (!discard_fee) {
error = strprintf(_("Invalid amount for %s=<amount>: '%s'"), "-discardfee", *arg);
return nullptr;
} else if (discard_fee.value() > HIGH_TX_FEE_PER_KB) {
warnings.push_back(AmountHighWarn("-discardfee") + Untranslated(" ") +
_("This is the transaction fee you may discard if change is smaller than dust at this level"));
}
walletInstance->m_discard_rate = CFeeRate{discard_fee.value()};
}
if (const auto arg{args.GetArg("-paytxfee")}) {
warnings.push_back(_("-paytxfee is deprecated and will be fully removed in v31.0."));
std::optional<CAmount> pay_tx_fee = ParseMoney(*arg);
if (!pay_tx_fee) {
error = AmountErrMsg("paytxfee", *arg);
return nullptr;
} else if (pay_tx_fee.value() > HIGH_TX_FEE_PER_KB) {
warnings.push_back(AmountHighWarn("-paytxfee") + Untranslated(" ") +
_("This is the transaction fee you will pay if you send a transaction."));
}
walletInstance->m_pay_tx_fee = CFeeRate{pay_tx_fee.value(), 1000};
if (chain && walletInstance->m_pay_tx_fee < chain->relayMinFee()) {
error = strprintf(_("Invalid amount for %s=<amount>: '%s' (must be at least %s)"),
"-paytxfee", *arg, chain->relayMinFee().ToString());
return nullptr;
}
}
if (const auto arg{args.GetArg("-maxtxfee")}) {
std::optional<CAmount> max_fee = ParseMoney(*arg);
if (!max_fee) {
error = AmountErrMsg("maxtxfee", *arg);
return nullptr;
} else if (max_fee.value() > HIGH_MAX_TX_FEE) {
warnings.push_back(strprintf(_("%s is set very high! Fees this large could be paid on a single transaction."), "-maxtxfee"));
}
if (chain && CFeeRate{max_fee.value(), 1000} < chain->relayMinFee()) {
error = strprintf(_("Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
"-maxtxfee", *arg, chain->relayMinFee().ToString());
return nullptr;
}
walletInstance->m_default_max_tx_fee = max_fee.value();
}
if (const auto arg{args.GetArg("-consolidatefeerate")}) {
if (std::optional<CAmount> consolidate_feerate = ParseMoney(*arg)) {
walletInstance->m_consolidate_feerate = CFeeRate(*consolidate_feerate);
} else {
error = AmountErrMsg("consolidatefeerate", *arg);
return nullptr;
}
}
if (chain && chain->relayMinFee().GetFeePerK() > HIGH_TX_FEE_PER_KB) {
warnings.push_back(AmountHighWarn("-minrelaytxfee") + Untranslated(" ") +
_("The wallet will avoid paying less than the minimum relay fee."));
}
walletInstance->m_confirm_target = args.GetIntArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET);
walletInstance->m_spend_zero_conf_change = args.GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE);
walletInstance->m_signal_rbf = args.GetBoolArg("-walletrbf", DEFAULT_WALLET_RBF);
walletInstance->SetBroadcastTransactions(args.GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST));
walletInstance->WalletLogPrintf("Wallet completed loading in %15dms\n", Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));

View File

@@ -871,6 +871,8 @@ public:
/** Mark a transaction as replaced by another transaction. */
bool MarkReplaced(const Txid& originalHash, const Txid& newHash);
static bool LoadWalletArgs(std::shared_ptr<CWallet> wallet, const WalletContext& context, bilingual_str& error, std::vector<bilingual_str>& warnings);
/* Initializes the wallet, returns a new CWallet instance or a null pointer in case of an error */
static std::shared_ptr<CWallet> Create(WalletContext& context, const std::string& name, std::unique_ptr<WalletDatabase> database, uint64_t wallet_creation_flags, bilingual_str& error, std::vector<bilingual_str>& warnings);