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

[KS-70] Minimal RageP2P wrapper #12296

Merged
merged 1 commit into from
Mar 8, 2024
Merged

[KS-70] Minimal RageP2P wrapper #12296

merged 1 commit into from
Mar 8, 2024

Conversation

bolekk
Copy link
Contributor

@bolekk bolekk commented Mar 5, 2024

A minimal counterpart of libOCR's peer_v2+endpoint_v2+bootstrapper_v2 with following differences:

  1. Ability to change a set of peers dynamically.
  2. Identify peers by their PeerIDs instead of Oracle IDs.

Copy link
Contributor

github-actions bot commented Mar 5, 2024

I see that you haven't updated any README files. Would it make sense to do so?

@bolekk bolekk force-pushed the feature/KS-70-p2p-peer branch from 49acf9b to b51b904 Compare March 6, 2024 19:14
@bolekk bolekk marked this pull request as ready for review March 6, 2024 19:15
@bolekk bolekk requested review from a team as code owners March 6, 2024 19:15
@bolekk bolekk force-pushed the feature/KS-70-p2p-peer branch from b51b904 to 122ef31 Compare March 6, 2024 19:27
lggr logger.Logger
}

func NewPeer(cfg PeerConfig, lggr logger.Logger) (Peer, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm generally not a fan of returning interfaces: it's idiomatic in Go to return concrete types (eg. structs) and accept interfaces. So in this case, it's fine (but odd) to return *peer and then expect any users to use an interface type throughout.

Arguably I'd say the same thing about the Peer interface type -- it should live in the consuming package (or in a types package). If its purpose is to define the public interface, you can do that on the struct directly.

Copy link
Contributor Author

@bolekk bolekk Mar 7, 2024

Choose a reason for hiding this comment

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

Agreed with returning concrete types (fixing here).

I'm a fan of having an explicit interface because then I can generate mocks with Mockery. Can that be done for structs too?
If not, I'm OK with moving the interface to a "types" sub-package. I understand the arguments for placing it in the consuming package but what if there are multiple consumers? They shouldn't depend on one another so there would be multiple copies of the same interface and mock.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure you can generate a mock from a struct, but in that case I would leave the interface as a private detail of the package (and specifically the test files) and use mockery on that

services.Service
UpdatePeerAddresses(peerIDs []ragetypes.PeerID) error
Send(peerID ragetypes.PeerID, msg []byte) error
Receive() <-chan Message
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a benefit to exposing the internal detail of how reception happens (i.e. via a channel)? As opposed to exposing a generic Receive(Message) function?

Copy link
Contributor

Choose a reason for hiding this comment

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

I would bet the channel makes things more difficult if you are mapping to grpc streams underneath.

Copy link
Contributor

Choose a reason for hiding this comment

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

chan seems fine for a raw API though 🤷

Copy link
Contributor Author

Choose a reason for hiding this comment

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

By "generic Receive(Message) function?" do you mean a callback? I want to push all messages to some Receiver/Dispatcher object as they arrive, channel seems fine to me.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, I mean hiding the channel as an internal detail as opposed to having it as an external one. One benefit for exposing the channel I guess is that you can use it for synchronization with select.

for _, pid := range peerIDs {
pid := pid
if pid == p.myID { // don't create a self-stream
continue
Copy link
Collaborator

@patrick-dowell patrick-dowell Mar 7, 2024

Choose a reason for hiding this comment

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

Is it common in golang to use continues in for loops? I was told to avoid using them in most languages because they act a bit like jumps and can make it a little harder to understand control flow in loops. It's pretty easy to avoid using them:

if pid != p.myID {
   .... rest of the for loop logic here
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You can make arguments either way. I remember reading an opinion that the more nested some logic is the harder it is to understand. I don't know of any Go-specific recommendations, maybe @jmank88 knows.

Copy link
Contributor

Choose a reason for hiding this comment

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

I haven't seen much objection to continue in go, but there is definitely a tendency towards reducing nesting/indentation, so yeah maybe that alleviates this concern.

I suppose that there is an argument that using a continue in a for like this is actually analogous to the go proverb "return early, return often", which is meant to reduce indentation 🤷

A minimal counterpart of libOCR's peer_v2+endpoint_v2+bootstrapper_v2 with following differences:
1. Ability to change a set of peers dynamically.
2. Identify peers by their PeerIDs instead of Oracle IDs.
@bolekk bolekk force-pushed the feature/KS-70-p2p-peer branch from b48d48e to fd5c79b Compare March 8, 2024 02:41
@bolekk bolekk added this pull request to the merge queue Mar 8, 2024
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Mar 8, 2024
@bolekk bolekk added this pull request to the merge queue Mar 8, 2024
Merged via the queue into develop with commit 19b0485 Mar 8, 2024
97 checks passed
@bolekk bolekk deleted the feature/KS-70-p2p-peer branch March 8, 2024 15:35
ogtownsend pushed a commit that referenced this pull request Mar 14, 2024
A minimal counterpart of libOCR's peer_v2+endpoint_v2+bootstrapper_v2 with following differences:
1. Ability to change a set of peers dynamically.
2. Identify peers by their PeerIDs instead of Oracle IDs.
Comment on lines +113 to +124
if err := p.discoverer.RemoveGroup(defaultGroupID); err != nil {
p.lggr.Warnw("failed to remove old group", "groupID", defaultGroupID)
}
peerIDs := []ragetypes.PeerID{}
for pid := range peers {
peerIDs = append(peerIDs, pid)
}
if err := p.discoverer.AddGroup(defaultGroupID, peerIDs, p.cfg.Bootstrappers); err != nil {
p.lggr.Warnw("failed to add group", "groupID", defaultGroupID)
return err
}
return nil
Copy link
Contributor

Choose a reason for hiding this comment

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

Double checking, is your goal to have a fully connected graph of all peers?

I believe you could avoid the need to recreate the group (and thus potentially rediscover already known peers) by slightly modifying the logic here:

  • keep track of latest group id gid you used
  • when UpdateConnections is called:
    • register the new set of peers under a new group id gid'
    • remove the old groupid gid
    • gid := gid'

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nice! I didn't realize that it's OK for groups to overlap. I'll change it in a separate PR, thanks :)

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.

5 participants