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  }