github.com/MetalBlockchain/metalgo@v1.11.9/network/example_test.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package network 5 6 import ( 7 "context" 8 "os" 9 "time" 10 11 "go.uber.org/zap" 12 13 "github.com/MetalBlockchain/metalgo/genesis" 14 "github.com/MetalBlockchain/metalgo/ids" 15 "github.com/MetalBlockchain/metalgo/message" 16 "github.com/MetalBlockchain/metalgo/snow/networking/router" 17 "github.com/MetalBlockchain/metalgo/snow/validators" 18 "github.com/MetalBlockchain/metalgo/utils/constants" 19 "github.com/MetalBlockchain/metalgo/utils/logging" 20 "github.com/MetalBlockchain/metalgo/utils/set" 21 "github.com/MetalBlockchain/metalgo/version" 22 ) 23 24 var _ router.ExternalHandler = (*testExternalHandler)(nil) 25 26 // Note: all of the external handler's methods are called on peer goroutines. It 27 // is possible for multiple concurrent calls to happen with different NodeIDs. 28 // However, a given NodeID will only be performing one call at a time. 29 type testExternalHandler struct { 30 log logging.Logger 31 } 32 33 // Note: HandleInbound will be called with raw P2P messages, the networking 34 // implementation does not implicitly register timeouts, so this handler is only 35 // called by messages explicitly sent by the peer. If timeouts are required, 36 // that must be handled by the user of this utility. 37 func (t *testExternalHandler) HandleInbound(_ context.Context, message message.InboundMessage) { 38 t.log.Info( 39 "receiving message", 40 zap.Stringer("op", message.Op()), 41 ) 42 } 43 44 func (t *testExternalHandler) Connected(nodeID ids.NodeID, version *version.Application, subnetID ids.ID) { 45 t.log.Info( 46 "connected", 47 zap.Stringer("nodeID", nodeID), 48 zap.Stringer("version", version), 49 zap.Stringer("subnetID", subnetID), 50 ) 51 } 52 53 func (t *testExternalHandler) Disconnected(nodeID ids.NodeID) { 54 t.log.Info( 55 "disconnected", 56 zap.Stringer("nodeID", nodeID), 57 ) 58 } 59 60 type testAggressiveValidatorManager struct { 61 validators.Manager 62 } 63 64 func (*testAggressiveValidatorManager) Contains(ids.ID, ids.NodeID) bool { 65 return true 66 } 67 68 func ExampleNewTestNetwork() { 69 log := logging.NewLogger( 70 "networking", 71 logging.NewWrappedCore( 72 logging.Info, 73 os.Stdout, 74 logging.Colors.ConsoleEncoder(), 75 ), 76 ) 77 78 // Needs to be periodically updated by the caller to have the latest 79 // validator set 80 validators := &testAggressiveValidatorManager{ 81 Manager: validators.NewManager(), 82 } 83 84 // If we want to be able to communicate with non-primary network subnets, we 85 // should register them here. 86 trackedSubnets := set.Set[ids.ID]{} 87 88 // Messages and connections are handled by the external handler. 89 handler := &testExternalHandler{ 90 log: log, 91 } 92 93 network, err := NewTestNetwork( 94 log, 95 constants.TahoeID, 96 validators, 97 trackedSubnets, 98 handler, 99 ) 100 if err != nil { 101 log.Fatal( 102 "failed to create test network", 103 zap.Error(err), 104 ) 105 return 106 } 107 108 // We need to initially connect to some nodes in the network before peer 109 // gossip will enable connecting to all the remaining nodes in the network. 110 bootstrappers := genesis.SampleBootstrappers(constants.TahoeID, 5) 111 for _, bootstrapper := range bootstrappers { 112 network.ManuallyTrack(bootstrapper.ID, bootstrapper.IP) 113 } 114 115 // Typically network.StartClose() should be called based on receiving a 116 // SIGINT or SIGTERM. For the example, we close the network after 15s. 117 go log.RecoverAndPanic(func() { 118 time.Sleep(15 * time.Second) 119 network.StartClose() 120 }) 121 122 // network.Send(...) and network.Gossip(...) can be used here to send 123 // messages to peers. 124 125 // Calling network.Dispatch() will block until a fatal error occurs or 126 // network.StartClose() is called. 127 err = network.Dispatch() 128 log.Info( 129 "network exited", 130 zap.Error(err), 131 ) 132 }