Add transaction size and zaddr output limit checks to z_sendmany #1808

Merged
merged 1 commit into from Nov 7, 2016

Conversation

Projects
None yet
6 participants
@bitcartel
Contributor

bitcartel commented Nov 6, 2016

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.

@str4d

This comment has been minimized.

Show comment
Hide comment
@str4d

str4d Nov 6, 2016

Contributor

utACK, only comment is on the size of the CTxIn: how large is an empty one? The transparent dust threshold used 148 bytes as the minimum CTxIn size required to spend a transparent output, so as long as we are consistent with that, I'm happy.

Contributor

str4d commented Nov 6, 2016

utACK, only comment is on the size of the CTxIn: how large is an empty one? The transparent dust threshold used 148 bytes as the minimum CTxIn size required to spend a transparent output, so as long as we are consistent with that, I'm happy.

@bitcartel

This comment has been minimized.

Show comment
Hide comment
@bitcartel

bitcartel Nov 6, 2016

Contributor

Empty CTxIn is only 41 bytes. Updating patch to use 148 bytes, per the comment in transaction.h.

Contributor

bitcartel commented Nov 6, 2016

Empty CTxIn is only 41 bytes. Updating patch to use 148 bytes, per the comment in transaction.h.

@sammy007

This comment has been minimized.

Show comment
Hide comment
@sammy007

sammy007 Nov 6, 2016

Please add an RPC call to check if TX satisfies the conditions so pools can check it before submission.

sammy007 commented Nov 6, 2016

Please add an RPC call to check if TX satisfies the conditions so pools can check it before submission.

@bitcartel

This comment has been minimized.

Show comment
Hide comment
@bitcartel

bitcartel Nov 7, 2016

Contributor

@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.

Contributor

bitcartel commented Nov 7, 2016

@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.

src/wallet/rpcwallet.cpp
+// 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

This comment has been minimized.

@ebfull

ebfull Nov 7, 2016

Contributor

I would rather use GetSerializeSize() on a blank JSDescription (they are constant size) than forget to modify this constant. :)

@ebfull

ebfull Nov 7, 2016

Contributor

I would rather use GetSerializeSize() on a blank JSDescription (they are constant size) than forget to modify this constant. :)

This comment has been minimized.

@bitcartel

bitcartel Nov 7, 2016

Contributor

Done.

@bitcartel

bitcartel Nov 7, 2016

Contributor

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

This comment has been minimized.

@ebfull

ebfull Nov 7, 2016

Contributor

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?

@ebfull

ebfull Nov 7, 2016

Contributor

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?

This comment has been minimized.

@bitcartel

bitcartel Nov 7, 2016

Contributor

Added txout change, which is likely, when sending from taddr.

@bitcartel

bitcartel Nov 7, 2016

Contributor

Added txout change, which is likely, when sending from taddr.

@ebfull

This comment has been minimized.

Show comment
Hide comment
@ebfull

ebfull Nov 7, 2016

Contributor

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.

Contributor

ebfull commented Nov 7, 2016

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.

@nathan-at-least

utACK. Minor request to replace magic numbers with named constants.

src/wallet/rpcwallet.cpp
+ CTransaction tx(mtx);
+ txsize += tx.GetSerializeSize(SER_NETWORK, tx.nVersion);
+ if (fromTaddr) {
+ txsize += 148; // transaction.h comment: spending taddr output requires CTxIn >= 148 bytes.

This comment has been minimized.

@nathan-at-least

nathan-at-least Nov 7, 2016

Contributor

Replace 148 with a named constant or #define.

@nathan-at-least

nathan-at-least Nov 7, 2016

Contributor

Replace 148 with a named constant or #define.

This comment has been minimized.

@bitcartel

bitcartel Nov 7, 2016

Contributor

Ok

@bitcartel

bitcartel Nov 7, 2016

Contributor

Ok

src/wallet/rpcwallet.cpp
+ 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

This comment has been minimized.

@nathan-at-least

nathan-at-least Nov 7, 2016

Contributor

Replace 34 with a named constant or #define.

@nathan-at-least

nathan-at-least Nov 7, 2016

Contributor

Replace 34 with a named constant or #define.

This comment has been minimized.

@bitcartel

bitcartel Nov 7, 2016

Contributor

Ok

@bitcartel

bitcartel Nov 7, 2016

Contributor

Ok

@ebfull

This comment has been minimized.

Show comment
Hide comment
@ebfull

ebfull Nov 7, 2016

Contributor

utACK w.r.t new commits.

Contributor

ebfull commented Nov 7, 2016

utACK w.r.t new commits.

@bitcartel

This comment has been minimized.

Show comment
Hide comment
Contributor

bitcartel commented Nov 7, 2016

@nathan-at-least

This comment has been minimized.

Show comment
Hide comment
@nathan-at-least

nathan-at-least Nov 7, 2016

Contributor

@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.

Contributor

nathan-at-least commented Nov 7, 2016

@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.

@nathan-at-least

This comment has been minimized.

Show comment
Hide comment
@nathan-at-least

nathan-at-least Nov 7, 2016

Contributor

ACK w/ pos/neg verification of the wallet test.

Contributor

nathan-at-least commented Nov 7, 2016

ACK w/ pos/neg verification of the wallet test.

@bitcartel

This comment has been minimized.

Show comment
Hide comment
@bitcartel

bitcartel Nov 7, 2016

Contributor

@zkbot r+

Contributor

bitcartel commented Nov 7, 2016

@zkbot r+

@zkbot

This comment has been minimized.

Show comment
Hide comment
@zkbot

zkbot Nov 7, 2016

Contributor

📌 Commit 3920292 has been approved by bitcartel

Contributor

zkbot commented Nov 7, 2016

📌 Commit 3920292 has been approved by bitcartel

@zkbot

This comment has been minimized.

Show comment
Hide comment
@zkbot

zkbot Nov 7, 2016

Contributor

⌛️ Testing commit 3920292 with merge 3920292...

Contributor

zkbot commented Nov 7, 2016

⌛️ Testing commit 3920292 with merge 3920292...

@zkbot

This comment has been minimized.

Show comment
Hide comment
@zkbot

zkbot Nov 7, 2016

Contributor

☀️ Test successful - zcash

Contributor

zkbot commented Nov 7, 2016

☀️ Test successful - zcash

@zkbot zkbot merged commit 3920292 into zcash:master Nov 7, 2016

1 check passed

homu Test successful
Details
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment