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

Use libp2p gossipsub upstream validator framework #4318

Merged
merged 31 commits into from
Dec 20, 2019

Conversation

prestonvanloon
Copy link
Member

@prestonvanloon prestonvanloon commented Dec 18, 2019

Resolves #4317

Thanks to @protolambda for pointing this out.

This is now a refactoring to use the gossipsub validator framework.

nisdas
nisdas previously approved these changes Dec 18, 2019
nisdas
nisdas previously approved these changes Dec 18, 2019
@prestonvanloon prestonvanloon added OK to merge Blocked Blocked by research or external factors and removed OK to merge labels Dec 18, 2019
@prestonvanloon
Copy link
Member Author

This solution is not going to work as is. Adding a pubsub validator to reject all re-propagation will block all messages from being received.

The problem with using the pubsub validator framework for validation is that when you need to inspect the message contents, you would need to deserialize the message more than once for any given valid message. With the assumption that the majority of the messages will be valid, this could be an expensive task.

As is, we all repropagate messages once, thanks to content addressable message IDs. The problem is that we want to stop propagation of messages that are invalid.

My thinking now is that we consider these two approaches:

  • Add some functionality in gossipsub to disable automatic propagation of any topic message
  • Use the existing validator framework and deserialize messages twice. Alternatively, come up with some caching mechanism to try to avoid deserializing the messages twice, but this idea smells.

I've reached out to @raulk on telegram to see if there is any expert feedback from their team.

@protolambda
Copy link

There's another option: introduce a preprocessing step, to then continue with the preprocessed message in validation and the subscription.
I see three options for continuation there:

  • overload the message interface that gets passed around, and decode it into the right typed data from preprocessing for validation/processing.
  • add a metadata getter to the message. To attach things to during processing, to use at a later stage.
  • refactor more, make the pipeline more compositional, and somehow progressively process the message at each stage, instead of repeating things like decoding

@prestonvanloon
Copy link
Member Author

prestonvanloon commented Dec 18, 2019

overload the message interface that gets passed around, and decode it into the right typed data from preprocessing for validation/processing.

refactor more, make the pipeline more compositional, and somehow progressively process the message at each stage, instead of repeating things like decoding

These options would certainly solve our problem.

I imagine this pipeline:

  1. Incoming pubsub.Message
  2. Check seen message ID, peer signature verification, other pubsub metadata checks
  3. Preprocess -> decode message
  4. Validate -> check message contents
  5. Propagate
  6. Subscriber receives (decoded) message -> handle message at application layer

@raulk
Copy link

raulk commented Dec 18, 2019

Yes, I agree that we could add a baggage map where validators could store deserialised payloads or other computed/derived information, for downstream validators to reuse. We could also propagate this baggage to the final consumer.

@whyrusleeping
Copy link

Oh hey! we already have a place for the validators to put things for the consumer, you can set Message.ValidatorData in the validator, and it is accessible by the receiver.

ref: libp2p/go-libp2p-pubsub#231

@raulk
Copy link

raulk commented Dec 18, 2019

Yep, it turns out this is already implemented and I had missed it :-)

@prestonvanloon
Copy link
Member Author

Awesome. Thanks @whyrusleeping @raulk @protolambda. We'll refactor our validation pipeline and use that field to pass around the message data. Thanks!!!

@prestonvanloon
Copy link
Member Author

OK this is ready for review again. I was experiencing some weird behavior that appears to run a validator on broadcast as well as the subscriber. libp2p/go-libp2p-pubsub#250

If anyone knows how to disable the validator on publish, I'd appreciate that info.

@prestonvanloon prestonvanloon added Ready For Review A pull request ready for code review and removed Blocked Blocked by research or external factors labels Dec 19, 2019
@prestonvanloon prestonvanloon changed the title Add reject all pubsub validator to stop automatic propagation Use libp2p gossipsub upstream validator framework Dec 19, 2019
rauljordan
rauljordan previously approved these changes Dec 19, 2019
Copy link

@protolambda protolambda left a comment

Choose a reason for hiding this comment

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

A few nitpicks, I'm following this PR, good work so far 👍

