Merge 23c926d859 into merged_master (Bitcoin PR #18699)

This commit is contained in:
Andrew Poelstra 2020-11-26 01:08:37 +00:00
commit d4711bdf91
26 changed files with 278 additions and 239 deletions

View file

@ -29,6 +29,7 @@
#include <util/fees.h>
#include <util/moneystr.h>
#include <util/rbf.h>
#include <util/string.h>
#include <util/translation.h>
#include <validation.h>
#include <wallet/coincontrol.h>
@ -157,34 +158,34 @@ void UnloadWallet(std::shared_ptr<CWallet>&& wallet)
}
}
std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const WalletLocation& location, std::string& error, std::vector<std::string>& warnings)
std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const WalletLocation& location, bilingual_str& error, std::vector<bilingual_str>& warnings)
{
try {
if (!CWallet::Verify(chain, location, false, error, warnings)) {
error = "Wallet file verification failed: " + error;
error = Untranslated("Wallet file verification failed.") + Untranslated(" ") + error;
return nullptr;
}
std::shared_ptr<CWallet> wallet = CWallet::CreateWalletFromFile(chain, location, error, warnings);
if (!wallet) {
error = "Wallet loading failed: " + error;
error = Untranslated("Wallet loading failed.") + Untranslated(" ") + error;
return nullptr;
}
AddWallet(wallet);
wallet->postInitProcess();
return wallet;
} catch (const std::runtime_error& e) {
error = e.what();
error = Untranslated(e.what());
return nullptr;
}
}
std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, std::string& error, std::vector<std::string>& warnings)
std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings)
{
return LoadWallet(chain, WalletLocation(name), error, warnings);
}
WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, std::string& error, std::vector<std::string>& warnings, std::shared_ptr<CWallet>& result)
WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings, std::shared_ptr<CWallet>& result)
{
// Indicate that the wallet is actually supposed to be blank and not just blank to make it encrypted
bool create_blank = (wallet_creation_flags & WALLET_FLAG_BLANK_WALLET);
@ -197,39 +198,39 @@ WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString&
// Check the wallet file location
WalletLocation location(name);
if (location.Exists()) {
error = "Wallet " + location.GetName() + " already exists.";
error = strprintf(Untranslated("Wallet %s already exists."), location.GetName());
return WalletCreationStatus::CREATION_FAILED;
}
// Wallet::Verify will check if we're trying to create a wallet with a duplicate name.
if (!CWallet::Verify(chain, location, false, error, warnings)) {
error = "Wallet file verification failed: " + error;
error = Untranslated("Wallet file verification failed.") + Untranslated(" ") + error;
return WalletCreationStatus::CREATION_FAILED;
}
// Do not allow a passphrase when private keys are disabled
if (!passphrase.empty() && (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
error = "Passphrase provided but private keys are disabled. A passphrase is only used to encrypt private keys, so cannot be used for wallets with private keys disabled.";
error = Untranslated("Passphrase provided but private keys are disabled. A passphrase is only used to encrypt private keys, so cannot be used for wallets with private keys disabled.");
return WalletCreationStatus::CREATION_FAILED;
}
// Make the wallet
std::shared_ptr<CWallet> wallet = CWallet::CreateWalletFromFile(chain, location, error, warnings, wallet_creation_flags);
if (!wallet) {
error = "Wallet creation failed: " + error;
error = Untranslated("Wallet creation failed.") + Untranslated(" ") + error;
return WalletCreationStatus::CREATION_FAILED;
}
// Encrypt the wallet
if (!passphrase.empty() && !(wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
if (!wallet->EncryptWallet(passphrase)) {
error = "Error: Wallet created but failed to encrypt.";
error = Untranslated("Error: Wallet created but failed to encrypt.");
return WalletCreationStatus::ENCRYPTION_FAILED;
}
if (!create_blank) {
// Unlock the wallet
if (!wallet->Unlock(passphrase)) {
error = "Error: Wallet was encrypted but could not be unlocked";
error = Untranslated("Error: Wallet was encrypted but could not be unlocked");
return WalletCreationStatus::ENCRYPTION_FAILED;
}
@ -241,7 +242,7 @@ WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString&
} else {
for (auto spk_man : wallet->GetActiveScriptPubKeyMans()) {
if (!spk_man->SetupGeneration()) {
error = "Unable to generate initial keys";
error = Untranslated("Unable to generate initial keys");
return WalletCreationStatus::CREATION_FAILED;
}
}
@ -2882,7 +2883,7 @@ SigningResult CWallet::SignMessage(const std::string& message, const PKHash& pkh
return SigningResult::PRIVATE_KEY_NOT_AVAILABLE;
}
bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosInOut, std::string& strFailReason, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, CCoinControl coinControl)
bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosInOut, bilingual_str& error, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, CCoinControl coinControl)
{
std::vector<CRecipient> vecSend;
@ -2892,7 +2893,7 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
// ELEMENTS:
if (!txOut.nValue.IsExplicit() || !txOut.nAsset.IsExplicit()) {
strFailReason = _("Pre-funded amounts must be non-blinded").translated;
error = _("Pre-funded amounts must be non-blinded");
return false;
}
@ -2917,7 +2918,7 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
CTransactionRef tx_new;
BlindDetails* blind_details = g_con_elementsmode ? new BlindDetails() : NULL;
if (!CreateTransaction(vecSend, tx_new, nFeeRet, nChangePosInOut, strFailReason, coinControl, false, blind_details)) {
if (!CreateTransaction(vecSend, tx_new, nFeeRet, nChangePosInOut, error, coinControl, false, blind_details)) {
return false;
}
@ -3057,7 +3058,7 @@ void resetBlindDetails(BlindDetails* det) {
det->only_change_pos = -1;
}
bool fillBlindDetails(BlindDetails* det, CWallet* wallet, CMutableTransaction& txNew, std::vector<CInputCoin>& selected_coins, std::string& strFailReason) {
bool fillBlindDetails(BlindDetails* det, CWallet* wallet, CMutableTransaction& txNew, std::vector<CInputCoin>& selected_coins, bilingual_str& error) {
int num_inputs_blinded = 0;
// Fill in input blinding details
@ -3110,7 +3111,7 @@ bool fillBlindDetails(BlindDetails* det, CWallet* wallet, CMutableTransaction& t
det->o_asset_blinds[det->only_change_pos] = uint256();
wallet->WalletLogPrintf("Unblinding change at index %d due to lack of inputs and other outputs being blinded.\n", det->only_change_pos);
} else {
strFailReason = _("Change output could not be blinded as there are no blinded inputs and no other blinded outputs.").translated;
error = _("Change output could not be blinded as there are no blinded inputs and no other blinded outputs.");
return false;
}
} else {
@ -3125,7 +3126,7 @@ bool fillBlindDetails(BlindDetails* det, CWallet* wallet, CMutableTransaction& t
det->o_asset_blinds[det->only_recipient_blind_index] = uint256();
wallet->WalletLogPrintf("Unblinding single blinded output at index %d due to lack of inputs and other outputs being blinded.\n", det->only_recipient_blind_index);
} else {
strFailReason = _("Transaction output could not be blinded as there are no blinded inputs and no other blinded outputs.").translated;
error = _("Transaction output could not be blinded as there are no blinded inputs and no other blinded outputs.");
return false;
}
}
@ -3134,7 +3135,7 @@ bool fillBlindDetails(BlindDetails* det, CWallet* wallet, CMutableTransaction& t
return true;
}
bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransactionRef& tx, CAmount& nFeeRet, int& nChangePosInOut, std::string& strFailReason, const CCoinControl& coin_control, bool sign, BlindDetails* blind_details, const IssuanceDetails* issuance_details) {
bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransactionRef& tx, CAmount& nFeeRet, int& nChangePosInOut, bilingual_str& error, const CCoinControl& coin_control, bool sign, BlindDetails* blind_details, const IssuanceDetails* issuance_details) {
if (blind_details || issuance_details) {
assert(g_con_elementsmode);
}
@ -3164,12 +3165,12 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
}
if (g_con_elementsmode && recipient.asset.IsNull()) {
strFailReason = _("No asset provided for recipient").translated;
error = _("No asset provided for recipient");
return false;
}
if (mapValue[recipient.asset] < 0 || recipient.nAmount < 0) {
strFailReason = _("Transaction amounts must not be negative").translated;
error = _("Transaction amounts must not be negative");
return false;
}
mapValue[recipient.asset] += recipient.nAmount;
@ -3179,7 +3180,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
}
if (vecSend.empty())
{
strFailReason = _("Transaction must have at least one recipient").translated;
error = _("Transaction must have at least one recipient");
return false;
}
@ -3225,7 +3226,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
// destination in case we don't need change.
CTxDestination dest;
if (index >= reservedest.size() || !reservedest[index]->GetReservedDestination(dest, true)) {
strFailReason = _("Transaction needs a change address, but we can't generate it. Please call keypoolrefill first.").translated;
error = _("Transaction needs a change address, but we can't generate it. Please call keypoolrefill first.");
// ELEMENTS: We need to put a dummy destination here. Core uses an empty script
// but we can't because empty scripts indicate fees (which trigger assertation
// failures in `BlindTransaction`). We also set the index to -1, indicating
@ -3261,7 +3262,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
CTxDestination dest;
if (index >= reservedest.size() || !reservedest[index]->GetReservedDestination(dest, true)) {
strFailReason = _("Keypool ran out, please call keypoolrefill first").translated;
error = _("Keypool ran out, please call keypoolrefill first");
return false;
}
@ -3347,7 +3348,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
if (recipient.fSubtractFeeFromAmount)
{
if (recipient.asset != policyAsset) {
strFailReason = strprintf("Wallet does not support more than one type of fee at a time, therefore can not subtract fee from address amount, which is of a different asset id. fee asset: %s recipient asset: %s", policyAsset.GetHex(), recipient.asset.GetHex());
error = Untranslated(strprintf("Wallet does not support more than one type of fee at a time, therefore can not subtract fee from address amount, which is of a different asset id. fee asset: %s recipient asset: %s", policyAsset.GetHex(), recipient.asset.GetHex()));
return false;
}
@ -3368,12 +3369,12 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
if (recipient.fSubtractFeeFromAmount && nFeeRet > 0)
{
if (txout.nValue.GetAmount() < 0)
strFailReason = _("The transaction amount is too small to pay the fee").translated;
error = _("The transaction amount is too small to pay the fee");
else
strFailReason = _("The transaction amount is too small to send after the fee has been deducted").translated;
error = _("The transaction amount is too small to send after the fee has been deducted");
}
else
strFailReason = _("Transaction amount too small").translated;
error = _("Transaction amount too small");
return false;
}
@ -3415,7 +3416,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
continue;
}
else {
strFailReason = _("Insufficient funds").translated;
error = _("Insufficient funds");
return false;
}
}
@ -3434,7 +3435,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
// Fill a vout to ourself
const std::map<CAsset, std::pair<int, CScript>>::const_iterator itScript = mapScriptChange.find(assetChange.first);
if (itScript == mapScriptChange.end()) {
strFailReason = strprintf("No change destination provided for asset %s", assetChange.first.GetHex());
error = Untranslated(strprintf("No change destination provided for asset %s", assetChange.first.GetHex()));
return false;
}
@ -3467,7 +3468,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
}
else if ((unsigned int)itPos->second > txNew.vout.size())
{
strFailReason = _("Change index out of range").translated;
error = _("Change index out of range");
return false;
}
@ -3600,7 +3601,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
}
if (blind_details) {
if (!fillBlindDetails(blind_details, this, txNew, selected_coins, strFailReason)) {
if (!fillBlindDetails(blind_details, this, txNew, selected_coins, error)) {
return false;
}
@ -3609,14 +3610,14 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
int ret = BlindTransaction(blind_details->i_amount_blinds, blind_details->i_asset_blinds, blind_details->i_assets, blind_details->i_amounts, blind_details->o_amount_blinds, blind_details->o_asset_blinds, blind_details->o_pubkeys, issuance_asset_keys, issuance_token_keys, txNew);
assert(ret != -1);
if (ret != blind_details->num_to_blind) {
strFailReason = _("Unable to blind the transaction properly. This should not happen.").translated;
error = _("Unable to blind the transaction properly. This should not happen.");
return false;
}
}
nBytes = CalculateMaximumSignedTxSize(CTransaction(txNew), this, &coin_control);
if (nBytes < 0) {
strFailReason = _("Missing solving data for estimating transaction size").translated;
error = _("Missing solving data for estimating transaction size");
return false;
}
@ -3628,7 +3629,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
nFeeNeeded = GetMinimumFee(*this, nBytes, coin_control, &feeCalc);
if (feeCalc.reason == FeeReason::FALLBACK && !m_allow_fallback_fee) {
// eventually allow a fallback fee
strFailReason = _("Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.").translated;
error = _("Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.");
return false;
}
@ -3679,7 +3680,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
int ret = BlindTransaction(blind_details->i_amount_blinds, blind_details->i_asset_blinds, blind_details->i_assets, blind_details->i_amounts, blind_details->o_amount_blinds, blind_details->o_asset_blinds, blind_details->o_pubkeys, issuance_asset_keys, issuance_token_keys, txNew);
assert(ret != -1);
if (ret != blind_details->num_to_blind) {
strFailReason = _("Unable to blind the transaction properly. This should not happen.").translated;
error = _("Unable to blind the transaction properly. This should not happen.");
return false;
}
} else {
@ -3698,7 +3699,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
// fee to pay for the new output and still meet nFeeNeeded
// Or we should have just subtracted fee from recipients and
// nFeeNeeded should not have changed
strFailReason = _("Transaction fee and change calculation failed").translated;
error = _("Transaction fee and change calculation failed");
return false;
}
@ -3728,7 +3729,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
int ret = BlindTransaction(blind_details->i_amount_blinds, blind_details->i_asset_blinds, blind_details->i_assets, blind_details->i_amounts, blind_details->o_amount_blinds, blind_details->o_asset_blinds, blind_details->o_pubkeys, issuance_asset_keys, issuance_token_keys, txNew);
assert(ret != -1);
if (ret != blind_details->num_to_blind) {
strFailReason = _("Unable to blind the transaction properly. This should not happen.").translated;
error = _("Unable to blind the transaction properly. This should not happen.");
return false;
}
break; // Done, able to increase fee from change
@ -3844,7 +3845,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
if (sign) {
if (!SignTransaction(txNew)) {
strFailReason = _("Signing transaction failed").translated;
error = _("Signing transaction failed");
return false;
}
} else if (blind_details) {
@ -3864,20 +3865,20 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
// Limit size
if (GetTransactionWeight(*tx) > MAX_STANDARD_TX_WEIGHT)
{
strFailReason = _("Transaction too large").translated;
error = _("Transaction too large");
return false;
}
}
if (nFeeRet > m_default_max_tx_fee) {
strFailReason = TransactionErrorString(TransactionError::MAX_FEE_EXCEEDED);
error = Untranslated(TransactionErrorString(TransactionError::MAX_FEE_EXCEEDED));
return false;
}
if (gArgs.GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS)) {
// Lastly, ensure this tx will pass the mempool's chain limits
if (!chain().checkChainLimits(tx)) {
strFailReason = _("Transaction has too long of a mempool chain").translated;
error = _("Transaction has too long of a mempool chain");
return false;
}
}
@ -4595,7 +4596,7 @@ std::vector<std::string> CWallet::GetDestValues(const std::string& prefix) const
return values;
}
bool CWallet::Verify(interfaces::Chain& chain, const WalletLocation& location, bool salvage_wallet, std::string& error_string, std::vector<std::string>& warnings)
bool CWallet::Verify(interfaces::Chain& chain, const WalletLocation& location, bool salvage_wallet, bilingual_str& error_string, std::vector<bilingual_str>& warnings)
{
// Do some checking on wallet path. It should be either a:
//
@ -4609,17 +4610,17 @@ bool CWallet::Verify(interfaces::Chain& chain, const WalletLocation& location, b
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(location.GetName()).filename() == location.GetName()))) {
error_string = strprintf(
error_string = Untranslated(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)",
location.GetName(), GetWalletDir());
location.GetName(), GetWalletDir()));
return false;
}
// Make sure that the wallet path doesn't clash with an existing wallet path
if (IsWalletLoaded(wallet_path)) {
error_string = strprintf("Error loading wallet %s. Duplicate -wallet filename specified.", location.GetName());
error_string = Untranslated(strprintf("Error loading wallet %s. Duplicate -wallet filename specified.", location.GetName()));
return false;
}
@ -4631,7 +4632,7 @@ bool CWallet::Verify(interfaces::Chain& chain, const WalletLocation& location, b
return false;
}
} catch (const fs::filesystem_error& e) {
error_string = strprintf("Error loading wallet %s. %s", location.GetName(), fsbridge::get_filesystem_error_message(e));
error_string = Untranslated(strprintf("Error loading wallet %s. %s", location.GetName(), fsbridge::get_filesystem_error_message(e)));
return false;
}
@ -4647,7 +4648,7 @@ bool CWallet::Verify(interfaces::Chain& chain, const WalletLocation& location, b
return WalletBatch::VerifyDatabaseFile(wallet_path, warnings, error_string);
}
std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, const WalletLocation& location, std::string& error, std::vector<std::string>& warnings, uint64_t wallet_creation_flags)
std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, const WalletLocation& location, bilingual_str& error, std::vector<bilingual_str>& warnings, uint64_t wallet_creation_flags)
{
const std::string walletFile = WalletDataFilePath(location.GetPath()).string();
@ -4660,7 +4661,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
std::unique_ptr<CWallet> tempWallet = MakeUnique<CWallet>(&chain, location, WalletDatabase::Create(location.GetPath()));
DBErrors nZapWalletRet = tempWallet->ZapWalletTx(vWtx);
if (nZapWalletRet != DBErrors::LOAD_OK) {
error = strprintf(_("Error loading %s: Wallet corrupted").translated, walletFile);
error = strprintf(_("Error loading %s: Wallet corrupted"), walletFile);
return nullptr;
}
}
@ -4675,26 +4676,26 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
DBErrors nLoadWalletRet = walletInstance->LoadWallet(fFirstRun);
if (nLoadWalletRet != DBErrors::LOAD_OK) {
if (nLoadWalletRet == DBErrors::CORRUPT) {
error = strprintf(_("Error loading %s: Wallet corrupted").translated, walletFile);
error = strprintf(_("Error loading %s: Wallet corrupted"), walletFile);
return nullptr;
}
else if (nLoadWalletRet == DBErrors::NONCRITICAL_ERROR)
{
warnings.push_back(strprintf(_("Error reading %s! All keys read correctly, but transaction data"
" or address book entries might be missing or incorrect.").translated,
" or address book entries might be missing or incorrect."),
walletFile));
}
else if (nLoadWalletRet == DBErrors::TOO_NEW) {
error = strprintf(_("Error loading %s: Wallet requires newer version of %s").translated, walletFile, PACKAGE_NAME);
error = strprintf(_("Error loading %s: Wallet requires newer version of %s"), walletFile, PACKAGE_NAME);
return nullptr;
}
else if (nLoadWalletRet == DBErrors::NEED_REWRITE)
{
error = strprintf(_("Wallet needed to be rewritten: restart %s to complete").translated, PACKAGE_NAME);
error = strprintf(_("Wallet needed to be rewritten: restart %s to complete"), PACKAGE_NAME);
return nullptr;
}
else {
error = strprintf(_("Error loading %s").translated, walletFile);
error = strprintf(_("Error loading %s"), walletFile);
return nullptr;
}
}
@ -4720,7 +4721,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
// Legacy wallets need SetupGeneration here.
for (auto spk_man : walletInstance->GetActiveScriptPubKeyMans()) {
if (!spk_man->SetupGeneration()) {
error = _("Unable to generate initial keys").translated;
error = _("Unable to generate initial keys");
return nullptr;
}
}
@ -4730,36 +4731,36 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
walletInstance->chainStateFlushed(chain.getTipLocator());
} else if (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS) {
// Make it impossible to disable private keys after creation
error = strprintf(_("Error loading %s: Private keys can only be disabled during creation").translated, walletFile);
error = strprintf(_("Error loading %s: Private keys can only be disabled during creation"), walletFile);
return NULL;
} else if (walletInstance->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
for (auto spk_man : walletInstance->GetActiveScriptPubKeyMans()) {
if (spk_man->HavePrivateKeys()) {
warnings.push_back(strprintf(_("Warning: Private keys detected in wallet {%s} with disabled private keys").translated, walletFile));
warnings.push_back(strprintf(_("Warning: Private keys detected in wallet {%s} with disabled private keys"), walletFile));
break;
}
}
}
if (!gArgs.GetArg("-addresstype", "").empty() && !ParseOutputType(gArgs.GetArg("-addresstype", ""), walletInstance->m_default_address_type)) {
error = strprintf(_("Unknown address type '%s'").translated, gArgs.GetArg("-addresstype", ""));
error = strprintf(_("Unknown address type '%s'"), gArgs.GetArg("-addresstype", ""));
return nullptr;
}
if (!gArgs.GetArg("-changetype", "").empty() && !ParseOutputType(gArgs.GetArg("-changetype", ""), walletInstance->m_default_change_type)) {
error = strprintf(_("Unknown change type '%s'").translated, gArgs.GetArg("-changetype", ""));
error = strprintf(_("Unknown change type '%s'"), gArgs.GetArg("-changetype", ""));
return nullptr;
}
if (gArgs.IsArgSet("-mintxfee")) {
CAmount n = 0;
if (!ParseMoney(gArgs.GetArg("-mintxfee", ""), n) || 0 == n) {
error = AmountErrMsg("mintxfee", gArgs.GetArg("-mintxfee", "")).translated;
error = AmountErrMsg("mintxfee", gArgs.GetArg("-mintxfee", ""));
return nullptr;
}
if (n > HIGH_TX_FEE_PER_KB) {
warnings.push_back(AmountHighWarn("-mintxfee").translated + " " +
_("This is the minimum transaction fee you pay on every transaction.").translated);
warnings.push_back(AmountHighWarn("-mintxfee") + Untranslated(" ") +
_("This is the minimum transaction fee you pay on every transaction."));
}
walletInstance->m_min_fee = CFeeRate(n);
}
@ -4767,12 +4768,12 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
if (gArgs.IsArgSet("-fallbackfee")) {
CAmount nFeePerK = 0;
if (!ParseMoney(gArgs.GetArg("-fallbackfee", ""), nFeePerK)) {
error = strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'").translated, gArgs.GetArg("-fallbackfee", ""));
error = strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'"), gArgs.GetArg("-fallbackfee", ""));
return nullptr;
}
if (nFeePerK > HIGH_TX_FEE_PER_KB) {
warnings.push_back(AmountHighWarn("-fallbackfee").translated + " " +
_("This is the transaction fee you may pay when fee estimates are not available.").translated);
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(nFeePerK);
}
@ -4782,28 +4783,28 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
if (gArgs.IsArgSet("-discardfee")) {
CAmount nFeePerK = 0;
if (!ParseMoney(gArgs.GetArg("-discardfee", ""), nFeePerK)) {
error = strprintf(_("Invalid amount for -discardfee=<amount>: '%s'").translated, gArgs.GetArg("-discardfee", ""));
error = strprintf(_("Invalid amount for -discardfee=<amount>: '%s'"), gArgs.GetArg("-discardfee", ""));
return nullptr;
}
if (nFeePerK > HIGH_TX_FEE_PER_KB) {
warnings.push_back(AmountHighWarn("-discardfee").translated + " " +
_("This is the transaction fee you may discard if change is smaller than dust at this level").translated);
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(nFeePerK);
}
if (gArgs.IsArgSet("-paytxfee")) {
CAmount nFeePerK = 0;
if (!ParseMoney(gArgs.GetArg("-paytxfee", ""), nFeePerK)) {
error = AmountErrMsg("paytxfee", gArgs.GetArg("-paytxfee", "")).translated;
error = AmountErrMsg("paytxfee", gArgs.GetArg("-paytxfee", ""));
return nullptr;
}
if (nFeePerK > HIGH_TX_FEE_PER_KB) {
warnings.push_back(AmountHighWarn("-paytxfee").translated + " " +
_("This is the transaction fee you will pay if you send a transaction.").translated);
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(nFeePerK, 1000);
if (walletInstance->m_pay_tx_fee < chain.relayMinFee()) {
error = strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)").translated,
error = strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"),
gArgs.GetArg("-paytxfee", ""), chain.relayMinFee().ToString());
return nullptr;
}
@ -4812,23 +4813,23 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
if (gArgs.IsArgSet("-maxtxfee")) {
CAmount nMaxFee = 0;
if (!ParseMoney(gArgs.GetArg("-maxtxfee", ""), nMaxFee)) {
error = AmountErrMsg("maxtxfee", gArgs.GetArg("-maxtxfee", "")).translated;
error = AmountErrMsg("maxtxfee", gArgs.GetArg("-maxtxfee", ""));
return nullptr;
}
if (nMaxFee > HIGH_MAX_TX_FEE) {
warnings.push_back(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction.").translated);
warnings.push_back(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction."));
}
if (CFeeRate(nMaxFee, 1000) < chain.relayMinFee()) {
error = strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)").translated,
gArgs.GetArg("-maxtxfee", ""), chain.relayMinFee().ToString());
error = strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
gArgs.GetArg("-maxtxfee", ""), chain.relayMinFee().ToString());
return nullptr;
}
walletInstance->m_default_max_tx_fee = nMaxFee;
}
if (chain.relayMinFee().GetFeePerK() > HIGH_TX_FEE_PER_KB) {
warnings.push_back(AmountHighWarn("-minrelaytxfee").translated + " " +
_("The wallet will avoid paying less than the minimum relay fee.").translated);
warnings.push_back(AmountHighWarn("-minrelaytxfee") + Untranslated(" ") +
_("The wallet will avoid paying less than the minimum relay fee."));
}
walletInstance->m_confirm_target = gArgs.GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET);
@ -4888,7 +4889,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
}
if (rescan_height != block_height) {
error = _("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)").translated;
error = _("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)");
return nullptr;
}
}
@ -4913,7 +4914,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
{
WalletRescanReserver reserver(*walletInstance);
if (!reserver.reserve() || (ScanResult::SUCCESS != walletInstance->ScanForWalletTransactions(chain.getBlockHash(rescan_height), rescan_height, {} /* max height */, reserver, true /* update */).status)) {
error = _("Failed to rescan the wallet during initialization").translated;
error = _("Failed to rescan the wallet during initialization");
return nullptr;
}
}
@ -4973,7 +4974,7 @@ const CAddressBookData* CWallet::FindAddressBookEntry(const CTxDestination& dest
return &address_book_it->second;
}
bool CWallet::UpgradeWallet(int version, std::string& error, std::vector<std::string>& warnings)
bool CWallet::UpgradeWallet(int version, bilingual_str& error, std::vector<bilingual_str>& warnings)
{
int prev_version = GetVersion();
int nMaxVersion = version;
@ -4982,12 +4983,12 @@ bool CWallet::UpgradeWallet(int version, std::string& error, std::vector<std::st
WalletLogPrintf("Performing wallet upgrade to %i\n", FEATURE_LATEST);
nMaxVersion = FEATURE_LATEST;
SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately
}
else
} else {
WalletLogPrintf("Allowing wallet upgrade up to %i\n", nMaxVersion);
}
if (nMaxVersion < GetVersion())
{
error = _("Cannot downgrade wallet").translated;
error = _("Cannot downgrade wallet");
return false;
}
SetMaxVersion(nMaxVersion);
@ -4997,7 +4998,7 @@ bool CWallet::UpgradeWallet(int version, std::string& error, std::vector<std::st
// Do not upgrade versions to any version between HD_SPLIT and FEATURE_PRE_SPLIT_KEYPOOL unless already supporting HD_SPLIT
int max_version = GetVersion();
if (!CanSupportFeature(FEATURE_HD_SPLIT) && max_version >= FEATURE_HD_SPLIT && max_version < FEATURE_PRE_SPLIT_KEYPOOL) {
error = _("Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use version 169900 or no version specified.").translated;
error = _("Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use version 169900 or no version specified.");
return false;
}