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

Gossipsub v1.1 #1720

Merged
merged 141 commits into from
Jan 7, 2021
Merged

Gossipsub v1.1 #1720

merged 141 commits into from
Jan 7, 2021

Conversation

AgeManning
Copy link
Contributor

Description

This PR upgrades the current gossipsub implementation to support the v1.1 spec.

It adds a number of features, bug fixes and performance improvements.

Besides support for all new 1.1 features, other improvements that are of particular note:

  • Improved duplicate LRU-time cache (this was previously a severe bottleneck for large message throughput topics)
  • Extended message validation configuration options
  • Arbitrary topics (users can now implement their own hashing schemes)
  • Improved message validation handling - Invalid messages are no longer dropped but sent to the behaviour for application-level processing (including scoring)
  • Support for floodsub, gossipsub v1 and gossipsub v2
  • Protobuf encoding has been shifted into the behaviour. This has permitted two improvements:
    1. Message size verification during publishing (report to the user if the message is too large before attempting to send).
    2. Message fragmentation. If an RPC is too large it is fragmented into its sub components and sent in smaller chunks.

Additional Notes

The peer eXchange protocol defined in the v1.1 spec is inactive in its current form. The current implementation permits sending PeerId in PRUNE messages, however a PeerId is not sufficient to form a new connection to a peer. A Signed Address Record is required to safely transmit peer identity information. Once these are confirmed (libp2p/specs#217) a future PR will implement these and make PX usable.

Final Note

This is currently undergoing further testing and an audit and I may modify this slightly as bugs come up :)

@mxinden
Copy link
Member

mxinden commented Nov 20, 2020

As promised I gave this another review, see sigp#93.

Given the size of #1720 I did my review directly inline. A lot of suggestions are just related to styling - I hope delivering my review as a pull request makes accepting those easier. Comments are prefixed with // mxinden:.

Let me know if this format works for you. If not, I can transform this into a traditional Github review.

Again, as #1720 is quite large, I have not yet fully reviewed all changes / additions.

@AgeManning
Copy link
Contributor Author

Thanks max. I think we've addressed all the comments. I've merged into your branch there. Let me know if anything is missed.

If all good, I'll merge that branch down and then merge latest master.

mxinden and others added 2 commits December 7, 2020 14:41
* protocols/gossipsub: Review

* Addressing most of the review comments

* Address reviewers comments

* Appease CI

Co-authored-by: blacktemplar <blacktemplar@a1.net>
Co-authored-by: Age Manning <Age@AgeManning.com>
@jolestar
Copy link
Contributor

jolestar commented Dec 7, 2020

It is possible to support a custom peer selector/filter strategy for publishing messages?

@AgeManning
Copy link
Contributor Author

It is possible to support a custom peer selector/filter strategy for publishing messages?

We could add this in, but I'm not sure why you would want to. What is it's intended purpose? Do you want it to apply just to publishing messages or also to forwarding?

Lets say you want to publish to only half the peers in your mesh (based on some filter). Those peers would then forward it to peers in their mesh and the message would propagate regardless (with added latency), including to those you don't directly publish to. This filtering would also affect the scoring that is implemented in 1.1 as some nodes would look like they are censoring.

Maybe if you could detail the reasons why you might want this I could provide more help.

@jolestar
Copy link
Contributor

jolestar commented Dec 9, 2020

We could add this in, but I'm not sure why you would want to. What is it's intended purpose? Do you want it to apply just to publishing messages or also to forwarding?

Lets say you want to publish to only half the peers in your mesh (based on some filter). Those peers would then forward it to peers in their mesh and the message would propagate regardless (with added latency), including to those you don't directly publish to. This filtering would also affect the scoring that is implemented in 1.1 as some nodes would look like they are censoring.

Maybe if you could detail the reasons why you might want this I could provide more help.