func noopValidator(_ context.Context, _ proto.Message, _ p2p.Broadcaster, _ bool) (bool, error) {
return true, nil
// noopValidator is a no-op that only decodes the message, but does not check its contents.
func (r *Service) noopValidator(ctx context.Context, _ peer.ID, msg *pubsub.Message) bool {

Choose a reason for hiding this comment

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

Maybe call it preProcessValidator to make clear what it really is?

Choose a reason for hiding this comment

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

Also, I think pubsub has a way to chain validators in sync, so you do not have to repeatedly call decodePubsubMessage, and put this as the preprocess validator instead.

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 is actually only used in test. From what I recall, all validators were run asynchronously. Chaining would be nice with your suggestion though.

From godocs:

RegisterTopicValidator registers a validator for topic. By default validators are asynchronous, which means they will run in a separate goroutine. The number of active goroutines is controlled by global and per topic validator throttles; if it exceeds the throttle threshold, messages will be dropped.

I'll leave this for now unless we can chain these.

return false
}
topic := msg.TopicIDs[0]
topic = strings.TrimSuffix(topic, r.p2p.Encoding().ProtocolSuffix())

Choose a reason for hiding this comment

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

Maybe the msg checks and topic extraction can be refactored into a helper function?

Choose a reason for hiding this comment

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

Nice refactor, ninja'd this problem before I submitted the review. Great

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks! Terence beat you to it lol

Copy link
Member

@terencechain terencechain left a comment

Choose a reason for hiding this comment

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

Looks good to me otherwise

beacon-chain/sync/validate_beacon_attestation.go Outdated Show resolved Hide resolved
Co-Authored-By: terence tsao <terence@prysmaticlabs.com>
Copy link
Member

@nisdas nisdas left a comment

Choose a reason for hiding this comment

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

For all our failed message validations, is there anyway to capture this in our metrics ?

}
seenAttesterSlashings.Set(cacheKey, true /*value*/, 1 /*cost*/)

if fromSelf {
Copy link
Member

Choose a reason for hiding this comment

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

does libp2p not process messages from self ?

Copy link
Member Author

Choose a reason for hiding this comment

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

That's right, it won't send messages from itself to the subscription. It does, however, run validation on all messages published or subscribed. I've added a bit of a hack to immediately return true in validation if the pubsub message comes from ourselves. This bypasses the validation effectively as suggested here libp2p/go-libp2p-pubsub#250 (comment)

@prylabs-bulldozer prylabs-bulldozer bot merged commit 961dd21 into master Dec 20, 2019
@delete-merged-branch delete-merged-branch bot deleted the pubsub-validator branch December 20, 2019 03:18
cryptomental pushed a commit to cryptomental/prysm that referenced this pull request Feb 24, 2020
* add reject all pubsub validator to stop automatic propagation of messages
* gaz
* Merge branch 'master' of github.com:prysmaticlabs/prysm into pubsub-validator
* refactor p2p validator pipeline
* add sanity check
* Merge branch 'pubsub-validator' of github.com:prysmaticlabs/prysm into pubsub-validator
* fixed up test
* rem
* gaz
* Merge refs/heads/master into pubsub-validator
* fix from self test
* ensure validator data is set
* resolve todo
* Merge refs/heads/master into pubsub-validator
* gaz
* Merge refs/heads/master into pubsub-validator
* Merge branch 'pubsub-validator' of github.com:prysmaticlabs/prysm into pubsub-validator
* Merge refs/heads/master into pubsub-validator
* remove all of the 'from self' logic. filed libp2p/go-libp2p-pubsub#250
* Merge branch 'pubsub-validator' of github.com:prysmaticlabs/prysm into pubsub-validator
* gaz
* update comment
* Merge refs/heads/master into pubsub-validator
* rename "VaidatorData"
* Merge branch 'pubsub-validator' of github.com:prysmaticlabs/prysm into pubsub-validator
* refactor
* one more bit of refactoring
* Update beacon-chain/sync/validate_beacon_attestation.go

Co-Authored-By: terence tsao <terence@prysmaticlabs.com>
* skip validation on self messages, add @nisdas feedback to increment failure counter
* Merge branch 'pubsub-validator' of github.com:prysmaticlabs/prysm into pubsub-validator
* remove flakey
cryptomental pushed a commit to cryptomental/prysm that referenced this pull request Feb 28, 2020
* add reject all pubsub validator to stop automatic propagation of messages
* gaz
* Merge branch 'master' of github.com:prysmaticlabs/prysm into pubsub-validator
* refactor p2p validator pipeline
* add sanity check
* Merge branch 'pubsub-validator' of github.com:prysmaticlabs/prysm into pubsub-validator
* fixed up test
* rem
* gaz
* Merge refs/heads/master into pubsub-validator
* fix from self test
* ensure validator data is set
* resolve todo
* Merge refs/heads/master into pubsub-validator
* gaz
* Merge refs/heads/master into pubsub-validator
* Merge branch 'pubsub-validator' of github.com:prysmaticlabs/prysm into pubsub-validator
* Merge refs/heads/master into pubsub-validator
* remove all of the 'from self' logic. filed libp2p/go-libp2p-pubsub#250
* Merge branch 'pubsub-validator' of github.com:prysmaticlabs/prysm into pubsub-validator
* gaz
* update comment
* Merge refs/heads/master into pubsub-validator
* rename "VaidatorData"
* Merge branch 'pubsub-validator' of github.com:prysmaticlabs/prysm into pubsub-validator
* refactor
* one more bit of refactoring
* Update beacon-chain/sync/validate_beacon_attestation.go

Co-Authored-By: terence tsao <terence@prysmaticlabs.com>
* skip validation on self messages, add @nisdas feedback to increment failure counter
* Merge branch 'pubsub-validator' of github.com:prysmaticlabs/prysm into pubsub-validator
* remove flakey
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Ready For Review A pull request ready for code review
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Gossipsub Usage Is Incorrect
7 participants