Add dynamic note selection that is responsive to changes in required fees.#689
Conversation
26858fb to
0f8465a
Compare
Codecov ReportBase: 72.58% // Head: 71.29% // Decreases project coverage by
Additional details and impacted files@@ Coverage Diff @@
## main #689 +/- ##
==========================================
- Coverage 72.58% 71.29% -1.30%
==========================================
Files 107 113 +6
Lines 10932 11387 +455
==========================================
+ Hits 7935 8118 +183
- Misses 2997 3269 +272
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. ☔ View full report at Codecov. |
There was a problem hiding this comment.
This will surely be a UX problem. Is there a way of doing a dry-run to know the estimated fee for a given amount to show on wallets' send flow? Waiting for the user to complete the whole transaction to deny it because of variable fees not calculated well beforehand seems pretty inconvenient
There was a problem hiding this comment.
Usually insufficient funds will be detected at note selection time, so the build-time check is really just a fall-back to ensure that the transaction doesn't violate balance rules. Also, the next generation of transaction construction will provide an intermediate result that has the privacy implications of the transaction listed out for the user's approval.
There was a problem hiding this comment.
Also, the next generation of transaction construction will provide an intermediate result that has the privacy implications of the transaction listed out for the user's approval.
I'm not following you here. In terms of wallet UX, can we have a function that given an amount, it will return an approximate fee so that wallet developers can validate their "send funds" forms UI?
There was a problem hiding this comment.
There's a subtlety here which is that we would need such a function to essentially prepare the transaction and "reserve" the notes/UTXOs that would be spent, so that we can be sure that the fee doesn't change between the time that the UI displays the fee and the time that the user goes to actually confirm the transaction; for example, if a new note comes in that would be preferentially selected by the note selection algorithm, the fees and the notes being spent could change in that interim. So, what we need to do is what we've discussed before: prepare the transaction and lock the notes to be spent to it, and then return that prepared transaction (along with its privacy implications) to be confirmed by the user. The fee should be displayed on the confirmation page.
There was a problem hiding this comment.
The problem with this approach is that it doesn't solve the problem I'm referring to, which is: "don't let the user proceed to a place that inevitably is an error state if it can be known beforehand".
The SDK will update every 20~ seconds and being the user in the send flow, it will refresh the available information and that information in the local state will be used to create the transaction. Any changes in balance should trigger a UI refresh in send flow so that it can be validated against the latest current state.
There was a problem hiding this comment.
We do know that there are certain combinations of amount and notes used that will make the fees an impediment for the transaction to be sent. The "dry-run" function I'm proposing is aimed to catch and report that particular situation so that wallet developers can validate their send form before proceeding. There will be situations like the one you mentioned where timing and chance will plot against it. *
Also, it can be the case that a wallet developer does not want a confirmation screen. So this additional step to safety check will not be present. Which makes this validation function more helpful to avoid failed transactions for consensus reasons which are a pain to explain to users.
- I hadn't thought of this. Can users be dusted into oblivion thanks to these new fee scheme?
There was a problem hiding this comment.
No; it is the responsibility of the ZIP 321 note selection implementation to ignore notes that are below the value of the fee required to spend them (though low-valued notes can have their value recovered by using them as a free input when spending a note that is by itself large enough to cover the full transaction amount.)
There was a problem hiding this comment.
In any case, this error needs to exist because we must always validate the transaction at construction time anyway. The transaction preparation step you're talking about is effectively the input selection step itself; it's been renamed 'propose_transaction' to make this a bit clearer: https://github.com/zcash/librustzcash/pull/689/files#diff-fedecff319cb43f7a4f8b913cdee2332ba452a6310e2470cf6cc7631ca83291cR126
ec80d6e to
d685530
Compare
d66cbfc to
3c6af22
Compare
e400f8a to
f120a01
Compare
0504f41 to
f0cff43
Compare
|
force-pushed to address review comments and integrate change selection more intimately with fee estimation. |
e70366d to
d14b52d
Compare
bca3122 to
a9e955e
Compare
str4d
left a comment
There was a problem hiding this comment.
Reviewed a9e955e862986abcf1c88a418b1234def97126ce. Overall this is looking good!
254f20c to
ff72cfe
Compare
e55a83c to
bd16035
Compare
|
force-pushed to address review comments and add handling of dust inputs. |
str4d
left a comment
There was a problem hiding this comment.
utACK bd16035c77163606ff24658569d29a0bfbcbe892 modulo comments.
There was a problem hiding this comment.
| - `impl {PartialOrd, Ord} for zcash_primitves::transaction::components::transparent::OutPoint` | |
| - `impl {PartialOrd, Ord} for zcash_primitives::transaction::components::transparent::OutPoint` |
This adds a set of abstractions that allow wallets to provide independent strategies for fee estimation and note selection, and implementations of these strategies that perform these operations in the same fashion as the existing `spend` and `shield_transparent_funds` functions. This required a somewhat hefty rework of the error handling in zcash_client_backend. It fixes an issue with the error types whereby callees needed to have a bit too much information about the error types produced by their callers. Reflect the updated note selection and error handling in zcash_client_sqlite.
The change selection algorithm has the most useful information for determining whether or not a note is dust, so this adds a new error case to `ChangeError` that allows the change selection to report the presence of input notes without economic value back to its caller.
bd16035 to
847ba49
Compare
|
@str4d I realized that I hadn't properly accounted for handling dust outputs in the change APIs, so I have force-pushed the second commit here to address the problem: https://github.com/zcash/librustzcash/compare/bd16035c77163606ff24658569d29a0bfbcbe892..847ba49761fdfec1213a6d6417db6165c549241e |
| - `TransactionBalance` | ||
| - `BasicFixedFeeChangeStrategy` - a `ChangeStrategy` implementation that | ||
| reproduces current wallet change behavior | ||
| - `fixed` a new module containing of change selection strategies for the |
There was a problem hiding this comment.
| - `fixed` a new module containing of change selection strategies for the | |
| - `fixed`, a new module containing of change selection strategies for the |
(or : as was used above)
| and types related to fee calculations. | ||
| - `FeeRule` a trait that describes how to compute the fee required for a | ||
| transaction given inputs and outputs to the transaction. | ||
| - `zcash_primitives::transaction::fees::fixed` a new module containing an implementation |
There was a problem hiding this comment.
| - `zcash_primitives::transaction::fees::fixed` a new module containing an implementation | |
| - `fixed`, a new module containing an implementation |
|
I will address the changelog comments in #694, which will follow immediately. |
| - `chain::error`: a module containing error types type that that can occur only | ||
| in chain validation and sync have been separated out from errors related to | ||
| other wallet operations. |
There was a problem hiding this comment.
| - `chain::error`: a module containing error types type that that can occur only | |
| in chain validation and sync have been separated out from errors related to | |
| other wallet operations. | |
| - `chain::error`: a module containing error types that can occur only in chain | |
| validation and sync, which have been separated out from errors related to | |
| other wallet operations. |
| to the function has been modified to take a unified spending key instead of a | ||
| Sapling extended spending key, and now also requires a `min_confirmations` |
There was a problem hiding this comment.
| to the function has been modified to take a unified spending key instead of a | |
| Sapling extended spending key, and now also requires a `min_confirmations` | |
| to the function have been modified to take a unified spending key instead of a | |
| Sapling extended spending key, and it now also requires a `min_confirmations` |
| /// Performs input selection and returns a proposal for the construction of a shielding | ||
| /// transaction. | ||
| /// | ||
| /// Implementations should return the maximum possible number of economically useful inputs |
There was a problem hiding this comment.
Is "maximum possible" correct? That would be all the notes held by the wallet.
I don't think "minimum possible" is correct either; while it's not useful to return additional unneeded notes, there's no guarantee or requirement that the returned set of notes be the minimum possible number.
This PR is best reviewed hiding whitespace changes.