github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/p2p/protocols/protocol_test.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 12:09:44</date> 10 //</624342660076802048> 11 12 13 package protocols 14 15 import ( 16 "context" 17 "errors" 18 "fmt" 19 "testing" 20 "time" 21 22 "github.com/ethereum/go-ethereum/p2p" 23 "github.com/ethereum/go-ethereum/p2p/discover" 24 "github.com/ethereum/go-ethereum/p2p/simulations/adapters" 25 p2ptest "github.com/ethereum/go-ethereum/p2p/testing" 26 ) 27 28 //握手消息类型 29 type hs0 struct { 30 C uint 31 } 32 33 //用nodeid终止/删除对等机的消息 34 type kill struct { 35 C discover.NodeID 36 } 37 38 //断开连接的消息 39 type drop struct { 40 } 41 42 ///protochandshake表示协议与模块无关的方面,并且 43 //第一个消息对等端作为初始交换的一部分发送和接收 44 type protoHandshake struct { 45 Version uint //本地和远程对等机应具有相同的版本 46 NetworkID string //本地和远程对等机应具有相同的网络ID 47 } 48 49 //检查协议握手验证本地和远程协议握手是否匹配 50 func checkProtoHandshake(testVersion uint, testNetworkID string) func(interface{}) error { 51 return func(rhs interface{}) error { 52 remote := rhs.(*protoHandshake) 53 if remote.NetworkID != testNetworkID { 54 return fmt.Errorf("%s (!= %s)", remote.NetworkID, testNetworkID) 55 } 56 57 if remote.Version != testVersion { 58 return fmt.Errorf("%d (!= %d)", remote.Version, testVersion) 59 } 60 return nil 61 } 62 } 63 64 //新协议设置协议 65 //这里的run函数演示了使用peerpool和handshake的典型协议 66 //以及注册到处理程序的消息 67 func newProtocol(pp *p2ptest.TestPeerPool) func(*p2p.Peer, p2p.MsgReadWriter) error { 68 spec := &Spec{ 69 Name: "test", 70 Version: 42, 71 MaxMsgSize: 10 * 1024, 72 Messages: []interface{}{ 73 protoHandshake{}, 74 hs0{}, 75 kill{}, 76 drop{}, 77 }, 78 } 79 return func(p *p2p.Peer, rw p2p.MsgReadWriter) error { 80 peer := NewPeer(p, rw, spec) 81 82 //启动一次性协议握手并检查有效性 83 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 84 defer cancel() 85 phs := &protoHandshake{42, "420"} 86 hsCheck := checkProtoHandshake(phs.Version, phs.NetworkID) 87 _, err := peer.Handshake(ctx, phs, hsCheck) 88 if err != nil { 89 return err 90 } 91 92 lhs := &hs0{42} 93 //模块握手演示同一类型消息的简单可重复交换 94 hs, err := peer.Handshake(ctx, lhs, nil) 95 if err != nil { 96 return err 97 } 98 99 if rmhs := hs.(*hs0); rmhs.C > lhs.C { 100 return fmt.Errorf("handshake mismatch remote %v > local %v", rmhs.C, lhs.C) 101 } 102 103 handle := func(ctx context.Context, msg interface{}) error { 104 switch msg := msg.(type) { 105 106 case *protoHandshake: 107 return errors.New("duplicate handshake") 108 109 case *hs0: 110 rhs := msg 111 if rhs.C > lhs.C { 112 return fmt.Errorf("handshake mismatch remote %v > local %v", rhs.C, lhs.C) 113 } 114 lhs.C += rhs.C 115 return peer.Send(ctx, lhs) 116 117 case *kill: 118 //演示使用对等池,终止另一个对等连接作为对消息的响应 119 id := msg.C 120 pp.Get(id).Drop(errors.New("killed")) 121 return nil 122 123 case *drop: 124 //对于测试,我们可以在接收到丢弃消息时触发自诱导断开。 125 return errors.New("dropped") 126 127 default: 128 return fmt.Errorf("unknown message type: %T", msg) 129 } 130 } 131 132 pp.Add(peer) 133 defer pp.Remove(peer) 134 return peer.Run(handle) 135 } 136 } 137 138 func protocolTester(t *testing.T, pp *p2ptest.TestPeerPool) *p2ptest.ProtocolTester { 139 conf := adapters.RandomNodeConfig() 140 return p2ptest.NewProtocolTester(t, conf.ID, 2, newProtocol(pp)) 141 } 142 143 func protoHandshakeExchange(id discover.NodeID, proto *protoHandshake) []p2ptest.Exchange { 144 145 return []p2ptest.Exchange{ 146 { 147 Expects: []p2ptest.Expect{ 148 { 149 Code: 0, 150 Msg: &protoHandshake{42, "420"}, 151 Peer: id, 152 }, 153 }, 154 }, 155 { 156 Triggers: []p2ptest.Trigger{ 157 { 158 Code: 0, 159 Msg: proto, 160 Peer: id, 161 }, 162 }, 163 }, 164 } 165 } 166 167 func runProtoHandshake(t *testing.T, proto *protoHandshake, errs ...error) { 168 pp := p2ptest.NewTestPeerPool() 169 s := protocolTester(t, pp) 170 //托多:多做一次握手 171 id := s.IDs[0] 172 if err := s.TestExchanges(protoHandshakeExchange(id, proto)...); err != nil { 173 t.Fatal(err) 174 } 175 var disconnects []*p2ptest.Disconnect 176 for i, err := range errs { 177 disconnects = append(disconnects, &p2ptest.Disconnect{Peer: s.IDs[i], Error: err}) 178 } 179 if err := s.TestDisconnected(disconnects...); err != nil { 180 t.Fatal(err) 181 } 182 } 183 184 func TestProtoHandshakeVersionMismatch(t *testing.T) { 185 runProtoHandshake(t, &protoHandshake{41, "420"}, errorf(ErrHandshake, errorf(ErrHandler, "(msg code 0): 41 (!= 42)").Error())) 186 } 187 188 func TestProtoHandshakeNetworkIDMismatch(t *testing.T) { 189 runProtoHandshake(t, &protoHandshake{42, "421"}, errorf(ErrHandshake, errorf(ErrHandler, "(msg code 0): 421 (!= 420)").Error())) 190 } 191 192 func TestProtoHandshakeSuccess(t *testing.T) { 193 runProtoHandshake(t, &protoHandshake{42, "420"}) 194 } 195 196 func moduleHandshakeExchange(id discover.NodeID, resp uint) []p2ptest.Exchange { 197 198 return []p2ptest.Exchange{ 199 { 200 Expects: []p2ptest.Expect{ 201 { 202 Code: 1, 203 Msg: &hs0{42}, 204 Peer: id, 205 }, 206 }, 207 }, 208 { 209 Triggers: []p2ptest.Trigger{ 210 { 211 Code: 1, 212 Msg: &hs0{resp}, 213 Peer: id, 214 }, 215 }, 216 }, 217 } 218 } 219 220 func runModuleHandshake(t *testing.T, resp uint, errs ...error) { 221 pp := p2ptest.NewTestPeerPool() 222 s := protocolTester(t, pp) 223 id := s.IDs[0] 224 if err := s.TestExchanges(protoHandshakeExchange(id, &protoHandshake{42, "420"})...); err != nil { 225 t.Fatal(err) 226 } 227 if err := s.TestExchanges(moduleHandshakeExchange(id, resp)...); err != nil { 228 t.Fatal(err) 229 } 230 var disconnects []*p2ptest.Disconnect 231 for i, err := range errs { 232 disconnects = append(disconnects, &p2ptest.Disconnect{Peer: s.IDs[i], Error: err}) 233 } 234 if err := s.TestDisconnected(disconnects...); err != nil { 235 t.Fatal(err) 236 } 237 } 238 239 func TestModuleHandshakeError(t *testing.T) { 240 runModuleHandshake(t, 43, fmt.Errorf("handshake mismatch remote 43 > local 42")) 241 } 242 243 func TestModuleHandshakeSuccess(t *testing.T) { 244 runModuleHandshake(t, 42) 245 } 246 247 //在多个对等点上测试复杂的交互、中继、丢弃 248 func testMultiPeerSetup(a, b discover.NodeID) []p2ptest.Exchange { 249 250 return []p2ptest.Exchange{ 251 { 252 Label: "primary handshake", 253 Expects: []p2ptest.Expect{ 254 { 255 Code: 0, 256 Msg: &protoHandshake{42, "420"}, 257 Peer: a, 258 }, 259 { 260 Code: 0, 261 Msg: &protoHandshake{42, "420"}, 262 Peer: b, 263 }, 264 }, 265 }, 266 { 267 Label: "module handshake", 268 Triggers: []p2ptest.Trigger{ 269 { 270 Code: 0, 271 Msg: &protoHandshake{42, "420"}, 272 Peer: a, 273 }, 274 { 275 Code: 0, 276 Msg: &protoHandshake{42, "420"}, 277 Peer: b, 278 }, 279 }, 280 Expects: []p2ptest.Expect{ 281 { 282 Code: 1, 283 Msg: &hs0{42}, 284 Peer: a, 285 }, 286 { 287 Code: 1, 288 Msg: &hs0{42}, 289 Peer: b, 290 }, 291 }, 292 }, 293 294 {Label: "alternative module handshake", Triggers: []p2ptest.Trigger{{Code: 1, Msg: &hs0{41}, Peer: a}, 295 {Code: 1, Msg: &hs0{41}, Peer: b}}}, 296 {Label: "repeated module handshake", Triggers: []p2ptest.Trigger{{Code: 1, Msg: &hs0{1}, Peer: a}}}, 297 {Label: "receiving repeated module handshake", Expects: []p2ptest.Expect{{Code: 1, Msg: &hs0{43}, Peer: a}}}} 298 } 299 300 func runMultiplePeers(t *testing.T, peer int, errs ...error) { 301 pp := p2ptest.NewTestPeerPool() 302 s := protocolTester(t, pp) 303 304 if err := s.TestExchanges(testMultiPeerSetup(s.IDs[0], s.IDs[1])...); err != nil { 305 t.Fatal(err) 306 } 307 //在一些消息交换之后,我们可以测试状态变化 308 //在这里,这只是由Peerpool演示的 309 //握手后,必须将对等方添加到池中 310 //睡眠时间(1) 311 tick := time.NewTicker(10 * time.Millisecond) 312 timeout := time.NewTimer(1 * time.Second) 313 WAIT: 314 for { 315 select { 316 case <-tick.C: 317 if pp.Has(s.IDs[0]) { 318 break WAIT 319 } 320 case <-timeout.C: 321 t.Fatal("timeout") 322 } 323 } 324 if !pp.Has(s.IDs[1]) { 325 t.Fatalf("missing peer test-1: %v (%v)", pp, s.IDs) 326 } 327 328 //peer 0发送索引为peer的kill请求<peer> 329 err := s.TestExchanges(p2ptest.Exchange{ 330 Triggers: []p2ptest.Trigger{ 331 { 332 Code: 2, 333 Msg: &kill{s.IDs[peer]}, 334 Peer: s.IDs[0], 335 }, 336 }, 337 }) 338 339 if err != nil { 340 t.Fatal(err) 341 } 342 343 //未被杀死的对等机发送删除请求 344 err = s.TestExchanges(p2ptest.Exchange{ 345 Triggers: []p2ptest.Trigger{ 346 { 347 Code: 3, 348 Msg: &drop{}, 349 Peer: s.IDs[(peer+1)%2], 350 }, 351 }, 352 }) 353 354 if err != nil { 355 t.Fatal(err) 356 } 357 358 //检查各个对等机上的实际DiscConnect错误 359 var disconnects []*p2ptest.Disconnect 360 for i, err := range errs { 361 disconnects = append(disconnects, &p2ptest.Disconnect{Peer: s.IDs[i], Error: err}) 362 } 363 if err := s.TestDisconnected(disconnects...); err != nil { 364 t.Fatal(err) 365 } 366 //测试是否已从对等池中删除断开连接的对等机 367 if pp.Has(s.IDs[peer]) { 368 t.Fatalf("peer test-%v not dropped: %v (%v)", peer, pp, s.IDs) 369 } 370 371 } 372 func XTestMultiplePeersDropSelf(t *testing.T) { 373 runMultiplePeers(t, 0, 374 fmt.Errorf("subprotocol error"), 375 fmt.Errorf("Message handler error: (msg code 3): dropped"), 376 ) 377 } 378 379 func XTestMultiplePeersDropOther(t *testing.T) { 380 runMultiplePeers(t, 1, 381 fmt.Errorf("Message handler error: (msg code 3): dropped"), 382 fmt.Errorf("subprotocol error"), 383 ) 384 } 385