github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/p2p/testing/protocoltester.go (about) 1 2 //此源码被清华学神尹成大魔王专业翻译分析并修改 3 //尹成QQ77025077 4 //尹成微信18510341407 5 //尹成所在QQ群721929980 6 //尹成邮箱 yinc13@mails.tsinghua.edu.cn 7 //尹成毕业于清华大学,微软区块链领域全球最有价值专家 8 //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620 9 //版权所有2017 Go Ethereum作者 10 //此文件是Go以太坊库的一部分。 11 // 12 //Go-Ethereum库是免费软件:您可以重新分发它和/或修改 13 //根据GNU发布的较低通用公共许可证的条款 14 //自由软件基金会,或者许可证的第3版,或者 15 //(由您选择)任何更高版本。 16 // 17 //Go以太坊图书馆的发行目的是希望它会有用, 18 //但没有任何保证;甚至没有 19 //适销性或特定用途的适用性。见 20 //GNU较低的通用公共许可证,了解更多详细信息。 21 // 22 //你应该收到一份GNU较低级别的公共许可证副本 23 //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。 24 25 /* 26 p2p/测试包提供了一个单元测试方案来检查 27 协议消息与一个透视节点和多个虚拟对等点交换 28 透视测试节点运行一个节点。服务,虚拟对等运行一个模拟节点 29 可用于发送和接收消息的 30 **/ 31 32 33 package testing 34 35 import ( 36 "bytes" 37 "fmt" 38 "io" 39 "io/ioutil" 40 "strings" 41 "sync" 42 "testing" 43 44 "github.com/ethereum/go-ethereum/log" 45 "github.com/ethereum/go-ethereum/node" 46 "github.com/ethereum/go-ethereum/p2p" 47 "github.com/ethereum/go-ethereum/p2p/discover" 48 "github.com/ethereum/go-ethereum/p2p/simulations" 49 "github.com/ethereum/go-ethereum/p2p/simulations/adapters" 50 "github.com/ethereum/go-ethereum/rlp" 51 "github.com/ethereum/go-ethereum/rpc" 52 ) 53 54 //ProtocolTester是用于单元测试协议的测试环境 55 //消息交换。它使用P2P/仿真框架 56 type ProtocolTester struct { 57 *ProtocolSession 58 network *simulations.Network 59 } 60 61 //NewProtocolTester构造了一个新的ProtocolTester 62 //它将透视节点ID、虚拟对等数和 63 //P2P服务器在对等连接上调用的协议运行函数 64 func NewProtocolTester(t *testing.T, id discover.NodeID, n int, run func(*p2p.Peer, p2p.MsgReadWriter) error) *ProtocolTester { 65 services := adapters.Services{ 66 "test": func(ctx *adapters.ServiceContext) (node.Service, error) { 67 return &testNode{run}, nil 68 }, 69 "mock": func(ctx *adapters.ServiceContext) (node.Service, error) { 70 return newMockNode(), nil 71 }, 72 } 73 adapter := adapters.NewSimAdapter(services) 74 net := simulations.NewNetwork(adapter, &simulations.NetworkConfig{}) 75 if _, err := net.NewNodeWithConfig(&adapters.NodeConfig{ 76 ID: id, 77 EnableMsgEvents: true, 78 Services: []string{"test"}, 79 }); err != nil { 80 panic(err.Error()) 81 } 82 if err := net.Start(id); err != nil { 83 panic(err.Error()) 84 } 85 86 node := net.GetNode(id).Node.(*adapters.SimNode) 87 peers := make([]*adapters.NodeConfig, n) 88 peerIDs := make([]discover.NodeID, n) 89 for i := 0; i < n; i++ { 90 peers[i] = adapters.RandomNodeConfig() 91 peers[i].Services = []string{"mock"} 92 peerIDs[i] = peers[i].ID 93 } 94 events := make(chan *p2p.PeerEvent, 1000) 95 node.SubscribeEvents(events) 96 ps := &ProtocolSession{ 97 Server: node.Server(), 98 IDs: peerIDs, 99 adapter: adapter, 100 events: events, 101 } 102 self := &ProtocolTester{ 103 ProtocolSession: ps, 104 network: net, 105 } 106 107 self.Connect(id, peers...) 108 109 return self 110 } 111 112 //停止停止P2P服务器 113 func (t *ProtocolTester) Stop() error { 114 t.Server.Stop() 115 return nil 116 } 117 118 //Connect打开远程对等节点并使用 119 //P2P/模拟与内存网络适配器的网络连接 120 func (t *ProtocolTester) Connect(selfID discover.NodeID, peers ...*adapters.NodeConfig) { 121 for _, peer := range peers { 122 log.Trace(fmt.Sprintf("start node %v", peer.ID)) 123 if _, err := t.network.NewNodeWithConfig(peer); err != nil { 124 panic(fmt.Sprintf("error starting peer %v: %v", peer.ID, err)) 125 } 126 if err := t.network.Start(peer.ID); err != nil { 127 panic(fmt.Sprintf("error starting peer %v: %v", peer.ID, err)) 128 } 129 log.Trace(fmt.Sprintf("connect to %v", peer.ID)) 130 if err := t.network.Connect(selfID, peer.ID); err != nil { 131 panic(fmt.Sprintf("error connecting to peer %v: %v", peer.ID, err)) 132 } 133 } 134 135 } 136 137 //testnode包装协议运行函数并实现node.service 138 //界面 139 type testNode struct { 140 run func(*p2p.Peer, p2p.MsgReadWriter) error 141 } 142 143 func (t *testNode) Protocols() []p2p.Protocol { 144 return []p2p.Protocol{{ 145 Length: 100, 146 Run: t.run, 147 }} 148 } 149 150 func (t *testNode) APIs() []rpc.API { 151 return nil 152 } 153 154 func (t *testNode) Start(server *p2p.Server) error { 155 return nil 156 } 157 158 func (t *testNode) Stop() error { 159 return nil 160 } 161 162 //mocknode是一个没有实际运行协议的testnode 163 //公开通道,以便测试可以手动触发并预期 164 //信息 165 type mockNode struct { 166 testNode 167 168 trigger chan *Trigger 169 expect chan []Expect 170 err chan error 171 stop chan struct{} 172 stopOnce sync.Once 173 } 174 175 func newMockNode() *mockNode { 176 mock := &mockNode{ 177 trigger: make(chan *Trigger), 178 expect: make(chan []Expect), 179 err: make(chan error), 180 stop: make(chan struct{}), 181 } 182 mock.testNode.run = mock.Run 183 return mock 184 } 185 186 //运行是一个协议运行函数,它只循环等待测试 187 //指示它触发或期望来自对等端的消息 188 func (m *mockNode) Run(peer *p2p.Peer, rw p2p.MsgReadWriter) error { 189 for { 190 select { 191 case trig := <-m.trigger: 192 wmsg := Wrap(trig.Msg) 193 m.err <- p2p.Send(rw, trig.Code, wmsg) 194 case exps := <-m.expect: 195 m.err <- expectMsgs(rw, exps) 196 case <-m.stop: 197 return nil 198 } 199 } 200 } 201 202 func (m *mockNode) Trigger(trig *Trigger) error { 203 m.trigger <- trig 204 return <-m.err 205 } 206 207 func (m *mockNode) Expect(exp ...Expect) error { 208 m.expect <- exp 209 return <-m.err 210 } 211 212 func (m *mockNode) Stop() error { 213 m.stopOnce.Do(func() { close(m.stop) }) 214 return nil 215 } 216 217 func expectMsgs(rw p2p.MsgReadWriter, exps []Expect) error { 218 matched := make([]bool, len(exps)) 219 for { 220 msg, err := rw.ReadMsg() 221 if err != nil { 222 if err == io.EOF { 223 break 224 } 225 return err 226 } 227 actualContent, err := ioutil.ReadAll(msg.Payload) 228 if err != nil { 229 return err 230 } 231 var found bool 232 for i, exp := range exps { 233 if exp.Code == msg.Code && bytes.Equal(actualContent, mustEncodeMsg(Wrap(exp.Msg))) { 234 if matched[i] { 235 return fmt.Errorf("message #%d received two times", i) 236 } 237 matched[i] = true 238 found = true 239 break 240 } 241 } 242 if !found { 243 expected := make([]string, 0) 244 for i, exp := range exps { 245 if matched[i] { 246 continue 247 } 248 expected = append(expected, fmt.Sprintf("code %d payload %x", exp.Code, mustEncodeMsg(Wrap(exp.Msg)))) 249 } 250 return fmt.Errorf("unexpected message code %d payload %x, expected %s", msg.Code, actualContent, strings.Join(expected, " or ")) 251 } 252 done := true 253 for _, m := range matched { 254 if !m { 255 done = false 256 break 257 } 258 } 259 if done { 260 return nil 261 } 262 } 263 for i, m := range matched { 264 if !m { 265 return fmt.Errorf("expected message #%d not received", i) 266 } 267 } 268 return nil 269 } 270 271 //mustencodemsg使用rlp对消息进行编码。 272 //一旦出错,它就会惊慌失措。 273 func mustEncodeMsg(msg interface{}) []byte { 274 contentEnc, err := rlp.EncodeToBytes(msg) 275 if err != nil { 276 panic("content encode error: " + err.Error()) 277 } 278 return contentEnc 279 } 280 281 type WrappedMsg struct { 282 Context []byte 283 Size uint32 284 Payload []byte 285 } 286 287 func Wrap(msg interface{}) interface{} { 288 data, _ := rlp.EncodeToBytes(msg) 289 return &WrappedMsg{ 290 Size: uint32(len(data)), 291 Payload: data, 292 } 293 }