-
Notifications
You must be signed in to change notification settings - Fork 215
Invalid signers cache #6873
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
Invalid signers cache #6873
Conversation
…th the same message
| cache.invalidSignersMap[hash] = struct{}{} | ||
| } | ||
|
|
||
| // HasInvalidSigners check whether the provided hash exists in int internal map or not |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo in int 🙃
| sync.RWMutex | ||
| invalidSignersMap map[string]struct{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure, maybe sync.Map would have also worked (shorter code)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
applied
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
back to map + mut due to reset method
| func (wrk *Worker) verifyMessageWithInvalidSigners(cnsMsg *consensus.Message) error { | ||
| // No need to guard this method by verification of common.EquivalentMessagesFlag as invalidSignersCache will have entries only for consensus v2 | ||
| invalidSignersHash := wrk.hasher.Compute(string(cnsMsg.InvalidSigners)) | ||
| if wrk.invalidSignersCache.HasInvalidSigners(string(invalidSignersHash)) { | ||
| // return error here to avoid further broadcast of this message | ||
| return ErrInvalidSignersAlreadyReceived | ||
| } | ||
|
|
||
| return nil | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So all good if someone sends a clandestine message with this topic shortly before Andromeda's activation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added check for flag to be active. used IsFlagEnabled as header epoch is unknown for this message
| func (sr *subroundEndRound) handleInvalidSignersOnAggSigFail() ([]byte, []byte, error) { | ||
| ctx, cancel := context.WithTimeout(context.Background(), sr.RoundHandler().TimeDuration()) | ||
| invalidPubKeys, err := sr.verifyNodesOnAggSigFail(ctx) | ||
| cancel() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not related to the changes from this PR, but this cancel() doesn't seem right to call it after the "intensive". Maybe move it up 1 line and call it on a defer?
|
|
||
| invalidSignersHash := sr.Hasher().Compute(string(cnsDta.InvalidSigners)) | ||
| invalidSignersCache := sr.InvalidSignersCache() | ||
| if invalidSignersCache.HasInvalidSigners(string(invalidSignersHash)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if there are different number of invalidSigners: first time 2: A and B, and in on a second message it gets only A, it seems that the message will be propagated 2 times?
| } | ||
|
|
||
| if len(pubKey) > 0 { | ||
| pubKeys = append(pubKeys, pubKey) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So we only collect the public keys of the good signers? And if there's any invalid one, we collect nothing. Should we find a better name for the function e.g. findGoodSigners?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not really, this method checks whether the invalid signers provided an invalid signature.. so this appends the invalid signers that we confirmed they had an invalid signature
| return err | ||
| pubKey, errVerify := sr.verifyInvalidSigner(msg) | ||
| if errVerify != nil { | ||
| return nil, errVerify |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thus, here we break & return, all good?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, it means we were not able to verify if the provided invalid signers indeed had invalid signatures
| err := sr.MessageSigningHandler().Verify(msg) | ||
| if err != nil { | ||
| return err | ||
| return "", err |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note to ourselves - this is the raw byte pubkey, not the hex-encoded one (from what I understand). No change needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
correct
| type invalidSignersCache struct { | ||
| sync.RWMutex | ||
| invalidSignersHashesMap map[string]struct{} | ||
| invalidSignersForHeaderMap map[string]map[string]struct{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, for each header, we retain the public keys of the "bad" signers (as a map, for easy lookup), correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
correct
| for _, pk := range invalidPublicKeys { | ||
| cache.invalidSignersForHeaderMap[string(headerHash)][pk] = struct{}{} | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice automatic de-duplication, in case we get different sets of bad signers for the same header 👍
| invalidSignersHash := cache.hasher.Compute(string(invalidSigners)) | ||
| _, hasSameInvalidSigners := cache.invalidSignersHashesMap[string(invalidSignersHash)] | ||
| if hasSameInvalidSigners { | ||
| return true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Early answer if we've previously received the exact same message, correct? I mean, this is just an optimization - is it a crucial one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am thinking out loud - if this node already knows about this exact set of invalid signers, for the given block, it will not forward the message / it will stop the gossip. Also, if the node does not know about this exact set, but knows about a superset of invalid signers (which include this set), it will also stop the gossip.
Correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for the first question, it indeed is just an optimization to avoid the Deserialization
for the second one, correct
| cnsMsg := &consensus.Message{} | ||
| err = cache.marshaller.Unmarshal(cnsMsg, msg.Data()) | ||
| if err != nil { | ||
| return false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunate / rare circumstance? If so, maybe we should log it (as warning perhaps)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hm.. not sure it is needed. worst case, the node will process twice the same message
| return false | ||
| } | ||
|
|
||
| messages, err := cache.signingHandler.Deserialize(invalidSigners) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe can be renamed from messages to signers. Or even invalidSigners, while the existing variable can be renamed to serializedInvalidSigners.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
applied suggestion, renamed to invalidSignersP2PMessages
| } | ||
| } | ||
|
|
||
| return knownInvalidSigners == len(messages) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Opinion (sorry if mistaken, I might have missed something): we can also return early if we find an unknown one, and skip the counting logic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good suggestion, applied
| return knownInvalidSigners == len(messages) | ||
| } | ||
|
|
||
| // Reset clears the internal map |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maps.
Reasoning behind the pull request
Proposed changes
Testing procedure
Pre-requisites
Based on the Contributing Guidelines the PR author and the reviewers must check the following requirements are met:
featbranch created?featbranch merging, do all satellite projects have a proper tag insidego.mod?