Add transaction size and zaddr output limit checks to z_sendmany.
This commit is contained in:
@@ -3166,6 +3166,17 @@ Value z_getoperationstatus_IMPL(const Array& params, bool fRemoveFinishedOperati
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
// Here we define the maximum number of zaddr outputs that can be included in a transaction.
|
||||
// If input notes are small, we might actually require more than one joinsplit per zaddr output.
|
||||
// For now though, we assume we use one joinsplit per zaddr output (and the second output note is change).
|
||||
// We reduce the result by 1 to ensure there is room for non-joinsplit CTransaction data.
|
||||
#define Z_SENDMANY_MAX_ZADDR_OUTPUTS ((MAX_TX_SIZE / JSDescription().GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)) - 1)
|
||||
|
||||
// transaction.h comment: spending taddr output requires CTxIn >= 148 bytes and typical taddr txout is 34 bytes
|
||||
#define CTXIN_SPEND_DUST_SIZE 148
|
||||
#define CTXOUT_REGULAR_SIZE 34
|
||||
|
||||
Value z_sendmany(const Array& params, bool fHelp)
|
||||
{
|
||||
if (!EnsureWalletIsAvailable(fHelp))
|
||||
@@ -3177,6 +3188,7 @@ Value z_sendmany(const Array& params, bool fHelp)
|
||||
"\nSend multiple times. Amounts are double-precision floating point numbers."
|
||||
"\nChange from a taddr flows to a new taddr address, while change from zaddr returns to itself."
|
||||
"\nWhen sending coinbase UTXOs to a zaddr, change is not alllowed. The entire value of the UTXO(s) must be consumed."
|
||||
+ strprintf("\nCurrently, the maximum number of zaddr outputs is %d due to transaction size limits.\n", Z_SENDMANY_MAX_ZADDR_OUTPUTS)
|
||||
+ HelpRequiringPassphrase() + "\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"fromaddress\" (string, required) The taddr or zaddr to send the funds from.\n"
|
||||
@@ -3284,6 +3296,30 @@ Value z_sendmany(const Array& params, bool fHelp)
|
||||
}
|
||||
}
|
||||
|
||||
// Check the number of zaddr outputs does not exceed the limit.
|
||||
if (zaddrRecipients.size() > Z_SENDMANY_MAX_ZADDR_OUTPUTS) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, too many zaddr outputs");
|
||||
}
|
||||
|
||||
// As a sanity check, estimate and verify that the size of the transaction will be valid.
|
||||
// Depending on the input notes, the actual tx size may turn out to be larger and perhaps invalid.
|
||||
size_t txsize = 0;
|
||||
CMutableTransaction mtx;
|
||||
mtx.nVersion = 2;
|
||||
for (int i = 0; i < zaddrRecipients.size(); i++) {
|
||||
mtx.vjoinsplit.push_back(JSDescription());
|
||||
}
|
||||
CTransaction tx(mtx);
|
||||
txsize += tx.GetSerializeSize(SER_NETWORK, tx.nVersion);
|
||||
if (fromTaddr) {
|
||||
txsize += CTXIN_SPEND_DUST_SIZE;
|
||||
txsize += CTXOUT_REGULAR_SIZE; // There will probably be taddr change
|
||||
}
|
||||
txsize += CTXOUT_REGULAR_SIZE * taddrRecipients.size();
|
||||
if (txsize > MAX_TX_SIZE) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Too many outputs, size of raw transaction would be larger than limit of %d bytes", MAX_TX_SIZE ));
|
||||
}
|
||||
|
||||
// Minimum confirmations
|
||||
int nMinDepth = 1;
|
||||
if (params.size() > 2) {
|
||||
|
||||
Reference in New Issue
Block a user