github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/network/test/cohort1/network_test.go (about)

     1  package cohort1
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"math/rand"
     7  	"regexp"
     8  	"strings"
     9  	"sync"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/libp2p/go-libp2p/core/peer"
    14  	"github.com/libp2p/go-libp2p/p2p/net/swarm"
    15  	"github.com/rs/zerolog"
    16  	"github.com/stretchr/testify/assert"
    17  	mockery "github.com/stretchr/testify/mock"
    18  	"github.com/stretchr/testify/require"
    19  	"github.com/stretchr/testify/suite"
    20  	"go.uber.org/atomic"
    21  	"golang.org/x/time/rate"
    22  
    23  	"github.com/onflow/flow-go/config"
    24  	"github.com/onflow/flow-go/model/flow"
    25  	"github.com/onflow/flow-go/model/flow/filter"
    26  	libp2pmessage "github.com/onflow/flow-go/model/libp2p/message"
    27  	"github.com/onflow/flow-go/model/messages"
    28  	"github.com/onflow/flow-go/module/irrecoverable"
    29  	"github.com/onflow/flow-go/module/metrics"
    30  	"github.com/onflow/flow-go/module/observable"
    31  	"github.com/onflow/flow-go/network"
    32  	"github.com/onflow/flow-go/network/channels"
    33  	"github.com/onflow/flow-go/network/internal/p2pfixtures"
    34  	"github.com/onflow/flow-go/network/internal/testutils"
    35  	"github.com/onflow/flow-go/network/message"
    36  	"github.com/onflow/flow-go/network/mocknetwork"
    37  	"github.com/onflow/flow-go/network/p2p"
    38  	p2pnode "github.com/onflow/flow-go/network/p2p/node"
    39  	p2ptest "github.com/onflow/flow-go/network/p2p/test"
    40  	"github.com/onflow/flow-go/network/p2p/unicast/ratelimit"
    41  	"github.com/onflow/flow-go/network/p2p/utils/ratelimiter"
    42  	"github.com/onflow/flow-go/network/underlay"
    43  	"github.com/onflow/flow-go/utils/unittest"
    44  )
    45  
    46  // libp2p emits a call to `Protect` with a topic-specific tag upon establishing each peering connection in a GossipSub mesh, see:
    47  // https://github.com/libp2p/go-libp2p-pubsub/blob/master/tag_tracer.go
    48  // One way to make sure such a mesh has formed, asynchronously, in unit tests, is to wait for libp2p.GossipSub such calls,
    49  // and that's what we do with tagsObserver.
    50  // Usage:
    51  // The tagsObserver struct observes the OnNext, OnError, and OnComplete events related to peer tags.
    52  // A channel 'tags' is used to communicate these tags, and the observer is subscribed to the observable connection manager.
    53  // Advantages:
    54  // Using tag observables helps understand the connectivity between different peers,
    55  // and can be valuable in testing scenarios where network connectivity is critical.
    56  // Issues:
    57  //   - Deviation from Production Code: This tag observation might be unique to the test environment,
    58  //     and therefore not reflect the behavior of the production code.
    59  //   - Mask Issues in the Production Environment: The observables are tied to testing and might
    60  //     lead to behaviors or errors that are masked or not evident within the actual production environment.
    61  //
    62  // TODO: Evaluate the necessity of tag observables in this test. Consider addressing the deviation from
    63  // production code and potential mask issues in the production environment. Evaluate the possibility
    64  // of removing this part eventually.
    65  type tagsObserver struct {
    66  	tags chan string
    67  	log  zerolog.Logger
    68  }
    69  
    70  func (co *tagsObserver) OnNext(peertag interface{}) {
    71  	pt, ok := peertag.(testutils.PeerTag)
    72  
    73  	if ok {
    74  		co.tags <- fmt.Sprintf("peer: %v tag: %v", pt.Peer, pt.Tag)
    75  	}
    76  
    77  }
    78  func (co *tagsObserver) OnError(err error) {
    79  	co.log.Error().Err(err).Msg("Tags Observer closed on an error")
    80  	close(co.tags)
    81  }
    82  func (co *tagsObserver) OnComplete() {
    83  	close(co.tags)
    84  }
    85  
    86  // TODO: eventually this should be moved to the p2pnet package.
    87  type NetworkTestSuite struct {
    88  	suite.Suite
    89  	sync.RWMutex
    90  	size        int // used to determine number of networks under test
    91  	libP2PNodes []p2p.LibP2PNode
    92  	networks    []*underlay.Network
    93  	obs         chan string // used to keep track of Protect events tagged by pubsub messages
    94  	ids         []*flow.Identity
    95  	metrics     *metrics.NoopCollector // no-op performance monitoring simulation
    96  	logger      zerolog.Logger
    97  	providers   []*unittest.UpdatableIDProvider
    98  	sporkId     flow.Identifier
    99  	mwCancel    context.CancelFunc
   100  	mwCtx       irrecoverable.SignalerContext
   101  }
   102  
   103  // TestNetworkTestSuit runs all the test methods in this test suit
   104  func TestNetworkTestSuite(t *testing.T) {
   105  	// should not run in parallel, some tests are stateful.
   106  	suite.Run(t, new(NetworkTestSuite))
   107  }
   108  
   109  // SetupTest initiates the test setups prior to each test
   110  func (suite *NetworkTestSuite) SetupTest() {
   111  	suite.logger = unittest.Logger()
   112  
   113  	suite.size = 2 // operates on two networks
   114  	suite.metrics = metrics.NewNoopCollector()
   115  
   116  	// create and start the networks and inject a connection observer
   117  	peerChannel := make(chan string)
   118  	ob := tagsObserver{
   119  		tags: peerChannel,
   120  		log:  suite.logger,
   121  	}
   122  
   123  	suite.sporkId = unittest.IdentifierFixture()
   124  
   125  	libP2PNodes := make([]p2p.LibP2PNode, 0)
   126  	identities := make(flow.IdentityList, 0)
   127  	tagObservables := make([]observable.Observable, 0)
   128  	idProvider := unittest.NewUpdatableIDProvider(flow.IdentityList{})
   129  	defaultFlowConfig, err := config.DefaultConfig()
   130  	require.NoError(suite.T(), err)
   131  	defaultFlowConfig.NetworkConfig.Unicast.UnicastManager.CreateStreamBackoffDelay = 1 * time.Millisecond
   132  
   133  	opts := []p2ptest.NodeFixtureParameterOption{p2ptest.WithUnicastHandlerFunc(nil)}
   134  
   135  	for i := 0; i < suite.size; i++ {
   136  		connManager, err := testutils.NewTagWatchingConnManager(
   137  			unittest.Logger(),
   138  			metrics.NewNoopCollector(),
   139  			&defaultFlowConfig.NetworkConfig.ConnectionManager)
   140  		require.NoError(suite.T(), err)
   141  
   142  		opts = append(opts,
   143  			p2ptest.WithConnectionManager(connManager),
   144  			p2ptest.WithRole(flow.RoleExecution),
   145  			p2ptest.OverrideFlowConfig(defaultFlowConfig)) // to suppress exponential backoff
   146  		node, nodeId := p2ptest.NodeFixture(suite.T(),
   147  			suite.sporkId,
   148  			suite.T().Name(),
   149  			idProvider,
   150  			opts...)
   151  		libP2PNodes = append(libP2PNodes, node)
   152  		identities = append(identities, &nodeId)
   153  		tagObservables = append(tagObservables, connManager)
   154  	}
   155  	idProvider.SetIdentities(identities)
   156  
   157  	suite.ids = identities
   158  	suite.libP2PNodes = libP2PNodes
   159  
   160  	suite.networks, suite.providers = testutils.NetworksFixture(suite.T(), suite.sporkId, suite.ids, suite.libP2PNodes)
   161  	for _, observableConnMgr := range tagObservables {
   162  		observableConnMgr.Subscribe(&ob)
   163  	}
   164  	suite.obs = peerChannel
   165  
   166  	require.Len(suite.Suite.T(), tagObservables, suite.size)
   167  	require.Len(suite.Suite.T(), suite.ids, suite.size)
   168  
   169  	ctx, cancel := context.WithCancel(context.Background())
   170  	suite.mwCancel = cancel
   171  
   172  	suite.mwCtx = irrecoverable.NewMockSignalerContext(suite.T(), ctx)
   173  
   174  	testutils.StartNodes(suite.mwCtx, suite.T(), suite.libP2PNodes)
   175  
   176  	for i, net := range suite.networks {
   177  		unittest.RequireComponentsReadyBefore(suite.T(), 1*time.Second, libP2PNodes[i])
   178  		net.Start(suite.mwCtx)
   179  		unittest.RequireComponentsReadyBefore(suite.T(), 1*time.Second, net)
   180  	}
   181  }
   182  
   183  func (suite *NetworkTestSuite) TearDownTest() {
   184  	suite.mwCancel()
   185  
   186  	testutils.StopComponents(suite.T(), suite.networks, 1*time.Second)
   187  	testutils.StopComponents(suite.T(), suite.libP2PNodes, 1*time.Second)
   188  	suite.libP2PNodes = nil
   189  	suite.ids = nil
   190  	suite.size = 0
   191  }
   192  
   193  // TestUpdateNodeAddresses tests that the UpdateNodeAddresses method correctly updates
   194  // the addresses of the staked network participants.
   195  func (suite *NetworkTestSuite) TestUpdateNodeAddresses() {
   196  	ctx, cancel := context.WithCancel(suite.mwCtx)
   197  	irrecoverableCtx := irrecoverable.NewMockSignalerContext(suite.T(), ctx)
   198  
   199  	// create a new staked identity
   200  	ids, libP2PNodes := testutils.LibP2PNodeForNetworkFixture(suite.T(), suite.sporkId, 1)
   201  	idProvider := unittest.NewUpdatableIDProvider(ids)
   202  	networkCfg := testutils.NetworkConfigFixture(
   203  		suite.T(),
   204  		*ids[0],
   205  		idProvider,
   206  		suite.sporkId,
   207  		libP2PNodes[0])
   208  	newNet, err := underlay.NewNetwork(networkCfg)
   209  	require.NoError(suite.T(), err)
   210  	require.Len(suite.T(), ids, 1)
   211  	newId := ids[0]
   212  
   213  	// start up nodes and peer managers
   214  	testutils.StartNodes(irrecoverableCtx, suite.T(), libP2PNodes)
   215  	defer testutils.StopComponents(suite.T(), libP2PNodes, 1*time.Second)
   216  
   217  	newNet.Start(irrecoverableCtx)
   218  	defer testutils.StopComponents(suite.T(), []network.EngineRegistry{newNet}, 1*time.Second)
   219  	unittest.RequireComponentsReadyBefore(suite.T(), 1*time.Second, newNet)
   220  
   221  	idList := flow.IdentityList(append(suite.ids, newId))
   222  
   223  	// needed to enable ID translation
   224  	suite.providers[0].SetIdentities(idList)
   225  
   226  	// unicast should fail to send because no address is known yet for the new identity
   227  	con, err := suite.networks[0].Register(channels.TestNetworkChannel, &mocknetwork.MessageProcessor{})
   228  	require.NoError(suite.T(), err)
   229  	err = con.Unicast(&libp2pmessage.TestMessage{
   230  		Text: "TestUpdateNodeAddresses",
   231  	}, newId.NodeID)
   232  	require.True(suite.T(), strings.Contains(err.Error(), swarm.ErrNoAddresses.Error()))
   233  
   234  	// update the addresses
   235  	suite.networks[0].UpdateNodeAddresses()
   236  
   237  	// now the message should send successfully
   238  	err = con.Unicast(&libp2pmessage.TestMessage{
   239  		Text: "TestUpdateNodeAddresses",
   240  	}, newId.NodeID)
   241  	require.NoError(suite.T(), err)
   242  
   243  	cancel()
   244  	unittest.RequireComponentsReadyBefore(suite.T(), 1*time.Second, newNet)
   245  }
   246  
   247  func (suite *NetworkTestSuite) TestUnicastRateLimit_Messages() {
   248  	unittest.SkipUnless(suite.T(), unittest.TEST_FLAKY, "flaky")
   249  	// limiter limit will be set to 5 events/sec the 6th event per interval will be rate limited
   250  	limit := rate.Limit(5)
   251  
   252  	// burst per interval
   253  	burst := 5
   254  
   255  	for _, net := range suite.networks {
   256  		require.NoError(suite.T(), net.Subscribe(channels.TestNetworkChannel))
   257  	}
   258  
   259  	messageRateLimiter := ratelimiter.NewRateLimiter(limit, burst, 3*time.Second)
   260  
   261  	// we only expect messages from the first networks on the test suite
   262  	expectedPID, err := unittest.PeerIDFromFlowID(suite.ids[0])
   263  	require.NoError(suite.T(), err)
   264  
   265  	// the onRateLimit call back we will use to keep track of how many times a rate limit happens.
   266  	rateLimits := atomic.NewUint64(0)
   267  
   268  	onRateLimit := func(peerID peer.ID, role, msgType, topic, reason string) {
   269  		require.Equal(suite.T(), reason, ratelimit.ReasonMessageCount.String())
   270  		require.Equal(suite.T(), expectedPID, peerID)
   271  		// update hook calls
   272  		rateLimits.Inc()
   273  	}
   274  
   275  	// setup rate limit distributor that will be used to track the number of rate limits via the onRateLimit callback.
   276  	consumer := testutils.NewRateLimiterConsumer(onRateLimit)
   277  	distributor := ratelimit.NewUnicastRateLimiterDistributor()
   278  	distributor.AddConsumer(consumer)
   279  
   280  	opts := []ratelimit.RateLimitersOption{ratelimit.WithMessageRateLimiter(messageRateLimiter), ratelimit.WithNotifier(distributor), ratelimit.WithDisabledRateLimiting(false)}
   281  	rateLimiters := ratelimit.NewRateLimiters(opts...)
   282  
   283  	defaultFlowConfig, err := config.DefaultConfig()
   284  	require.NoError(suite.T(), err)
   285  	defaultFlowConfig.NetworkConfig.Unicast.UnicastManager.CreateStreamBackoffDelay = 1 * time.Millisecond
   286  
   287  	idProvider := unittest.NewUpdatableIDProvider(suite.ids)
   288  	ids, libP2PNodes := testutils.LibP2PNodeForNetworkFixture(suite.T(),
   289  		suite.sporkId,
   290  		1,
   291  		p2ptest.WithUnicastRateLimitDistributor(distributor),
   292  		p2ptest.OverrideFlowConfig(defaultFlowConfig), // to suppress exponential backoff
   293  		p2ptest.WithConnectionGater(p2ptest.NewConnectionGater(idProvider, func(pid peer.ID) error {
   294  			if messageRateLimiter.IsRateLimited(pid) {
   295  				return fmt.Errorf("rate-limited peer")
   296  			}
   297  			return nil
   298  		})))
   299  	idProvider.SetIdentities(append(suite.ids, ids...))
   300  
   301  	netCfg := testutils.NetworkConfigFixture(
   302  		suite.T(),
   303  		*ids[0],
   304  		idProvider,
   305  		suite.sporkId,
   306  		libP2PNodes[0])
   307  	newNet, err := underlay.NewNetwork(
   308  		netCfg,
   309  		underlay.WithUnicastRateLimiters(rateLimiters),
   310  		underlay.WithPeerManagerFilters(testutils.IsRateLimitedPeerFilter(messageRateLimiter)))
   311  	require.NoError(suite.T(), err)
   312  
   313  	require.Len(suite.T(), ids, 1)
   314  	newId := ids[0]
   315  	idList := flow.IdentityList(append(suite.ids, newId))
   316  
   317  	suite.providers[0].SetIdentities(idList)
   318  
   319  	ctx, cancel := context.WithCancel(suite.mwCtx)
   320  	irrecoverableCtx := irrecoverable.NewMockSignalerContext(suite.T(), ctx)
   321  	testutils.StartNodes(irrecoverableCtx, suite.T(), libP2PNodes)
   322  	defer testutils.StopComponents(suite.T(), libP2PNodes, 1*time.Second)
   323  	testutils.StartNetworks(irrecoverableCtx, suite.T(), []network.EngineRegistry{newNet})
   324  
   325  	calls := atomic.NewUint64(0)
   326  	ch := make(chan struct{})
   327  	// registers an engine on the new network
   328  	newEngine := &mocknetwork.MessageProcessor{}
   329  	_, err = newNet.Register(channels.TestNetworkChannel, newEngine)
   330  	require.NoError(suite.T(), err)
   331  	newEngine.On("Process", channels.TestNetworkChannel, suite.ids[0].NodeID, mockery.Anything).Run(func(args mockery.Arguments) {
   332  		calls.Inc()
   333  		if calls.Load() >= 5 {
   334  			close(ch)
   335  		}
   336  	}).Return(nil)
   337  
   338  	// needed to enable ID translation
   339  	suite.providers[0].SetIdentities(idList)
   340  
   341  	// update the addresses
   342  	suite.networks[0].UpdateNodeAddresses()
   343  
   344  	// add our sender node as a direct peer to our receiving node, this allows us to ensure
   345  	// that connections to peers that are rate limited are completely prune. IsConnected will
   346  	// return true only if the node is a direct peer of the other, after rate limiting this direct
   347  	// peer should be removed by the peer manager.
   348  	p2ptest.LetNodesDiscoverEachOther(suite.T(), ctx, []p2p.LibP2PNode{libP2PNodes[0], suite.libP2PNodes[0]}, flow.IdentityList{ids[0], suite.ids[0]})
   349  	p2ptest.TryConnectionAndEnsureConnected(suite.T(), ctx, []p2p.LibP2PNode{libP2PNodes[0], suite.libP2PNodes[0]})
   350  
   351  	con0, err := suite.networks[0].Register(channels.TestNetworkChannel, &mocknetwork.MessageProcessor{})
   352  	require.NoError(suite.T(), err)
   353  
   354  	// with the rate limit configured to 5 msg/sec we send 10 messages at once and expect the rate limiter
   355  	// to be invoked at-least once. We send 10 messages due to the flakiness that is caused by async stream
   356  	// handling of streams.
   357  	for i := 0; i < 10; i++ {
   358  		err = con0.Unicast(&libp2pmessage.TestMessage{
   359  			Text: fmt.Sprintf("hello-%d", i),
   360  		}, newId.NodeID)
   361  		require.NoError(suite.T(), err)
   362  	}
   363  	// wait for all rate limits before shutting down network
   364  	unittest.RequireCloseBefore(suite.T(), ch, 100*time.Millisecond, "could not stop rate limit test ch on time")
   365  
   366  	// sleep for 1 seconds to allow connection pruner to prune connections
   367  	time.Sleep(2 * time.Second)
   368  
   369  	// ensure connection to rate limited peer is pruned
   370  	p2ptest.EnsureNotConnectedBetweenGroups(suite.T(), ctx, []p2p.LibP2PNode{libP2PNodes[0]}, []p2p.LibP2PNode{suite.libP2PNodes[0]})
   371  	p2pfixtures.EnsureNoStreamCreationBetweenGroups(suite.T(), ctx, []p2p.LibP2PNode{libP2PNodes[0]}, []p2p.LibP2PNode{suite.libP2PNodes[0]})
   372  
   373  	// eventually the rate limited node should be able to reconnect and send messages
   374  	require.Eventually(suite.T(), func() bool {
   375  		err = con0.Unicast(&libp2pmessage.TestMessage{
   376  			Text: "hello",
   377  		}, newId.NodeID)
   378  		return err == nil
   379  	}, 3*time.Second, 100*time.Millisecond)
   380  
   381  	// shutdown our network so that each message can be processed
   382  	cancel()
   383  	unittest.RequireCloseBefore(suite.T(), libP2PNodes[0].Done(), 100*time.Millisecond, "could not stop libp2p node on time")
   384  	unittest.RequireCloseBefore(suite.T(), newNet.Done(), 100*time.Millisecond, "could not stop network on time")
   385  
   386  	// expect our rate limited peer callback to be invoked once
   387  	require.True(suite.T(), rateLimits.Load() > 0)
   388  }
   389  
   390  func (suite *NetworkTestSuite) TestUnicastRateLimit_Bandwidth() {
   391  	// limiter limit will be set up to 1000 bytes/sec
   392  	limit := rate.Limit(1000)
   393  
   394  	// burst per interval
   395  	burst := 1000
   396  
   397  	// we only expect messages from the first network on the test suite
   398  	expectedPID, err := unittest.PeerIDFromFlowID(suite.ids[0])
   399  	require.NoError(suite.T(), err)
   400  
   401  	// setup bandwidth rate limiter
   402  	bandwidthRateLimiter := ratelimit.NewBandWidthRateLimiter(limit, burst, 4*time.Second)
   403  
   404  	// the onRateLimit call back we will use to keep track of how many times a rate limit happens
   405  	// after 5 rate limits we will close ch.
   406  	ch := make(chan struct{})
   407  	rateLimits := atomic.NewUint64(0)
   408  	onRateLimit := func(peerID peer.ID, role, msgType, topic, reason string) {
   409  		require.Equal(suite.T(), reason, ratelimit.ReasonBandwidth.String())
   410  
   411  		// we only expect messages from the first network on the test suite
   412  		require.NoError(suite.T(), err)
   413  		require.Equal(suite.T(), expectedPID, peerID)
   414  		// update hook calls
   415  		rateLimits.Inc()
   416  		close(ch)
   417  	}
   418  
   419  	consumer := testutils.NewRateLimiterConsumer(onRateLimit)
   420  	distributor := ratelimit.NewUnicastRateLimiterDistributor()
   421  	distributor.AddConsumer(consumer)
   422  	opts := []ratelimit.RateLimitersOption{ratelimit.WithBandwidthRateLimiter(bandwidthRateLimiter), ratelimit.WithNotifier(distributor), ratelimit.WithDisabledRateLimiting(false)}
   423  	rateLimiters := ratelimit.NewRateLimiters(opts...)
   424  
   425  	defaultFlowConfig, err := config.DefaultConfig()
   426  	require.NoError(suite.T(), err)
   427  	defaultFlowConfig.NetworkConfig.Unicast.UnicastManager.CreateStreamBackoffDelay = 1 * time.Millisecond
   428  
   429  	idProvider := unittest.NewUpdatableIDProvider(suite.ids)
   430  	// create a new staked identity
   431  	ids, libP2PNodes := testutils.LibP2PNodeForNetworkFixture(suite.T(),
   432  		suite.sporkId,
   433  		1,
   434  		p2ptest.WithUnicastRateLimitDistributor(distributor),
   435  		p2ptest.OverrideFlowConfig(defaultFlowConfig), // to suppress exponential backoff
   436  		p2ptest.WithConnectionGater(p2ptest.NewConnectionGater(idProvider, func(pid peer.ID) error {
   437  			// create connection gater, connection gater will refuse connections from rate limited nodes
   438  			if bandwidthRateLimiter.IsRateLimited(pid) {
   439  				return fmt.Errorf("rate-limited peer")
   440  			}
   441  
   442  			return nil
   443  		})))
   444  	idProvider.SetIdentities(append(suite.ids, ids...))
   445  	suite.providers[0].SetIdentities(append(suite.ids, ids...))
   446  
   447  	netCfg := testutils.NetworkConfigFixture(
   448  		suite.T(),
   449  		*ids[0],
   450  		idProvider,
   451  		suite.sporkId,
   452  		libP2PNodes[0])
   453  	newNet, err := underlay.NewNetwork(
   454  		netCfg,
   455  		underlay.WithUnicastRateLimiters(rateLimiters),
   456  		underlay.WithPeerManagerFilters(testutils.IsRateLimitedPeerFilter(bandwidthRateLimiter)))
   457  	require.NoError(suite.T(), err)
   458  	require.Len(suite.T(), ids, 1)
   459  	newId := ids[0]
   460  
   461  	ctx, cancel := context.WithCancel(suite.mwCtx)
   462  	irrecoverableCtx := irrecoverable.NewMockSignalerContext(suite.T(), ctx)
   463  
   464  	testutils.StartNodes(irrecoverableCtx, suite.T(), libP2PNodes)
   465  	defer testutils.StopComponents(suite.T(), libP2PNodes, 1*time.Second)
   466  
   467  	testutils.StartNetworks(irrecoverableCtx, suite.T(), []network.EngineRegistry{newNet})
   468  	unittest.RequireComponentsReadyBefore(suite.T(), 1*time.Second, newNet)
   469  
   470  	// registers an engine on the new network so that it can receive messages on the TestNetworkChannel
   471  	newEngine := &mocknetwork.MessageProcessor{}
   472  	_, err = newNet.Register(channels.TestNetworkChannel, newEngine)
   473  	require.NoError(suite.T(), err)
   474  	newEngine.On("Process", channels.TestNetworkChannel, suite.ids[0].NodeID, mockery.Anything).Return(nil)
   475  
   476  	idList := flow.IdentityList(append(suite.ids, newId))
   477  
   478  	// needed to enable ID translation
   479  	suite.providers[0].SetIdentities(idList)
   480  
   481  	// update the addresses
   482  	suite.networks[0].UpdateNodeAddresses()
   483  
   484  	// add our sender node as a direct peer to our receiving node, this allows us to ensure
   485  	// that connections to peers that are rate limited are completely prune. IsConnected will
   486  	// return true only if the node is a direct peer of the other, after rate limiting this direct
   487  	// peer should be removed by the peer manager.
   488  	p2ptest.LetNodesDiscoverEachOther(suite.T(), ctx, []p2p.LibP2PNode{libP2PNodes[0], suite.libP2PNodes[0]}, flow.IdentityList{ids[0], suite.ids[0]})
   489  
   490  	// create message with about 400bytes (300 random bytes + 100bytes message info)
   491  	b := make([]byte, 300)
   492  	for i := range b {
   493  		b[i] = byte('X')
   494  	}
   495  	// send 3 messages at once with a size of 400 bytes each. The third message will be rate limited
   496  	// as it is more than our allowed bandwidth of 1000 bytes.
   497  	con0, err := suite.networks[0].Register(channels.TestNetworkChannel, &mocknetwork.MessageProcessor{})
   498  	require.NoError(suite.T(), err)
   499  	for i := 0; i < 3; i++ {
   500  		err = con0.Unicast(&libp2pmessage.TestMessage{
   501  			Text: string(b),
   502  		}, newId.NodeID)
   503  		require.NoError(suite.T(), err)
   504  	}
   505  
   506  	// wait for all rate limits before shutting down network
   507  	unittest.RequireCloseBefore(suite.T(), ch, 100*time.Millisecond, "could not stop on rate limit test ch on time")
   508  
   509  	// sleep for 1 seconds to allow connection pruner to prune connections
   510  	time.Sleep(1 * time.Second)
   511  
   512  	// ensure connection to rate limited peer is pruned
   513  	p2ptest.EnsureNotConnectedBetweenGroups(suite.T(), ctx, []p2p.LibP2PNode{libP2PNodes[0]}, []p2p.LibP2PNode{suite.libP2PNodes[0]})
   514  	p2pfixtures.EnsureNoStreamCreationBetweenGroups(suite.T(), ctx, []p2p.LibP2PNode{libP2PNodes[0]}, []p2p.LibP2PNode{suite.libP2PNodes[0]})
   515  
   516  	// eventually the rate limited node should be able to reconnect and send messages
   517  	require.Eventually(suite.T(), func() bool {
   518  		err = con0.Unicast(&libp2pmessage.TestMessage{
   519  			Text: "",
   520  		}, newId.NodeID)
   521  		return err == nil
   522  	}, 5*time.Second, 100*time.Millisecond)
   523  
   524  	// shutdown our network so that each message can be processed
   525  	cancel()
   526  	unittest.RequireComponentsDoneBefore(suite.T(), 5*time.Second, newNet)
   527  
   528  	// expect our rate limited peer callback to be invoked once
   529  	require.Equal(suite.T(), uint64(1), rateLimits.Load())
   530  }
   531  
   532  func (suite *NetworkTestSuite) createOverlay(provider *unittest.UpdatableIDProvider) *mocknetwork.Overlay {
   533  	overlay := &mocknetwork.Overlay{}
   534  	overlay.On("Identities").Maybe().Return(func() flow.IdentityList {
   535  		return provider.Identities(filter.Any)
   536  	})
   537  	overlay.On("Topology").Maybe().Return(func() flow.IdentityList {
   538  		return provider.Identities(filter.Any)
   539  	}, nil)
   540  	// this test is not testing the topic validator, especially in spoofing,
   541  	// so we always return a valid identity. We only care about the node role for the test TestMaxMessageSize_Unicast
   542  	// where EN are the only node authorized to send chunk data response.
   543  	identityOpts := unittest.WithRole(flow.RoleExecution)
   544  	overlay.On("Identity", mockery.AnythingOfType("peer.ID")).Maybe().Return(unittest.IdentityFixture(identityOpts), true)
   545  	return overlay
   546  }
   547  
   548  // TestPing sends a message from the first network of the test suit to the last one and checks that the
   549  // last network receives the message and that the message is correctly decoded.
   550  func (suite *NetworkTestSuite) TestPing() {
   551  	receiveWG := sync.WaitGroup{}
   552  	receiveWG.Add(1)
   553  	// extracts sender id based on the mock option
   554  	var err error
   555  
   556  	senderNodeIndex := 0
   557  	targetNodeIndex := suite.size - 1
   558  
   559  	expectedPayload := "TestPingContentReception"
   560  	// mocks a target engine on the last node of the test suit that will receive the message on the test channel.
   561  	targetEngine := &mocknetwork.MessageProcessor{} // target engine on the last node of the test suit that will receive the message
   562  	_, err = suite.networks[targetNodeIndex].Register(channels.TestNetworkChannel, targetEngine)
   563  	require.NoError(suite.T(), err)
   564  	// target engine must receive the message once with the expected payload
   565  	targetEngine.On("Process", mockery.Anything, mockery.Anything, mockery.Anything).
   566  		Run(func(args mockery.Arguments) {
   567  			receiveWG.Done()
   568  
   569  			msgChannel, ok := args[0].(channels.Channel)
   570  			require.True(suite.T(), ok)
   571  			require.Equal(suite.T(), channels.TestNetworkChannel, msgChannel) // channel
   572  
   573  			msgOriginID, ok := args[1].(flow.Identifier)
   574  			require.True(suite.T(), ok)
   575  			require.Equal(suite.T(), suite.ids[senderNodeIndex].NodeID, msgOriginID) // sender id
   576  
   577  			msgPayload, ok := args[2].(*libp2pmessage.TestMessage)
   578  			require.True(suite.T(), ok)
   579  			require.Equal(suite.T(), expectedPayload, msgPayload.Text) // payload
   580  		}).Return(nil).Once()
   581  
   582  	// sends a direct message from first node to the last node
   583  	con0, err := suite.networks[senderNodeIndex].Register(channels.TestNetworkChannel, &mocknetwork.MessageProcessor{})
   584  	require.NoError(suite.T(), err)
   585  	err = con0.Unicast(&libp2pmessage.TestMessage{
   586  		Text: expectedPayload,
   587  	}, suite.ids[targetNodeIndex].NodeID)
   588  	require.NoError(suite.Suite.T(), err)
   589  
   590  	unittest.RequireReturnsBefore(suite.T(), receiveWG.Wait, 1*time.Second, "did not receive message")
   591  }
   592  
   593  // TestMultiPing_TwoPings sends two messages concurrently from the first network of the test suit to the last one,
   594  // and checks that the last network receives the messages and that the messages are correctly decoded.
   595  func (suite *NetworkTestSuite) TestMultiPing_TwoPings() {
   596  	suite.MultiPing(2)
   597  }
   598  
   599  // TestMultiPing_FourPings sends four messages concurrently from the first network of the test suit to the last one,
   600  // and checks that the last network receives the messages and that the messages are correctly decoded.
   601  func (suite *NetworkTestSuite) TestMultiPing_FourPings() {
   602  	suite.MultiPing(4)
   603  }
   604  
   605  // TestMultiPing_EightPings sends eight messages concurrently from the first network of the test suit to the last one,
   606  // and checks that the last network receives the messages and that the messages are correctly decoded.
   607  func (suite *NetworkTestSuite) TestMultiPing_EightPings() {
   608  	suite.MultiPing(8)
   609  }
   610  
   611  // MultiPing sends count-many distinct messages concurrently from the first network of the test suit to the last one.
   612  // It evaluates the correctness of reception of the content of the messages. Each message must be received by the
   613  // last network of the test suit exactly once.
   614  func (suite *NetworkTestSuite) MultiPing(count int) {
   615  	receiveWG := sync.WaitGroup{}
   616  	sendWG := sync.WaitGroup{}
   617  	senderNodeIndex := 0
   618  	targetNodeIndex := suite.size - 1
   619  
   620  	receivedPayloads := unittest.NewProtectedMap[string, struct{}]() // keep track of unique payloads received.
   621  
   622  	// regex to extract the payload from the message
   623  	regex := regexp.MustCompile(`^hello from: \d`)
   624  
   625  	// creates a conduit on sender to send messages to the target on the test channel.
   626  	con0, err := suite.networks[senderNodeIndex].Register(channels.TestNetworkChannel, &mocknetwork.MessageProcessor{})
   627  	require.NoError(suite.T(), err)
   628  
   629  	// mocks a target engine on the last node of the test suit that will receive the message on the test channel.
   630  	targetEngine := &mocknetwork.MessageProcessor{}
   631  	_, err = suite.networks[targetNodeIndex].Register(channels.TestNetworkChannel, targetEngine)
   632  	targetEngine.On("Process", mockery.Anything, mockery.Anything, mockery.Anything).
   633  		Run(func(args mockery.Arguments) {
   634  			receiveWG.Done()
   635  
   636  			msgChannel, ok := args[0].(channels.Channel)
   637  			require.True(suite.T(), ok)
   638  			require.Equal(suite.T(), channels.TestNetworkChannel, msgChannel) // channel
   639  
   640  			msgOriginID, ok := args[1].(flow.Identifier)
   641  			require.True(suite.T(), ok)
   642  			require.Equal(suite.T(), suite.ids[senderNodeIndex].NodeID, msgOriginID) // sender id
   643  
   644  			msgPayload, ok := args[2].(*libp2pmessage.TestMessage)
   645  			require.True(suite.T(), ok)
   646  			// payload
   647  			require.True(suite.T(), regex.MatchString(msgPayload.Text))
   648  			require.False(suite.T(), receivedPayloads.Has(msgPayload.Text)) // payload must be unique
   649  			receivedPayloads.Add(msgPayload.Text, struct{}{})
   650  		}).Return(nil)
   651  
   652  	for i := 0; i < count; i++ {
   653  		receiveWG.Add(1)
   654  		sendWG.Add(1)
   655  
   656  		expectedPayloadText := fmt.Sprintf("hello from: %d", i)
   657  		require.NoError(suite.T(), err)
   658  		err = con0.Unicast(&libp2pmessage.TestMessage{
   659  			Text: expectedPayloadText,
   660  		}, suite.ids[targetNodeIndex].NodeID)
   661  		require.NoError(suite.Suite.T(), err)
   662  
   663  		go func() {
   664  			// sends a direct message from first node to the last node
   665  			err := con0.Unicast(&libp2pmessage.TestMessage{
   666  				Text: expectedPayloadText,
   667  			}, suite.ids[targetNodeIndex].NodeID)
   668  			require.NoError(suite.Suite.T(), err)
   669  
   670  			sendWG.Done()
   671  		}()
   672  	}
   673  
   674  	unittest.RequireReturnsBefore(suite.T(), sendWG.Wait, 1*time.Second, "could not send unicasts on time")
   675  	unittest.RequireReturnsBefore(suite.T(), receiveWG.Wait, 1*time.Second, "could not receive unicasts on time")
   676  }
   677  
   678  // TestEcho sends an echo message from first network to the last network
   679  // the last network echos back the message. The test evaluates the correctness
   680  // of the message reception as well as its content
   681  func (suite *NetworkTestSuite) TestEcho() {
   682  	wg := sync.WaitGroup{}
   683  	// extracts sender id based on the mock option
   684  	var err error
   685  
   686  	wg.Add(2)
   687  	first := 0
   688  	last := suite.size - 1
   689  	// mocks a target engine on the first and last nodes of the test suit that will receive the message on the test channel.
   690  	targetEngine1 := &mocknetwork.MessageProcessor{}
   691  	con1, err := suite.networks[first].Register(channels.TestNetworkChannel, targetEngine1)
   692  	require.NoError(suite.T(), err)
   693  	targetEngine2 := &mocknetwork.MessageProcessor{}
   694  	con2, err := suite.networks[last].Register(channels.TestNetworkChannel, targetEngine2)
   695  	require.NoError(suite.T(), err)
   696  
   697  	// message sent from first node to the last node.
   698  	expectedSendMsg := "TestEcho"
   699  	// reply from last node to the first node.
   700  	expectedReplyMsg := "TestEcho response"
   701  
   702  	// mocks the target engine on the last node of the test suit that will receive the message on the test channel, and
   703  	// echos back the reply message to the sender.
   704  	targetEngine2.On("Process", mockery.Anything, mockery.Anything, mockery.Anything).
   705  		Run(func(args mockery.Arguments) {
   706  			wg.Done()
   707  
   708  			msgChannel, ok := args[0].(channels.Channel)
   709  			require.True(suite.T(), ok)
   710  			require.Equal(suite.T(), channels.TestNetworkChannel, msgChannel) // channel
   711  
   712  			msgOriginID, ok := args[1].(flow.Identifier)
   713  			require.True(suite.T(), ok)
   714  			require.Equal(suite.T(), suite.ids[first].NodeID, msgOriginID) // sender id
   715  
   716  			msgPayload, ok := args[2].(*libp2pmessage.TestMessage)
   717  			require.True(suite.T(), ok)
   718  			require.Equal(suite.T(), expectedSendMsg, msgPayload.Text) // payload
   719  
   720  			// echos back the same message back to the sender
   721  			require.NoError(suite.T(), con2.Unicast(&libp2pmessage.TestMessage{
   722  				Text: expectedReplyMsg,
   723  			}, suite.ids[first].NodeID))
   724  		}).Return(nil).Once()
   725  
   726  	// mocks the target engine on the last node of the test suit that will receive the message on the test channel, and
   727  	// echos back the reply message to the sender.
   728  	targetEngine1.On("Process", mockery.Anything, mockery.Anything, mockery.Anything).
   729  		Run(func(args mockery.Arguments) {
   730  			wg.Done()
   731  
   732  			msgChannel, ok := args[0].(channels.Channel)
   733  			require.True(suite.T(), ok)
   734  			require.Equal(suite.T(), channels.TestNetworkChannel, msgChannel) // channel
   735  
   736  			msgOriginID, ok := args[1].(flow.Identifier)
   737  			require.True(suite.T(), ok)
   738  			require.Equal(suite.T(), suite.ids[last].NodeID, msgOriginID) // sender id
   739  
   740  			msgPayload, ok := args[2].(*libp2pmessage.TestMessage)
   741  			require.True(suite.T(), ok)
   742  			require.Equal(suite.T(), expectedReplyMsg, msgPayload.Text) // payload
   743  		}).Return(nil)
   744  
   745  	// sends a direct message from first node to the last node
   746  	require.NoError(suite.T(), con1.Unicast(&libp2pmessage.TestMessage{
   747  		Text: expectedSendMsg,
   748  	}, suite.ids[last].NodeID))
   749  
   750  	unittest.RequireReturnsBefore(suite.T(), wg.Wait, 5*time.Second, "could not receive unicast on time")
   751  }
   752  
   753  // TestMaxMessageSize_Unicast evaluates that invoking Unicast method of the network on a message
   754  // size beyond the permissible unicast message size returns an error.
   755  func (suite *NetworkTestSuite) TestMaxMessageSize_Unicast() {
   756  	first := 0
   757  	last := suite.size - 1
   758  
   759  	// creates a network payload beyond the maximum message size
   760  	// Note: networkPayloadFixture considers 1000 bytes as the overhead of the encoded message,
   761  	// so the generated payload is 1000 bytes below the maximum unicast message size.
   762  	// We hence add up 1000 bytes to the input of network payload fixture to make
   763  	// sure that payload is beyond the permissible size.
   764  	payload := testutils.NetworkPayloadFixture(suite.T(), uint(underlay.DefaultMaxUnicastMsgSize)+1000)
   765  	event := &libp2pmessage.TestMessage{
   766  		Text: string(payload),
   767  	}
   768  
   769  	// sends a direct message from first node to the last node
   770  	con0, err := suite.networks[first].Register(channels.TestNetworkChannel, &mocknetwork.MessageProcessor{})
   771  	require.NoError(suite.T(), err)
   772  	require.Error(suite.T(), con0.Unicast(event, suite.ids[last].NodeID))
   773  }
   774  
   775  // TestLargeMessageSize_SendDirect asserts that a ChunkDataResponse is treated as a large message and can be unicasted
   776  // successfully even though it's size is greater than the default message size.
   777  func (suite *NetworkTestSuite) TestLargeMessageSize_SendDirect() {
   778  	sourceIndex := 0
   779  	targetIndex := suite.size - 1
   780  	targetId := suite.ids[targetIndex].NodeID
   781  
   782  	// creates a network payload with a size greater than the default max size using a known large message type
   783  	targetSize := uint64(underlay.DefaultMaxUnicastMsgSize) + 1000
   784  	event := unittest.ChunkDataResponseMsgFixture(unittest.IdentifierFixture(), unittest.WithApproximateSize(targetSize))
   785  
   786  	// expect one message to be received by the target
   787  	ch := make(chan struct{})
   788  	// mocks a target engine on the last node of the test suit that will receive the message on the test channel.
   789  	targetEngine := &mocknetwork.MessageProcessor{}
   790  	_, err := suite.networks[targetIndex].Register(channels.ProvideChunks, targetEngine)
   791  	require.NoError(suite.T(), err)
   792  	targetEngine.On("Process", mockery.Anything, mockery.Anything, mockery.Anything).
   793  		Run(func(args mockery.Arguments) {
   794  			defer close(ch)
   795  
   796  			msgChannel, ok := args[0].(channels.Channel)
   797  			require.True(suite.T(), ok)
   798  			require.Equal(suite.T(), channels.ProvideChunks, msgChannel) // channel
   799  
   800  			msgOriginID, ok := args[1].(flow.Identifier)
   801  			require.True(suite.T(), ok)
   802  			require.Equal(suite.T(), suite.ids[sourceIndex].NodeID, msgOriginID) // sender id
   803  
   804  			msgPayload, ok := args[2].(*messages.ChunkDataResponse)
   805  			require.True(suite.T(), ok)
   806  			require.Equal(suite.T(), event, msgPayload) // payload
   807  		}).Return(nil).Once()
   808  
   809  	// sends a direct message from source node to the target node
   810  	con0, err := suite.networks[sourceIndex].Register(channels.ProvideChunks, &mocknetwork.MessageProcessor{})
   811  	require.NoError(suite.T(), err)
   812  	require.NoError(suite.T(), con0.Unicast(event, targetId))
   813  
   814  	// check message reception on target
   815  	unittest.RequireCloseBefore(suite.T(), ch, 5*time.Second, "source node failed to send large message to target")
   816  }
   817  
   818  // TestMaxMessageSize_Publish evaluates that invoking Publish method of the network on a message
   819  // size beyond the permissible publish message size returns an error.
   820  func (suite *NetworkTestSuite) TestMaxMessageSize_Publish() {
   821  	firstIndex := 0
   822  	lastIndex := suite.size - 1
   823  	lastNodeId := suite.ids[lastIndex].NodeID
   824  
   825  	// creates a network payload beyond the maximum message size
   826  	// Note: networkPayloadFixture considers 1000 bytes as the overhead of the encoded message,
   827  	// so the generated payload is 1000 bytes below the maximum publish message size.
   828  	// We hence add up 1000 bytes to the input of network payload fixture to make
   829  	// sure that payload is beyond the permissible size.
   830  	payload := testutils.NetworkPayloadFixture(suite.T(), uint(p2pnode.DefaultMaxPubSubMsgSize)+1000)
   831  	event := &libp2pmessage.TestMessage{
   832  		Text: string(payload),
   833  	}
   834  	con0, err := suite.networks[firstIndex].Register(channels.TestNetworkChannel, &mocknetwork.MessageProcessor{})
   835  	require.NoError(suite.T(), err)
   836  
   837  	err = con0.Publish(event, lastNodeId)
   838  	require.Error(suite.Suite.T(), err)
   839  	require.ErrorContains(suite.T(), err, "exceeds configured max message size")
   840  }
   841  
   842  // TestUnsubscribe tests that an engine can unsubscribe from a topic it was earlier subscribed to and stop receiving
   843  // messages.
   844  func (suite *NetworkTestSuite) TestUnsubscribe() {
   845  	senderIndex := 0
   846  	targetIndex := suite.size - 1
   847  	targetId := suite.ids[targetIndex].NodeID
   848  
   849  	msgRcvd := make(chan struct{}, 2)
   850  	msgRcvdFun := func() {
   851  		<-msgRcvd
   852  	}
   853  
   854  	targetEngine := &mocknetwork.MessageProcessor{}
   855  	con2, err := suite.networks[targetIndex].Register(channels.TestNetworkChannel, targetEngine)
   856  	require.NoError(suite.T(), err)
   857  	targetEngine.On("Process", mockery.Anything, mockery.Anything, mockery.Anything).
   858  		Run(func(args mockery.Arguments) {
   859  			msgChannel, ok := args[0].(channels.Channel)
   860  			require.True(suite.T(), ok)
   861  			require.Equal(suite.T(), channels.TestNetworkChannel, msgChannel) // channel
   862  
   863  			msgOriginID, ok := args[1].(flow.Identifier)
   864  			require.True(suite.T(), ok)
   865  			require.Equal(suite.T(), suite.ids[senderIndex].NodeID, msgOriginID) // sender id
   866  
   867  			msgPayload, ok := args[2].(*libp2pmessage.TestMessage)
   868  			require.True(suite.T(), ok)
   869  			require.True(suite.T(), msgPayload.Text == "hello1") // payload, we only expect hello 1 that was sent before unsubscribe.
   870  			msgRcvd <- struct{}{}
   871  		}).Return(nil)
   872  
   873  	// first test that when both nodes are subscribed to the channel, the target node receives the message
   874  	con1, err := suite.networks[senderIndex].Register(channels.TestNetworkChannel, &mocknetwork.MessageProcessor{})
   875  	require.NoError(suite.T(), err)
   876  
   877  	// set up waiting for suite.size pubsub tags indicating a mesh has formed
   878  	for i := 0; i < suite.size; i++ {
   879  		select {
   880  		case <-suite.obs:
   881  		case <-time.After(2 * time.Second):
   882  			assert.FailNow(suite.T(), "could not receive pubsub tag indicating mesh formed")
   883  		}
   884  	}
   885  
   886  	err = con1.Publish(&libp2pmessage.TestMessage{
   887  		Text: string("hello1"),
   888  	}, targetId)
   889  	require.NoError(suite.T(), err)
   890  
   891  	unittest.RequireReturnsBefore(suite.T(), msgRcvdFun, 3*time.Second, "message not received")
   892  
   893  	// now unsubscribe the target node from the channel
   894  	require.NoError(suite.T(), con2.Close())
   895  
   896  	// now publish a new message from the first node
   897  	err = con1.Publish(&libp2pmessage.TestMessage{
   898  		Text: string("hello2"),
   899  	}, targetId)
   900  	assert.NoError(suite.T(), err)
   901  
   902  	// assert that the new message is not received by the target node
   903  	unittest.RequireNeverReturnBefore(suite.T(), msgRcvdFun, 2*time.Second, "message received unexpectedly")
   904  }
   905  
   906  // TestChunkDataPackMaxMessageSize tests that the max message size for a chunk data pack response is set to the large message size.
   907  func TestChunkDataPackMaxMessageSize(t *testing.T) {
   908  	// creates an outgoing chunk data pack response message (imitating an EN is sending a chunk data pack response to VN).
   909  	msg, err := message.NewOutgoingScope(
   910  		flow.IdentifierList{unittest.IdentifierFixture()},
   911  		channels.TopicFromChannel(channels.ProvideChunks, unittest.IdentifierFixture()),
   912  		&messages.ChunkDataResponse{
   913  			ChunkDataPack: *unittest.ChunkDataPackFixture(unittest.IdentifierFixture()),
   914  			Nonce:         rand.Uint64(),
   915  		},
   916  		unittest.NetworkCodec().Encode,
   917  		message.ProtocolTypeUnicast)
   918  	require.NoError(t, err)
   919  
   920  	// get the max message size for the message
   921  	size, err := underlay.UnicastMaxMsgSizeByCode(msg.Proto().Payload)
   922  	require.NoError(t, err)
   923  	require.Equal(t, underlay.LargeMsgMaxUnicastMsgSize, size)
   924  }