Thanks. My usage scenario is blockchain. I want to publish messages to some peers base on the peer's state, such as peer's type(lighting node/full node), block_height, or total_difficulity. If the Gossipsub does not support a custom strategy, the application needs to implement a custom Gossip protocol, such as subtract(https://github.com/paritytech/substrat) network/network-gossip. But the hardest part of the custom strategy is how to maintain the custom state of the peer. if the custom state can not keep in Gossipsub's peer state, it will very hard to implement a peer filter strategy.

@blacktemplar
Copy link
Contributor

blacktemplar commented Dec 10, 2020

We could add this in, but I'm not sure why you would want to. What is it's intended purpose? Do you want it to apply just to publishing messages or also to forwarding?
Lets say you want to publish to only half the peers in your mesh (based on some filter). Those peers would then forward it to peers in their mesh and the message would propagate regardless (with added latency), including to those you don't directly publish to. This filtering would also affect the scoring that is implemented in 1.1 as some nodes would look like they are censoring.
Maybe if you could detail the reasons why you might want this I could provide more help.

Thanks. My usage scenario is blockchain. I want to publish messages to some peers base on the peer's state, such as peer's type(lighting node/full node), block_height, or total_difficulity. If the Gossipsub does not support a custom strategy, the application needs to implement a custom Gossip protocol, such as subtract(https://github.com/paritytech/substrat) network/network-gossip. But the hardest part of the custom strategy is how to maintain the custom state of the peer. if the custom state can not keep in Gossipsub's peer state, it will very hard to implement a peer filter strategy.

I think you should try to solve that with dividing your topics. If you really need dynamic strategies for distributing messages I am not sure if gossipsub is the right way to do it. You would have to think how to handle the different states in your IHAVE messages too, so it becomes very complicated very fast.

* Update rustls requirement from 0.18.0 to 0.19.0 (libp2p#1852)

Updates the requirements on [rustls](https://github.com/ctz/rustls) to permit the latest version.
- [Release notes](https://github.com/ctz/rustls/releases)
- [Changelog](https://github.com/ctz/rustls/blob/main/OLDCHANGES.md)
- [Commits](rustls/rustls@v/0.18.0...v/0.19.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Prepare libp2p-websocket-0.26.1

* Update top-level libp2p-websocket patch version.

* [request-response] Refine success & error reporting for inbound requests. (libp2p#1867)

* Refine error reporting for inbound request handling.

At the moment one can neither get confirmation when a
response has been sent on the underlying transport, nor
is one aware of response omissions. The latter was
originally intended as a feature for support of
one-way protocols, which seems like a bad idea in
hindsight. The lack of notification for sent
responses may prohibit implementation of some
request-response protocols that need to ensure
a happens-before relation between sending a
response and a subsequent request, besides uses
for collecting statistics.

Even with these changes, there is no active notification
for failed inbound requests as a result of connections
unexpectedly closing, as is the case for outbound requests.
Instead, for pending inbound requests this scenario
can be identified if necessary by the absense of both
`InboundFailure` and `ResponseSent` events for a particular
previously received request. Interest in this situation is
not expected to be common and would otherwise require
explicitly tracking all inbound requests in the `RequestResponse`
behaviour, which would be a pity. `RequestResponse::send_response`
now also synchronously returns an error if the inbound upgrade
handling the request has been aborted, due to timeout or
closing of the connection, giving more options for graceful
error handling for inbound requests.

As an aside, the `Throttled` wrapper now no longer emits
inbound or outbound error events occurring in the context
of sending credit requests or responses. This is in addition
to not emitting `ResponseSent` events for ACK responses of
credit grants.

* Update protocols/request-response/src/lib.rs

Co-authored-by: Max Inden <mail@max-inden.de>

* Address some minor clippy warnings. (libp2p#1868)

* Track pending credit request IDs.

In order to avoid emitting events relating to credit grants or acks
on the public API. The public API should only emit events relating
to the actual requests and responses sent by client code.

* Small cleanup

* Cleanup

* Update versions and changelogs.

* Unreleased

Co-authored-by: Max Inden <mail@max-inden.de>

* core/benches: Add rudimentary benchmark for PeerId::from_bytes and clone (libp2p#1875)

* core: Add rudimentary benchmark for PeerId::from_bytes and clone

* .github/workflow: Include benchmarks

To ensure changes through pull requests won't make benchmarks fail to
compile or run, run them as part of CI.

* [mdns] Split response packets if necessary. (libp2p#1877)

* [mdns] Split response packets.

Prevent MDNS response packets becoming too large by creating
multi-packet responses. Also skip addresses that don't fit
into a TXT record or contain invalid characters.

* Update protocols/mdns/src/dns.rs

Co-authored-by: Max Inden <mail@max-inden.de>

* Refactor response packet construction.

* Update mdns changelog.

Co-authored-by: Max Inden <mail@max-inden.de>

* core/benches: Add PeerId sort_vec benchmark (libp2p#1878)

* Prepare v0.32 (libp2p#1879)

* [websocket] Update minimum async-tls patch version. (libp2p#1881)

* Update minimum async-tls patch version.

After the upgrade to rustls 0.19, this is the minimum
version required to build.

* Prepare libp2p patch.

* Update async-tls requirement from 0.10.2 to 0.11.0 (libp2p#1884)

* Update async-tls requirement from 0.10.2 to 0.11.0

Updates the requirements on [async-tls](https://github.com/async-std/async-tls) to permit the latest version.
- [Release notes](https://github.com/async-std/async-tls/releases)
- [Commits](async-rs/async-tls@v0.10.2...v0.11.0)

Signed-off-by: dependabot[bot] <support@github.com>

* *: Prepare release

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Max Inden <mail@max-inden.de>

* rename generic types + add default types + update documentation links

* fix broken intra links

* fix tests

* type annotation in example

* fix doc example

* Add compression to gossipsub

* Add snappy compression to the smoke tests

* Stack allocated PeerId (libp2p#1874)

* Stack allocate PeerId.

* Update stuff.

* Upgrade rusttls to fix build.

* Remove unnecessary manual implementations.

* Remove PeerId::into_bytes.

* Remove bytes dependency.

* Perform some cleanup.

* Use Into<kbucket::Key<K>>.

* Update versions and changelogs.

* Fix PR link.

* Fix benchmarks.

Co-authored-by: Roman S. Borschel <roman@parity.io>

* Remove copy and adjust validation ordering

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Roman S. Borschel <roman@parity.io>
Co-authored-by: Roman Borschel <romanb@users.noreply.github.com>
Co-authored-by: Max Inden <mail@max-inden.de>
Co-authored-by: blacktemplar <blacktemplar@a1.net>
Co-authored-by: David Craven <david@craven.ch>
@jolestar
Copy link
Contributor

We could add this in, but I'm not sure why you would want to. What is it's intended purpose? Do you want it to apply just to publishing messages or also to forwarding?
Lets say you want to publish to only half the peers in your mesh (based on some filter). Those peers would then forward it to peers in their mesh and the message would propagate regardless (with added latency), including to those you don't directly publish to. This filtering would also affect the scoring that is implemented in 1.1 as some nodes would look like they are censoring.
Maybe if you could detail the reasons why you might want this I could provide more help.

Thanks. My usage scenario is blockchain. I want to publish messages to some peers base on the peer's state, such as peer's type(lighting node/full node), block_height, or total_difficulity. If the Gossipsub does not support a custom strategy, the application needs to implement a custom Gossip protocol, such as subtract(https://github.com/paritytech/substrat) network/network-gossip. But the hardest part of the custom strategy is how to maintain the custom state of the peer. if the custom state can not keep in Gossipsub's peer state, it will very hard to implement a peer filter strategy.

I think you should try to solve that with dividing your topics. If you really need dynamic strategies for distributing messages I am not sure if gossipsub is the right way to do it. You would have to think how to handle the different states in your IHAVE messages too, so it becomes very complicated very fast.

The gossipsub protocol broadcast message base node's knowledge base, node exchange knowledge by IHAVE message. But IHAVE only support MessageID Vec, I think whether it is possible to support a weighted id, the weight may be message's index or other sortable property, it can help to filter peer and reduce repeat gossip messages.

@blacktemplar
Copy link
Contributor

We could add this in, but I'm not sure why you would want to. What is it's intended purpose? Do you want it to apply just to publishing messages or also to forwarding?
Lets say you want to publish to only half the peers in your mesh (based on some filter). Those peers would then forward it to peers in their mesh and the message would propagate regardless (with added latency), including to those you don't directly publish to. This filtering would also affect the scoring that is implemented in 1.1 as some nodes would look like they are censoring.
Maybe if you could detail the reasons why you might want this I could provide more help.

Thanks. My usage scenario is blockchain. I want to publish messages to some peers base on the peer's state, such as peer's type(lighting node/full node), block_height, or total_difficulity. If the Gossipsub does not support a custom strategy, the application needs to implement a custom Gossip protocol, such as subtract(https://github.com/paritytech/substrat) network/network-gossip. But the hardest part of the custom strategy is how to maintain the custom state of the peer. if the custom state can not keep in Gossipsub's peer state, it will very hard to implement a peer filter strategy.

I think you should try to solve that with dividing your topics. If you really need dynamic strategies for distributing messages I am not sure if gossipsub is the right way to do it. You would have to think how to handle the different states in your IHAVE messages too, so it becomes very complicated very fast.

The gossipsub protocol broadcast message base node's knowledge base, node exchange knowledge by IHAVE message. But IHAVE only support MessageID Vec, I think whether it is possible to support a weighted id, the weight may be message's index or other sortable property, it can help to filter peer and reduce repeat gossip messages.

I am not sure if I understand you correctly, but if you propose additions to the gossipsub protocol you are probably better of to propose them in https://github.com/libp2p/specs/.

Copy link
Member

@mxinden mxinden left a comment

Choose a reason for hiding this comment

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

I would be in favor of merging this pull request into master. As far as I can tell, the only outstanding task would be to fix the intra-doc links. What do you think @AgeManning @blacktemplar?

@@ -0,0 +1,58 @@
//! This trait allows of extended user-level decoding that can apply to message-data before a
Copy link
Member

Choose a reason for hiding this comment

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

Can you add a license header 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.

Can do.

I think its mostly stable now. Will fix the doc links.

@AgeManning
Copy link
Contributor Author

Fixed the doclinks and merged latest master.

@mxinden
Copy link
Member

mxinden commented Jan 6, 2021

Great. I will merge later today unless anyone objects till then.

@mxinden mxinden merged commit df7e73e into libp2p:master Jan 7, 2021
@mxinden
Copy link
Member

mxinden commented Jan 7, 2021

🎉 Thank you for the extensive amount of work you put into this.

Comment on lines +76 to +80
gossip_threshold: -10.0,
publish_threshold: -50.0,
graylist_threshold: -80.0,
accept_px_threshold: 10.0,
opportunistic_graft_threshold: 20.0,
Copy link
Contributor

Choose a reason for hiding this comment

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

@AgeManning could you please share how those values were defined?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

These essentially can be defined for whatever network you are running gossipsub on. Its been a few years, but I believe these were from the go-implementation at the time, which may have been used in some of the tests in the v1.1 gossipsub paper where they tested a few attack vectors.

These numbers shouldn't be set independently, but based on the maximum and minimum values you can get from the score.

Copy link
Contributor

Choose a reason for hiding this comment

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

I found this PR that says the values were inspired by LH status-im/nimbus-eth2#2091. These are the values used:

     gossipThreshold: -4000,
     publishThreshold: -8000,
     graylistThreshold: -16000

They are used here indeed https://gist.github.com/blacktemplar/5c1862cb3f0e32a1a7fb0b25e79e6e2c#file-51000-toml-L33, but LH doesn't use to configure GossipSub, but rather here

let gossip_threshold = -4000.0;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Now I"m confused about what you are asking.

The values in this repository i.e gossip_threshold: -10 is not the same value as what we have chosen in the Ethereum consensus network i.e -4000.

As I mentioned, these values need to be defined for whatever network you are running. For Ethereum's consensus network, we did a bunch of estimations and determined a bunch of numbers. That is entirely independent of the gossipsub protocol, which should run on any network.

If you question is specific to lighthouse or the Ethereum network, then that is a different question and probably should be asked on the lighthouse repo as those values are for a specific network.

You did point out that the metrics value uses the Ethereum consensus values as default. This probably should be using the same defaults as the rust-libp2p repo. At the time, Lighthouse was the only one consuming these metrics and so was built around our scoring values to get sane results in the histograms.

Copy link
Contributor

Choose a reason for hiding this comment

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

You're right, sorry for the confusion. It's clear now, thanks. I somehow misled myself looking at this PR that introduces params in the lighthouse rust-libp2p fork https://github.com/sigp/rust-libp2p/pull/556/files#diff-9f622a0085d0d96aef9e883b7afdcdd4a652e8801be7cfabf82819f5a74a70e0. Is there a lighthouse PR defining the values for lighthouse?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What specifically are you interested in?

Are you asking how we figured out what values to use in Lighthouse? There is an external document I can share with you if that's the case. The PR to lighthouse will likely just show values being added with no context.

Feel free to DM me in the Lighthouse discord if you like

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.

8 participants