Add core RelaySelector#1696
Conversation
Coverage Report for CI Build 29109211191Coverage increased (+0.07%) to 86.072%Details
Uncovered Changes
Coverage RegressionsNo coverage regressions found. Coverage Stats
💛 - Coveralls |
zealsham
left a comment
There was a problem hiding this comment.
Cack
one question, once a relay is marked as failed, its impossible to unfail except a total restart, Should we have time window for retryability ?
|
thanks for the review! @zealsham
keeping it out of this PR to stay focused on the selection refactor |
|
rebased onto master, integrated with #1695: relay selection moved out of |
xstoicunicornx
left a comment
There was a problem hiding this comment.
Strong cACK, it is a good idea to modularize the relay selection so it is reusable by implementers and makes it easier to enforce good relay selection practices.
However, have some large pieces of feedback that affect the overall implementation and some questions on the design decisions.
| pub struct SelectContext {} | ||
|
|
||
| impl SelectContext { | ||
| /// An unconstrained context: selection is uniform-random. | ||
| pub fn random() -> Self { Self {} } | ||
| } |
There was a problem hiding this comment.
What is the intended purpose of this? It doesn't seem to be used.
There was a problem hiding this comment.
There was a problem hiding this comment.
Since the AS-aware selection should be optional once it is implemented I think a better strategy would be to just create a new RelaySelector::select_as_aware method for AS-aware selection and not prematurely worry about it here. This would prevent callers who opt not to use AS-aware selection to not have deal with this extraneous struct, would prevent needing any sig change in the future (without the need for #[non-exhaustive]), and also potentially allow for feature gating AS-aware selection.
bc1cindy
left a comment
There was a problem hiding this comment.
thank you! @xstoicunicornx
ready for re-review!
| pub struct SelectContext {} | ||
|
|
||
| impl SelectContext { | ||
| /// An unconstrained context: selection is uniform-random. | ||
| pub fn random() -> Self { Self {} } | ||
| } |
There was a problem hiding this comment.
xstoicunicornx
left a comment
There was a problem hiding this comment.
Couple pieces of feedback.
| pub struct SelectContext {} | ||
|
|
||
| impl SelectContext { | ||
| /// An unconstrained context: selection is uniform-random. | ||
| pub fn random() -> Self { Self {} } | ||
| } |
There was a problem hiding this comment.
Since the AS-aware selection should be optional once it is implemented I think a better strategy would be to just create a new RelaySelector::select_as_aware method for AS-aware selection and not prematurely worry about it here. This would prevent callers who opt not to use AS-aware selection to not have deal with this extraneous struct, would prevent needing any sig change in the future (without the need for #[non-exhaustive]), and also potentially allow for feature gating AS-aware selection.
the reason to keep this in a single path is anti-fingerprinting: #919 explicitly calls out that divergent relay-selection behavior across wallets is itself a client fingerprint. A separate select_as_aware + feature-gated API would institutionalize an "asmap vs non-asmap" split, the exact fingerprint this is meant to reduce. (#919 even contemplates shipping it enabled by default.) I think the cleaner split is: feature-gate the asmap data/dependency (that's the real weight, and why #1514's PoC gates it), but keep a makes sense? |
IMO the main reason #1514 is taking a gated approach is because the ASMap library being used is https://github.com/0xB10C/asmap, and this implementation is in Rust. If that is done making ASMap-aware relay selection the default would make more sense since the main requirements would simply be access to the library and the ASMap data from https://github.com/bitcoin-core/asmap-data. |
agreed, so it's a dependency-availability gate, not an opt-in one. Keeps the case for a single FFI for 0xB10C/asmap + making it default is follow-up, this PR just keeps the primitive in the right shape for it. |
|
I understand the argument, but I need to understand more about how Are callers expected to only use methods on |
yes to all three, that's the intended contract:
same |
|
So what is the advantage of this approach, where |
the advantage isn't eliminating a call site, it's that the method-per-context approach ( that said, AS-aware can be added later as a second method without breaking, and the context is empty while it's still WIP, so no need to reserve it now. I'll drop it and ship thank you! |
One canonical relay-selection policy so integrators stop diverging.
Share the lib selection policy instead of hand-rolling it in the cli.
add
payjoin::relay::RelaySelector, a reusable OHTTP relay-selection primitive (uniform-random over non-failed relays, withmark_failedfailover), so integrators share one policy instead of each diverging.non-breaking:
io::fetch_ohttp_keyskeeps its single-relay signature; selection and failover live in the caller, which reuses one long-livedRelaySelector(the cli'sMailroomManager).SelectContextis the extension point for the AS-aware selection.follow-up referenced in #1695 (review) by @DanGould; directory selection stays in the manager; durable tracking is #1697
part of #1694 / part of #1586
disclosure: co-authored by Claude