-
Notifications
You must be signed in to change notification settings - Fork 322
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
No descriptor ids in spk txout index #1463
No descriptor ids in spk txout index #1463
Conversation
a652892
to
165f06b
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.
LGTM but I have a few suggestions before ACKing.
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.
Thanks for working on this. The range-based method bugs definitely need to be fixed. However, I'm not sure if a total-revamp of the behavior is the correct way forward?
I'm okay with disallowing reassignment of a keychain's descriptor. However, I still think assigning the same descriptor to multiple keychains is important (for consistency). Let me explain.
Currently, our API allows adding overlapping descriptors. I.e. a non-wildcard descriptor which derives a spk that exists in a wildcard descriptor. There is just no good way to detect for this. With the changes presented in this PR, doing the above (which is impossible to detect) will cause undefined behavior, whereas the previous implementation handles this perfectly.
Therefore, for consistency, I think we should just enable both and scenarios and handle things consistently (as we are doing before).
// The reason we need a tricky algorithm is because of the "lookahead" feature which means | ||
// that some of the spks in the SpkTxoutIndex will not have been revealed yet. So we need to | ||
// filter out those spks that are above the last_revealed for that keychain. To do this we | ||
// iterate through the last_revealed for each keychain and the spks for each keychain in | ||
// tandem. This minimizes BTreeMap queries. | ||
core::iter::from_fn(move || loop { | ||
let ((keychain, index), spk) = iter_spks.next()?; | ||
// We need to find the last revealed that matches the current spk we are considering so | ||
// we skip ahead. | ||
while current_keychain?.0 < keychain { | ||
current_keychain = iter_last_revealed.next(); | ||
} | ||
let (current_keychain, last_revealed) = current_keychain?; | ||
|
||
if current_keychain == keychain && Some(*index) <= last_revealed { | ||
break Some(((keychain.clone(), *index), spk.as_script())); | ||
} | ||
}) |
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'm trying to understand the performance implications of this (since this complex-ish logic seems to be here for performance reasons, otherwise a .filter
can work too).
I.e. let's say the caller is using a large lookahead (1000+) with a large amount of keychains. Would it be more performant to loop through all lookahead spks (except for the last keychain) - as we are doing here. Or, would it be more performant to do multiple .range
calls on inner.all_spks()
per keychain?
My argument is that performance is more of an issue for usecases with larger keychains-counts/spk-counts/lookahead-values.
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.
Indeed this is written so it hits the optimal time complexity in the number of keychains.
Let
Let's consider the worst case performance when the query matches all keychains and
For the previous implementation where you do two lookups you have to do
Setting
However, I really like the API changes done in this PR. I.e.
|
The way to detect it is to check the value returned by |
Yes, but that means we need to error when that happens (since it's non-viable to iterate through all of the wildcard-descriptor's spks). This means all methods that may need to derive more spks have to return an error. I don't think this is a reasonable API. |
The two claims made here are wrong in my view:
update: I improved docs around this in d2629cb also mentioning that it's up to the user not to insert overlapping descriptors. |
403620e
to
d2629cb
Compare
I've been thinking about The keychain For persisting, it's a more accurate representation to persist the In addition, I was in discussion with @LLFourn yesterday. He suggested that we should consider NOT persisting descriptors via the |
1b6fe8c
to
f456a04
Compare
Steps after this PR (not in any specific order):
|
I'm tempted to remove all instances where we prematurely collect, but can leave it for another PR. |
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.
self-ACK 3070b2d
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.
ACK 3070b2d
plus an additional comment about reveal_to_target
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.
tACK 3070b2d
I also manually tested the examples with signet descriptors and got back no errors and expected balance after scan and sync.
The underlying SpkTxOutIndex should not use DescriptorIds to index because this loses the ordering relationship of the spks so queries on subranges of keychains work. Along with that we enforce that there is a strict 1-to-1 relationship between descriptors and keychains. Violating this leads to an error in insert_descriptor now. In general I try to make the translation layer between the SpkTxOutIndex and the KeychainTxOutIndex thinner. Ergonomics of this will be improved in next commit. The test from the previous commit passes.
The previous commit b9c5b9d added IndexSpk. This goes further and adds `Indexed` and `KeychainIndexed` type alises (IndexSpk is Indexed<ScriptBuf>) and attempts to standardize the structure of return types more generally.
3070b2d
to
0017037
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.
ACK 8dd1744
0017037
to
8dd1744
Compare
Fixes #1459
This reverts part of the changes in #1203. There the
SpkTxOutIndex<(K,u32)>
was changed toSpkTxOutIndex<(DescriptorId, u32>)
. This led to a complicated translation logic inKeychainTxOutIndex
(where the API is based onK
) to transform calls to it to calls to the underlyingSpkTxOutIndex
(which now indexes byDescriptorId
). The translation layer was broken when it came to translating range queries from theKeychainTxOutIndex
. My solution was just to revert this part of the change and remove the need for a translation layer (almost) altogether. A thin translation layer remains to ensure that un-revealed spks are filtered out before being returned from theKeychainTxOutIndex
methods.I feel like this PR could be extended to include a bunch of ergonomics improvements that are easier to implement now. But I think that's the point of #1451 so I held off and should probably go and scope creep that one instead.
Checklists
All Submissions:
cargo fmt
andcargo clippy
before committingBugfixes: