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

feat: running validators in REST API #2373

Merged
merged 20 commits into from
Feb 1, 2024

Conversation

gabrielmer
Copy link
Contributor

@gabrielmer gabrielmer commented Jan 26, 2024

Description

We currently add message validators to libp2p's gossipsub, which are run before sending a message. In this PR, we're running the validators in POST /relay/v1/messages/{pubsubTopic} REST handler in order to catch earlier any wrong message and be able to return the user an error in case it's invalid and the message is not published.

In addition to that, a check for messages bigger than the maximum configured size was added to the handler. That's also a check currently made at the libp2p layer before relaying the message, and we want to catch these messages earlier in the flow.

A big change of this PR is that we got rid of topic-specific validators. Now the same validators will run for every pubsub topic.

After completing this PR, a new PR will be opened implementing the same validation logic for other autosharding and lightpush's REST handlers.

Changes

  • removed topic-specific validators and converted them to general validators
  • running validators in POST /relay/v1/messages/{pubsubTopic} REST handler
  • checking for max message size in the above REST handler
  • implemented test to check that the max size validator is run at the handler

Issue

Part of #2284

@gabrielmer gabrielmer marked this pull request as draft January 26, 2024 14:45
@gabrielmer gabrielmer self-assigned this Jan 26, 2024
Copy link

github-actions bot commented Jan 26, 2024

You can find the image built from this PR at

quay.io/wakuorg/nwaku-pr:2373

Built from 2f820b7

@gabrielmer gabrielmer force-pushed the chore-add-message-size-check-in-rest-3 branch from c71585e to 8cf79cd Compare January 26, 2024 17:07
@gabrielmer gabrielmer marked this pull request as ready for review January 26, 2024 17:36
Copy link
Contributor

@SionoiS SionoiS left a comment

Choose a reason for hiding this comment

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

👍 This approach seams sensible. No strong opinion either way. Maybe WakuMessages could check their own size?

Comment on lines 138 to 139
(await node.wakuRelay.validateMessage(pubsubTopic, message)).isOkOr:
return RestApiResponse.badRequest("Failed to publish: " & error)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Notice that for RLN's case for example, the validator's inside logic is used directly in the handler and therefore we had more possible error messages to return the user.

Once we use our validators directly, which only return if validation passed or not, we can only have one possible error message per validator.

The specific details still get logged, but one con of this approach vs hardcoding the checks in the handlers is that we can only have one unique error message per validator

@gabrielmer
Copy link
Contributor Author

👍 This approach seams sensible. No strong opinion either way. Maybe WakuMessages could check their own size?

Makes sense! Thought about it and found 2 issues to this.

First one, is that we don't use a WakuMessage.init() proc or something similar that runs logic when creating a WakuMessage, we just assign values to the struct as they are. We could create one, but not sure if refactoring it in the whole code only for this use case is worth it.

Apart from that, the easiest way to calculate the size in bytes of a WakuMessage is to create the struct and then check its size. We could calculate the size of all its separate fields and add them together, but that might be prone to bugs in case we add a field or make any change in the type.

LMK what you all think :))

Copy link
Collaborator

@Ivansete-status Ivansete-status left a comment

Choose a reason for hiding this comment

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

Thanks for the PR!
I've added a few comments. If possible, I'd try to simplify the approach and just have one kind of validator (avoiding the use of the generic/default validators list) but ofc I might be missing something :)

@SionoiS
Copy link
Contributor

SionoiS commented Jan 29, 2024

Apart from that, the easiest way to calculate the size in bytes of a WakuMessage is to create the struct and then check its size. We could calculate the size of all its separate fields and add them together, but that might be prone to bugs in case we add a field or make any change in the type.

What I was thinking is something like

if not myMessage.isWakuValid():
   return err("Max size 150KB! This message is too large per Waku RFC 64.")

if not myMessage.isGossipSubValid():
   return err("Max size 1MiB! This message is too large for GossipSub.")

Plus some tests.

@gabrielmer
Copy link
Contributor Author

Apart from that, the easiest way to calculate the size in bytes of a WakuMessage is to create the struct and then check its size. We could calculate the size of all its separate fields and add them together, but that might be prone to bugs in case we add a field or make any change in the type.

What I was thinking is something like

if not myMessage.isWakuValid():
   return err("Max size 150KB! This message is too large per Waku RFC 64.")

if not myMessage.isGossipSubValid():
   return err("Max size 1MiB! This message is too large for GossipSub.")

Plus some tests.

Oooh got it! So basically having the check inside a proc. That's cool, 100% can be useful and nicer :)

Copy link
Contributor

@NagyZoltanPeter NagyZoltanPeter left a comment

Choose a reason for hiding this comment

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

Overall thank you for this great stuff. I agree with the comments added before me, but I can approve it from my side, bet you will answer the rest. ;-)

@gabrielmer gabrielmer force-pushed the chore-add-message-size-check-in-rest-3 branch 2 times, most recently from d82b19c to 298fe4c Compare January 30, 2024 12:14
@SionoiS
Copy link
Contributor

SionoiS commented Jan 30, 2024

@gabrielmer you are aware of #1700 right?

@gabrielmer
Copy link
Contributor Author

@gabrielmer you are aware of #1700 right?

Ooooh, was definitely not aware of that GitHub issue! I was aware of the overall idea, that's why I took this approach here with validators instead of hardcoding the checks.

Thanks!

@gabrielmer
Copy link
Contributor Author

Changing PR to draft as there's still many changes to be done

@gabrielmer gabrielmer force-pushed the chore-add-message-size-check-in-rest-3 branch from b919235 to df60564 Compare January 31, 2024 10:39
return ValidationResult.Accept
return wrappedValidator

proc isValidSize(message: WakuMessage): Future[Result[void, string]] {.async.} =
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll also add to this proc a check that the message size is smaller than GossipSub's max.

Currently the max size is defined in nim-libp2p here: https://github.com/status-im/nim-libp2p/blob/e3c967ad1939fb33b8e13759037d193734acd202/libp2p/protocols/pubsub/pubsub.nim#L556

I don't want to have it hardcoded, so I'll first open a PR in nim-libp2p defining it as a global const and will then add an if condition in this proc

@gabrielmer gabrielmer marked this pull request as ready for review January 31, 2024 16:36
@gabrielmer
Copy link
Contributor Author

gabrielmer commented Jan 31, 2024

I think I implemented all the feedback received, please let me know if I missed something or if there's anything else we can improve :)

So this PR doesn't get way too big, I'll implement the same validation logic in a separate PR for lightpush's and autosharding's REST handlers.

Copy link
Contributor

@SionoiS SionoiS left a comment

Choose a reason for hiding this comment

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

LGTM thanks!

@gabrielmer gabrielmer changed the title feat: running validators in REST API (in progress) feat: running validators in REST API Jan 31, 2024
Copy link
Collaborator

@Ivansete-status Ivansete-status left a comment

Choose a reason for hiding this comment

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

Looks great indeed! However, I can't approve yet as per the doubt I have re rest/relay/handlers.nim :)

@@ -135,16 +135,8 @@ proc installRelayApiHandlers*(router: var RestRouter, node: WakuNode, cache: Mes
if not success:
return RestApiResponse.internalServerError("Failed to publish: error appending RLN proof to message")

# validate the message before sending it
let result = node.wakuRlnRelay.validateMessageAndUpdateLog(message)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why are we removing this wakuRlnRelay validation? This is quite important :) Or are we making this validation in another place?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes!

So now we register the validator here:

node.wakuRelay.addValidator(validator, "RLN validation failed")

And this runs in the REST handler here:

(await node.wakuRelay.validateMessage(pubsubTopic, message)).isOkOr:

So instead of hardcoding again the RLN validation in the handler, this gets run when going over all the registered validators

Copy link
Collaborator

Choose a reason for hiding this comment

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

Beautiful!, I see that the validation is performed in the following place:

let validationRes = wakuRlnRelay.validateMessageAndUpdateLog(message)

Copy link
Collaborator

@Ivansete-status Ivansete-status left a comment

Choose a reason for hiding this comment

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

LGTM! Thanks for the master-piece PR and the patience! 🥳

@@ -135,16 +135,8 @@ proc installRelayApiHandlers*(router: var RestRouter, node: WakuNode, cache: Mes
if not success:
return RestApiResponse.internalServerError("Failed to publish: error appending RLN proof to message")

# validate the message before sending it
let result = node.wakuRlnRelay.validateMessageAndUpdateLog(message)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Beautiful!, I see that the validation is performed in the following place:

let validationRes = wakuRlnRelay.validateMessageAndUpdateLog(message)

@gabrielmer gabrielmer force-pushed the chore-add-message-size-check-in-rest-3 branch from 6171f31 to f08420f Compare February 1, 2024 16:45
@gabrielmer gabrielmer merged commit 59d8b62 into master Feb 1, 2024
9 of 10 checks passed
@gabrielmer gabrielmer deleted the chore-add-message-size-check-in-rest-3 branch February 1, 2024 17:16
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