Skip to content

Commit

Permalink
Merge bitcoin#22337: wallet: Use bilingual_str for errors
Browse files Browse the repository at this point in the history
92993aa Change SignTransaction's input_errors to use bilingual_str (Andrew Chow)
171366e Use bilingual_str for address fetching functions (Andrew Chow)
9571c69 Add bilingual_str::clear() (Andrew Chow)

Pull request description:

  In a couple of places in the wallet, errors are `std::string`. In order for these errors to be translated, change them to use `bilingual_str`.

ACKs for top commit:
  hebasto:
    re-ACK 92993aa, only rebased since my [previous](bitcoin#22337 (review)) review, verified with
  klementtan:
    Code review ACK 92993aa
  meshcollider:
    Code review ACK 92993aa

Tree-SHA512: 5400e419dd87db8c49b67ed0964de2d44b58010a566ca246f2f0760ed9ef6a9b6f6df7a6adcb211b315b74c727bfe8c7d07eb5690b5922fa5828ceef4c83461f
  • Loading branch information
meshcollider authored and vijaydasmp committed Jun 22, 2024
1 parent b3a0b52 commit d78c54e
Show file tree
Hide file tree
Showing 17 changed files with 64 additions and 50 deletions.
6 changes: 3 additions & 3 deletions src/coinjoin/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -638,14 +638,14 @@ bool CCoinJoinClientSession::SignFinalTransaction(const CTxMemPool& mempool, con

// 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();
Expand Down
9 changes: 5 additions & 4 deletions src/rpc/rawtransaction_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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)));
Expand Down
3 changes: 2 additions & 1 deletion src/rpc/rawtransaction_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <map>
#include <string>

struct bilingual_str;
class FillableSigningProvider;
class UniValue;
struct CMutableTransaction;
Expand All @@ -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
Expand Down
11 changes: 6 additions & 5 deletions src/script/sign.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);

Expand All @@ -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;
Expand All @@ -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
Expand Down
3 changes: 2 additions & 1 deletion src/script/sign.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class CScriptID;
class CTransaction;
class SigningProvider;

struct bilingual_str;
struct CMutableTransaction;

/** Interface for signature creators. */
Expand Down Expand Up @@ -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
3 changes: 2 additions & 1 deletion src/test/fuzz/script_sign.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/util/setup_common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,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.
Expand Down
3 changes: 2 additions & 1 deletion src/test/util/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <outputtype.h>
#include <script/standard.h>
#ifdef ENABLE_WALLET
#include <util/translation.h>
#include <wallet/wallet.h>
#endif

Expand All @@ -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);
Expand Down
6 changes: 6 additions & 0 deletions src/util/translation.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion src/wallet/interfaces.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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
Expand Down
10 changes: 5 additions & 5 deletions src/wallet/rpcwallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
},
Expand Down Expand Up @@ -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);
},
Expand Down Expand Up @@ -3684,7 +3684,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);
Expand Down
18 changes: 9 additions & 9 deletions src/wallet/scriptpubkeyman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@
#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();

// 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);
Expand Down Expand Up @@ -708,7 +708,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);
}
Expand Down Expand Up @@ -1764,11 +1764,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;
}
{
Expand All @@ -1782,12 +1782,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};
Expand Down Expand Up @@ -1870,7 +1870,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;
Expand Down Expand Up @@ -2164,7 +2164,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) {
Expand Down
12 changes: 6 additions & 6 deletions src/wallet/scriptpubkeyman.h
Original file line number Diff line number Diff line change
Expand Up @@ -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; }

Expand Down Expand Up @@ -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; };
/** Adds script and derivation path information to a PSBT, and optionally signs it. */
Expand Down Expand Up @@ -316,7 +316,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;

Expand Down Expand Up @@ -356,7 +356,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;
TransactionError FillPSBT(PartiallySignedTransaction& psbt, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr) const override;

Expand Down Expand Up @@ -548,7 +548,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;
Expand Down Expand Up @@ -586,7 +586,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;
TransactionError FillPSBT(PartiallySignedTransaction& psbt, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr) const override;

Expand Down
3 changes: 2 additions & 1 deletion src/wallet/test/coinselector_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -64,7 +65,7 @@ static void add_coin(CWallet& wallet, const CAmount& nValue, int nAge = 6*24, bo
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);
Expand Down
Loading

0 comments on commit d78c54e

Please sign in to comment.