diff --git a/src/coinjoin/client.cpp b/src/coinjoin/client.cpp index e260ca21abeb8e..a0de82d350056b 100644 --- a/src/coinjoin/client.cpp +++ b/src/coinjoin/client.cpp @@ -638,14 +638,14 @@ bool CCoinJoinClientSession::SignFinalTransaction(CNode& peer, CChainState& acti // fill values for found outpoints m_wallet.chain().findCoins(coins); - std::map<int, std::string> signing_errors; + std::map<int, bilingual_str> signing_errors; m_wallet.SignTransaction(finalMutableTransaction, coins, SIGHASH_ALL | SIGHASH_ANYONECANPAY, signing_errors); for (const auto& [input_index, error_string] : signing_errors) { // NOTE: this is a partial signing so it's expected for SignTransaction to return // "Input not found or already spent" errors for inputs that aren't ours - if (error_string != "Input not found or already spent") { - WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::%s -- signing input %d failed: %s!\n", __func__, input_index, error_string); + if (error_string.original != "Input not found or already spent") { + WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::%s -- signing input %d failed: %s!\n", __func__, input_index, error_string.original); UnlockCoins(); keyHolderStorage.ReturnAll(); SetNull(); diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h index dcc399a29de9d8..d84688dcc0b247 100644 --- a/src/interfaces/chain.h +++ b/src/interfaces/chain.h @@ -198,7 +198,7 @@ class Chain virtual bool broadcastTransaction(const CTransactionRef& tx, const CAmount& max_tx_fee, bool relay, - std::string& err_string) = 0; + bilingual_str& err_string) = 0; //! Calculate mempool ancestor and descendant counts for the given transaction. virtual void getTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants) = 0; diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index be4a3de4217dcb..c29f536374b407 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -883,7 +883,7 @@ class ChainImpl : public Chain auto it = m_node.mempool->GetIter(txid); return it && (*it)->GetCountWithDescendants() > 1; } - bool broadcastTransaction(const CTransactionRef& tx, const CAmount& max_tx_fee, bool relay, std::string& err_string) override + bool broadcastTransaction(const CTransactionRef& tx, const CAmount& max_tx_fee, bool relay, bilingual_str& err_string) override { const TransactionError err = BroadcastTransaction(m_node, tx, err_string, max_tx_fee, relay, /*wait_callback*/ false); // Chain clients only care about failures to accept the tx to the mempool. Disregard non-mempool related failures. diff --git a/src/node/transaction.cpp b/src/node/transaction.cpp index 76264ffb1cfda1..9c039c1a6e0bac 100644 --- a/src/node/transaction.cpp +++ b/src/node/transaction.cpp @@ -13,6 +13,7 @@ #include <validationinterface.h> #include <node/context.h> #include <node/transaction.h> +#include <util/translation.h> #include <future> @@ -28,7 +29,7 @@ static TransactionError HandleATMPError(const TxValidationState& state, std::str } } -TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef tx, std::string& err_string, const CAmount& max_tx_fee, bool relay, bool wait_callback, bool bypass_limits) +TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef tx, bilingual_str& err_string, const CAmount& max_tx_fee, bool relay, bool wait_callback, bool bypass_limits) { // BroadcastTransaction can be called by either sendrawtransaction RPC or wallet RPCs. // node.peerman is assigned both before chain clients and before RPC server is accepting calls, @@ -59,7 +60,7 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t const MempoolAcceptResult result = AcceptToMemoryPool(node.chainman->ActiveChainstate(), *node.mempool, tx, bypass_limits, true /* test_accept */); if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) { - return HandleATMPError(result.m_state, err_string); + return HandleATMPError(result.m_state, err_string.original); } else if (result.m_base_fees.value() > max_tx_fee) { return TransactionError::MAX_FEE_EXCEEDED; } @@ -68,7 +69,7 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t const MempoolAcceptResult result = AcceptToMemoryPool(node.chainman->ActiveChainstate(), *node.mempool, tx, bypass_limits, false /* test_accept */); if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) { - return HandleATMPError(result.m_state, err_string); + return HandleATMPError(result.m_state, err_string.original); } // Transaction was accepted to the mempool. diff --git a/src/node/transaction.h b/src/node/transaction.h index 7da45f602865dd..315c22cad8bcc4 100644 --- a/src/node/transaction.h +++ b/src/node/transaction.h @@ -35,13 +35,13 @@ static const CFeeRate DEFAULT_MAX_RAW_TX_FEE_RATE{COIN / 10}; * * @param[in] node reference to node context * @param[in] tx the transaction to broadcast - * @param[out] err_string reference to std::string to fill with error string if available + * @param[out] err_string reference to bilingual_str to fill with error string if available * @param[in] max_tx_fee reject txs with fees higher than this (if 0, accept any fee) * @param[in] relay flag if both mempool insertion and p2p relay are requested * @param[in] wait_callback wait until callbacks have been processed to avoid stale result due to a sequentially RPC. * return error */ -[[nodiscard]] TransactionError BroadcastTransaction(NodeContext& node, CTransactionRef tx, std::string& err_string, const CAmount& highfee, bool relay, bool wait_callback, bool bypass_limits = false); +[[nodiscard]] TransactionError BroadcastTransaction(NodeContext& node, CTransactionRef tx, bilingual_str& err_string, const CAmount& highfee, bool relay, bool wait_callback, bool bypass_limits = false); /** * Return transaction with a given hash. diff --git a/src/qt/psbtoperationsdialog.cpp b/src/qt/psbtoperationsdialog.cpp index b6229531926ba6..c31ca27ef6e9ee 100644 --- a/src/qt/psbtoperationsdialog.cpp +++ b/src/qt/psbtoperationsdialog.cpp @@ -100,7 +100,7 @@ void PSBTOperationsDialog::broadcastTransaction() } CTransactionRef tx = MakeTransactionRef(mtx); - std::string err_string; + bilingual_str err_string; TransactionError error = BroadcastTransaction( *m_client_model->node().context(), tx, err_string, DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK(), /* relay */ true, /* await_callback */ false); diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index da0010acc6ab6e..c8bda878d312b2 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -41,6 +41,7 @@ #include <util/moneystr.h> #include <util/strencodings.h> #include <util/string.h> +#include <util/translation.h> #include <validation.h> #include <validationinterface.h> #include <util/irange.h> @@ -1164,12 +1165,12 @@ RPCHelpMan sendrawtransaction() bool bypass_limits = false; if (!request.params[3].isNull()) bypass_limits = request.params[3].get_bool(); - std::string err_string; + bilingual_str err_string; AssertLockNotHeld(cs_main); NodeContext& node = EnsureAnyNodeContext(request.context); const TransactionError err = BroadcastTransaction(node, tx, err_string, max_raw_tx_fee, /* relay */ true, /* wait_callback */ true, bypass_limits); if (TransactionError::OK != err) { - throw JSONRPCTransactionError(err, err_string); + throw JSONRPCTransactionError(err, err_string.original); } return tx->GetHash().GetHex(); diff --git a/src/rpc/rawtransaction_util.cpp b/src/rpc/rawtransaction_util.cpp index 11df0c274ef665..6453c14622f74e 100644 --- a/src/rpc/rawtransaction_util.cpp +++ b/src/rpc/rawtransaction_util.cpp @@ -18,6 +18,7 @@ #include <util/strencodings.h> #include <validation.h> #include <txmempool.h> +#include <util/translation.h> CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime) { @@ -227,22 +228,22 @@ void SignTransaction(CMutableTransaction& mtx, const SigningProvider* keystore, int nHashType = ParseSighashString(hashType); // Script verification errors - std::map<int, std::string> input_errors; + std::map<int, bilingual_str> input_errors; bool complete = SignTransaction(mtx, keystore, coins, nHashType, input_errors); SignTransactionResultToJSON(mtx, complete, coins, input_errors, result); } -void SignTransactionResultToJSON(CMutableTransaction& mtx, bool complete, const std::map<COutPoint, Coin>& coins, const std::map<int, std::string>& input_errors, UniValue& result) +void SignTransactionResultToJSON(CMutableTransaction& mtx, bool complete, const std::map<COutPoint, Coin>& coins, const std::map<int, bilingual_str>& input_errors, UniValue& result) { // Make errors UniValue UniValue vErrors(UniValue::VARR); for (const auto& err_pair : input_errors) { - if (err_pair.second == "Missing amount") { + if (err_pair.second.original == "Missing amount") { // This particular error needs to be an exception for some reason throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing amount for %s", coins.at(mtx.vin.at(err_pair.first).prevout).out.ToString())); } - TxInErrorToJSON(mtx.vin.at(err_pair.first), vErrors, err_pair.second); + TxInErrorToJSON(mtx.vin.at(err_pair.first), vErrors, err_pair.second.original); } result.pushKV("hex", EncodeHexTx(CTransaction(mtx))); diff --git a/src/rpc/rawtransaction_util.h b/src/rpc/rawtransaction_util.h index f36a7c092b2365..c7c9c471b0c8d9 100644 --- a/src/rpc/rawtransaction_util.h +++ b/src/rpc/rawtransaction_util.h @@ -8,6 +8,7 @@ #include <map> #include <string> +struct bilingual_str; class FillableSigningProvider; class UniValue; struct CMutableTransaction; @@ -26,7 +27,7 @@ class SigningProvider; * @param result JSON object where signed transaction results accumulate */ void SignTransaction(CMutableTransaction& mtx, const SigningProvider* keystore, const std::map<COutPoint, Coin>& coins, const UniValue& hashType, UniValue& result); -void SignTransactionResultToJSON(CMutableTransaction& mtx, bool complete, const std::map<COutPoint, Coin>& coins, const std::map<int, std::string>& input_errors, UniValue& result); +void SignTransactionResultToJSON(CMutableTransaction& mtx, bool complete, const std::map<COutPoint, Coin>& coins, const std::map<int, bilingual_str>& input_errors, UniValue& result); /** * Parse a prevtxs UniValue array and get the map of coins from it diff --git a/src/script/sign.cpp b/src/script/sign.cpp index bb120d784c29c7..c9491f65f57d93 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -11,6 +11,7 @@ #include <script/signingprovider.h> #include <script/standard.h> #include <uint256.h> +#include <util/translation.h> typedef std::vector<unsigned char> valtype; @@ -385,7 +386,7 @@ bool IsSolvable(const SigningProvider& provider, const CScript& script) return false; } -bool SignTransaction(CMutableTransaction& mtx, const SigningProvider* keystore, const std::map<COutPoint, Coin>& coins, int nHashType, std::map<int, std::string>& input_errors) +bool SignTransaction(CMutableTransaction& mtx, const SigningProvider* keystore, const std::map<COutPoint, Coin>& coins, int nHashType, std::map<int, bilingual_str>& input_errors) { bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE); @@ -397,7 +398,7 @@ bool SignTransaction(CMutableTransaction& mtx, const SigningProvider* keystore, CTxIn& txin = mtx.vin[i]; auto coin = coins.find(txin.prevout); if (coin == coins.end() || coin->second.IsSpent()) { - input_errors[i] = "Input not found or already spent"; + input_errors[i] = _("Input not found or already spent"); continue; } const CScript& prevPubKey = coin->second.out.scriptPubKey; @@ -415,12 +416,12 @@ bool SignTransaction(CMutableTransaction& mtx, const SigningProvider* keystore, if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), &serror)) { if (serror == SCRIPT_ERR_INVALID_STACK_OPERATION) { // Unable to sign input and verification failed (possible attempt to partially sign). - input_errors[i] = "Unable to sign input, invalid stack size (possibly missing key)"; + input_errors[i] = Untranslated("Unable to sign input, invalid stack size (possibly missing key)"); } else if (serror == SCRIPT_ERR_SIG_NULLFAIL) { // Verification failed (possibly due to insufficient signatures). - input_errors[i] = "CHECK(MULTI)SIG failing with non-zero signature (possibly need more signatures)"; + input_errors[i] = Untranslated("CHECK(MULTI)SIG failing with non-zero signature (possibly need more signatures)"); } else { - input_errors[i] = ScriptErrorString(serror); + input_errors[i] = Untranslated(ScriptErrorString(serror)); } } else { // If this input succeeds, make sure there is no error set for it diff --git a/src/script/sign.h b/src/script/sign.h index 61881215ea6485..e1311a22834562 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -20,6 +20,7 @@ class CScriptID; class CTransaction; class SigningProvider; +struct bilingual_str; struct CMutableTransaction; /** Interface for signature creators. */ @@ -163,6 +164,6 @@ void UpdateInput(CTxIn& input, const SignatureData& data); bool IsSolvable(const SigningProvider& provider, const CScript& script); /** Sign the CMutableTransaction */ -bool SignTransaction(CMutableTransaction& mtx, const SigningProvider* provider, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, std::string>& input_errors); +bool SignTransaction(CMutableTransaction& mtx, const SigningProvider* provider, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, bilingual_str>& input_errors); #endif // BITCOIN_SCRIPT_SIGN_H diff --git a/src/test/fuzz/script_sign.cpp b/src/test/fuzz/script_sign.cpp index eb83d7074e54f8..8f2159fa61339d 100644 --- a/src/test/fuzz/script_sign.cpp +++ b/src/test/fuzz/script_sign.cpp @@ -13,6 +13,7 @@ #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> +#include <util/translation.h> #include <cassert> #include <cstdint> @@ -134,7 +135,7 @@ FUZZ_TARGET_INIT(script_sign, initialize_script_sign) } coins[*outpoint] = *coin; } - std::map<int, std::string> input_errors; + std::map<int, bilingual_str> input_errors; // (void)SignTransaction(sign_transaction_tx_to, &provider, coins, fuzzed_data_provider.ConsumeIntegral<int>(), input_errors); } } diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index 742eda02d449d5..08cdf92d9f291a 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -479,7 +479,7 @@ CMutableTransaction TestChainSetup::CreateValidMempoolTransaction(CTransactionRe input_coins.insert({outpoint_to_spend, utxo_to_spend}); // - Default signature hashing type int nHashType = SIGHASH_ALL; - std::map<int, std::string> input_errors; + std::map<int, bilingual_str> input_errors; assert(SignTransaction(mempool_txn, &keystore, input_coins, nHashType, input_errors)); // If submit=true, add transaction to the mempool. diff --git a/src/test/util/wallet.cpp b/src/test/util/wallet.cpp index c3f6856e5e4009..ee0457097db524 100644 --- a/src/test/util/wallet.cpp +++ b/src/test/util/wallet.cpp @@ -8,6 +8,7 @@ #include <outputtype.h> #include <script/standard.h> #ifdef ENABLE_WALLET +#include <util/translation.h> #include <wallet/wallet.h> #endif @@ -18,7 +19,7 @@ const std::string ADDRESS_BCRT1_UNSPENDABLE = "bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqq std::string getnewaddress(CWallet& w) { CTxDestination dest; - std::string error; + bilingual_str error; if (!w.GetNewDestination("", dest, error)) assert(false); return EncodeDestination(dest); diff --git a/src/util/translation.h b/src/util/translation.h index 3b27704f5237cd..7ce78c5faa751d 100644 --- a/src/util/translation.h +++ b/src/util/translation.h @@ -30,6 +30,12 @@ struct bilingual_str { { return original.empty(); } + + void clear() + { + original.clear(); + translated.clear(); + } }; inline bilingual_str operator+(bilingual_str lhs, const bilingual_str& rhs) diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp index 9f1ebb49fda765..cd501631f40f49 100644 --- a/src/wallet/interfaces.cpp +++ b/src/wallet/interfaces.cpp @@ -18,6 +18,7 @@ #include <uint256.h> #include <util/check.h> #include <util/system.h> +#include <util/translation.h> #include <util/ui_change_type.h> #include <validation.h> #include <wallet/context.h> @@ -155,7 +156,7 @@ class WalletImpl : public Wallet bool getNewDestination(const std::string label, CTxDestination& dest) override { LOCK(m_wallet->cs_wallet); - std::string error; + bilingual_str error; return m_wallet->GetNewDestination(label, dest, error); } bool getPubKey(const CScript& script, const CKeyID& address, CPubKey& pub_key) override diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index f9b29f28e5aac3..b684f1bd7dc92f 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -268,9 +268,9 @@ RPCHelpMan getnewaddress() label = LabelFromValue(request.params[0]); CTxDestination dest; - std::string error; + bilingual_str error; if (!pwallet->GetNewDestination(label, dest, error)) { - throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, error); + throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, error.original); } return EncodeDestination(dest); }, @@ -303,9 +303,9 @@ RPCHelpMan getrawchangeaddress() } CTxDestination dest; - std::string error; + bilingual_str error; if (!pwallet->GetNewChangeDestination(dest, error)) { - throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, error); + throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, error.original); } return EncodeDestination(dest); }, @@ -3695,7 +3695,7 @@ RPCHelpMan signrawtransactionwithwallet() int nHashType = ParseSighashString(request.params[2]); // Script verification errors - std::map<int, std::string> input_errors; + std::map<int, bilingual_str> input_errors; bool complete = pwallet->SignTransaction(mtx, coins, nHashType, input_errors); UniValue result(UniValue::VOBJ); diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index 678022e1f22e75..834acec3489020 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -15,7 +15,7 @@ #include <util/translation.h> #include <wallet/scriptpubkeyman.h> -bool LegacyScriptPubKeyMan::GetNewDestination(CTxDestination& dest, std::string& error) +bool LegacyScriptPubKeyMan::GetNewDestination(CTxDestination& dest, bilingual_str& error) { LOCK(cs_KeyStore); error.clear(); @@ -23,7 +23,7 @@ bool LegacyScriptPubKeyMan::GetNewDestination(CTxDestination& dest, std::string& // Generate a new key that is added to wallet CPubKey new_key; if (!GetKeyFromPool(new_key, false)) { - error = _("Error: Keypool ran out, please call keypoolrefill first").translated; + error = _("Error: Keypool ran out, please call keypoolrefill first"); return false; } //LearnRelatedScripts(new_key); @@ -709,7 +709,7 @@ bool LegacyScriptPubKeyMan::CanProvide(const CScript& script, SignatureData& sig } } -bool LegacyScriptPubKeyMan::SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, std::string>& input_errors) const +bool LegacyScriptPubKeyMan::SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, bilingual_str>& input_errors) const { return ::SignTransaction(tx, this, coins, sighash, input_errors); } @@ -1775,11 +1775,11 @@ bool LegacyScriptPubKeyMan::GetHDChain(CHDChain& hdChainRet) const void LegacyScriptPubKeyMan::SetInternal(bool internal) {} -bool DescriptorScriptPubKeyMan::GetNewDestination(CTxDestination& dest, std::string& error) +bool DescriptorScriptPubKeyMan::GetNewDestination(CTxDestination& dest, bilingual_str& error) { // Returns true if this descriptor supports getting new addresses. Conditions where we may be unable to fetch them (e.g. locked) are caught later if (!CanGetAddresses(m_internal)) { - error = "No addresses available"; + error = _("No addresses available"); return false; } { @@ -1793,12 +1793,12 @@ bool DescriptorScriptPubKeyMan::GetNewDestination(CTxDestination& dest, std::str std::vector<CScript> scripts_temp; if (m_wallet_descriptor.range_end <= m_max_cached_index && !TopUp(1)) { // We can't generate anymore keys - error = "Error: Keypool ran out, please call keypoolrefill first"; + error = _("Error: Keypool ran out, please call keypoolrefill first"); return false; } if (!m_wallet_descriptor.descriptor->ExpandFromCache(m_wallet_descriptor.next_index, m_wallet_descriptor.cache, scripts_temp, out_keys)) { // We can't generate anymore keys - error = "Error: Keypool ran out, please call keypoolrefill first"; + error = _("Error: Keypool ran out, please call keypoolrefill first"); return false; } const OutputType type{OutputType::LEGACY}; @@ -1881,7 +1881,7 @@ bool DescriptorScriptPubKeyMan::Encrypt(const CKeyingMaterial& master_key, Walle bool DescriptorScriptPubKeyMan::GetReservedDestination(bool internal, CTxDestination& address, int64_t& index, CKeyPool& keypool) { LOCK(cs_desc_man); - std::string error; + bilingual_str error; bool result = GetNewDestination(address, error); index = m_wallet_descriptor.next_index - 1; return result; @@ -2181,7 +2181,7 @@ bool DescriptorScriptPubKeyMan::CanProvide(const CScript& script, SignatureData& return IsMine(script); } -bool DescriptorScriptPubKeyMan::SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, std::string>& input_errors) const +bool DescriptorScriptPubKeyMan::SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, bilingual_str>& input_errors) const { std::unique_ptr<FlatSigningProvider> keys = std::make_unique<FlatSigningProvider>(); for (const auto& coin_pair : coins) { diff --git a/src/wallet/scriptpubkeyman.h b/src/wallet/scriptpubkeyman.h index 9c639b73ebfb7b..abe25c4512ae09 100644 --- a/src/wallet/scriptpubkeyman.h +++ b/src/wallet/scriptpubkeyman.h @@ -159,7 +159,7 @@ class ScriptPubKeyMan explicit ScriptPubKeyMan(WalletStorage& storage) : m_storage(storage) {} virtual ~ScriptPubKeyMan() {}; - virtual bool GetNewDestination(CTxDestination& dest, std::string& error) { return false; } + virtual bool GetNewDestination(CTxDestination& dest, bilingual_str& error) { return false; } virtual isminetype IsMine(const CScript& script) const { return ISMINE_NO; } virtual isminetype IsMine(const CTxDestination& dest) const { return ISMINE_NO; } @@ -208,7 +208,7 @@ class ScriptPubKeyMan virtual bool CanProvide(const CScript& script, SignatureData& sigdata) { return false; } /** Creates new signatures and adds them to the transaction. Returns whether all inputs were signed */ - virtual bool SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, std::string>& input_errors) const { return false; } + virtual bool SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, bilingual_str>& input_errors) const { return false; } /** Sign a message with the given script */ virtual SigningResult SignMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) const { return SigningResult::SIGNING_FAILED; }; virtual bool SignSpecialTxPayload(const uint256& hash, const CKeyID& keyid, std::vector<unsigned char>& vchSig) const { return false; } @@ -317,7 +317,7 @@ class LegacyScriptPubKeyMan : public ScriptPubKeyMan, public FillableSigningProv public: using ScriptPubKeyMan::ScriptPubKeyMan; - bool GetNewDestination(CTxDestination& dest, std::string& error) override; + bool GetNewDestination(CTxDestination& dest, bilingual_str& error) override; isminetype IsMine(const CScript& script) const override; isminetype IsMine(const CTxDestination& dest) const override; @@ -357,7 +357,7 @@ class LegacyScriptPubKeyMan : public ScriptPubKeyMan, public FillableSigningProv bool CanProvide(const CScript& script, SignatureData& sigdata) override; - bool SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, std::string>& input_errors) const override; + bool SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, bilingual_str>& input_errors) const override; SigningResult SignMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) const override; bool SignSpecialTxPayload(const uint256& hash, const CKeyID& keyid, std::vector<unsigned char>& vchSig) const override; TransactionError FillPSBT(PartiallySignedTransaction& psbt, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr) const override; @@ -550,7 +550,7 @@ class DescriptorScriptPubKeyMan : public ScriptPubKeyMan mutable RecursiveMutex cs_desc_man; - bool GetNewDestination(CTxDestination& dest, std::string& error) override; + bool GetNewDestination(CTxDestination& dest, bilingual_str& error) override; isminetype IsMine(const CScript& script) const override; bool CheckDecryptionKey(const CKeyingMaterial& master_key, bool accept_no_keys = false) override; @@ -588,7 +588,7 @@ class DescriptorScriptPubKeyMan : public ScriptPubKeyMan bool CanProvide(const CScript& script, SignatureData& sigdata) override; - bool SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, std::string>& input_errors) const override; + bool SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, bilingual_str>& input_errors) const override; SigningResult SignMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) const override; bool SignSpecialTxPayload(const uint256& hash, const CKeyID& keyid, std::vector<unsigned char>& vchSig) const override; TransactionError FillPSBT(PartiallySignedTransaction& psbt, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr) const override; diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp index c7ce15447b945a..84b84338408200 100644 --- a/src/wallet/test/coinselector_tests.cpp +++ b/src/wallet/test/coinselector_tests.cpp @@ -8,6 +8,7 @@ #include <random.h> #include <test/util/setup_common.h> #include <validation.h> +#include <util/translation.h> #include <wallet/coincontrol.h> #include <wallet/coinselection.h> #include <wallet/test/wallet_test_fixture.h> @@ -61,7 +62,7 @@ static void add_coin(std::vector<COutput>& coins, CWallet& wallet, const CAmount tx.vout[nInput].nValue = nValue; if (spendable) { CTxDestination dest; - std::string error; + bilingual_str error; const bool destination_ok = wallet.GetNewDestination("", dest, error); assert(destination_ok); tx.vout[nInput].scriptPubKey = GetScriptForDestination(dest); diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index ac0603d9883049..71fc66e7f2a4df 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -81,7 +81,7 @@ static CMutableTransaction TestSimpleSpend(const CTransaction& from, uint32_t in keystore.AddKey(key); std::map<COutPoint, Coin> coins; coins[mtx.vin[0].prevout].out = from.vout[index]; - std::map<int, std::string> input_errors; + std::map<int, bilingual_str> input_errors; BOOST_CHECK(SignTransaction(mtx, &keystore, coins, SIGHASH_ALL, input_errors)); return mtx; } @@ -1188,7 +1188,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_disableprivkeys, TestChain100Setup) wallet->SetWalletFlag(WALLET_FLAG_DISABLE_PRIVATE_KEYS); BOOST_CHECK(!wallet->TopUpKeyPool(1000)); CTxDestination dest; - std::string error; + bilingual_str error; BOOST_CHECK(!wallet->GetNewDestination("", dest, error)); } @@ -1244,7 +1244,7 @@ BOOST_FIXTURE_TEST_CASE(CreateWallet, TestChain100Setup) CallFunctionInValidationInterfaceQueue([&promise] { promise.get_future().wait(); }); - std::string error; + bilingual_str error; m_coinbase_txns.push_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]); auto block_tx = TestSimpleSpend(*m_coinbase_txns[0], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey())); m_coinbase_txns.push_back(CreateAndProcessBlock({block_tx}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]); @@ -1381,7 +1381,7 @@ BOOST_FIXTURE_TEST_CASE(ZapSelectTx, TestChain100Setup) key.MakeNewKey(true); AddKey(*wallet, key); - std::string error; + bilingual_str error; m_coinbase_txns.push_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]); auto block_tx = TestSimpleSpend(*m_coinbase_txns[0], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey())); CreateAndProcessBlock({block_tx}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 29d6104270a677..62075be7ad413c 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1141,7 +1141,7 @@ bool CWallet::ResendTransaction(const uint256& hashTx) assert(it != mapWallet.end()); CWalletTx& wtx = it->second; - std::string unused_err_string; + bilingual_str unused_err_string; return wtx.SubmitMemoryPoolAndRelay(unused_err_string, true); } @@ -2086,7 +2086,7 @@ void CWallet::ReacceptWalletTransactions() // Try to add wallet transactions to memory pool for (const std::pair<const int64_t, CWalletTx*>& item : mapSorted) { CWalletTx& wtx = *(item.second); - std::string unused_err_string; + bilingual_str unused_err_string; wtx.SubmitMemoryPoolAndRelay(unused_err_string, false); } } @@ -2107,7 +2107,7 @@ bool CWalletTx::CanBeResent() const !IsLockedByInstantSend(); } -bool CWalletTx::SubmitMemoryPoolAndRelay(std::string& err_string, bool relay) +bool CWalletTx::SubmitMemoryPoolAndRelay(bilingual_str& err_string, bool relay) { if (!CanBeResent()) return false; @@ -2423,7 +2423,7 @@ void CWallet::ResendWalletTransactions() // the last block. SubmitMemoryPoolAndRelay() will not rebroadcast // any confirmed or conflicting txs. if (wtx.nTimeReceived > m_best_block_time - 5 * 60) continue; - std::string unused_err_string; + bilingual_str unused_err_string; if (wtx.SubmitMemoryPoolAndRelay(unused_err_string, true)) ++submitted_tx_count; } } // cs_wallet @@ -2995,11 +2995,11 @@ bool CWallet::SignTransaction(CMutableTransaction& tx) const const CWalletTx& wtx = mi->second; coins[input.prevout] = Coin(wtx.tx->vout[input.prevout.n], wtx.m_confirm.block_height, wtx.IsCoinBase()); } - std::map<int, std::string> input_errors; + std::map<int, bilingual_str> input_errors; return SignTransaction(tx, coins, SIGHASH_ALL, input_errors); } -bool CWallet::SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, std::string>& input_errors) const +bool CWallet::SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, bilingual_str>& input_errors) const { // Try to sign with all ScriptPubKeyMans for (ScriptPubKeyMan* spk_man : GetAllScriptPubKeyMans()) { @@ -3897,9 +3897,9 @@ void CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::ve return; } - std::string err_string; + bilingual_str err_string; if (!wtx.SubmitMemoryPoolAndRelay(err_string, true)) { - WalletLogPrintf("CommitTransaction(): Transaction cannot be broadcast immediately, %s\n", err_string); + WalletLogPrintf("CommitTransaction(): Transaction cannot be broadcast immediately, %s\n", err_string.original); // TODO: if we expect the failure to be long term or permanent, instead delete wtx from the wallet and return failure. } } @@ -4092,7 +4092,7 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize) return res; } -bool CWallet::GetNewDestination(const std::string label, CTxDestination& dest, std::string& error) +bool CWallet::GetNewDestination(const std::string label, CTxDestination& dest, bilingual_str& error) { error.clear(); bool result = false; @@ -4103,7 +4103,7 @@ bool CWallet::GetNewDestination(const std::string label, CTxDestination& dest, s spk_man->TopUp(); result = spk_man->GetNewDestination(dest, error); } else { - error = strprintf("Error: No addresses available."); + error = strprintf(_("Error: No addresses available.")); } if (result) { SetAddressBook(dest, label, "receive"); @@ -4112,14 +4112,14 @@ bool CWallet::GetNewDestination(const std::string label, CTxDestination& dest, s return result; } -bool CWallet::GetNewChangeDestination(CTxDestination& dest, std::string& error) +bool CWallet::GetNewChangeDestination(CTxDestination& dest, bilingual_str& error) { LOCK(cs_wallet); error.clear(); ReserveDestination reservedest(this); if (!reservedest.GetReservedDestination(dest, true)) { - error = _("Error: Keypool ran out, please call keypoolrefill first").translated; + error = _("Error: Keypool ran out, please call keypoolrefill first"); return false; } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index b2f967cf112f03..1116d46dda053a 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -542,7 +542,7 @@ class CWalletTx bool CanBeResent() const; /** Pass this transaction to node for mempool insertion and relay to peers if flag set to true */ - bool SubmitMemoryPoolAndRelay(std::string& err_string, bool relay); + bool SubmitMemoryPoolAndRelay(bilingual_str& err_string, bool relay); // TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct // annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The annotation @@ -1105,7 +1105,7 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati /** Fetch the inputs and sign with SIGHASH_ALL. */ bool SignTransaction(CMutableTransaction& tx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); /** Sign the tx given the input coins and sighash. */ - bool SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, std::string>& input_errors) const; + bool SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, bilingual_str>& input_errors) const; SigningResult SignMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) const; /** Sign the payload of special transaction. * Because wallet is not aware about special transactions entity, @@ -1203,8 +1203,8 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati */ void MarkDestinationsDirty(const std::set<CTxDestination>& destinations) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - bool GetNewDestination(const std::string label, CTxDestination& dest, std::string& error); - bool GetNewChangeDestination(CTxDestination& dest, std::string& error); + bool GetNewDestination(const std::string label, CTxDestination& dest, bilingual_str& error); + bool GetNewChangeDestination(CTxDestination& dest, bilingual_str& error); isminetype IsMine(const CTxDestination& dest) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); isminetype IsMine(const CScript& script) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);