github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/network/p2p/node/resourceManager_test.go (about)

     1  package p2pnode_test
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"math"
     7  	"sync"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/libp2p/go-libp2p"
    12  	"github.com/libp2p/go-libp2p/core/network"
    13  	rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager"
    14  	"github.com/stretchr/testify/require"
    15  
    16  	"github.com/onflow/flow-go/config"
    17  	"github.com/onflow/flow-go/model/flow"
    18  	"github.com/onflow/flow-go/module/irrecoverable"
    19  	mockmodule "github.com/onflow/flow-go/module/mock"
    20  	"github.com/onflow/flow-go/network/internal/p2putils"
    21  	"github.com/onflow/flow-go/network/p2p"
    22  	p2ptest "github.com/onflow/flow-go/network/p2p/test"
    23  	"github.com/onflow/flow-go/network/p2p/unicast/protocols"
    24  	"github.com/onflow/flow-go/utils/unittest"
    25  )
    26  
    27  // TestCreateStream_InboundConnResourceLimit ensures that the setting the resource limit config for
    28  // PeerDefaultLimits.ConnsInbound restricts the number of inbound connections created from a peer to the configured value.
    29  // NOTE: If this test becomes flaky, it indicates a violation of the single inbound connection guarantee.
    30  // In such cases the test should not be quarantined but requires immediate resolution.
    31  func TestCreateStream_InboundConnResourceLimit(t *testing.T) {
    32  	idProvider := mockmodule.NewIdentityProvider(t)
    33  	ctx, cancel := context.WithCancel(context.Background())
    34  	defer cancel()
    35  	signalerCtx := irrecoverable.NewMockSignalerContext(t, ctx)
    36  
    37  	cfg, err := config.DefaultConfig()
    38  	require.NoError(t, err)
    39  	cfg.NetworkConfig.Unicast.UnicastManager.CreateStreamBackoffDelay = 10 * time.Millisecond
    40  
    41  	sporkID := unittest.IdentifierFixture()
    42  
    43  	sender, id1 := p2ptest.NodeFixture(
    44  		t,
    45  		sporkID,
    46  		t.Name(),
    47  		idProvider,
    48  		p2ptest.WithDefaultResourceManager(),
    49  		p2ptest.OverrideFlowConfig(cfg))
    50  
    51  	receiver, id2 := p2ptest.NodeFixture(
    52  		t,
    53  		sporkID,
    54  		t.Name(),
    55  		idProvider,
    56  		p2ptest.WithDefaultResourceManager(),
    57  		p2ptest.OverrideFlowConfig(cfg))
    58  
    59  	idProvider.On("ByPeerID", sender.ID()).Return(&id1, true).Maybe()
    60  	idProvider.On("ByPeerID", receiver.ID()).Return(&id2, true).Maybe()
    61  
    62  	p2ptest.StartNodes(t, signalerCtx, []p2p.LibP2PNode{sender, receiver})
    63  	defer p2ptest.StopNodes(t, []p2p.LibP2PNode{sender, receiver}, cancel)
    64  
    65  	p2ptest.LetNodesDiscoverEachOther(t, signalerCtx, []p2p.LibP2PNode{sender, receiver}, flow.IdentityList{&id1, &id2})
    66  
    67  	var allStreamsCreated sync.WaitGroup
    68  	// at this point both nodes have discovered each other and we can now create an
    69  	// arbitrary number of streams from sender -> receiver. This will force libp2p
    70  	// to create multiple streams concurrently and attempt to reuse the single pairwise
    71  	// connection. If more than one connection is established while creating the conccurent
    72  	// streams this indicates a bug in the libp2p PeerBaseLimitConnsInbound limit.
    73  	defaultProtocolID := protocols.FlowProtocolID(sporkID)
    74  	expectedNumOfStreams := int64(50)
    75  	for i := int64(0); i < expectedNumOfStreams; i++ {
    76  		allStreamsCreated.Add(1)
    77  		go func() {
    78  			defer allStreamsCreated.Done()
    79  			require.NoError(t, sender.Host().Connect(ctx, receiver.Host().Peerstore().PeerInfo(receiver.ID())))
    80  			_, err := sender.Host().NewStream(ctx, receiver.ID(), defaultProtocolID)
    81  			require.NoError(t, err)
    82  		}()
    83  	}
    84  
    85  	unittest.RequireReturnsBefore(t, allStreamsCreated.Wait, 2*time.Second, "could not create streams on time")
    86  	require.Len(t, receiver.Host().Network().ConnsToPeer(sender.ID()), 1)
    87  	actualNumOfStreams := p2putils.CountStream(sender.Host(), receiver.ID(), p2putils.Protocol(defaultProtocolID), p2putils.Direction(network.DirOutbound))
    88  	require.Equal(t,
    89  		expectedNumOfStreams,
    90  		int64(actualNumOfStreams),
    91  		fmt.Sprintf("expected to create %d number of streams got %d", expectedNumOfStreams, actualNumOfStreams))
    92  }
    93  
    94  type testPeerLimitConfig struct {
    95  	// nodeCount is the number of nodes in the test.
    96  	nodeCount int
    97  
    98  	// maxInboundPeerStream is the maximum number of inbound streams from a single peer to the receiver.
    99  	maxInboundPeerStream int
   100  
   101  	// maxInboundStreamProtocol is the maximum number of inbound streams at the receiver using a specific protocol; it accumulates all streams from all senders.
   102  	maxInboundStreamProtocol int
   103  
   104  	// maxInboundStreamPeerProtocol is the maximum number of inbound streams at the receiver from a single peer using a specific protocol.
   105  	maxInboundStreamPeerProtocol int
   106  
   107  	// maxInboundStreamTransient is the maximum number of inbound transient streams at the receiver; it accumulates all streams from all senders across all protocols.
   108  	// transient streams are those that are not associated fully with a peer and protocol.
   109  	maxInboundStreamTransient int
   110  
   111  	// maxInboundStreamSystem is the maximum number of inbound streams at the receiver; it accumulates all streams from all senders across all protocols.
   112  	maxInboundStreamSystem int
   113  
   114  	// unknownProtocol when set to true will cause senders to use an unknown protocol ID when creating streams.
   115  	unknownProtocol bool
   116  }
   117  
   118  // maxLimit returns the maximum limit across all limits.
   119  func (t testPeerLimitConfig) maxLimit() int {
   120  	max := 0
   121  	if t.maxInboundPeerStream > max && t.maxInboundPeerStream != math.MaxInt {
   122  		max = t.maxInboundPeerStream
   123  	}
   124  	if t.maxInboundStreamProtocol > max && t.maxInboundStreamProtocol != math.MaxInt {
   125  		max = t.maxInboundStreamProtocol
   126  	}
   127  	if t.maxInboundStreamPeerProtocol > max && t.maxInboundStreamPeerProtocol != math.MaxInt {
   128  		max = t.maxInboundStreamPeerProtocol
   129  	}
   130  	if t.maxInboundStreamTransient > max && t.maxInboundStreamTransient != math.MaxInt {
   131  		max = t.maxInboundStreamTransient
   132  	}
   133  	if t.maxInboundStreamSystem > max && t.maxInboundStreamSystem != math.MaxInt {
   134  		max = t.maxInboundStreamSystem
   135  	}
   136  	return max
   137  }
   138  
   139  // baseCreateStreamInboundStreamResourceLimitConfig returns a testPeerLimitConfig with default values.
   140  func baseCreateStreamInboundStreamResourceLimitConfig() *testPeerLimitConfig {
   141  	return &testPeerLimitConfig{
   142  		nodeCount:                    10,
   143  		maxInboundPeerStream:         100,
   144  		maxInboundStreamProtocol:     100,
   145  		maxInboundStreamPeerProtocol: 100,
   146  		maxInboundStreamTransient:    100,
   147  		maxInboundStreamSystem:       100,
   148  	}
   149  }
   150  
   151  func TestCreateStream_DefaultConfig(t *testing.T) {
   152  	testCreateStreamInboundStreamResourceLimits(t, baseCreateStreamInboundStreamResourceLimitConfig())
   153  }
   154  
   155  func TestCreateStream_MinPeerLimit(t *testing.T) {
   156  	base := baseCreateStreamInboundStreamResourceLimitConfig()
   157  	base.maxInboundPeerStream = 1
   158  	testCreateStreamInboundStreamResourceLimits(t, base)
   159  }
   160  
   161  func TestCreateStream_MaxPeerLimit(t *testing.T) {
   162  
   163  	base := baseCreateStreamInboundStreamResourceLimitConfig()
   164  	base.maxInboundPeerStream = math.MaxInt
   165  	testCreateStreamInboundStreamResourceLimits(t, base)
   166  }
   167  
   168  func TestCreateStream_MinProtocolLimit(t *testing.T) {
   169  	// max inbound protocol is not preserved; can be partially due to count stream not counting inbound streams on a protocol
   170  	unittest.SkipUnless(t, unittest.TEST_TODO, "broken test")
   171  	base := baseCreateStreamInboundStreamResourceLimitConfig()
   172  	base.maxInboundStreamProtocol = 1
   173  	testCreateStreamInboundStreamResourceLimits(t, base)
   174  }
   175  
   176  func TestCreateStream_MaxProtocolLimit(t *testing.T) {
   177  	base := baseCreateStreamInboundStreamResourceLimitConfig()
   178  	base.maxInboundStreamProtocol = math.MaxInt
   179  	testCreateStreamInboundStreamResourceLimits(t, base)
   180  }
   181  
   182  func TestCreateStream_MinPeerProtocolLimit(t *testing.T) {
   183  	// max inbound stream peer protocol is not preserved; can be partially due to count stream not counting inbound streams on a protocol
   184  	unittest.SkipUnless(t, unittest.TEST_TODO, "broken test")
   185  	base := baseCreateStreamInboundStreamResourceLimitConfig()
   186  	base.maxInboundStreamPeerProtocol = 1
   187  	testCreateStreamInboundStreamResourceLimits(t, base)
   188  }
   189  
   190  func TestCreateStream_MaxPeerProtocolLimit(t *testing.T) {
   191  	base := baseCreateStreamInboundStreamResourceLimitConfig()
   192  	base.maxInboundStreamPeerProtocol = math.MaxInt
   193  	testCreateStreamInboundStreamResourceLimits(t, base)
   194  }
   195  
   196  func TestCreateStream_MinTransientLimit(t *testing.T) {
   197  	base := baseCreateStreamInboundStreamResourceLimitConfig()
   198  	base.maxInboundStreamTransient = 1
   199  	testCreateStreamInboundStreamResourceLimits(t, base)
   200  }
   201  
   202  func TestCreateStream_MaxTransientLimit(t *testing.T) {
   203  	base := baseCreateStreamInboundStreamResourceLimitConfig()
   204  	base.maxInboundStreamTransient = math.MaxInt
   205  	testCreateStreamInboundStreamResourceLimits(t, base)
   206  }
   207  
   208  func TestCreateStream_MinSystemLimit(t *testing.T) {
   209  	base := baseCreateStreamInboundStreamResourceLimitConfig()
   210  	base.maxInboundStreamSystem = 1
   211  	testCreateStreamInboundStreamResourceLimits(t, base)
   212  }
   213  
   214  func TestCreateStream_MaxSystemLimit(t *testing.T) {
   215  	// max inbound stream protocol is not preserved; can be partially due to count stream not counting inbound streams on a protocol
   216  	unittest.SkipUnless(t, unittest.TEST_TODO, "broken test")
   217  	base := baseCreateStreamInboundStreamResourceLimitConfig()
   218  	base.maxInboundStreamSystem = math.MaxInt
   219  	testCreateStreamInboundStreamResourceLimits(t, base)
   220  }
   221  
   222  func TestCreateStream_DefaultConfigWithUnknownProtocol(t *testing.T) {
   223  	// limits are not enforced when using an unknown protocol ID
   224  	unittest.SkipUnless(t, unittest.TEST_TODO, "broken test")
   225  	base := baseCreateStreamInboundStreamResourceLimitConfig()
   226  	base.unknownProtocol = true
   227  	testCreateStreamInboundStreamResourceLimits(t, base)
   228  }
   229  
   230  func TestCreateStream_PeerLimitLessThanPeerProtocolLimit(t *testing.T) {
   231  	// the case where peer-level limit is lower than the peer-protocol-level limit.
   232  	base := baseCreateStreamInboundStreamResourceLimitConfig()
   233  	base.maxInboundPeerStream = 5          // each peer can only create 5 streams.
   234  	base.maxInboundStreamPeerProtocol = 10 // each peer can create 10 streams on a specific protocol (but should still be limited by the peer-level limit).
   235  	testCreateStreamInboundStreamResourceLimits(t, base)
   236  }
   237  
   238  func TestCreateStream_PeerLimitGreaterThanPeerProtocolLimit(t *testing.T) {
   239  	// the case where peer-level limit is higher than the peer-protocol-level limit.
   240  	// max inbound stream peer protocol is not preserved; can be partially due to count stream not counting inbound streams on a protocol
   241  	unittest.SkipUnless(t, unittest.TEST_TODO, "broken test")
   242  	base := baseCreateStreamInboundStreamResourceLimitConfig()
   243  	base.maxInboundPeerStream = 10        // each peer can create 10 streams.
   244  	base.maxInboundStreamPeerProtocol = 5 // each peer can create 5 streams on a specific protocol.
   245  	base.maxInboundStreamProtocol = 100   // overall limit is 100 streams on a specific protocol (across all peers).
   246  	base.maxInboundStreamTransient = 1000 // overall limit is 1000 transient streams.
   247  	base.maxInboundStreamSystem = 1000    // overall limit is 1000 system-wide streams.
   248  	testCreateStreamInboundStreamResourceLimits(t, base)
   249  }
   250  
   251  func TestCreateStream_ProtocolLimitLessThanPeerProtocolLimit(t *testing.T) {
   252  	// max inbound stream peer protocol is not preserved; can be partially due to count stream not counting inbound streams on a protocol
   253  	unittest.SkipUnless(t,
   254  		unittest.TEST_TODO, "broken test")
   255  	// the case where protocol-level limit is lower than the peer-protocol-level limit.
   256  	base := baseCreateStreamInboundStreamResourceLimitConfig()
   257  	base.maxInboundStreamProtocol = 5      // each peer can create 5 streams on a specific protocol.
   258  	base.maxInboundStreamPeerProtocol = 10 // each peer can create 10 streams on a specific protocol (but should still be limited by the protocol-level limit).
   259  	testCreateStreamInboundStreamResourceLimits(t, base)
   260  }
   261  
   262  func TestCreateStream_ProtocolLimitGreaterThanPeerProtocolLimit(t *testing.T) {
   263  	// TODO: with libp2p upgrade to v0.32.2; this test is failing as the peer protocol limit is not being enforced, and
   264  	// rather the protocol limit is being enforced, this test expects each peer not to be allowed more than 5 streams on a specific protocol.
   265  	// However, the maximum number of streams on a specific protocol (and specific peer) are being enforced instead.
   266  	// A quick investigation shows that it may be due to the way libp2p treats our unicast protocol (it is not a limit-enforcing protocol).
   267  	// But further investigation is required to confirm this.
   268  	unittest.SkipUnless(t, unittest.TEST_TODO, "broken test")
   269  	// the case where protocol-level limit is higher than the peer-protocol-level limit.
   270  	base := baseCreateStreamInboundStreamResourceLimitConfig()
   271  	base.maxInboundStreamProtocol = 10    // overall limit is 10 streams on a specific protocol (across all peers).
   272  	base.maxInboundStreamPeerProtocol = 5 // each peer can create 5 streams on a specific protocol.
   273  	base.maxInboundStreamTransient = 1000 // overall limit is 1000 transient streams.
   274  	base.maxInboundStreamSystem = 1000    // overall limit is 1000 system-wide streams.
   275  	testCreateStreamInboundStreamResourceLimits(t, base)
   276  }
   277  
   278  func TestCreateStream_TransientLimitLessThanPeerProtocolLimit(t *testing.T) {
   279  	// the case where transient-level limit is lower than the peer-protocol-level limit.
   280  	base := baseCreateStreamInboundStreamResourceLimitConfig()
   281  	base.maxInboundStreamTransient = 5     // overall limit is 5 transient streams (across all peers).
   282  	base.maxInboundStreamPeerProtocol = 10 // each peer can create 10 streams on a specific protocol (but should still be limited by the transient-level limit).
   283  	testCreateStreamInboundStreamResourceLimits(t, base)
   284  }
   285  
   286  // testCreateStreamInboundStreamResourceLimits tests the inbound stream limits for a given testPeerLimitConfig. It creates
   287  // a number of senders and a single receiver. The receiver will have a resource manager with the given limits.
   288  // The senders will have a resource manager with infinite limits to ensure that they can create as many streams as they want.
   289  // The test will create a number of streams from each sender to the receiver. The test will then check that the limits are
   290  // being enforced correctly.
   291  // The number of streams is determined by the maxLimit() of the testPeerLimitConfig, which is the maximum limit across all limits (peer, protocol, transient, system), excluding
   292  // the math.MaxInt limits.
   293  func testCreateStreamInboundStreamResourceLimits(t *testing.T, cfg *testPeerLimitConfig) {
   294  	idProvider := mockmodule.NewIdentityProvider(t)
   295  	ctx, cancel := context.WithCancel(context.Background())
   296  	defer cancel()
   297  	signalerCtx := irrecoverable.NewMockSignalerContext(t, ctx)
   298  	sporkID := unittest.IdentifierFixture()
   299  
   300  	flowCfg, err := config.DefaultConfig()
   301  	require.NoError(t, err)
   302  	flowCfg.NetworkConfig.Unicast.UnicastManager.CreateStreamBackoffDelay = 10 * time.Millisecond
   303  
   304  	// sender nodes will have infinite stream limit to ensure that they can create as many streams as they want.
   305  	resourceManagerSnd, err := rcmgr.NewResourceManager(rcmgr.NewFixedLimiter(rcmgr.InfiniteLimits))
   306  	require.NoError(t, err)
   307  	senders, senderIds := p2ptest.NodesFixture(t,
   308  		sporkID,
   309  		t.Name(), cfg.nodeCount,
   310  		idProvider,
   311  		p2ptest.WithResourceManager(resourceManagerSnd),
   312  		p2ptest.OverrideFlowConfig(flowCfg))
   313  
   314  	// receiver node will run with default limits and no scaling.
   315  	limits := rcmgr.DefaultLimits
   316  	libp2p.SetDefaultServiceLimits(&limits)
   317  	l := limits.Scale(0, 0)
   318  	partial := rcmgr.PartialLimitConfig{
   319  		System: rcmgr.ResourceLimits{
   320  			StreamsInbound: rcmgr.LimitVal(cfg.maxInboundStreamSystem),
   321  			ConnsInbound:   rcmgr.LimitVal(cfg.nodeCount),
   322  		},
   323  		Transient: rcmgr.ResourceLimits{
   324  			ConnsInbound:   rcmgr.LimitVal(cfg.nodeCount),
   325  			StreamsInbound: rcmgr.LimitVal(cfg.maxInboundStreamTransient),
   326  		},
   327  		ProtocolDefault: rcmgr.ResourceLimits{
   328  			StreamsInbound: rcmgr.LimitVal(cfg.maxInboundStreamProtocol),
   329  		},
   330  		ProtocolPeerDefault: rcmgr.ResourceLimits{
   331  			StreamsInbound: rcmgr.LimitVal(cfg.maxInboundStreamPeerProtocol),
   332  		},
   333  		PeerDefault: rcmgr.ResourceLimits{
   334  			StreamsInbound: rcmgr.LimitVal(cfg.maxInboundPeerStream),
   335  		},
   336  		Conn: rcmgr.ResourceLimits{
   337  			StreamsInbound: rcmgr.LimitVal(cfg.maxInboundPeerStream),
   338  		},
   339  		Stream: rcmgr.ResourceLimits{
   340  			StreamsInbound: rcmgr.LimitVal(cfg.maxInboundPeerStream),
   341  		},
   342  	}
   343  	l = partial.Build(l)
   344  	resourceManagerRcv, err := rcmgr.NewResourceManager(rcmgr.NewFixedLimiter(l))
   345  	require.NoError(t, err)
   346  	receiver, id2 := p2ptest.NodeFixture(t,
   347  		sporkID,
   348  		t.Name(),
   349  		idProvider,
   350  		p2ptest.WithResourceManager(resourceManagerRcv),
   351  		p2ptest.OverrideFlowConfig(flowCfg))
   352  
   353  	for i, sender := range senders {
   354  		idProvider.On("ByPeerID", sender.ID()).Return(senderIds[i], true).Maybe()
   355  	}
   356  	idProvider.On("ByPeerID", receiver.ID()).Return(&id2, true).Maybe()
   357  
   358  	nodes := append(senders, receiver)
   359  	ids := append(senderIds, &id2)
   360  
   361  	p2ptest.StartNodes(t, signalerCtx, nodes)
   362  	defer p2ptest.StopNodes(t, nodes, cancel)
   363  
   364  	p2ptest.LetNodesDiscoverEachOther(t, signalerCtx, nodes, ids)
   365  
   366  	var allStreamsCreated sync.WaitGroup
   367  
   368  	protocolID := protocols.FlowProtocolID(sporkID)
   369  	if cfg.unknownProtocol {
   370  		protocolID = protocols.FlowProtocolID(unittest.IdentifierFixture())
   371  	}
   372  
   373  	loadLimit := cfg.maxLimit()
   374  	require.Greaterf(t, loadLimit, 0, "test limit must be greater than 0; got %d", loadLimit)
   375  
   376  	streamListMu := sync.Mutex{}             // mutex to protect the streamsList.
   377  	streamsList := make([]network.Stream, 0) // list of all streams created to avoid garbage collection.
   378  	for sIndex := range senders {
   379  		for i := 0; i < loadLimit; i++ {
   380  			allStreamsCreated.Add(1)
   381  			go func(sIndex int) {
   382  				defer allStreamsCreated.Done()
   383  				sender := senders[sIndex]
   384  				s, err := sender.Host().NewStream(ctx, receiver.ID(), protocolID)
   385  				if err != nil {
   386  					// we don't care about the error here; as we are trying to break a limit; so we expect some of the stream creations to fail.
   387  					return
   388  				}
   389  
   390  				require.NotNil(t, s)
   391  				streamListMu.Lock()
   392  				streamsList = append(streamsList, s)
   393  				streamListMu.Unlock()
   394  			}(sIndex)
   395  		}
   396  	}
   397  
   398  	unittest.RequireReturnsBefore(t, allStreamsCreated.Wait, 2*time.Second, "could not create streams on time")
   399  
   400  	// transient sanity-check
   401  	require.NoError(t, resourceManagerRcv.ViewTransient(func(scope network.ResourceScope) error {
   402  		// number of in-transient streams must be less than or equal to the max transient limit
   403  		require.LessOrEqual(t, int64(scope.Stat().NumStreamsInbound), int64(cfg.maxInboundStreamTransient))
   404  
   405  		// number of in-transient streams must be less than or equal the total number of streams created.
   406  		require.LessOrEqual(t, int64(scope.Stat().NumStreamsInbound), int64(len(streamsList)))
   407  		return nil
   408  	}))
   409  
   410  	// system-wide limit sanity-check
   411  	require.NoError(t, resourceManagerRcv.ViewSystem(func(scope network.ResourceScope) error {
   412  		require.LessOrEqual(t, int64(scope.Stat().NumStreamsInbound), int64(cfg.maxInboundStreamSystem), "system-wide limit is not being enforced")
   413  		return nil
   414  	}))
   415  
   416  	totalInboundStreams := 0
   417  	for _, sender := range senders {
   418  		actualNumOfStreams := p2putils.CountStream(receiver.Host(), sender.ID(), p2putils.Direction(network.DirInbound))
   419  		// number of inbound streams must be less than or equal to the peer-level limit for each sender.
   420  		require.LessOrEqual(t, int64(actualNumOfStreams), int64(cfg.maxInboundPeerStream))
   421  		require.LessOrEqual(t, int64(actualNumOfStreams), int64(cfg.maxInboundStreamPeerProtocol))
   422  		totalInboundStreams += actualNumOfStreams
   423  	}
   424  	// sanity check; the total number of inbound streams must be less than or equal to the system-wide limit.
   425  	// TODO: this must be a hard equal check; but falls short; to be shared with libp2p community.
   426  	// Failing at this line means the system-wide limit is not being enforced.
   427  	require.LessOrEqual(t, totalInboundStreams, cfg.maxInboundStreamSystem)
   428  	// sanity check; the total number of inbound streams must be less than or equal to the protocol-level limit.
   429  	require.LessOrEqual(t, totalInboundStreams, cfg.maxInboundStreamProtocol)
   430  }