-
Notifications
You must be signed in to change notification settings - Fork 259
[New Feature] BIP 352 Silent Payments Address Support #769
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
base: dev
Are you sure you want to change the base?
Conversation
|
Thanks a lot @notTanveer for your work!! I haven't dived yet in the code but tested this PR on Raspberry Pi OS Manual Build:
Also, for "Export spend pubkey" and "Export scan privkey", I think it would improve the UX to first show the key before proceeding with the QR, similar to how the SP address is displayed first. Additionally, maybe it makes sense to show a |
99020da to
b532e9b
Compare
Ah, I’d already fixed that error but forgot to push, should be good now! |
|
Tested on Raspberry Pi OS manual build. Really neat UI. Functionally LGTM. I'd suggest to add screenshots for all the new screens, including the warning screen before showing the scan key and both spend and public key screenshots. |
203eb66 to
eb57f46
Compare
|
I only briefly scanned through the As far as I know, BIP-352 says basically nothing about what can or cannot be in a label. It lists incrementing integers as the most foolproof, trivially recoverable approach (i.e. every SP wallet can just automatically scan out to label So it seems overly restrictive to assume that only upper/lower/digit chars are valid. Josie's first example of a possible non-incrementing integer use case was a user account number. But what if the account numbers are specified like: IF we allow arbitrary text labels, it feels like we should allow common symbols as well. Which would mean the keyboard would be the same as the existing bip39 passphrase keyboard. Which would mean there's no need to refactor (other than to rename that keyboard class to be more general). THAT ALL BEING SAID... my sense so far is that the best practice is to assume the incrementing integer approach. There are so few wallet implementations that there's not enough data points to even suggest what an emerging consensus might be. But the incrementing integer approach was explained to me as the "don't shoot yourself in the foot" approach (because it's trivially easy for a wallet to recover those kinds of labels). This all leads me to think that maybe this is a better approach:
And then if some of the keyboard cleanup offers real improvements (DRY, readability, flexibility) without going too far into unnecessary premature optimization, then consider pulling those changes out into their own isolated refactor PR. As it is, those changes make this PR much harder to review and a bigger "ask" to get merged. |
|
I agree completely, if users don’t store or record their labels, there’s a high risk they’ll forget them over time. In fact, I initially wanted to add a warning screen when labels are chosen. I started out considering only numeric labels, but ultimately decided to allow any choice. To steer users toward numeric labels, though, I set the keyboard default to digits, and that required refactoring the keyboard screen to accommodate only numbers and letters. For symbols, I followed the Bitcoin design convention, which only includes alphanumeric characters, so that’s the approach I took. The BIP itself doesn’t explicitly limit label formats, but it does emphasize integers: “Let Bm = Bspend + hash(bscan || m)·G where m is an incrementable integer starting from 1.” It made sense to stick with integers, which again led to needing a keyboard refactor to avoid redundant code. All that said, I think I’ll move forward with the approach you described. As a first step, I’ll keep the initial pull request small—just basic Silent Payment address generation. |
|
I still think integer-only labels have a place here (though, again, users should be encouraged to leave labels disabled). But I'd like to hear what others think. |
268a384 to
ce58eea
Compare
|
updated the labels to support only integers for now. also did a small refactor on the details and labels screens to clean up some redundancy. now that i think about it — should we consider setting a limit on the label value? like 100K or maybe u32? EDIT: now that labels have a separate enable button, should i get rid of the 'Add Label' screen? |
102c3cb to
58a6f60
Compare
58a6f60 to
2e37615
Compare
|
|
||
|
|
||
|
|
||
| def encode_labeled_silent_payment_address(b_scan: ec.PrivateKey, B_spend: ec.PublicKey, label, network: str = "main", version: int = 0) -> str: |
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.
Type hint on label would be nice.
..., label: int | str | bytes, ...The convention seems to be to have spaces between each "|" which I hate, but, alas, a lot of these conventions are annoying (e.g. I would prefer to have no whitespace around = when setting default vals for input args).
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.
That being said, I'm not sure having a separate function for labels is necessary. It's probably cleaner to just have an optional label arg in encode_silent_payment_address that defaults to None.
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.
..., label: int | str | bytes, ...
since KeyboardScreen(used in LabelEntryView) always gives back a string, wondering if this should just be str across the board?
f45728e to
0e23341
Compare
| title=_("Scan Private Key Details"), | ||
| key_label=_("Scan Private Key"), |
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.
TRANSLATOR_NOTE - this one could be misinterpreted as a command ("Scan your private key now" instead of talking about the "scan private thing" as a noun). Have to make sure the translators aren't confused about the intention here.
src/seedsigner/views/seed_views.py
Outdated
| super().__init__() | ||
| self.seed_num = seed_num | ||
|
|
||
| #TODO: extend support for alphabets and special characters |
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 phrase this as something like "arbitrary (non-integer) labels"
|
This PR definitely needs to add a flow test to be considered complete! I'd suggest:
|
89f6a5a to
479b244
Compare
cb6d43c to
2f3d599
Compare
tests/test_flows_seed.py
Outdated
| ) | ||
|
|
||
|
|
||
| def test_bip352_generate_sp_address_with_labels_no_label_flow(self): |
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.
Super minor nit: "with labels no label" is confusing. Might be clearer in all of these test names to use "labels_enabled" / "labels_disabled" and then maybe something like "skip_label" / "specify_label"? Or "with_label" / "without_label"? You get the idea...
Also elsewhere we use double underscore to help provide extra clarity / separation in names when needed. I don't know if any flow tests use it, but I find it useful. e.g. labels_enabled__skip_label...
tests/test_flows_seed.py
Outdated
| FlowStep(seed_views.SeedBIP352SilentPaymentsOptionsView), | ||
| ] | ||
| ) | ||
|
|
||
|
|
||
| def test_bip352_export_scan_privkey_flow(self): | ||
| mnemonic = "blush twice taste dawn feed second opinion lazy thumb play neglect impact".split() | ||
| self.controller.storage.set_pending_seed(Seed(mnemonic=mnemonic)) | ||
| self.controller.storage.finalize_pending_seed() | ||
|
|
||
| self.settings.set_value(SettingsConstants.SETTING__BIP352_SILENT_PAYMENTS, SettingsConstants.OPTION__ENABLED) | ||
|
|
||
| self.run_sequence( | ||
| initial_destination_view_args=dict(seed_num=0), | ||
| sequence=[ | ||
| FlowStep(seed_views.SeedOptionsView, button_data_selection=seed_views.SeedOptionsView.BIP352_SILENT_PAYMENTS), |
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 probably would have just directly connected these tests into one sequence.
The strict separation here is slightly more rigorous, of course, just a tiny bit unnecessary.
| mnemonic = "blush twice taste dawn feed second opinion lazy thumb play neglect impact".split() | ||
| self.controller.storage.set_pending_seed(Seed(mnemonic=mnemonic)) | ||
| self.controller.storage.finalize_pending_seed() |
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 leverage the pytest harness to do this in something like setup_class (I can't recall the exact method name) where it's done once for the entire class before any of its child tests are run and is then present for all tests.
There's another method that's run before each individual test. I can't recall which scope would be required for this sort of pre-test config.
|
Can you regenerate the screenshots and update them in the PR description? I know at least the "DANGER" screen has changed. |
src/seedsigner/views/seed_views.py
Outdated
| # the first option allows the user to generate a static reusable SP address. | ||
| # next two options help in exporting the spend public key and scan private key, | ||
| # which is important for detecting incoming payments. | ||
| GENERATE_SP_ADDRESS = ButtonOption("Generate SP address") |
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 we just added an option here for "SP address + label" (or something like that) in order to avoid the label Yes/No screen entirely?
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.
Also worth thinking about if "Generate SP address" could offer a tiny bit more guidance: "Shareable SP address"?
Or just: "Silent payment address"? Or "Export SP address" to match our xpub approach?
Basically, "Generate" is taking up a lot space but isn't really useful.
708c3f3 to
2d47bfa
Compare
|
I believe i've addressed all the feedback. Changes:
Questions:
|
|
cACK 1d984f8 I haven't had the time to dive into this code, but did run the PR and did some functionality testing. Looks really good. Looking forward to getting SP functionality merged into SeedSigner. Thanks for this work! |
a4ae27d to
738d5ab
Compare
738d5ab to
0e6b4b0
Compare
|
Linking sp() output descriptor bip proposal for visibility Great to see the progress made on Label UI/UX |
Description
Implemented support for BIP-352 Silent Payment address generation (including label support), and also refactored the keyboard input screens.
This PR builds on top of Keith’s awesome work here: kdmukai/seedsigner#bip352_silent_payments_basic_support
Key changes:
Refactor
I included the refactor in this PR since the changes were minimal and related. For easier review, I recommend starting with the first commit, which focuses solely on SP address generation.
Screenshots
This pull request is categorized as a:
Checklist
pytestand made sure all unit tests pass before sumbitting the PRIf you modified or added functionality/workflow, did you add new unit tests?
I have tested this PR on the following platforms/os: