Skip to content

request filter part one#154

Merged
tock-ibm merged 1 commit intohyperledger:mainfrom
DorKatzelnick:RequestFilter
Aug 10, 2025
Merged

request filter part one#154
tock-ibm merged 1 commit intohyperledger:mainfrom
DorKatzelnick:RequestFilter

Conversation

@DorKatzelnick
Copy link
Contributor

following PR #131

@DorKatzelnick DorKatzelnick requested a review from tock-ibm August 3, 2025 13:40
Copy link
Contributor

Choose a reason for hiding this comment

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

package folder name should be the same as the package name: requestfilter.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

maxSize := ms.maxSizeBytes
requestSize := requestSizeInBytes(request)
if requestSize > maxSize {
return fmt.Errorf("the request's size exceeds the maximum size")
Copy link
Contributor

Choose a reason for hiding this comment

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

Add the expected values, e.g.:

fmt.Errorf("the request's size is too big: actual=%d, max size limit=%d", actual, max)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

// Signature verification rule
// TODO: implement signature validation

type NoOpSigFilter struct{}
Copy link
Contributor

Choose a reason for hiding this comment

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

Implement the Rule interface, add the methods

Copy link
Contributor Author

Choose a reason for hiding this comment

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

partially implemented

Comment on lines +25 to +39
// PayloadNotEmptyRule - checks that the payload in the request is not nil.
var PayloadNotEmptyRule = Rule(payloadNotEmptyRule{})

type payloadNotEmptyRule struct{}

func (a payloadNotEmptyRule) Verify(request *comm.Request) error {
if request.Payload == nil {
return fmt.Errorf("empty payload field")
}
return nil
}

func (a payloadNotEmptyRule) Update(config FilterConfig) error {
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.

This can be part of the size filter file or alone in its own file

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

return nil
}

func (ms *MaxSizeFilter) Update(config FilterConfig) error {
Copy link
Contributor

@tock-ibm tock-ibm Aug 5, 2025

Choose a reason for hiding this comment

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

Lets think of a way to make it thread safe... Either here or in the calling entity.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

added RWmutex to verifier

Comment on lines +46 to +49
// requestSizeInBytes return the (approximated) size in bytes of a request
func requestSizeInBytes(request *comm.Request) uint64 {
return uint64(len(request.Payload) + len(request.Signature))
}
Copy link
Contributor

Choose a reason for hiding this comment

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

this method is too small... just put it in the calling function

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed


// Verfiy checks that the size of the request does not exceeds the maximal size in bytes.
func (ms *MaxSizeFilter) Verify(request *comm.Request) error {
maxSize := ms.maxSizeBytes
Copy link
Contributor

Choose a reason for hiding this comment

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

why convert to a local var? just use the field

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

Comment on lines +46 to +49
// requestSizeInBytes return the (approximated) size in bytes of a request
func requestSizeInBytes(request *comm.Request) uint64 {
return uint64(len(request.Payload) + len(request.Signature))
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a one line method that is only used once... just put this one line where it is called.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

}

// PayloadNotEmptyRule - checks that the payload in the request is not nil.
var PayloadNotEmptyRule = Rule(payloadNotEmptyRule{})
Copy link
Contributor

Choose a reason for hiding this comment

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

Why?
I think this

type payloadNotEmptyRule struct{}

can just be public and that's all...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

require.NoError(t, err)
}

func TestSigVerifyFilter(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

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

The convention in Go is to place the unit tests of structs that are in a file in a separate file, i.e.
rule_test,go
sigfilter_test.go
sizefilter_test.go
etc,

here do only the tests that check the integrative nature of RulesVerifier. e.g. thread safety, atomicity of updates etc.

also a common practice is to run with coverage and make sure we have decent coverage, i.e. >90% for simple components and 80% in general for more difficult stuff.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

reorganized the tests. added a couple of concurrency tests. coverage is around 87% for now.

Comment on lines +102 to +121
type testfiltersupport struct {
maxSize uint64
}

func (tfs *testfiltersupport) GetMaxSizeBytes() (uint64, error) {
return tfs.maxSize, nil
}
Copy link
Contributor

Choose a reason for hiding this comment

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

If you mock this interface with counterfeiter, you can easily inject errors and any value you want... It is generally preferred in Go.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

replaced all interfaces with mocks

after review

Signed-off-by: Dor.Katzelnick <Dor.Katzelnick@ibm.com>
Copy link
Contributor

@tock-ibm tock-ibm left a comment

Choose a reason for hiding this comment

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

@DorKatzelnick I approve with some minor comment to be taken on next PR

Comment on lines +85 to +87
case <-time.After(7 * time.Second):
t.Error("concurrent verify took too long")
}
Copy link
Contributor

Choose a reason for hiding this comment

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

On normal machines you can make this assumption (all goroutines enter together, no more than 1s) but with loaded CI machines that has a (very small) potential to cause flakes.

In addition, the code above this point does not really check the goroutine enter the rw lock together as the 1s delay is after you exit Verify.
Another approach would be to use a mock filter that sleeps for a 1s when Verify is called.
The best approach would be to combine this with code that counts the maximal number of threads inside the Verify. Like:

enter verify, increment a (atomic) counter,
sleep T
update (atomic) max-of-counter
sleep T
decrement counter
exit verify

assert max-of-counter > 1

Having said all that, this is way too much... do it if you have some spare time in the next PR

@tock-ibm tock-ibm merged commit 96134d8 into hyperledger:main Aug 10, 2025
5 checks passed
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.

2 participants