-
Notifications
You must be signed in to change notification settings - Fork 257
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 transparent address gap limit handling & general address rotation functionality. #1673
base: main
Are you sure you want to change the base?
Add transparent address gap limit handling & general address rotation functionality. #1673
Conversation
62c1394
to
bd2df86
Compare
bd2df86
to
4b99663
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1673 +/- ##
==========================================
+ Coverage 54.33% 54.36% +0.02%
==========================================
Files 173 174 +1
Lines 20282 20830 +548
==========================================
+ Hits 11021 11324 +303
- Misses 9261 9506 +245 ☔ View full report in Codecov by Sentry. |
1386dd1
to
49230de
Compare
…handling-prep Preparatory refactoring for #1673
b39c6c3
to
3ac0396
Compare
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.
Flushing some comments from an old review.
8796acb
to
0fa362f
Compare
3a91e3c
to
4cbefae
Compare
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.
Flushing partial review comments as of 4cbefae.
// NB: we have reduced the initial space of generated ephemeral addresses | ||
// from 20 addresses to 3, as ephemeral addresses should always be used in | ||
// a transaction immediatly after being reserved, and as a consequence | ||
// there is no significant benefit in having a larger gap limit. |
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.
This is altering an existing migration.
- If the new migration does not remove unnecessary gap-limit-generated addresses from previously-migrated databases, then we end up with data inconsistencies between wallets that we need to be aware of and handle (somehow) basically indefinitely.
- If the new migration does remove unnecessary gap-limit-generated addresses from previously-migrated databases, then altering this existing migration is unnecessary.
So I don't think we want to alter the migration in either case, and we should instead remove the unneeded gap limit addresses from the removed table (which we can reliably do leveraging its structure).
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.
The rationale for altering this migration is the same as the rationale for a 3-address ephemeral gap limit being acceptable in the first place: in practice, no such gaps should appear; therefore, the existing allocation of 20 addresses just means that those addresses are persisted to the wallet "early".
In some sense, all 2^31 possible addresses already "exist"; it's just a question of whether the wallet has written them down locally.
021fa6b
to
f07321e
Compare
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.
Flushing review comments as of f07321e. I only have zcash_client_sqlite/src/wallet/transparent/ephemeral.rs
and zcash_client_sqlite/src/wallet/init/migrations/transparent_gap_limit_handling.rs
left to review.
/// The provided [`UnifiedAddressRequest`] is used to pregenerate unified addresses that correspond | ||
/// to the transparent address index in question; such unified addresses need not internally | ||
/// contain a transparent receiver, and may be overwritten when these addresses are exposed via the | ||
/// [`WalletWrite::get_next_available_address`] or [`WalletWrite::get_address_for_index`] methods. |
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.
TODO: Confirm that they do indeed get overwritten, rather than having their receivers merged.
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.
get_next_available_address
calls upsert_address
, and there's actually a problem here; the current semantics of that method are that they won't alter the composition of the address, so what will happen is that the generated address won't actually be persisted (though it will be returned to the user.) What should probably happen is that some placeholder value for the address should be inserted into the address
field, and the update should occur only if the value is that placeholder; otherwise get_next_available_address
should return an error.
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.
The other thing here is that we actually want get_next_available_address
to alter its behavior depending upon the address request; if the request contains a transparent element, then its diversifier index should be drawn from within the transparent range, i.e. it should be the first unreserved address within the gap; if it doesn't contain a transparent element, then it should correspond to the first unreserved diversifier index in the range of values greater than 2^32 (I presume we don't want to do anything in the space between 2^31 and 2^32 because that's the "hardened transparent" range?)
ec4c558
to
3bba679
Compare
This is a large change that unifies the handling of ephemeral transparent addresses for ZIP 320 support with generalized "gap limit" handling for transparent wallet recovery. The best way to understand this commit is to start from the `transparent_gap_limit_handling` database migration that drives the change in behavior.
Co-authored-by: Jack Grigg <[email protected]>
…resses. The rationale behind this change is that current implementations of UTXO retrieval do not attempt to avoid revealing that multiple addresses belong to the same wallet when using a light wallet server to check for transparent UTXOs. A comprehensive solution to this problem requires changes to the light wallet protocol such that wallets no longer need to submit batches of addresses to the light wallet server, and can instead determine whether outputs exist for their addresses locally. By setting the default gap limit to 10 addresses, we make it possible for wallets that add privacy-preserving UTXO checking in the future (either by connecting to full node indexes directly in a privacy-preserving manner or via changes that take advantage of an updated light wallet protocol) to then start generating new addresses within a range of the industry-standard 20 address gap limit that have not yet been revealed to belong to the wallet.
3bba679
to
15063c6
Compare
force-pushed to address comments from code review Then force-pushed to rebase on |
15063c6
to
a7f04c8
Compare
In the presence of gap-limit addresses, querying for UTXOs based exclusively upon the last height at which such a query was executed is inadequate to fully recover the contents of a wallet; when a transaction is discovered in the past, this may advance the gap limit, and newly exposed addresses may receive outputs immediately following the discovered transaction. We can expect that when a transparent output belonging to the wallet is discovered, that the height at which that transaction was mined was checked in a query that included _all_ of addresses having child indices less than or equal to that of the involved address. Therefore, it's safe to start looking for addresses in the gap as of that point.
…ess exposure height.
a7f04c8
to
fae0271
Compare
force-pushed to fix bugs caught in CI |
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.
Probably utACK fae0271 but the exposed_at_height
needs either addressing or reasoning.
#[cfg(feature = "transparent-inputs")] | ||
ReachedGapLimit(AccountUuid, u32), | ||
ReachedGapLimit(u32, KeyScope), |
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.
Nit: KeyScope
is a level above the address index, so I'd prefer the tuple being in the opposite order.
@@ -1,184 +1,68 @@ | |||
//! Functions for wallet support of ephemeral transparent addresses. | |||
use std::cmp::{max, min}; | |||
//! Functikjns for wallet support of ephemeral transparent addresses. |
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.
No idea how this got broken.
//! Functikjns for wallet support of ephemeral transparent addresses. | |
//! Functions for wallet support of ephemeral transparent addresses. |
conn.execute_batch(&format!( | ||
r#" | ||
ALTER TABLE addresses ADD COLUMN key_scope INTEGER NOT NULL DEFAULT {external_scope_code}; | ||
ALTER TABLE addresses ADD COLUMN transparent_child_index INTEGER; |
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.
An exposed_at_height
column is not added here, so AFAICT that column will be null
for every existing address in the table, while ephemeral addresses that get inserted have this set correctly. Given that going forward we set this for all address scopes (not just ephemeral AFAIR), we should set this correctly for existing addresses as well (to the best of our knowledge, i.e. no worse than if the wallet were recovered from seed).
|
||
conn.execute_batch(&format!( | ||
r#" | ||
ALTER TABLE addresses ADD COLUMN key_scope INTEGER NOT NULL DEFAULT {external_scope_code}; |
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.
Confirming that we did indeed only store external addresses in here previously? Definitely the case for shielded, and I believe we weren't generating change addresses for transparent.
CREATE TABLE addresses_new ( | ||
id INTEGER NOT NULL PRIMARY KEY, | ||
account_id INTEGER NOT NULL, | ||
key_scope INTEGER NOT NULL DEFAULT {external_scope_code}, |
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.
Do we need to leave the default set? It's convenient for the migration (so could be retained above), but it could cause us issues during future query refactoring if the final table auto-fills the column (fixing a data error here would not be pleasant).
No description provided.