github.com/cranelv/ethereum_mpc@v0.0.0-20191031014521-23aeb1415092/consensus_pbft/pbft/broadcast_test.go (about) 1 /* 2 Copyright IBM Corp. 2016 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package pbft 18 19 import ( 20 "fmt" 21 "testing" 22 "time" 23 24 "github.com/ethereum/go-ethereum/consensus_pbft/pbftTypes" 25 "github.com/ethereum/go-ethereum/consensus_pbft/consensusInterface" 26 "github.com/ethereum/go-ethereum/consensus_pbft/message" 27 "github.com/ethereum/go-ethereum/p2p/discover" 28 "github.com/ethereum/go-ethereum/log" 29 "github.com/ethereum/go-ethereum/consensus_pbft/singletons" 30 ) 31 32 type mockMsg struct { 33 msg *message.Message 34 dest *pbftTypes.PeerID 35 } 36 37 type mockComm struct { 38 self pbftTypes.ReplicaID 39 n uint64 40 msgCh chan mockMsg 41 } 42 43 func (m *mockComm) Unicast(msg *message.Message, dest *pbftTypes.PeerID) error { 44 m.msgCh <- mockMsg{msg, dest} 45 return nil 46 } 47 48 func (m *mockComm) Broadcast(msg *message.Message, t pbftTypes.Peer_Type) error { 49 return nil 50 } 51 52 func (m *mockComm) GetNetworkNodes() (pbftTypes.Peer, []pbftTypes.Peer, error) { 53 return nil, nil, nil 54 } 55 56 func (m *mockComm) GetNetworkNodeIDs() (*pbftTypes.PeerID, []*pbftTypes.PeerID, error) { 57 var h []*pbftTypes.PeerID 58 for n := uint64(0); n < m.n; n++ { 59 peerId := stringToPeerId(fmt.Sprintf("vp%d", n)) 60 h = append(h, &peerId) 61 } 62 return h[m.self], h, nil 63 } 64 func newIdentify(m* mockComm) consensusInterface.ValidatorIdentifyInterface { 65 identify := &PbftIdentify{} 66 _,peers,_ := m.GetNetworkNodeIDs() 67 for i,peerId := range peers{ 68 peer := PbftPeer{&discover.Node{ID:discover.NodeID(*peerId)},pbftTypes.Peer_VALIDATOR} 69 identify.validatorInfo = append(identify.validatorInfo, PbftInfo{pbftTypes.ReplicaID(i),&peer}) 70 } 71 return identify 72 } 73 func TestBroadcast(t *testing.T) { 74 log.InitLog(5) 75 m := &mockComm{ 76 self: 1, 77 n: 4, 78 msgCh: make(chan mockMsg, 4), 79 } 80 sent := make(map[pbftTypes.PeerID]int) 81 go func() { 82 for msg := range m.msgCh { 83 sent[*msg.dest]++ 84 } 85 }() 86 identify := newIdentify(m) 87 b := newBroadcaster(m.self, 4, 1, time.Second,identify, m) 88 89 msg := &message.Message{Payload: []byte("hi")} 90 b.Broadcast(msg) 91 time.Sleep(100 * time.Millisecond) 92 b.Close() 93 94 sentCount := 0 95 for _, q := range sent { 96 if q == 1 { 97 sentCount++ 98 } 99 } 100 101 if sentCount < 2 { 102 t.Errorf("broadcast did not send to all peers: %v", sent) 103 } 104 } 105 106 type mockStuckComm struct { 107 mockComm 108 done chan struct{} 109 } 110 111 func (m *mockStuckComm) Unicast(msg *message.Message, dest *pbftTypes.PeerID) error { 112 ret := m.mockComm.Unicast(msg, dest) 113 if *dest == stringToPeerId("vp0") { 114 select { 115 case <-time.After(2 * time.Second): 116 return fmt.Errorf("timeout") 117 case <-m.done: 118 return fmt.Errorf("closed") 119 } 120 } 121 return ret 122 } 123 124 func TestBroadcastStuck(t *testing.T) { 125 log.InitLog(5 ) 126 m := &mockStuckComm{ 127 mockComm: mockComm{ 128 self: 1, 129 n: 4, 130 msgCh: make(chan mockMsg), 131 }, 132 done: make(chan struct{}), 133 } 134 sent := make(map[string][]*pbftTypes.PeerID) 135 go func() { 136 for msg := range m.msgCh { 137 key := string(msg.msg.Payload) 138 singletons.Log.Info(key) 139 sent[key] = append(sent[key], msg.dest) 140 } 141 }() 142 identify := newIdentify(&m.mockComm) 143 b := newBroadcaster(m.self, 4, 1, time.Second,identify, m) 144 145 maxc := 20 146 for c := 0; c < maxc; c++ { 147 b.Broadcast(&message.Message{Payload: []byte(fmt.Sprintf("%d", c))}) 148 } 149 150 done := make(chan struct{}) 151 go func() { 152 select { 153 case <-done: 154 return 155 case <-time.After(time.Second): 156 t.Fatal("blocked") 157 } 158 }() 159 time.Sleep(100 * time.Millisecond) 160 close(m.done) 161 b.Close() 162 close(done) 163 164 sendDone := 0 165 for _, q := range sent { 166 if len(q) >= 2 { 167 sendDone++ 168 } 169 } 170 if sendDone != maxc { 171 t.Errorf("expected %d sent messages: %v", maxc, sent) 172 } 173 } 174 175 func TestBroadcastUnicast(t *testing.T) { 176 m := &mockComm{ 177 self: 1, 178 n: 4, 179 msgCh: make(chan mockMsg, 4), 180 } 181 sent := make(map[pbftTypes.PeerID]int) 182 go func() { 183 for msg := range m.msgCh { 184 sent[*msg.dest]++ 185 } 186 }() 187 identify := newIdentify(m) 188 b := newBroadcaster(m.self, 4, 1, time.Second,identify, m) 189 190 msg := &message.Message{Payload: []byte("hi")} 191 b.Unicast(msg, 0) 192 time.Sleep(100 * time.Millisecond) 193 b.Close() 194 195 sentCount := 0 196 for _, q := range sent { 197 if q == 1 { 198 sentCount++ 199 } 200 } 201 202 if sentCount != 1 { 203 t.Errorf("broadcast did not send to dest peer: %v", sent) 204 } 205 } 206 207 type mockFailComm struct { 208 mockComm 209 done chan struct{} 210 } 211 212 func (m *mockFailComm) Unicast(msg *message.Message, dest *pbftTypes.PeerID) error { 213 return fmt.Errorf("always fails on purpose") 214 } 215 216 func TestBroadcastAllFail(t *testing.T) { 217 m := &mockFailComm{ 218 mockComm: mockComm{ 219 self: 1, 220 n: 4, 221 msgCh: make(chan mockMsg), 222 }, 223 done: make(chan struct{}), 224 } 225 identify := newIdentify(&m.mockComm) 226 b := newBroadcaster(m.self, 4, 1, time.Second,identify, m) 227 228 maxc := 20 229 for c := 0; c < maxc; c++ { 230 b.Broadcast(&message.Message{Payload: []byte(fmt.Sprintf("%d", c))}) 231 } 232 233 done := make(chan struct{}) 234 go func() { 235 close(m.done) 236 b.Close() // If the broadcasts are still trying (despite all the failures), this call blocks until the timeout 237 close(done) 238 }() 239 240 select { 241 case <-done: 242 return 243 case <-time.After(time.Second): 244 t.Fatal("Could not successfully close broadcaster, after 1 second") 245 } 246 } 247 248 func TestBroadcastTimeout(t *testing.T) { 249 log.InitLog(5) 250 expectTime := 10 * time.Second 251 deltaTime := 50 * time.Millisecond 252 m := &mockIndefinitelyStuckComm{ 253 mockComm: mockComm{ 254 self: 1, 255 n: 4, 256 msgCh: make(chan mockMsg), 257 }, 258 done: make(chan struct{}), 259 } 260 identify := newIdentify(&m.mockComm) 261 b := newBroadcaster(m.self, 4, 1, expectTime,identify, m) 262 broadcastDone := make(chan time.Time) 263 264 beginTime := time.Now() 265 go func() { 266 b.Broadcast(&message.Message{Payload: []byte(fmt.Sprintf("%d", 1))}) 267 broadcastDone <- time.Now() 268 }() 269 270 checkTime := expectTime + deltaTime 271 select { 272 case endTime := <-broadcastDone: 273 t.Log("Broadcast consume time: ", endTime.Sub(beginTime)) 274 close(broadcastDone) 275 close(m.done) 276 return 277 case <-time.After(checkTime): 278 close(broadcastDone) 279 close(m.done) 280 t.Fatalf("Broadcast timeout after %v, expected %v", checkTime, expectTime) 281 } 282 } 283 284 type mockIndefinitelyStuckComm struct { 285 mockComm 286 done chan struct{} 287 } 288 289 func (m *mockIndefinitelyStuckComm) Unicast(msg *message.Message, dest *pbftTypes.PeerID) error { 290 if *dest == stringToPeerId("vp0") { 291 <-m.done 292 } 293 return fmt.Errorf("Always failing, on purpose, with vp0 stuck") 294 } 295 296 func TestBroadcastIndefinitelyStuck(t *testing.T) { 297 m := &mockIndefinitelyStuckComm{ 298 mockComm: mockComm{ 299 self: 1, 300 n: 4, 301 msgCh: make(chan mockMsg), 302 }, 303 done: make(chan struct{}), 304 } 305 identify := newIdentify(&m.mockComm) 306 b := newBroadcaster(m.self, 4, 1, time.Second,identify, m) 307 308 broadcastDone := make(chan struct{}) 309 310 go func() { 311 maxc := 3 312 for c := 0; c < maxc; c++ { 313 b.Broadcast(&message.Message{Payload: []byte(fmt.Sprintf("%d", c))}) 314 } 315 close(broadcastDone) 316 }() 317 318 select { 319 case <-broadcastDone: 320 // Success 321 case <-time.After(10 * time.Second): 322 t.Errorf("Got blocked for too long") 323 } 324 325 close(m.done) 326 b.Close() 327 }