Handle Multiple Graft Topics Correctly #386
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Background
With every iteration of the heartbeat routine for a peer running gossipsub, it will ascertain whether it has enough peers in its mesh for a topic. If there are not enough peers it will retrieve the relevant peers and add them to its mesh. Doing this for the same peer for multiple topics, we can batch all the
GRAFT
messages for the different topics into a single RPC message.Problem
In
sendGraftPrune
while looping through all the topics to send a message out for, we take the pointer to string value of the topic and utilize that in our control message. Unfortunately in a loop that reference doesn't hold for each topic, instead changing for each iteration in a loop. So we instead end up referring to the last element in the original topic slice for all theGRAFT
topic ids in our newControlGraft
message. To illustrate this:https://play.golang.org/p/1cPEh5fYIvx
Solution
The solution is simple where we copy each topic before referencing them, this mitigates the problem with the other topics being overwritten in the message. Also a regression test has been added to test this exact case. There maybe more cases like this in the repo but I couldn't find anything similar so far when I scanned though the code.