-
Notifications
You must be signed in to change notification settings - Fork 237
[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?
805f0be
to
2e2bb8d
Compare
3f8feb6
to
89f6a5a
Compare
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. |
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 translators don't necessarily experience the translation strings in this sort of linear fashion.
Each TRANSLATOR_NOTE is only displayed for the translation string that immediately follows it; the subsequent entries won't have any context hints. It's best to treat each translation string as being totally devoid of any surrounding / sequential context.
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:
|
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
pytest
and 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: