github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/consensus/hotstuff/integration/connect_test.go (about) 1 package integration 2 3 import ( 4 "testing" 5 6 "github.com/stretchr/testify/mock" 7 "github.com/stretchr/testify/require" 8 9 "github.com/onflow/flow-go/consensus/hotstuff/model" 10 "github.com/onflow/flow-go/model/flow" 11 ) 12 13 func Connect(t *testing.T, instances []*Instance) { 14 15 // first, create a map of all instances and a queue for each 16 lookup := make(map[flow.Identifier]*Instance) 17 for _, in := range instances { 18 lookup[in.localID] = in 19 } 20 21 // then, for each instance, initialize a wired up communicator 22 for _, sender := range instances { 23 sender := sender // avoid capturing loop variable in closure 24 25 *sender.notifier = *NewMockedCommunicatorConsumer() 26 sender.notifier.On("OnOwnProposal", mock.Anything, mock.Anything).Run( 27 func(args mock.Arguments) { 28 header, ok := args[0].(*flow.Header) 29 require.True(t, ok) 30 31 // sender should always have the parent 32 sender.updatingBlocks.RLock() 33 _, exists := sender.headers[header.ParentID] 34 sender.updatingBlocks.RUnlock() 35 if !exists { 36 t.Fatalf("parent for proposal not found (sender: %x, parent: %x)", sender.localID, header.ParentID) 37 } 38 39 // convert into proposal immediately 40 proposal := model.ProposalFromFlow(header) 41 42 // store locally and loop back to engine for processing 43 sender.ProcessBlock(proposal) 44 45 // check if we should block the outgoing proposal 46 if sender.blockPropOut(proposal) { 47 return 48 } 49 50 // iterate through potential receivers 51 for _, receiver := range instances { 52 53 // we should skip ourselves always 54 if receiver.localID == sender.localID { 55 continue 56 } 57 58 // check if we should block the incoming proposal 59 if receiver.blockPropIn(proposal) { 60 continue 61 } 62 63 receiver.ProcessBlock(proposal) 64 } 65 }, 66 ) 67 sender.notifier.On("OnOwnVote", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Run( 68 func(args mock.Arguments) { 69 blockID, ok := args[0].(flow.Identifier) 70 require.True(t, ok) 71 view, ok := args[1].(uint64) 72 require.True(t, ok) 73 sigData, ok := args[2].([]byte) 74 require.True(t, ok) 75 recipientID, ok := args[3].(flow.Identifier) 76 require.True(t, ok) 77 // convert into vote 78 vote := model.VoteFromFlow(sender.localID, blockID, view, sigData) 79 80 // get the receiver 81 receiver, exists := lookup[recipientID] 82 if !exists { 83 t.Fatalf("recipient doesn't exist (sender: %x, receiver: %x)", sender.localID, recipientID) 84 } 85 86 // if we are next leader we should be receiving our own vote 87 if recipientID != sender.localID { 88 // check if we should block the outgoing vote 89 if sender.blockVoteOut(vote) { 90 return 91 } 92 93 // check if e should block the incoming vote 94 if receiver.blockVoteIn(vote) { 95 return 96 } 97 } 98 99 // submit the vote to the receiving event loop (non-blocking) 100 receiver.queue <- vote 101 }, 102 ) 103 sender.notifier.On("OnOwnTimeout", mock.Anything).Run( 104 func(args mock.Arguments) { 105 timeoutObject, ok := args[0].(*model.TimeoutObject) 106 require.True(t, ok) 107 // iterate through potential receivers 108 for _, receiver := range instances { 109 110 // we should skip ourselves always 111 if receiver.localID == sender.localID { 112 continue 113 } 114 115 // check if we should block the outgoing value 116 if sender.blockTimeoutObjectOut(timeoutObject) { 117 continue 118 } 119 120 // check if we should block the incoming value 121 if receiver.blockTimeoutObjectIn(timeoutObject) { 122 continue 123 } 124 125 receiver.queue <- timeoutObject 126 } 127 }) 128 } 129 }