perf(light): Use cache when verifying signatures#4322
perf(light): Use cache when verifying signatures#4322melekes merged 18 commits intocometbft:mainfrom
Conversation
791470a to
76c5e4f
Compare
types/validation.go
Outdated
| cacheKey := string(val.Address) + string(voteSignBytes) | ||
| _, ok := verifiedSignatureCache[cacheKey] |
There was a problem hiding this comment.
Nice! This has a malleabiltiy vector though if addresses weren't fixed size. Its also not zero-allocation, which is good to have at the sig verification level.
Perhaps structure the map using vote sign bytes as the key, and then the val address as the value? Not sure we can avoid the string casts for immutability reasons, so maybe we just live with the allocs. Should see how much it slows it down in the normal case.
Also can we allow passing in a nil map (skipping the check if nil)
There was a problem hiding this comment.
Updated to make these changes.
- Using
string(voteSignBytes)as the key and val address as the value - Check
verifiedSignatureCache != nilbefore any usage. Passnilwhere ever the cache does not need to be used
ValarDragon
left a comment
There was a problem hiding this comment.
LGTM, nice work!
But we should add a tests around non-nil caches being provided, and tally logic for counting to 2/3rds still working!
ea25d8e to
d01fd92
Compare
|
@ValarDragon thinking about this more, aren't the VoteSignBytes actually likely to be the same across signatures? I see a comment that says they differ only in the timestamp, the rest of the fields are identical. Would it not be better to use the validator address or the commit signature as the cache key? |
|
So we need to be sure that all 3 arguments for The key being the signature makes sense to me, since your right sign_bytes can get re-used. And then the value of the map being struct{sign_bytes, public_key} perhaps, where we check those two fields |
54590a6 to
6c3d2c6
Compare
1dd5304 to
1955212
Compare
|
I added unit tests and changed the cache schema. Opening this for review. Will still do some perf tests / benchmarks to try to measure performance improvement. |
.changelog/unreleased/improvements/2365-deduplicate-light-signature-checks.md
Outdated
Show resolved
Hide resolved
4f588b3 to
94ce647
Compare
This comment was marked as resolved.
This comment was marked as resolved.
94ce647 to
31835c8
Compare
|
Please don't force-push. It makes reviewing impossible |
cason
left a comment
There was a problem hiding this comment.
I wonder whether the signatures cache should I type by itself, instead of using a map[string]SignatureCacheValue. This will probably render it simple to implement and test.
Moreover, I wonder whether the tests can indeed confirm that the cache is being used. I think that a mock signature verifier/key should be used in this case, so we are really sure that the verification methods are not invoked.
.changelog/unreleased/improvements/2365-deduplicate-light-signature-checks.md
Outdated
Show resolved
Hide resolved
This comment was marked as resolved.
This comment was marked as resolved.
Yes. The consensus logic uses it, for instance |
Co-authored-by: Daniel <daniel.cason@informal.systems>
Created a new type for |
| cache map[string]SignatureCacheValue | ||
| } | ||
|
|
||
| func NewSignatureCache() SignatureCache { |
There was a problem hiding this comment.
I don't see how this is better than the original map[string]SignatureCacheValue. @cason is this what you had in mind?
There was a problem hiding this comment.
Yes, so we can implement this abstraction in the way we prefer.
cason
left a comment
There was a problem hiding this comment.
Thank you a lot for this effort.
There are some details that we should take care of, but I'd say that we can take it over from here.
| cache map[string]SignatureCacheValue | ||
| } | ||
|
|
||
| func NewSignatureCache() SignatureCache { |
There was a problem hiding this comment.
Yes, so we can implement this abstraction in the way we prefer.
| sig := commit.Signatures[idx] | ||
| verifiedSignatureCache.Add(string(sig.Signature), SignatureCacheValue{ | ||
| ValidatorAddress: sig.ValidatorAddress, | ||
| VoteSignBytes: commit.VoteSignBytes(chainID, int32(idx)), |
There was a problem hiding this comment.
This call requires proto encoding, namely is kind of expensive. Don't we have these bytes already computed?
| } | ||
|
|
||
| type signatureCache struct { | ||
| cache map[string]SignatureCacheValue |
There was a problem hiding this comment.
This cache grows over time, should we somehow restrict its size?
There was a problem hiding this comment.
Should we add a new changelog entry for the creation of the SignatureCache type?
Closes #2365 This PR adds two new methods to `light` package: `VerifyCommitLightTrustingWithCache` and `VerifyCommitLightWithCache` so that we don't have to verify the same signatures twice. Pending some perf tests/benchmarks to measure performance improvement. --------- Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com> Co-authored-by: Daniel <daniel.cason@informal.systems>
Closes #2365 This PR adds two new methods to `light` package: `VerifyCommitLightTrustingWithCache` and `VerifyCommitLightWithCache` so that we don't have to verify the same signatures twice. Pending some perf tests/benchmarks to measure performance improvement. --------- Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com> Co-authored-by: Daniel <daniel.cason@informal.systems>
Closes #2365 This PR adds two new methods to `light` package: `VerifyCommitLightTrustingWithCache` and `VerifyCommitLightWithCache` so that we don't have to verify the same signatures twice. Pending some perf tests/benchmarks to measure performance improvement. --------- Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com> Co-authored-by: Daniel <daniel.cason@informal.systems>
Closes #2365 This PR adds two new methods to `light` package: `VerifyCommitLightTrustingWithCache` and `VerifyCommitLightWithCache` so that we don't have to verify the same signatures twice. Pending some perf tests/benchmarks to measure performance improvement. --------- Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com> Co-authored-by: Daniel <daniel.cason@informal.systems>
Closes #2365
This PR adds two new methods to
lightpackage:VerifyCommitLightTrustingWithCacheandVerifyCommitLightWithCacheso that we don't have to verify the same signatures twice.Pending some perf tests/benchmarks to measure performance improvement.