|
|
@ -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) { |
|
|
|