github.com/koko1123/flow-go-1@v0.29.6/consensus/hotstuff/integration/connect_test.go (about)

     1  package integration
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	"github.com/stretchr/testify/mock"
     8  
     9  	"github.com/koko1123/flow-go-1/consensus/hotstuff/mocks"
    10  	"github.com/koko1123/flow-go-1/consensus/hotstuff/model"
    11  	"github.com/koko1123/flow-go-1/model/flow"
    12  )
    13  
    14  func Connect(instances []*Instance) {
    15  
    16  	// first, create a map of all instances and a queue for each
    17  	lookup := make(map[flow.Identifier]*Instance)
    18  	for _, in := range instances {
    19  		lookup[in.localID] = in
    20  	}
    21  
    22  	// then, for each instance, initialize a wired up communicator
    23  	for _, sender := range instances {
    24  		sender := sender // avoid capturing loop variable in closure
    25  
    26  		*sender.communicator = mocks.Communicator{}
    27  		sender.communicator.On("BroadcastProposalWithDelay", mock.Anything, mock.Anything).Return(
    28  			func(header *flow.Header, delay time.Duration) error {
    29  
    30  				// sender should always have the parent
    31  				parent, exists := sender.headers[header.ParentID]
    32  				if !exists {
    33  					return fmt.Errorf("parent for proposal not found (sender: %x, parent: %x)", sender.localID, header.ParentID)
    34  				}
    35  
    36  				// fill in the header chain ID and height
    37  				header.ChainID = parent.ChainID
    38  				header.Height = parent.Height + 1
    39  
    40  				// convert into proposal immediately
    41  				proposal := model.ProposalFromFlow(header, parent.View)
    42  
    43  				// store locally and loop back to engine for processing
    44  				sender.ProcessBlock(proposal)
    45  
    46  				// check if we should block the outgoing proposal
    47  				if sender.blockPropOut(proposal) {
    48  					return nil
    49  				}
    50  
    51  				// iterate through potential receivers
    52  				for _, receiver := range instances {
    53  
    54  					// we should skip ourselves always
    55  					if receiver.localID == sender.localID {
    56  						continue
    57  					}
    58  
    59  					// check if we should block the incoming proposal
    60  					if receiver.blockPropIn(proposal) {
    61  						return nil
    62  					}
    63  
    64  					receiver.ProcessBlock(proposal)
    65  				}
    66  
    67  				return nil
    68  			},
    69  		)
    70  		sender.communicator.On("SendVote", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(
    71  			func(blockID flow.Identifier, view uint64, sigData []byte, recipientID flow.Identifier) error {
    72  
    73  				// convert into vote
    74  				vote := model.VoteFromFlow(sender.localID, blockID, view, sigData)
    75  
    76  				// should never send to self
    77  				if recipientID == sender.localID {
    78  					return fmt.Errorf("can't send to self (sender: %x)", sender.localID)
    79  				}
    80  
    81  				// check if we should block the outgoing vote
    82  				if sender.blockVoteOut(vote) {
    83  					return nil
    84  				}
    85  
    86  				// get the receiver
    87  				receiver, exists := lookup[recipientID]
    88  				if !exists {
    89  					return fmt.Errorf("recipient doesn't exist (sender: %x, receiver: %x)", sender.localID, recipientID)
    90  				}
    91  
    92  				// check if e should block the incoming vote
    93  				if receiver.blockVoteIn(vote) {
    94  					return nil
    95  				}
    96  
    97  				// submit the vote to the receiving event loop (non-blocking)
    98  				receiver.queue <- vote
    99  
   100  				return nil
   101  			},
   102  		)
   103  	}
   104  }