github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/p2p/test_util.go (about) 1 package p2p 2 3 import ( 4 "fmt" 5 "net" 6 "time" 7 8 "github.com/gnolang/gno/tm2/pkg/crypto" 9 "github.com/gnolang/gno/tm2/pkg/crypto/ed25519" 10 "github.com/gnolang/gno/tm2/pkg/errors" 11 "github.com/gnolang/gno/tm2/pkg/log" 12 "github.com/gnolang/gno/tm2/pkg/p2p/config" 13 "github.com/gnolang/gno/tm2/pkg/p2p/conn" 14 "github.com/gnolang/gno/tm2/pkg/random" 15 "github.com/gnolang/gno/tm2/pkg/versionset" 16 ) 17 18 const testCh = 0x01 19 20 // ------------------------------------------------ 21 22 func AddPeerToSwitchPeerSet(sw *Switch, peer Peer) { 23 sw.peers.Add(peer) 24 } 25 26 func CreateRandomPeer(outbound bool) *peer { 27 addr, netAddr := CreateRoutableAddr() 28 p := &peer{ 29 peerConn: peerConn{ 30 outbound: outbound, 31 socketAddr: netAddr, 32 }, 33 nodeInfo: NodeInfo{NetAddress: netAddr}, 34 mconn: &conn.MConnection{}, 35 } 36 p.SetLogger(log.NewNoopLogger().With("peer", addr)) 37 return p 38 } 39 40 func CreateRoutableAddr() (addr string, netAddr *NetAddress) { 41 for { 42 id := ed25519.GenPrivKey().PubKey().Address().ID() 43 var err error 44 addr = fmt.Sprintf("%s@%v.%v.%v.%v:26656", id, random.RandInt()%256, random.RandInt()%256, random.RandInt()%256, random.RandInt()%256) 45 netAddr, err = NewNetAddressFromString(addr) 46 if err != nil { 47 panic(err) 48 } 49 if netAddr.Routable() { 50 break 51 } 52 } 53 return 54 } 55 56 // ------------------------------------------------------------------ 57 // Connects switches via arbitrary net.Conn. Used for testing. 58 59 const TEST_HOST = "localhost" 60 61 // MakeConnectedSwitches returns n switches, connected according to the connect func. 62 // If connect==Connect2Switches, the switches will be fully connected. 63 // initSwitch defines how the i'th switch should be initialized (ie. with what reactors). 64 // NOTE: panics if any switch fails to start. 65 func MakeConnectedSwitches(cfg *config.P2PConfig, n int, initSwitch func(int, *Switch) *Switch, connect func([]*Switch, int, int)) []*Switch { 66 switches := make([]*Switch, n) 67 for i := 0; i < n; i++ { 68 switches[i] = MakeSwitch(cfg, i, TEST_HOST, "123.123.123", initSwitch) 69 } 70 71 if err := StartSwitches(switches); err != nil { 72 panic(err) 73 } 74 75 for i := 0; i < n; i++ { 76 for j := i + 1; j < n; j++ { 77 connect(switches, i, j) 78 } 79 } 80 81 return switches 82 } 83 84 // Connect2Switches will connect switches i and j via net.Pipe(). 85 // Blocks until a connection is established. 86 // NOTE: caller ensures i and j are within bounds. 87 func Connect2Switches(switches []*Switch, i, j int) { 88 switchI := switches[i] 89 switchJ := switches[j] 90 91 c1, c2 := conn.NetPipe() 92 93 doneCh := make(chan struct{}) 94 go func() { 95 err := switchI.addPeerWithConnection(c1) 96 if err != nil { 97 panic(err) 98 } 99 doneCh <- struct{}{} 100 }() 101 go func() { 102 err := switchJ.addPeerWithConnection(c2) 103 if err != nil { 104 panic(err) 105 } 106 doneCh <- struct{}{} 107 }() 108 <-doneCh 109 <-doneCh 110 } 111 112 func (sw *Switch) addPeerWithConnection(conn net.Conn) error { 113 pc, err := testInboundPeerConn(conn, sw.config, sw.nodeKey.PrivKey) 114 if err != nil { 115 if err := conn.Close(); err != nil { 116 sw.Logger.Error("Error closing connection", "err", err) 117 } 118 return err 119 } 120 121 ni, err := handshake(conn, time.Second, sw.nodeInfo) 122 if err != nil { 123 if err := conn.Close(); err != nil { 124 sw.Logger.Error("Error closing connection", "err", err) 125 } 126 return err 127 } 128 129 p := newPeer( 130 pc, 131 MConnConfig(sw.config), 132 ni, 133 sw.reactorsByCh, 134 sw.chDescs, 135 sw.StopPeerForError, 136 ) 137 138 if err = sw.addPeer(p); err != nil { 139 pc.CloseConn() 140 return err 141 } 142 143 return nil 144 } 145 146 // StartSwitches calls sw.Start() for each given switch. 147 // It returns the first encountered error. 148 func StartSwitches(switches []*Switch) error { 149 for _, s := range switches { 150 err := s.Start() // start switch and reactors 151 if err != nil { 152 return err 153 } 154 } 155 return nil 156 } 157 158 func MakeSwitch( 159 cfg *config.P2PConfig, 160 i int, 161 network, version string, 162 initSwitch func(int, *Switch) *Switch, 163 opts ...SwitchOption, 164 ) *Switch { 165 nodeKey := NodeKey{ 166 PrivKey: ed25519.GenPrivKey(), 167 } 168 nodeInfo := testNodeInfo(nodeKey.ID(), fmt.Sprintf("node%d", i)) 169 170 t := NewMultiplexTransport(nodeInfo, nodeKey, MConnConfig(cfg)) 171 172 if err := t.Listen(*nodeInfo.NetAddress); err != nil { 173 panic(err) 174 } 175 176 // TODO: let the config be passed in? 177 sw := initSwitch(i, NewSwitch(cfg, t, opts...)) 178 sw.SetLogger(log.NewNoopLogger().With("switch", i)) 179 sw.SetNodeKey(&nodeKey) 180 181 for ch := range sw.reactorsByCh { 182 nodeInfo.Channels = append(nodeInfo.Channels, ch) 183 } 184 185 // TODO: We need to setup reactors ahead of time so the NodeInfo is properly 186 // populated and we don't have to do those awkward overrides and setters. 187 t.nodeInfo = nodeInfo 188 sw.SetNodeInfo(nodeInfo) 189 190 return sw 191 } 192 193 func testInboundPeerConn( 194 conn net.Conn, 195 config *config.P2PConfig, 196 ourNodePrivKey crypto.PrivKey, 197 ) (peerConn, error) { 198 return testPeerConn(conn, config, false, false, ourNodePrivKey, nil) 199 } 200 201 func testPeerConn( 202 rawConn net.Conn, 203 cfg *config.P2PConfig, 204 outbound, persistent bool, 205 ourNodePrivKey crypto.PrivKey, 206 socketAddr *NetAddress, 207 ) (pc peerConn, err error) { 208 conn := rawConn 209 210 // Fuzz connection 211 if cfg.TestFuzz { 212 // so we have time to do peer handshakes and get set up 213 conn = FuzzConnAfterFromConfig(conn, 10*time.Second, cfg.TestFuzzConfig) 214 } 215 216 // Encrypt connection 217 conn, err = upgradeSecretConn(conn, cfg.HandshakeTimeout, ourNodePrivKey) 218 if err != nil { 219 return pc, errors.Wrap(err, "Error creating peer") 220 } 221 222 // Only the information we already have 223 return newPeerConn(outbound, persistent, conn, socketAddr), nil 224 } 225 226 // ---------------------------------------------------------------- 227 // rand node info 228 229 func testNodeInfo(id ID, name string) NodeInfo { 230 return testNodeInfoWithNetwork(id, name, "testing") 231 } 232 233 func testVersionSet() versionset.VersionSet { 234 return versionset.VersionSet{ 235 versionset.VersionInfo{ 236 Name: "p2p", 237 Version: "v0.0.0", // dontcare 238 }, 239 } 240 } 241 242 func testNodeInfoWithNetwork(id ID, name, network string) NodeInfo { 243 return NodeInfo{ 244 VersionSet: testVersionSet(), 245 NetAddress: NewNetAddressFromIPPort(id, net.ParseIP("127.0.0.1"), 0), 246 Network: network, 247 Software: "p2ptest", 248 Version: "v1.2.3-rc.0-deadbeef", 249 Channels: []byte{testCh}, 250 Moniker: name, 251 Other: NodeInfoOther{ 252 TxIndex: "on", 253 RPCAddress: fmt.Sprintf("127.0.0.1:%d", 0), 254 }, 255 } 256 }