Merge pull request #5919 from nuttycom/feature/z_sendmany_tx_limit
Add -orchardactionlimit parameter to guard against memory exhaustion.
This commit is contained in:
commit
8ca33e06f7
|
@ -61,6 +61,12 @@ Option handling
|
|||
to specify the number of blocks back from the chain tip that anchors will be
|
||||
selected from when spending notes. By default, anchors will now be selected
|
||||
to have 3 confirmations. Values greater than 100 are not supported.
|
||||
- A new `-orchardactionlimit` option has been added to allow the user to
|
||||
override the default maximum of 50 Orchard actions per transaction.
|
||||
Transactions that contain large numbers of Orchard actions can use
|
||||
large amounts of memory for proving, so the 50-action default limit is
|
||||
imposed to guard against memory exhaustion. Systems with more than 16G
|
||||
of memory can safely set this parameter to allow 200 actions or more.
|
||||
|
||||
RPC Interface
|
||||
-------------
|
||||
|
|
|
@ -290,9 +290,23 @@ uint256 AsyncRPCOperation_sendmany::main_impl() {
|
|||
"Resubmit with the `privacyPolicy` parameter set to `AllowRevealedAmounts` "
|
||||
"or weaker if you wish to allow this transaction to proceed anyway.");
|
||||
}
|
||||
|
||||
// Sending from Orchard to transparent will be caught above in the
|
||||
// AllowRevealedRecipients check; sending to Sprout is disallowed
|
||||
// entirely.
|
||||
|
||||
if (spendable.orchardNoteMetadata.size() > nOrchardActionLimit) {
|
||||
throw JSONRPCError(
|
||||
RPC_INVALID_PARAMETER,
|
||||
strprintf(
|
||||
"Attempting to spend %u Orchard notes would exceed the current limit "
|
||||
"of %u notes, which exists to prevent memory exhaustion. Restart with "
|
||||
"`-orchardactionlimit=N` where N >= %u to allow the wallet to attempt "
|
||||
"to construct this transaction.",
|
||||
spendable.orchardNoteMetadata.size(),
|
||||
nOrchardActionLimit,
|
||||
spendable.orchardNoteMetadata.size()));
|
||||
}
|
||||
}
|
||||
|
||||
spendable.LogInputs(getId());
|
||||
|
@ -553,7 +567,6 @@ uint256 AsyncRPCOperation_sendmany::main_impl() {
|
|||
[&](const libzcash::OrchardRawAddress& addr) {
|
||||
auto value = r.amount;
|
||||
auto memo = r.memo.has_value() ? std::optional(get_memo_from_hex_string(r.memo.value())) : std::nullopt;
|
||||
|
||||
builder_.AddOrchardOutput(ovks.second, addr, value, memo);
|
||||
}
|
||||
}, r.address);
|
||||
|
|
|
@ -5064,6 +5064,7 @@ UniValue z_sendmany(const UniValue& params, bool fHelp)
|
|||
std::set<RecipientAddress> recipientAddrs;
|
||||
std::vector<SendManyRecipient> recipients;
|
||||
CAmount nTotalOut = 0;
|
||||
size_t nOrchardOutputs = 0;
|
||||
for (const UniValue& o : outputs.getValues()) {
|
||||
if (!o.isObject())
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
|
||||
|
@ -5129,6 +5130,22 @@ UniValue z_sendmany(const UniValue& params, bool fHelp)
|
|||
involvesUnifiedAddress = true;
|
||||
}
|
||||
|
||||
if (std::holds_alternative<libzcash::OrchardRawAddress>(addr.value())) {
|
||||
nOrchardOutputs += 1;
|
||||
if (nOrchardOutputs > nOrchardActionLimit) {
|
||||
throw JSONRPCError(
|
||||
RPC_INVALID_PARAMETER,
|
||||
strprintf(
|
||||
"Attempting to create %u Orchard outputs would exceed the current limit "
|
||||
"of %u notes, which exists to prevent memory exhaustion. Restart with "
|
||||
"`-orchardactionlimit=N` where N >= %u to allow the wallet to attempt "
|
||||
"to construct this transaction.",
|
||||
nOrchardOutputs,
|
||||
nOrchardActionLimit,
|
||||
nOrchardOutputs));
|
||||
}
|
||||
}
|
||||
|
||||
recipients.push_back(SendManyRecipient(ua, addr.value(), nAmount, memo));
|
||||
nTotalOut += nAmount;
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ bool bSpendZeroConfChange = DEFAULT_SPEND_ZEROCONF_CHANGE;
|
|||
bool fSendFreeTransactions = DEFAULT_SEND_FREE_TRANSACTIONS;
|
||||
bool fPayAtLeastCustomFee = true;
|
||||
unsigned int nAnchorConfirmations = DEFAULT_ANCHOR_CONFIRMATIONS;
|
||||
unsigned int nOrchardActionLimit = DEFAULT_ORCHARD_ACTION_LIMIT;
|
||||
|
||||
const char * DEFAULT_WALLET_DAT = "wallet.dat";
|
||||
|
||||
|
@ -6333,6 +6334,7 @@ std::string CWallet::GetWalletHelpString(bool showDebug)
|
|||
strUsage += HelpMessageOpt("-migrationdestaddress=<zaddr>", _("Set the Sapling migration address"));
|
||||
strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)"),
|
||||
CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE)));
|
||||
strUsage += HelpMessageOpt("-orchardactionlimit=<n>", strprintf(_("Set the maximum number of Orchard actions permitted in a transaction (default %u)"), DEFAULT_ORCHARD_ACTION_LIMIT));
|
||||
strUsage += HelpMessageOpt("-paytxfee=<amt>", strprintf(_("Fee (in %s/kB) to add to transactions you send (default: %s)"),
|
||||
CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK())));
|
||||
strUsage += HelpMessageOpt("-rescan", _("Rescan the block chain for missing wallet transactions on startup"));
|
||||
|
@ -6603,6 +6605,13 @@ bool CWallet::ParameterInteraction(const CChainParams& params)
|
|||
}
|
||||
nAnchorConfirmations = confirmations;
|
||||
}
|
||||
if (mapArgs.count("-orchardactionlimit")) {
|
||||
int64_t limit = atoi64(mapArgs["-orchardactionlimit"]);
|
||||
if (limit < 1) {
|
||||
return UIError(strprintf(_("Invalid value for -orchardactionlimit='%u' (must be least 1)"), limit));
|
||||
}
|
||||
nOrchardActionLimit = limit;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -54,6 +54,9 @@ extern bool bSpendZeroConfChange;
|
|||
extern bool fSendFreeTransactions;
|
||||
extern bool fPayAtLeastCustomFee;
|
||||
extern unsigned int nAnchorConfirmations;
|
||||
// The maximum number of Orchard actions permitted within a single transaction.
|
||||
// This can be overridden with the -orchardactionlimit config option
|
||||
extern unsigned int nOrchardActionLimit;
|
||||
|
||||
static const unsigned int DEFAULT_KEYPOOL_SIZE = 100;
|
||||
//! -paytxfee default
|
||||
|
@ -82,6 +85,8 @@ static const size_t WALLET_MNEMONIC_ENTROPY_LENGTH = 32;
|
|||
static const unsigned int DEFAULT_ANCHOR_CONFIRMATIONS = 3;
|
||||
// Default minimum number of confirmations for note selection
|
||||
static const unsigned int DEFAULT_NOTE_CONFIRMATIONS = 10;
|
||||
//! -orchardactionlimit default
|
||||
static const unsigned int DEFAULT_ORCHARD_ACTION_LIMIT = 50;
|
||||
|
||||
extern const char * DEFAULT_WALLET_DAT;
|
||||
|
||||
|
|
Loading…
Reference in New Issue