Skip to content

Commit 2018e96

Browse files
committed
Abandon transactions on shielded operations if they can not be broadcast immediately
1 parent 3b69b90 commit 2018e96

File tree

3 files changed

+21
-4
lines changed

3 files changed

+21
-4
lines changed

src/wallet/asyncrpcoperation_common.cpp

+13-1
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,29 @@
66

77
#include <core_io.h>
88
#include <init.h>
9+
#include <policy/policy.h>
910
#include <rpc/protocol.h>
1011
#include <rpc/request.h>
12+
#include <consensus/validation.h>
1113

1214
extern UniValue signrawtransactionwithwallet(const JSONRPCRequest& request);
1315

1416
UniValue SendTransaction(CTransactionRef& tx, CWallet* const pwallet, bool testmode) {
1517
mapValue_t mapValue;
1618
UniValue o(UniValue::VOBJ);
19+
20+
// Extremely large transactions with lots of inputs can cost the network
21+
// almost as much to process as they cost the sender in fees, because
22+
// computing signature hashes is O(ninputs*txsize). Limiting transactions
23+
// to MAX_STANDARD_TX_WEIGHT mitigates CPU exhaustion attacks.
24+
if (GetTransactionWeight(*tx) > MAX_STANDARD_TX_WEIGHT)
25+
{
26+
throw JSONRPCError(RPC_WALLET_ERROR, "Transaction too large");
27+
}
28+
1729
// Send the transaction
1830
if (!testmode) {
19-
pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */);
31+
pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, true);
2032
o.pushKV("txid", tx->GetHash().GetHex());
2133
} else {
2234
// Test mode does not send the transaction to the network.

src/wallet/wallet.cpp

+7-2
Original file line numberDiff line numberDiff line change
@@ -5229,7 +5229,7 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std
52295229
return true;
52305230
}
52315231

5232-
void CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm)
5232+
void CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm, bool forceError)
52335233
{
52345234
auto locked_chain = chain().lock();
52355235
LOCK(cs_wallet);
@@ -5265,7 +5265,12 @@ void CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::ve
52655265
std::string err_string;
52665266
if (!wtx.SubmitMemoryPoolAndRelay(err_string, true, *locked_chain)) {
52675267
WalletLogPrintf("CommitTransaction(): Transaction cannot be broadcast immediately, %s\n", err_string);
5268-
// TODO: if we expect the failure to be long term or permanent, instead delete wtx from the wallet and return failure.
5268+
if (forceError) {
5269+
if (AbandonTransaction(*locked_chain, wtx.GetHash())) {
5270+
WalletLogPrintf("CommitTransaction(): Transaction %s has been abandoned\n", wtx.GetHash().ToString());
5271+
throw std::runtime_error(strprintf("Could not commit transaction: %s", err_string));
5272+
}
5273+
}
52695274
}
52705275
}
52715276

src/wallet/wallet.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -1502,7 +1502,7 @@ class CWallet final : public FillableSigningProvider, private interfaces::Chain:
15021502
* @param mapValue[in] key-values to be set on the transaction.
15031503
* @param orderForm[in] BIP 70 / BIP 21 order form details to be set on the transaction.
15041504
*/
1505-
void CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm);
1505+
void CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm, bool forceError = false);
15061506

15071507
bool DummySignTx(CMutableTransaction &txNew, const std::set<CTxOut> &txouts, bool use_max_sig = false) const
15081508
{

0 commit comments

Comments
 (0)