Skip to content

Commit

Permalink
Merge pull request onflow#5323 from onflow/khalil/1908-fix-gossipsub-…
Browse files Browse the repository at this point in the history
…integration-test

Khalil/1908 fix gossipsub integration test
  • Loading branch information
kc1116 authored Feb 21, 2024
2 parents fce3336 + e13a684 commit 57b5376
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

pubsub "github.com/libp2p/go-libp2p-pubsub"
pb "github.com/libp2p/go-libp2p-pubsub/pb"
pubsub_pb "github.com/libp2p/go-libp2p-pubsub/pb"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/rs/zerolog"
mockery "github.com/stretchr/testify/mock"
Expand Down Expand Up @@ -1018,6 +1019,24 @@ func TestValidationInspector_InspectRpcPublishMessages(t *testing.T) {
// The victim node is configured to use the GossipSubInspector to detect spam and the scoring system to mitigate spam.
// The test ensures that the victim node is disconnected from the spammer node on the GossipSub mesh after the spam detection is triggered.
func TestGossipSubSpamMitigationIntegration(t *testing.T) {
t.Run("gossipsub spam mitigation invalid grafts", func(t *testing.T) {
testGossipSubSpamMitigationIntegration(t, p2pmsg.CtrlMsgGraft)
})
t.Run("gossipsub spam mitigation invalid prunes", func(t *testing.T) {
testGossipSubSpamMitigationIntegration(t, p2pmsg.CtrlMsgPrune)
})
t.Run("gossipsub spam mitigation invalid ihaves", func(t *testing.T) {
testGossipSubSpamMitigationIntegration(t, p2pmsg.CtrlMsgIHave)
})
}

// testGossipSubSpamMitigationIntegration tests that the spam mitigation feature of GossipSub is working as expected.
// The test puts together the spam detection (through the GossipSubInspector) and the spam mitigation (through the
// scoring system) and ensures that the mitigation is triggered when the spam detection detects spam.
// The test scenario involves a spammer node that sends a large number of control messages for the specified control message type to a victim node.
// The victim node is configured to use the GossipSubInspector to detect spam and the scoring system to mitigate spam.
// The test ensures that the victim node is disconnected from the spammer node on the GossipSub mesh after the spam detection is triggered.
func testGossipSubSpamMitigationIntegration(t *testing.T, msgType p2pmsg.ControlMessageType) {
idProvider := mock.NewIdentityProvider(t)
sporkID := unittest.IdentifierFixture()
spammer := corruptlibp2p.NewGossipSubRouterSpammer(t, sporkID, flow.RoleConsensus, idProvider)
Expand Down Expand Up @@ -1058,8 +1077,8 @@ func TestGossipSubSpamMitigationIntegration(t *testing.T) {
}
})

spamRpcCount := 100 // total number of individual rpc messages to send
spamCtrlMsgCount := int64(100) // total number of control messages to send on each RPC
spamRpcCount := 1000 // total number of individual rpc messages to send
spamCtrlMsgCount := int64(1000) // total number of control messages to send on each RPC

// unknownTopic is an unknown topic to the victim node but shaped like a valid topic (i.e., it has the correct prefix and spork ID).
unknownTopic := channels.Topic(fmt.Sprintf("%s/%s", p2ptest.GossipSubTopicIdFixture(), sporkID))
Expand Down Expand Up @@ -1088,29 +1107,39 @@ func TestGossipSubSpamMitigationIntegration(t *testing.T) {
return unittest.ProposalFixture()
})

// prepares spam graft and prune messages with different strategies.
graftCtlMsgsWithUnknownTopic := spammer.GenerateCtlMessages(int(spamCtrlMsgCount), p2ptest.WithGraft(spamRpcCount, unknownTopic.String()))
graftCtlMsgsWithMalformedTopic := spammer.GenerateCtlMessages(int(spamCtrlMsgCount), p2ptest.WithGraft(spamRpcCount, malformedTopic.String()))
graftCtlMsgsInvalidSporkIDTopic := spammer.GenerateCtlMessages(int(spamCtrlMsgCount), p2ptest.WithGraft(spamRpcCount, invalidSporkIDTopic.String()))
graftCtlMsgsDuplicateTopic := spammer.GenerateCtlMessages(int(spamCtrlMsgCount), // sets duplicate to +2 above the threshold to ensure that the victim node will penalize the spammer node
p2ptest.WithGraft(cfg.NetworkConfig.GossipSub.RpcInspector.Validation.GraftPrune.DuplicateTopicIdThreshold+2, duplicateTopic.String()))

pruneCtlMsgsWithUnknownTopic := spammer.GenerateCtlMessages(int(spamCtrlMsgCount), p2ptest.WithPrune(spamRpcCount, unknownTopic.String()))
pruneCtlMsgsWithMalformedTopic := spammer.GenerateCtlMessages(int(spamCtrlMsgCount), p2ptest.WithPrune(spamRpcCount, malformedTopic.String()))
pruneCtlMsgsInvalidSporkIDTopic := spammer.GenerateCtlMessages(int(spamCtrlMsgCount), p2ptest.WithGraft(spamRpcCount, invalidSporkIDTopic.String()))
pruneCtlMsgsDuplicateTopic := spammer.GenerateCtlMessages(int(spamCtrlMsgCount), // sets duplicate to +2 above the threshold to ensure that the victim node will penalize the spammer node
p2ptest.WithPrune(cfg.NetworkConfig.GossipSub.RpcInspector.Validation.GraftPrune.DuplicateTopicIdThreshold+2, duplicateTopic.String()))
var unknownTopicSpam []pubsub_pb.ControlMessage
var malformedTopicSpam []pubsub_pb.ControlMessage
var invalidSporkIDTopicSpam []pubsub_pb.ControlMessage
var duplicateTopicSpam []pubsub_pb.ControlMessage

switch msgType {
case p2pmsg.CtrlMsgGraft:
unknownTopicSpam = spammer.GenerateCtlMessages(int(spamCtrlMsgCount), p2ptest.WithGraft(spamRpcCount, unknownTopic.String()))
malformedTopicSpam = spammer.GenerateCtlMessages(int(spamCtrlMsgCount), p2ptest.WithGraft(spamRpcCount, malformedTopic.String()))
invalidSporkIDTopicSpam = spammer.GenerateCtlMessages(int(spamCtrlMsgCount), p2ptest.WithGraft(spamRpcCount, invalidSporkIDTopic.String()))
duplicateTopicSpam = spammer.GenerateCtlMessages(int(spamCtrlMsgCount), // sets duplicate to +2 above the threshold to ensure that the victim node will penalize the spammer node
p2ptest.WithGraft(cfg.NetworkConfig.GossipSub.RpcInspector.Validation.GraftPrune.DuplicateTopicIdThreshold+2, duplicateTopic.String()))
case p2pmsg.CtrlMsgPrune:
unknownTopicSpam = spammer.GenerateCtlMessages(int(spamCtrlMsgCount), p2ptest.WithPrune(spamRpcCount, unknownTopic.String()))
malformedTopicSpam = spammer.GenerateCtlMessages(int(spamCtrlMsgCount), p2ptest.WithPrune(spamRpcCount, malformedTopic.String()))
invalidSporkIDTopicSpam = spammer.GenerateCtlMessages(int(spamCtrlMsgCount), p2ptest.WithGraft(spamRpcCount, invalidSporkIDTopic.String()))
duplicateTopicSpam = spammer.GenerateCtlMessages(int(spamCtrlMsgCount), // sets duplicate to +2 above the threshold to ensure that the victim node will penalize the spammer node
p2ptest.WithPrune(cfg.NetworkConfig.GossipSub.RpcInspector.Validation.GraftPrune.DuplicateTopicIdThreshold+2, duplicateTopic.String()))
case p2pmsg.CtrlMsgIHave:
unknownTopicSpam = spammer.GenerateCtlMessages(int(spamCtrlMsgCount), p2ptest.WithIHave(spamRpcCount, 100, unknownTopic.String()))
malformedTopicSpam = spammer.GenerateCtlMessages(int(spamCtrlMsgCount), p2ptest.WithIHave(spamRpcCount, 100, malformedTopic.String()))
invalidSporkIDTopicSpam = spammer.GenerateCtlMessages(int(spamCtrlMsgCount), p2ptest.WithIHave(spamRpcCount, 100, invalidSporkIDTopic.String()))
duplicateTopicSpam = spammer.GenerateCtlMessages(int(spamCtrlMsgCount), // sets duplicate to +2 above the threshold to ensure that the victim node will penalize the spammer node
p2ptest.WithIHave(cfg.NetworkConfig.GossipSub.RpcInspector.Validation.IHave.DuplicateTopicIdThreshold+spamRpcCount, 100, duplicateTopic.String()))
default:
t.Fatal("invalid control message type expected graft or prune")
}

