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

     1  package p2pnode_test
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/libp2p/go-libp2p/core/peer"
     9  
    10  	"github.com/onflow/flow-go/model/flow"
    11  	"github.com/onflow/flow-go/module/irrecoverable"
    12  	mockmodule "github.com/onflow/flow-go/module/mock"
    13  	"github.com/onflow/flow-go/network"
    14  	"github.com/onflow/flow-go/network/p2p"
    15  	p2pbuilderconfig "github.com/onflow/flow-go/network/p2p/builder/config"
    16  	"github.com/onflow/flow-go/network/p2p/connection"
    17  	p2ptest "github.com/onflow/flow-go/network/p2p/test"
    18  	"github.com/onflow/flow-go/utils/unittest"
    19  )
    20  
    21  // TestDisconnectingFromDisallowListedNode ensures that:
    22  // (1) the node disconnects from a disallow listed node while the node is connected to other (allow listed) nodes.
    23  // (2) new inbound or outbound connections to and from disallow-listed nodes are rejected.
    24  // (3) When a disallow-listed node is allow-listed again, the node reconnects to it.
    25  func TestDisconnectingFromDisallowListedNode(t *testing.T) {
    26  	ctx, cancel := context.WithCancel(context.Background())
    27  	signalerCtx := irrecoverable.NewMockSignalerContext(t, ctx)
    28  
    29  	sporkID := unittest.IdentifierFixture()
    30  	idProvider := mockmodule.NewIdentityProvider(t)
    31  
    32  	peerIDSlice := peer.IDSlice{}
    33  	// node 1 is the node that will be disallow-listing another node (node 2).
    34  	node1, identity1 := p2ptest.NodeFixture(t,
    35  		sporkID,
    36  		t.Name(),
    37  		idProvider,
    38  		p2ptest.WithPeerManagerEnabled(&p2pbuilderconfig.PeerManagerConfig{
    39  			ConnectionPruning: true,
    40  			UpdateInterval:    connection.DefaultPeerUpdateInterval,
    41  			ConnectorFactory:  connection.DefaultLibp2pBackoffConnectorFactory(),
    42  		},
    43  			func() peer.IDSlice {
    44  				return peerIDSlice
    45  			}),
    46  		p2ptest.WithConnectionGater(p2ptest.NewConnectionGater(idProvider, func(p peer.ID) error {
    47  			// allow all the connections, except for the ones that are disallow-listed, which are determined when
    48  			// this connection gater object queries the disallow listing oracle that will be provided to it by
    49  			// the libp2p node. So, here, we don't need to do anything except just enabling the connection gater.
    50  			return nil
    51  		})))
    52  	idProvider.On("ByPeerID", node1.ID()).Return(&identity1, true).Maybe()
    53  	peerIDSlice = append(peerIDSlice, node1.ID())
    54  
    55  	// node 2 is the node that will be disallow-listed by node 1.
    56  	node2, identity2 := p2ptest.NodeFixture(t, sporkID, t.Name(), idProvider)
    57  	idProvider.On("ByPeerID", node2.ID()).Return(&identity2, true).Maybe()
    58  	peerIDSlice = append(peerIDSlice, node2.ID())
    59  
    60  	// node 3 is the node that will be connected to node 1 (to ensure that node 1 is still able to connect to other nodes
    61  	// after disallow-listing node 2).
    62  	node3, identity3 := p2ptest.NodeFixture(t, sporkID, t.Name(), idProvider)
    63  	idProvider.On("ByPeerID", node3.ID()).Return(&identity3, true).Maybe()
    64  	peerIDSlice = append(peerIDSlice, node3.ID())
    65  
    66  	nodes := []p2p.LibP2PNode{node1, node2, node3}
    67  	ids := flow.IdentityList{&identity1, &identity2, &identity3}
    68  
    69  	p2ptest.StartNodes(t, signalerCtx, nodes)
    70  	defer p2ptest.StopNodes(t, nodes, cancel)
    71  
    72  	p2ptest.LetNodesDiscoverEachOther(t, ctx, nodes, ids)
    73  
    74  	// initially all nodes should be connected to each other.
    75  	p2ptest.RequireConnectedEventually(t, nodes, 100*time.Millisecond, 2*time.Second)
    76  
    77  	// phase-1: node 1 disallow-lists node 2.
    78  	node1.OnDisallowListNotification(node2.ID(), network.DisallowListedCauseAlsp)
    79  
    80  	// eventually node 1 should be disconnected from node 2 while other nodes should remain connected.
    81  	// we choose a timeout of 2 seconds because peer manager updates peers every 1 second.
    82  	p2ptest.RequireEventuallyNotConnected(t, []p2p.LibP2PNode{node1}, []p2p.LibP2PNode{node2}, 100*time.Millisecond, 2*time.Second)
    83  
    84  	// but nodes 1 and 3 should remain connected as well as nodes 2 and 3.
    85  	// we choose a short timeout because we expect the nodes to remain connected.
    86  	p2ptest.RequireConnectedEventually(t, []p2p.LibP2PNode{node1, node3}, 1*time.Millisecond, 100*time.Millisecond)
    87  	p2ptest.RequireConnectedEventually(t, []p2p.LibP2PNode{node2, node3}, 1*time.Millisecond, 100*time.Millisecond)
    88  
    89  	// while node 2 is disallow-listed, it cannot connect to node 1. Also, node 1 cannot directly dial and connect to node 2, unless
    90  	// it is allow-listed again.
    91  	p2ptest.EnsureNotConnectedBetweenGroups(t, ctx, []p2p.LibP2PNode{node1}, []p2p.LibP2PNode{node2})
    92  
    93  	// phase-2: now we allow-list node 1 back
    94  	node1.OnAllowListNotification(node2.ID(), network.DisallowListedCauseAlsp)
    95  
    96  	// eventually node 1 should be connected to node 2 again, hence all nodes should be connected to each other.
    97  	// we choose a timeout of 5 seconds because peer manager updates peers every 1 second and we need to wait for
    98  	// any potential random backoffs to expire (min 1 second).
    99  	p2ptest.RequireConnectedEventually(t, nodes, 100*time.Millisecond, 5*time.Second)
   100  }