github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/p2p/testing/protocolsession.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 package testing 26 27 import ( 28 "errors" 29 "fmt" 30 "sync" 31 "time" 32 33 "github.com/ethereum/go-ethereum/log" 34 "github.com/ethereum/go-ethereum/p2p" 35 "github.com/ethereum/go-ethereum/p2p/discover" 36 "github.com/ethereum/go-ethereum/p2p/simulations/adapters" 37 ) 38 39 var errTimedOut = errors.New("timed out") 40 41 //ProtocolSession是对运行的枢轴节点的准模拟。 42 //可以发送(触发器)或 43 //接收(预期)消息 44 type ProtocolSession struct { 45 Server *p2p.Server 46 IDs []discover.NodeID 47 adapter *adapters.SimAdapter 48 events chan *p2p.PeerEvent 49 } 50 51 //交换是协议测试的基本单元 52 //数组中的触发器和预期将立即异步运行 53 //因此,对于具有不同消息类型的同一对等端,不能有多个预期值 54 //因为它是不可预测的,哪个期望会收到哪个消息 55 //(对于Expect 1和2,可能会发送消息2和1,两个Expect都会抱怨错误的消息代码) 56 //在会话上定义交换 57 type Exchange struct { 58 Label string 59 Triggers []Trigger 60 Expects []Expect 61 Timeout time.Duration 62 } 63 64 //触发器是交换的一部分,透视节点的传入消息 65 //同行发送 66 type Trigger struct { 67 Msg interface{} //要发送的消息类型 68 Code uint64 //给出报文代码 69 Peer discover.NodeID //向其发送消息的对等方 70 Timeout time.Duration //发送超时时间 71 } 72 73 //Expect是来自透视节点的交换传出消息的一部分 74 //由对等方接收 75 type Expect struct { 76 Msg interface{} //预期的消息类型 77 Code uint64 //现在给出了消息代码 78 Peer discover.NodeID //期望消息的对等机 79 Timeout time.Duration //接收超时时间 80 } 81 82 //disconnect表示一个disconnect事件,由testdisconnected使用并检查 83 type Disconnect struct { 84 Peer discover.NodeID //DiscConnected对等 85 Error error //断开连接原因 86 } 87 88 //触发器从对等方发送消息 89 func (s *ProtocolSession) trigger(trig Trigger) error { 90 simNode, ok := s.adapter.GetNode(trig.Peer) 91 if !ok { 92 return fmt.Errorf("trigger: peer %v does not exist (1- %v)", trig.Peer, len(s.IDs)) 93 } 94 mockNode, ok := simNode.Services()[0].(*mockNode) 95 if !ok { 96 return fmt.Errorf("trigger: peer %v is not a mock", trig.Peer) 97 } 98 99 errc := make(chan error) 100 101 go func() { 102 log.Trace(fmt.Sprintf("trigger %v (%v)....", trig.Msg, trig.Code)) 103 errc <- mockNode.Trigger(&trig) 104 log.Trace(fmt.Sprintf("triggered %v (%v)", trig.Msg, trig.Code)) 105 }() 106 107 t := trig.Timeout 108 if t == time.Duration(0) { 109 t = 1000 * time.Millisecond 110 } 111 select { 112 case err := <-errc: 113 return err 114 case <-time.After(t): 115 return fmt.Errorf("timout expecting %v to send to peer %v", trig.Msg, trig.Peer) 116 } 117 } 118 119 //Expect检查透视节点发送的消息的期望值 120 func (s *ProtocolSession) expect(exps []Expect) error { 121 //构建每个节点的期望图 122 peerExpects := make(map[discover.NodeID][]Expect) 123 for _, exp := range exps { 124 if exp.Msg == nil { 125 return errors.New("no message to expect") 126 } 127 peerExpects[exp.Peer] = append(peerExpects[exp.Peer], exp) 128 } 129 130 //为每个节点构造一个mocknode映射 131 mockNodes := make(map[discover.NodeID]*mockNode) 132 for nodeID := range peerExpects { 133 simNode, ok := s.adapter.GetNode(nodeID) 134 if !ok { 135 return fmt.Errorf("trigger: peer %v does not exist (1- %v)", nodeID, len(s.IDs)) 136 } 137 mockNode, ok := simNode.Services()[0].(*mockNode) 138 if !ok { 139 return fmt.Errorf("trigger: peer %v is not a mock", nodeID) 140 } 141 mockNodes[nodeID] = mockNode 142 } 143 144 //done chanell在函数返回时取消所有创建的goroutine 145 done := make(chan struct{}) 146 defer close(done) 147 //errc从中捕获第一个错误 148 errc := make(chan error) 149 150 wg := &sync.WaitGroup{} 151 wg.Add(len(mockNodes)) 152 for nodeID, mockNode := range mockNodes { 153 nodeID := nodeID 154 mockNode := mockNode 155 go func() { 156 defer wg.Done() 157 158 //求和所有期望超时值以给出最大值 159 //完成所有期望的时间。 160 //mocknode.expect检查所有接收到的消息 161 //每个消息的预期消息和超时列表 162 //其中不能单独检查。 163 var t time.Duration 164 for _, exp := range peerExpects[nodeID] { 165 if exp.Timeout == time.Duration(0) { 166 t += 2000 * time.Millisecond 167 } else { 168 t += exp.Timeout 169 } 170 } 171 alarm := time.NewTimer(t) 172 defer alarm.Stop() 173 174 //expecterrc用于检查是否返回错误 175 //从mocknode.expect不是nil并将其发送到 176 //只有在这种情况下才是errc。 177 //完成通道将在功能关闭时关闭 178 expectErrc := make(chan error) 179 go func() { 180 select { 181 case expectErrc <- mockNode.Expect(peerExpects[nodeID]...): 182 case <-done: 183 case <-alarm.C: 184 } 185 }() 186 187 select { 188 case err := <-expectErrc: 189 if err != nil { 190 select { 191 case errc <- err: 192 case <-done: 193 case <-alarm.C: 194 errc <- errTimedOut 195 } 196 } 197 case <-done: 198 case <-alarm.C: 199 errc <- errTimedOut 200 } 201 202 }() 203 } 204 205 go func() { 206 wg.Wait() 207 //当所有Goroutine完成时关闭errc,从errc返回nill err 208 close(errc) 209 }() 210 211 return <-errc 212 } 213 214 //测试交换测试一系列针对会话的交换 215 func (s *ProtocolSession) TestExchanges(exchanges ...Exchange) error { 216 for i, e := range exchanges { 217 if err := s.testExchange(e); err != nil { 218 return fmt.Errorf("exchange #%d %q: %v", i, e.Label, err) 219 } 220 log.Trace(fmt.Sprintf("exchange #%d %q: run successfully", i, e.Label)) 221 } 222 return nil 223 } 224 225 //测试交换测试单个交换。 226 //默认超时值为2秒。 227 func (s *ProtocolSession) testExchange(e Exchange) error { 228 errc := make(chan error) 229 done := make(chan struct{}) 230 defer close(done) 231 232 go func() { 233 for _, trig := range e.Triggers { 234 err := s.trigger(trig) 235 if err != nil { 236 errc <- err 237 return 238 } 239 } 240 241 select { 242 case errc <- s.expect(e.Expects): 243 case <-done: 244 } 245 }() 246 247 //全球超时或在所有期望都满足时结束 248 t := e.Timeout 249 if t == 0 { 250 t = 2000 * time.Millisecond 251 } 252 alarm := time.NewTimer(t) 253 select { 254 case err := <-errc: 255 return err 256 case <-alarm.C: 257 return errTimedOut 258 } 259 } 260 261 //testDisconnected测试作为参数提供的断开 262 //disconnect结构描述了在哪个对等机上预期出现的断开连接错误 263 func (s *ProtocolSession) TestDisconnected(disconnects ...*Disconnect) error { 264 expects := make(map[discover.NodeID]error) 265 for _, disconnect := range disconnects { 266 expects[disconnect.Peer] = disconnect.Error 267 } 268 269 timeout := time.After(time.Second) 270 for len(expects) > 0 { 271 select { 272 case event := <-s.events: 273 if event.Type != p2p.PeerEventTypeDrop { 274 continue 275 } 276 expectErr, ok := expects[event.Peer] 277 if !ok { 278 continue 279 } 280 281 if !(expectErr == nil && event.Error == "" || expectErr != nil && expectErr.Error() == event.Error) { 282 return fmt.Errorf("unexpected error on peer %v. expected '%v', got '%v'", event.Peer, expectErr, event.Error) 283 } 284 delete(expects, event.Peer) 285 case <-timeout: 286 return fmt.Errorf("timed out waiting for peers to disconnect") 287 } 288 } 289 return nil 290 }