// start spamming the victim peer
spammer.SpamControlMessage(t, victimNode, graftCtlMsgsWithUnknownTopic)
spammer.SpamControlMessage(t, victimNode, graftCtlMsgsWithMalformedTopic)
spammer.SpamControlMessage(t, victimNode, graftCtlMsgsInvalidSporkIDTopic)
spammer.SpamControlMessage(t, victimNode, graftCtlMsgsDuplicateTopic)

spammer.SpamControlMessage(t, victimNode, pruneCtlMsgsWithUnknownTopic)
spammer.SpamControlMessage(t, victimNode, pruneCtlMsgsWithMalformedTopic)
spammer.SpamControlMessage(t, victimNode, pruneCtlMsgsInvalidSporkIDTopic)
spammer.SpamControlMessage(t, victimNode, pruneCtlMsgsDuplicateTopic)
spammer.SpamControlMessage(t, victimNode, unknownTopicSpam)
spammer.SpamControlMessage(t, victimNode, malformedTopicSpam)
spammer.SpamControlMessage(t, victimNode, invalidSporkIDTopicSpam)
spammer.SpamControlMessage(t, victimNode, duplicateTopicSpam)
scoreOptParameters := cfg.NetworkConfig.GossipSub.ScoringParameters.PeerScoring.Internal.Thresholds
// wait for three GossipSub heartbeat intervals to ensure that the victim node has penalized the spammer node.
require.Eventually(t, func() bool {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ func testGossipSubInvalidMessageDeliveryScoring(t *testing.T, spamMsgFactory fun
require.NoError(t, err)
// we override the decay interval to 1 second so that the score is updated within 1 second intervals.
cfg.NetworkConfig.GossipSub.RpcTracer.ScoreTracerInterval = 1 * time.Second
cfg.NetworkConfig.GossipSub.ScoringParameters.PeerScoring.Internal.TopicParameters.InvalidMessageDeliveriesDecay = .01

victimNode, victimIdentity := p2ptest.NodeFixture(
t,
sporkId,
Expand Down Expand Up @@ -446,7 +448,8 @@ func TestGossipSubMeshDeliveryScoring_Replay_Will_Not_Counted(t *testing.T) {
conf.NetworkConfig.GossipSub.RpcTracer.ScoreTracerInterval = 1 * time.Second
blockTopicOverrideParams := defaultTopicScoreParams(t)
blockTopicOverrideParams.MeshMessageDeliveriesActivation = 1 * time.Second // we start observing the mesh message deliveries after 1 second of the node startup.
thisNode, thisId := p2ptest.NodeFixture( // this node is the one that will be penalizing the under-performer node.
// this node is the one that will be penalizing the under-performer node.
thisNode, thisId := p2ptest.NodeFixture(
t,
sporkId,
t.Name(),
Expand Down

0 comments on commit 57b5376

Please sign in to comment.