-
Notifications
You must be signed in to change notification settings - Fork 37
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
Pad ohttp req/res messages to consistent 8192 bytes #395
Conversation
dedec61
to
b404a91
Compare
Clients pad OHTTP requests and responses so that when they're sent to an OHTTP relay that relay can't distingush the type of BIP 77 message e.g. POST, GET, Response 202, Response 200. Co-authored-by: nothingmuch <[email protected]>
If these arguments were statically sized we wouldn't need to test it. Do that |
ac0f294
to
1a9179b
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.
concept ACK
1a9179b
to
d6f927c
Compare
Pull Request Test Coverage Report for Build 12063584579Details
💛 - Coveralls |
payjoin/src/send/mod.rs
Outdated
let mut res_buf = [0u8; crate::ohttp::ENCAPSULATED_MESSAGE_BYTES]; | ||
res_buf[..response.len()].copy_from_slice(response); | ||
let response = ohttp_decapsulate(self.ohttp_ctx, &res_buf) |
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.
Following the same pattern as V2GetContext::process_response:
let mut res_buf = [0u8; crate::ohttp::ENCAPSULATED_MESSAGE_BYTES]; | |
res_buf[..response.len()].copy_from_slice(response); | |
let response = ohttp_decapsulate(self.ohttp_ctx, &res_buf) | |
let response_array: &[u8; crate::ohttp::ENCAPSULATED_MESSAGE_BYTES] = | |
response | |
.try_into() | |
.map_err(|_| InternalValidationError::UnexpectedResponseSize(response.len()))?; | |
let response = ohttp_decapsulate(ohttp_ctx, response_array) |
Also seems better to propagate an error instead of truncating to response.len() in case the length doesn't match the expected size.
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.
this is important, because if response.len() > crate::ohttp::ENCAPSULATED_MESSAGE_BYTES
then this will panic due to slice out of range crashing the directory
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 selected "Request changes" because spacebear's suggestion is required (addresses out of range panic in directory). my suggestions are mere comments.
payjoin/src/ohttp.rs
Outdated
|
||
let mut bhttp_req = [0u8; PADDED_BHTTP_REQ_BYTES]; | ||
let mut cursor = std::io::Cursor::new(&mut bhttp_req[..]); | ||
let _ = bhttp_message.write_bhttp(bhttp::Mode::KnownLength, &mut cursor); |
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.
IIRC wrapping with Cursor is not necessary as a mut slice implements Write (not sure if write_bhttp needs Seek?)
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.
Ah, we need .as_mut_slice. We kept missing this method when we stayed up late trying to fix it.
payjoin/src/send/mod.rs
Outdated
let mut res_buf = [0u8; crate::ohttp::ENCAPSULATED_MESSAGE_BYTES]; | ||
res_buf[..response.len()].copy_from_slice(response); | ||
let response = ohttp_decapsulate(self.ohttp_ctx, &res_buf) |
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.
this is important, because if response.len() > crate::ohttp::ENCAPSULATED_MESSAGE_BYTES
then this will panic due to slice out of range crashing the directory
payjoin-directory/src/lib.rs
Outdated
@@ -23,7 +23,8 @@ pub const DEFAULT_DIR_PORT: u16 = 8080; | |||
pub const DEFAULT_DB_HOST: &str = "localhost:6379"; | |||
pub const DEFAULT_TIMEOUT_SECS: u64 = 30; | |||
|
|||
const MAX_BUFFER_SIZE: usize = 65536; | |||
const PADDED_BHTTP_BYTES: usize = 8192; |
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.
we should probably document the total waste (8192 - ohttp overhead - 7168) somewhere, but not sure where is a good place to do that
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 was wondering about this. Can we match them to create no or less waste? my understanding is that we just need leeway for sufficiently long URLs in headers
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.
when we tried to account for the bhttp overhead we got lost in details and specifically how it varies... i'm not sure what we can promise there
my framing it as "waste" was misleading, so we should come up with a way of explaining this gap in sizes more clearly.
the bhttp encoding overhead, any variability in the vhost, uri path, etc must all fit in this ~1kib budget... that seems reasonable as a value, i'm not sure if we should match these more closely although i can only think of pretty contrived reasons why you'd that much
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.
path in an OHTTP request is in practice quite small since the target path details are encapsulated and the request ought to go to the OHTTP gateway to be marshaled to the specific path target encoded in the BHTTP. In our examples, we just use /
as the path, and the host https://payjo.in'.
https://payjo.in/` is 17 bytes. That makes me think this overhead is actually a lot more than it needs to be and 256 bytes, being an order of magnitude greater, is almost certainly enough for any legitimate use assuming BIP 77 is the primary use. Getting 768 additional bytes if we used 256 bytes in the payload is an ~11% increase in payload size, which is a pretty big gain for working with PSBTs for payjoins.
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 thought 7168 seemed and was deemed sufficient for the 2 party case? has anything changed the underlying rationale for that? FWIW a similar% gain would be obtained by not encoding the psbt as base64 in v2
Take advantage of the edit to use `&[u8]` function signatures where applicable to reduce tech debt.
d6f927c
to
c031be7
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.
This seems mergeable to me as is.
However, if there are good reasons to doubt 7168 * 6/8 = ~5KiB PSBT as being sufficiently large, or 8192 as being sufficiently small then it should probably be addressed.
Both seem rather arbitrary to me, but ~5KiB being sufficiently large for BIP 77 is the more important one to get right i guess? A budget of about a dozen each of inputs and outputs per party with room to spare seems like it's more than enough for the stated use cases.
The only argument I can think of that might make a difference in user experience -- and even that is very dubious -- depends on the actual MTU. The lowest value on wikipedia for common media is 1452, which * 5 = 7260. For one packet to make a perceptible difference on average would imply the user is suffering from pretty extreme packet loss. Assuming this argument actually makes sense (again I think it doesn't) then i guess we should calculate and verify precise values for the bhttp overhead etc to make sure it all fits in less than 7260 bytes. Otherwise the argument for utilizing the existing headroom in 8192 bytes more efficiently seems very marginal for the 2 party case.
You sound very confident that this will not be followed with a breaking change. Merging. |
Merely very confident that I can't come up with a good argument for increasing or decreasing either of the two sizes ;-) |
Padded messages (POST, GET, Response 202, Response 200) are no longer distinguishable
Rationale: 7kb x 2x/min / 1h = ~1MB/hr which is not too much overhead.
We must also specify a 30s timeout in BIP 77 for long polling and say that clients MUST poll as soon as they receive a response so as not to fingerprint clients based on request timing.TODO left in BIP commentsresize
ing vectors.