Skip to content
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

Protocol combinators #60

Merged
merged 9 commits into from
Nov 13, 2024
Merged

Protocol combinators #60

merged 9 commits into from
Nov 13, 2024

Conversation

fjarri
Copy link
Member

@fjarri fjarri commented Nov 2, 2024

We have several different situations where we need to build on top of an existing protocol or combine several of them:

  1. Modifying messages the node sends, keeping Round::Protocol the same. This is useful for writing tests.
  2. Chaining two protocols together. This is useful e.g. for joining Presigning and Signing in CGGMP.
  3. Executing two independent protocols simultaneously. See Add a zip combinator for protocols #61, will be implemented in another PR.
  4. Building on top of an existing protocol, adding features. See Add an extend combinator for protocols. #62, will be implemented in another PR.
  • Scenario 1 done as misbehave. Override macro and its machinery is removed from testing.
  • Scenario 2 done as chain.

Also:

  • Renamed FirstRound trait to EntryPoint. It is not bound on Round anymore.
  • Added Protocol type and ENTRY_ROUND constant to EntryPoint.
  • EntryPoint and FinalizeOutcome::AnotherRound now use a new BoxedRound wrapper type.
  • Added an impl of ProtocolError for () for protocols that don't use errors.
  • Added a dummy CorrectnessProof trait.
  • RoundId now supports nesting.

Notes:

  • Naming is kind of awkward. Suggestions?
  • Random idea: should EntryPoint::new take &self? This way we can basically formalize the concept of protocol constructors used in synedrion.
  • Should misbehave go into testing? Or gated behind the testing feature?
  • Should we keep the default value of EntryPoint::ENTRY_ROUND, or make the user define it explicitly every time?
  • The system with From bounds in the chain combinator is a little awkward, since we have to clone stuff for the first protocol. Some kind of a "splitting" trait might be more idiomatic, to split the full inputs into the inputs for Protocol 1 and the inputs for Protocol 2.
  • Also it requires us to impl From for the type from the original protocol, which may be foreign in practice.

@fjarri fjarri force-pushed the combinators branch 2 times, most recently from bbf4b82 to a006b37 Compare November 3, 2024 23:41
@coveralls
Copy link

coveralls commented Nov 3, 2024

Pull Request Test Coverage Report for Build 11823590883

Details

  • 403 of 615 (65.53%) changed or added relevant lines in 11 files are covered.
  • 7 unchanged lines in 1 file lost coverage.
  • Overall coverage decreased (-2.5%) to 68.992%

Changes Missing Coverage Covered Lines Changed/Added Lines %
manul/src/session/session.rs 24 26 92.31%
manul/src/session/evidence.rs 8 16 50.0%
manul/src/protocol/object_safe.rs 38 48 79.17%
manul/src/combinators/misbehave.rs 143 156 91.67%
manul/src/protocol/errors.rs 0 22 0.0%
manul/src/protocol/round.rs 17 53 32.08%
manul/src/combinators/chain.rs 159 280 56.79%
Files with Coverage Reduction New Missed Lines %
manul/src/protocol/object_safe.rs 7 78.1%
Totals Coverage Status
Change from base Build 11602146783: -2.5%
Covered Lines: 1731
Relevant Lines: 2509

💛 - Coveralls

@fjarri fjarri force-pushed the combinators branch 2 times, most recently from 369068b to 9922b66 Compare November 3, 2024 23:47
@fjarri fjarri marked this pull request as ready for review November 3, 2024 23:50
@fjarri fjarri requested a review from dvdplm November 3, 2024 23:51
CHANGELOG.md Show resolved Hide resolved
examples/src/lib.rs Show resolved Hide resolved
@@ -149,14 +149,15 @@ struct Round1Payload {
x: u8,
}

impl<Id: PartyId> FirstRound<Id> for Round1<Id> {
impl<Id: PartyId> EntryPoint<Id> for Round1<Id> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Naming ideas:

