-
Notifications
You must be signed in to change notification settings - Fork 43
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
Multiparty Senders: NS1R #434
base: master
Are you sure you want to change the base?
Multiparty Senders: NS1R #434
Conversation
d78288f
to
5ea6853
Compare
Can any of this be broken up and merged before all of the TODOs are done? It'd be cool to include this to maintain as an experimental feature as soon as possible and would help inform the shape of a stable API? What does the minimum merge look like? |
a4407be
to
5b61773
Compare
Absolutely! Everything multi party related should be featured gated so the risk is minimal. The most minimal change that I would like to make before considering merging are reverting the hacks I had to make to v2 or v1 receiver and sender. This is not a lot of work. After that I will open up for reviews. After that the bulk of remaining work is really just validation on both the sender and receiver sides. |
7411bd9
to
ac1447d
Compare
Pull Request Test Coverage Report for Build 13229947560Details
💛 - Coveralls |
d645e2b
to
f0c9b6b
Compare
payjoin/src/receive/mod.rs
Outdated
#[cfg(all(feature = "v2", feature = "multi_party"))] | ||
pub mod multi_party; | ||
|
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.
Move this below optional_parameters with the version stuff
pub fn try_preserving_privacy( | ||
&self, | ||
candidate_inputs: impl IntoIterator<Item = InputPair>, | ||
) -> Result<InputPair, SelectionError> { | ||
// TODO(armins) classic v1 privacy preserving selection doenst allow for many outputs | ||
// lets just pick the first one | ||
// self.v1.try_preserving_privacy(candidate_inputs) | ||
Ok(candidate_inputs.into_iter().next().unwrap()) | ||
} |
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.
Get rid of this fn as public if it's not actually avoiding UIH / other privacy pitfalls
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.
Done
sender_contexts: Vec<SessionContext>, | ||
} | ||
|
||
impl MultiPartyProvisionalProposal { |
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.
Just name these structs as e.g. ProvisionalProposal
so that they're fully qualified as ..::multi_party::ProvisionalProposal
and not ..::multi_party::MultiPartyProvisionalProposal
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.
Done
let mut agg_psbt = self.v2_proposals.first().expect("checked above").v1().psbt.clone(); | ||
for proposal in self.v2_proposals.iter().skip(1) { | ||
let proposal = proposal.v1().psbt.clone(); | ||
agg_psbt.combine(proposal).unwrap(); |
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.
handle, don't unwrap
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.
done!
f0c9b6b
to
204d456
Compare
204d456
to
329e0e1
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.
There's a ton here. It's already come a long way.
In order of importance I left comments regarding changes to existing public API, changes to existing modules, the multi-party implementation, my hygiene preferences for innline comments vs docstrings and commit separation.
I think the first commit can be pulled out of this PR and merged. It's unrelated and just nice-to-have. The PSBT merging seems mostly there, and we can merge it early because it should only be enabled in the experimental multi-party feature (which we may want to hide during the experimental phase as _multi-party
).
I do wonder how much it makes sense for the MergePsbtExt to be a Trait vs. a couple of feature-gated pub(crate) fn
s. I don't really think it's its own trait, since the trait isn't relied on in a function signature, but rather an extension of functionality, so I lean toward the latter. I think even feature gating the new methods in PsbtExt
rather than defining a completely new trait would be appropriate since they're internal, but pure functions are simpler.
The multi-party state machine is shaping up. Awesome to see tests work with minimal disruption to the existing abstractions. I'd like to have my comments addressing public API mutations addressed before merge, since afaict they only serve to enable multi-party and make less sense in the context of exclusive v1
, v2
use. Same with the changes to existing modules where the abstraction layers get muddy. Let's get those clean before merge.
I'm OK merging the multi-party state machine with some rough edges in the name of progress. We're not going to get it perfect the first time, and it's not going to make complete sense until we have integration into payjoin-cli
.
I would like to see the inline TODOs that don't define a TODO addressed, straggling lines removed, intermediate commit lint errors addressed, and inline comments pushed into docstrings or abstracted into new functions with their own docstrings. I'd also like to see the optional_parameters docstring update as its own commit.
This is a lot of comment, but hey this is a lot of PR. We're getting there. Let's pull the independent elements of this out of this to be merged this week and I think the more critical API problems are addressable in short order as well.
I didn't review the integration test implementation for the sake of time and because this review has already been so long. I believe the principles conveyed in the review apply there too, especially the one about duplication in payjoin-test-utils and tech debt. I'll revisit on the next request for review.
payjoin/src/psbt/merge/mod.rs
Outdated
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.
A nit would be to just name this merge.rs instead of merge/mod.rs
since there's no other file in the folder.
payjoin/src/psbt/merge/mod.rs
Outdated
} | ||
} | ||
|
||
// Tests |
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 comment can be removed
payjoin/src/receive/v2/mod.rs
Outdated
@@ -27,7 +27,7 @@ const SUPPORTED_VERSIONS: &[usize] = &[1, 2]; | |||
static TWENTY_FOUR_HOURS_DEFAULT_EXPIRY: Duration = Duration::from_secs(60 * 60 * 24); | |||
|
|||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] | |||
struct SessionContext { | |||
pub struct SessionContext { |
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 internal so pub(crate)
instead of pub
.
payjoin/src/receive/v2/mod.rs
Outdated
// TODO hack to get multi party working. A better solution would be to allow extract_v2_req to be seperate from the rest of the v2 context | ||
pub fn new(v1: v1::PayjoinProposal, context: SessionContext) -> Self { Self { v1, context } } |
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 don't want to affect the v2 API with a hack. This could be merged as pub(crate)
if possible or otherwise integrated into the state machine as your TODO suggests.
payjoin/src/send/mod.rs
Outdated
// TODO cannot check fee for optimistic v2 merges as they include utxo with missing info | ||
if !self.allow_optimistic_merge { | ||
self.check_fees(&proposal, contributed_fee)?; | ||
} |
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 is the TODO here? This is a general comment. Record what is TO be DOne.
@@ -408,6 +416,7 @@ fn serialize_url( | |||
fee_contribution: Option<AdditionalFeeContribution>, | |||
min_fee_rate: FeeRate, | |||
version: &str, | |||
opt_in_to_optimistic_merge: bool, |
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.
Would prefer to have a send::multi_party::serialize_url that encapsulates send::serialize_url to abstract these sepecifics away from the general case.
payjoin/src/send/multi_party/mod.rs
Outdated
|
||
impl<'a> SenderBuilder<'a> { | ||
/// Build a sender with optimistic merge enabled | ||
/// TODO(armins) this is pretty much skipping all the validating and checks |
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.
tell me what you want TODO
329e0e1
to
b1ee525
Compare
A struct with named fields replaces the tuple abstraction over sender Params `maxadditionalfeecontribution` and `additionalfeeoutputindex`. Cherry-pick'd off #434
b1ee525
to
9945d04
Compare
@DanGould I'm going to break out the psbt merge commits in its own PR. That work can be independently reviewed while I work on the remainding mp sender |
ccc4ba9
to
00e024e
Compare
The following is an expansion of the BIP77 protocol that allows for multiple senders to opt in to a optimisitic merge with other potential senders at a cost of an additional round of communication. The protocol does not introduce new message types instead it re-uses the existing v2 structs. Everything touching NS1R is feature gated behind the `multi_party` flag. The remaining work is: Multi party version of `try_preserving_privacy`. Currently when the v2 reciever is assembling a payjoin it calls in the v1 `try_preserving_privacy` method which invalidates for txs with > 2 outputs. We would either need to relax this constraint or write a bespoke version of `try_preserving_privacy` that optimizes for the multiparty case. The latter is more favorable in my opnion.
00e024e
to
9884aee
Compare
The following is an expansion of the BIP77 protocol that allows for
multiple senders to opt in to a optimisitic merge with other potential
senders at a cost of an additional round of communication. The protocol
does not introduce new message types instead it re-uses the existing v2
structs. Everything touching NS1R is feature gated behind the
multi_party
flag.The remaining work is:
Multi party version of
try_preserving_privacy
. Currently when thev2 reciever is assembling a payjoin it calls in the v1
try_preserving_privacy
method which invalidates for txs with > 2outputs. We would either need to relax this constraint or write a
bespoke version of
try_preserving_privacy
that optimizes for themultiparty case. The latter is more favorable in my opnion.
For more context please take a look at: https://github.com/orgs/payjoin/discussions/411
Outside of this PR we should consider expanding BIP77 to describe the protocol upgrades made in this PR