Create fallback ohttp-relay logic for payjoin-cli#607
Create fallback ohttp-relay logic for payjoin-cli#607DanGould merged 2 commits intopayjoin:masterfrom
Conversation
Pull Request Test Coverage Report for Build 15071763691Details
💛 - Coveralls |
faa5d95 to
b3c5707
Compare
|
Nice lookin' draft. There are some code repeats that can probably be squashed but you probably know that and are just sharing early. I suppose this fixes #528? A mention in the OP will close the issue when this merges, if so. Thanks Ben |
36376eb to
1b80380
Compare
ec11bd6 to
6685f85
Compare
4d9104a to
8f032e6
Compare
c424ad6 to
001379c
Compare
There was a problem hiding this comment.
I gave this a once over as a way to stop blocking and make progress but bear in mind I didn't load the code and give it the most thorough review. Some questions:
- is the http dependency new or is it already in
cargo tree? If so, which version? May you please specify exactly instead of just"1" - same for rand. Do we need rand explicitly or is
payjoin::bitcoin::randavailable in all configurations? - How necessary are the dual code paths for _danger-local-https? To what extent may they be reduced?
- Will the relay state mutex unlock ever be contentious (lots of clients during
resume?) If so, we should usetokio::sync::Mutextoawaitinstead of blocking theasyncfn. If not, the synchronous one is fine.
I did check through commit text for rationale but missed answers to these questions
Hope this allows us to continue the conversation even though more thorough review may be required
This is important work for reliability of payjoin clients in the wild, so we need to make sure this is shaping up to be an excellent reference once merged.
payjoin-cli/src/app/v2.rs
Outdated
| let selected_relay = self.relay_state.lock().unwrap().get_selected_relay(); | ||
| let ohttp_relay = match selected_relay { | ||
| Some(relay) => relay, | ||
| None => validate_relay(&self.config, self.relay_state.clone()).await?, | ||
| }; | ||
|
|
There was a problem hiding this comment.
This has got to be a non-duplicated helper
payjoin-cli/src/app/v2.rs
Outdated
| } | ||
| } | ||
|
|
||
| //Local relays are incapable of acting as proxies so we must opportunistically fetch keys from the config |
There was a problem hiding this comment.
we could also GET directly from the payjoin-directory 🤔 not sure if that's any worse or less cumbersome than ohttp_keys configuration
There was a problem hiding this comment.
My only qualm about doing a direct GET request is that the local test that uses this then must depend on a good connection to the directory. This path currently only exists as our tests use dummy relays and pre-configured ohttp-keys so no changes are needed for those tests with these dual path functions
There was a problem hiding this comment.
This comment should be /// not //
|
Thanks for the feedback, always helpful to get some nudges in the right direction
It looks like the payjoin tree uses
rand can definitely be just from within payjoin, we can remove the independent dep there.
|
13b6273 to
a9af1e3
Compare
8bb7896 to
f13ddfa
Compare
I do not think we need to use async Mutex as all of our mutex unlocking and usage is done within small blocks and our mutexes are dropped before any sort of await call is made. |
payjoin-cli/src/app/v2.rs
Outdated
| let status_code = error | ||
| .to_string() | ||
| .split_whitespace() | ||
| .find_map(|code| http::StatusCode::from_str(code).ok()) | ||
| .expect("Could not find status code"); |
There was a problem hiding this comment.
I am doing some string splits here instead of changing the payjoin io Error::UnexpectedStatusCode It still feels a bit brittle, curious about other ideas you might have beyond making InternalError public.
There was a problem hiding this comment.
Making the error public is the way to go, perhaps with just an/some private variants
b3ea7d5 to
78ee4f2
Compare
|
I think I spoke imprecisely. The Internal Error should remain private. If it's time to make certain variants that are public, but keep an |
DanGould
left a comment
There was a problem hiding this comment.
The error handling proposed after my last comment is more complicated than I had imagined. I don't think we need a pub enum PublicError type because we already have an Error type that is public, it just needs to be a non-exhaustive enum with an Internal variant.
Since we've gone back and forth a couple of times, I took the liberty to write up a sketch of what I'm talking about. If we're not stabilizing the error and would rather kick the error can down the road this seems like the incremental step forward:
Read the last 2 commits here: https://github.com/DanGould/rust-payjoin/tree/ohttp-fallback
and specifically check out this section
payjoin-cli/Cargo.toml
Outdated
| hyper-util = { version = "0.1", optional = true } | ||
| log = "0.4.7" | ||
| payjoin = { version = "0.23.0", default-features = false } | ||
| payjoin = { path="../payjoin", default-features = false } |
There was a problem hiding this comment.
This change doesn't need to be here. We're already patching payjoin from crates.io with our local path in the top level Cargo.toml
Lines 5 to 6 in e2b66a2
|
what msrv is This isn't included until |
0fdc761 to
c97f23f
Compare
|
Since using this |
|
One fix would be to make the current InternalError into InternalErrorInner and then make a pub struct InternalError(InternalErrorInner). Otherwise, #[doc(hidden)] on both the Internal Variant AND pub enum InternalError could work. |
3c4d612 to
83abee1
Compare
DanGould
left a comment
There was a problem hiding this comment.
I like how you dealt with the error now.
However we've got some .unwrap()s on locks. Shouldn't those be .expect()s?
| { | ||
| cmd = cmd.arg( | ||
| Arg::new("ohttp_relay") | ||
| Arg::new("ohttp_relays") |
There was a problem hiding this comment.
How does this work? Someone passes --ohttp_relays "https://a.com" --ohttp_relays "https:://b.com"? Wouldn't we still want the singular --ohttp_relay name? Or do you expect them to be passed --ohttp_relays "https:://b.com","https://b.com ?
https://docs.rs/clap-action-command/latest/clap_action_command/fn.get_many.html
There was a problem hiding this comment.
How about we pass them as one or more value like --ohttp-relays "https://pj.benalleng.com,https://pj.bobspacebkk.com" or --ohttp-relays "https://pj.benalleng.com"?
| match ohttp_keys { | ||
| Ok(keys) => return Ok(Some(keys)), | ||
| Err(error) => match error { | ||
| payjoin::io::Error(InternalError::UnexpectedStatusCode(_)) => { | ||
| log::debug!("{error:?}"); | ||
| return Err(error.into()); | ||
| } | ||
| _ => { | ||
| log::debug!("Failed to connect to relay: {selected_relay}, {error:?}"); | ||
| relay_state.lock().unwrap().add_failed_relay(selected_relay); | ||
| } | ||
| }, | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
The same flatten done to the other match should probably happen here too
421e017 to
c57927c
Compare
So that they can be matched on in downstream logic. Keep Internal variants private.
The reliance on ohttp-relays can cause some distruption if they ever go offline but we did not have any examples of a fallback mechanism for choosing the relays at random and falling back to other relays in case they fail. This adds a new RelayState to manage which relays have already been tried and ulitmately hangs on to the first successful relay that it reaches.
DanGould
left a comment
There was a problem hiding this comment.
tACK 152393f
This is way more reliable. I think we need to think about what errors we exactly expose publicly (re: #403 but moreso to be a good reference example) and see if we abstract the RelayState away from the main v2.rs file. We can also very likely remove some of the duplicate flags for local-https in the follow up.
The reliance on ohttp-relays can cause some distruption if they ever go offline but we did not have any examples of a fallback mechanism for choosing the relays at random and falling back to other relays in case they fail.
This adds a new RelayState to manage which relays have already been tried and ulitmately hangs on to the first successful relay that it reaches per session.
Closes #528