  • Init
  • Start
  • Gateway
  • ProtocolStart
  • InitRound
  • Kickoff

Can you elaborate a bit on why "FirstRound" is a bad name? I kind of liked it because it's very descriptive.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was logical when FirstRound was bound on Round, but it's not anymore. Now it's more like a Round factory.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be especially true if we make it stateful (see the note in the PR description).

examples/src/simple_chain.rs Show resolved Hide resolved
examples/src/simple_chain.rs Outdated Show resolved Hide resolved
manul/src/protocol/errors.rs Show resolved Hide resolved
manul/src/protocol/object_safe.rs Outdated Show resolved Hide resolved
manul/src/protocol/round.rs Outdated Show resolved Hide resolved
manul/src/protocol/round.rs Outdated Show resolved Hide resolved
manul/src/protocol/round.rs Outdated Show resolved Hide resolved
@fjarri fjarri force-pushed the combinators branch 2 times, most recently from b69876d to b9c3fcd Compare November 4, 2024 23:41
manul/src/combinators/chain.rs Outdated Show resolved Hide resolved
manul/src/combinators/chain.rs Outdated Show resolved Hide resolved
manul/src/combinators/chain.rs Outdated Show resolved Hide resolved
manul/src/combinators/chain.rs Show resolved Hide resolved
1. Define a type that will serve as the inputs for the new joined protocol.
Most likely it will be a union between inputs of the first and the second protocol.

2. Implement [`Chained`] for a type of your choice. Usually it will be an empty token type.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"empty token type": you mean like a ZST e.g. struct ProtoC?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep. Do you think "zero-sized type" would be more understandable here? Technically, it doesn't have to be zero-sized, it's just never instantiated by the crate.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think "token" is the correct term to use here, but given the world we live in, I suspect readers may confuse "token" with "cryptocurrency token".
Given you have a "usually" here, it doesn't have to be technically exact, it's more of a suggestion.

How about "Usually it will be a (possibly zero-sized) marker type."? Otherwise "token type" is fine too.

manul/src/combinators/chain.rs Outdated Show resolved Hide resolved
manul/src/combinators/chain.rs Outdated Show resolved Hide resolved
manul/src/combinators/misbehave.rs Show resolved Hide resolved
manul/src/combinators/misbehave.rs Show resolved Hide resolved
manul/src/protocol/round.rs Outdated Show resolved Hide resolved
@dvdplm
Copy link
Contributor

dvdplm commented Nov 13, 2024

  • Naming is kind of awkward. Suggestions?

I'm struggling with this. I don't love EntryPoint but it's pretty clear what it is/does. Let's go with that and if either of us have a brilliant idea we'll revisit.

  • Random idea: should EntryPoint::new take &self? This way we can basically formalize the concept of protocol constructors used in synedrion.

I like this!

  • Should misbehave go into testing? Or gated behind the testing feature?

I like misbehave to be difficult to misuse. Today we want to use it in tests, so let's put it there until we need it. I can totally envision a scenario where the core team wants to build a malicious node to test on (private?) testnets so maybe it'd be useful to have misbehave under a feature, but let's do that when the need arises.

  • The system with From bounds in the chain combinator is a little awkward, since we have to clone stuff for the first protocol. Some kind of a "splitting" trait might be more idiomatic, to split the full inputs into the inputs for Protocol 1 and the inputs for Protocol 2.

  • Also it requires us to impl From for the type from the original protocol, which may be foreign in practice.

Hmm. I like the idea of a "splitting" trait, but I don't have a strong opinion on this.

Copy link
Contributor

@dvdplm dvdplm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This LGTM. I left a few more thoughts&nitpicks – feel free to make the changes or not and then merge.

@fjarri
Copy link
Member Author

fjarri commented Nov 13, 2024

Random idea: should EntryPoint::new take &self? This way we can basically formalize the concept of protocol constructors used in synedrion.
Hmm. I like the idea of a "splitting" trait, but I don't have a strong opinion on this.

This is actually coming in #68

@fjarri
Copy link
Member Author

fjarri commented Nov 13, 2024

I remember seeing your comment about tinyvec vs smallvec, and, having looked at them, I agree that tinyvec is preferable.

@fjarri fjarri merged commit b8dc733 into entropyxyz:master Nov 13, 2024
8 checks passed
@fjarri fjarri deleted the combinators branch November 14, 2024 23:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants