github.com/okex/exchain@v1.8.0/libs/tendermint/p2p/peer_test.go (about) 1 package p2p 2 3 import ( 4 "fmt" 5 golog "log" 6 "math" 7 "net" 8 "testing" 9 "time" 10 11 "github.com/tendermint/go-amino" 12 13 "github.com/pkg/errors" 14 "github.com/stretchr/testify/assert" 15 "github.com/stretchr/testify/require" 16 17 "github.com/okex/exchain/libs/tendermint/crypto" 18 "github.com/okex/exchain/libs/tendermint/crypto/ed25519" 19 "github.com/okex/exchain/libs/tendermint/libs/bytes" 20 "github.com/okex/exchain/libs/tendermint/libs/log" 21 22 "github.com/okex/exchain/libs/tendermint/config" 23 tmconn "github.com/okex/exchain/libs/tendermint/p2p/conn" 24 ) 25 26 func TestPeerBasic(t *testing.T) { 27 assert, require := assert.New(t), require.New(t) 28 29 // simulate remote peer 30 rp := &remotePeer{PrivKey: ed25519.GenPrivKey(), Config: cfg} 31 rp.Start() 32 defer rp.Stop() 33 34 p, err := createOutboundPeerAndPerformHandshake(rp.Addr(), cfg, tmconn.DefaultMConnConfig()) 35 require.Nil(err) 36 37 err = p.Start() 38 require.Nil(err) 39 defer p.Stop() 40 41 assert.True(p.IsRunning()) 42 assert.True(p.IsOutbound()) 43 assert.False(p.IsPersistent()) 44 p.persistent = true 45 assert.True(p.IsPersistent()) 46 assert.Equal(rp.Addr().DialString(), p.RemoteAddr().String()) 47 assert.Equal(rp.ID(), p.ID()) 48 } 49 50 func TestPeerSend(t *testing.T) { 51 assert, require := assert.New(t), require.New(t) 52 53 config := cfg 54 55 // simulate remote peer 56 rp := &remotePeer{PrivKey: ed25519.GenPrivKey(), Config: config} 57 rp.Start() 58 defer rp.Stop() 59 60 p, err := createOutboundPeerAndPerformHandshake(rp.Addr(), config, tmconn.DefaultMConnConfig()) 61 require.Nil(err) 62 63 err = p.Start() 64 require.Nil(err) 65 66 defer p.Stop() 67 68 assert.True(p.CanSend(testCh)) 69 assert.True(p.Send(testCh, []byte("Asylum"))) 70 } 71 72 func createOutboundPeerAndPerformHandshake( 73 addr *NetAddress, 74 config *config.P2PConfig, 75 mConfig tmconn.MConnConfig, 76 ) (*peer, error) { 77 chDescs := []*tmconn.ChannelDescriptor{ 78 {ID: testCh, Priority: 1}, 79 } 80 reactorsByCh := map[byte]Reactor{testCh: NewTestReactor(chDescs, true)} 81 pk := ed25519.GenPrivKey() 82 pc, err := testOutboundPeerConn(addr, config, false, pk) 83 if err != nil { 84 return nil, err 85 } 86 timeout := 1 * time.Second 87 ourNodeInfo := testNodeInfo(addr.ID, "host_peer") 88 peerNodeInfo, err := handshake(pc.conn, timeout, ourNodeInfo) 89 if err != nil { 90 return nil, err 91 } 92 93 p := newPeer(pc, mConfig, peerNodeInfo, reactorsByCh, chDescs, func(p Peer, r interface{}) {}) 94 p.SetLogger(log.TestingLogger().With("peer", addr)) 95 return p, nil 96 } 97 98 func testDial(addr *NetAddress, cfg *config.P2PConfig) (net.Conn, error) { 99 if cfg.TestDialFail { 100 return nil, fmt.Errorf("dial err (peerConfig.DialFail == true)") 101 } 102 103 conn, err := addr.DialTimeout(cfg.DialTimeout) 104 if err != nil { 105 return nil, err 106 } 107 return conn, nil 108 } 109 110 func testOutboundPeerConn( 111 addr *NetAddress, 112 config *config.P2PConfig, 113 persistent bool, 114 ourNodePrivKey crypto.PrivKey, 115 ) (peerConn, error) { 116 117 var pc peerConn 118 conn, err := testDial(addr, config) 119 if err != nil { 120 return pc, errors.Wrap(err, "Error creating peer") 121 } 122 123 pc, err = testPeerConn(conn, config, true, persistent, ourNodePrivKey, addr) 124 if err != nil { 125 if cerr := conn.Close(); cerr != nil { 126 return pc, errors.Wrap(err, cerr.Error()) 127 } 128 return pc, err 129 } 130 131 // ensure dialed ID matches connection ID 132 if addr.ID != pc.ID() { 133 if cerr := conn.Close(); cerr != nil { 134 return pc, errors.Wrap(err, cerr.Error()) 135 } 136 return pc, ErrSwitchAuthenticationFailure{addr, pc.ID()} 137 } 138 139 return pc, nil 140 } 141 142 type remotePeer struct { 143 PrivKey crypto.PrivKey 144 Config *config.P2PConfig 145 addr *NetAddress 146 channels bytes.HexBytes 147 listenAddr string 148 listener net.Listener 149 } 150 151 func (rp *remotePeer) Addr() *NetAddress { 152 return rp.addr 153 } 154 155 func (rp *remotePeer) ID() ID { 156 return PubKeyToID(rp.PrivKey.PubKey()) 157 } 158 159 func (rp *remotePeer) Start() { 160 if rp.listenAddr == "" { 161 rp.listenAddr = "127.0.0.1:0" 162 } 163 164 l, e := net.Listen("tcp", rp.listenAddr) // any available address 165 if e != nil { 166 golog.Fatalf("net.Listen tcp :0: %+v", e) 167 } 168 rp.listener = l 169 rp.addr = NewNetAddress(PubKeyToID(rp.PrivKey.PubKey()), l.Addr()) 170 if rp.channels == nil { 171 rp.channels = []byte{testCh} 172 } 173 go rp.accept() 174 } 175 176 func (rp *remotePeer) Stop() { 177 rp.listener.Close() 178 } 179 180 func (rp *remotePeer) Dial(addr *NetAddress) (net.Conn, error) { 181 conn, err := addr.DialTimeout(1 * time.Second) 182 if err != nil { 183 return nil, err 184 } 185 pc, err := testInboundPeerConn(conn, rp.Config, rp.PrivKey) 186 if err != nil { 187 return nil, err 188 } 189 _, err = handshake(pc.conn, time.Second, rp.nodeInfo()) 190 if err != nil { 191 return nil, err 192 } 193 return conn, err 194 } 195 196 func (rp *remotePeer) accept() { 197 conns := []net.Conn{} 198 199 for { 200 conn, err := rp.listener.Accept() 201 if err != nil { 202 golog.Printf("Failed to accept conn: %+v", err) 203 for _, conn := range conns { 204 _ = conn.Close() 205 } 206 return 207 } 208 209 pc, err := testInboundPeerConn(conn, rp.Config, rp.PrivKey) 210 if err != nil { 211 golog.Fatalf("Failed to create a peer: %+v", err) 212 } 213 214 _, err = handshake(pc.conn, time.Second, rp.nodeInfo()) 215 if err != nil { 216 golog.Fatalf("Failed to perform handshake: %+v", err) 217 } 218 219 conns = append(conns, conn) 220 } 221 } 222 223 func (rp *remotePeer) nodeInfo() NodeInfo { 224 return DefaultNodeInfo{ 225 ProtocolVersion: defaultProtocolVersion, 226 DefaultNodeID: rp.Addr().ID, 227 ListenAddr: rp.listener.Addr().String(), 228 Network: "testing", 229 Version: "1.2.3-rc0-deadbeef", 230 Channels: rp.channels, 231 Moniker: "remote_peer", 232 } 233 } 234 235 func TestGetChIdStr(t *testing.T) { 236 var i byte 237 for ; i < math.MaxUint8; i++ { 238 require.EqualValues(t, fmt.Sprintf("%#x", i), getChIdStr(i)) 239 } 240 } 241 242 const hextable = "0123456789abcdef" 243 244 func chidToHex(v byte) string { 245 size := 3 246 if v > 15 { 247 size += 1 248 } 249 ret := make([]byte, size) 250 ret[0] = '0' 251 ret[1] = 'x' 252 if v > 15 { 253 ret[2] = hextable[v>>4] 254 ret[3] = hextable[v&0x0f] 255 } else { 256 ret[2] = hextable[v] 257 } 258 return amino.BytesToStr(ret) 259 } 260 261 func BenchmarkChIdFormat(b *testing.B) { 262 b.Run("fmt", func(b *testing.B) { 263 b.ReportAllocs() 264 for i := 0; i < b.N; i++ { 265 _ = fmt.Sprintf("%#x", byte(i)) 266 } 267 }) 268 b.Run("hex", func(b *testing.B) { 269 b.ReportAllocs() 270 for i := 0; i < b.N; i++ { 271 _ = chidToHex(byte(i)) 272 } 273 }) 274 b.Run("table", func(b *testing.B) { 275 b.ReportAllocs() 276 for i := 0; i < b.N; i++ { 277 _ = getChIdStr(byte(i)) 278 } 279 }) 280 }