-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add transaction size and zaddr output limit checks to z_sendmany #1808
Conversation
utACK, only comment is on the size of the |
Empty CTxIn is only 41 bytes. Updating patch to use 148 bytes, per the comment in transaction.h. |
Please add an RPC call to check if TX satisfies the conditions so pools can check it before submission. |
8d3338f
to
6c22ca0
Compare
@sammy007 Estimating and checking the size of the transaction will happen before any joinsplit processing takes place, so you won't spend any computing resources up-front. |
// 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 / 1802) - 1) // Serialized JSDescription is 1802 bytes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would rather use GetSerializeSize()
on a blank JSDescription
(they are constant size) than forget to modify this constant. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@@ -3284,6 +3292,29 @@ 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) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if a change address takes this over the limit? Are there other ways the underlying API might add data to the transaction that wouldn't be accounted for in these changes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added txout change, which is likely, when sending from taddr.
I would rather add this kind of stuff to an underlying abstraction than to sendmany in particular. We need a transaction assembler. ACK modulo comments. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
utACK. Minor request to replace magic numbers with named constants.
CTransaction tx(mtx); | ||
txsize += tx.GetSerializeSize(SER_NETWORK, tx.nVersion); | ||
if (fromTaddr) { | ||
txsize += 148; // transaction.h comment: spending taddr output requires CTxIn >= 148 bytes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace 148
with a named constant or #define
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok
if (fromTaddr) { | ||
txsize += 148; // transaction.h comment: spending taddr output requires CTxIn >= 148 bytes. | ||
} | ||
txsize += 34 * taddrRecipients.size(); // rule of thumb, a regular taddr output is 34 bytes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace 34
with a named constant or #define
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok
6c22ca0
to
3920292
Compare
utACK w.r.t new commits. |
Ping @nathan-at-least |
@bitcartel utACK on my minor nits about defined constants. I've run the "wallet test" on this branch as is, and now I'm going to rerun it after reverting all the non-test changes. |
ACK w/ pos/neg verification of the wallet test. |
@zkbot r+ |
📌 Commit 3920292 has been approved by |
☀️ Test successful - zcash |
Estimate and check if the size of a transaction, for a given number of taddr and zaddr outputs, will be valid. Based on the current implementation of z_sendmany, one zaddr output requires (at least) one joinsplit. Future optimizations should reduce the number of joinsplits required.
The distribution of value across input notes impacts the number of joinsplits required for a zaddr output e.g. small notes being used to send a big value to a zaddr. We should add more sophisticated checking in future.
Given that the maximum size of a transaction is currently 100,000 bytes, the maximum number of joinsplits in a tx is 55. This is reduced to 54 to be conservative and ensure there is room for CTransaction data.
In practice, we might want to communicate and recommend a user to use upto 50 zaddr outputs, which will require 50 joinsplits, and take around 25-30 minutes to compute on an i7.