github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/consensus/integration/slow_test.go (about) 1 package integration_test 2 3 import ( 4 "sync" 5 "testing" 6 "time" 7 8 "github.com/onflow/flow-go/model/flow" 9 "github.com/onflow/flow-go/model/messages" 10 "github.com/onflow/flow-go/network/channels" 11 ) 12 13 // TestMessagesLost verifies if a node lost some messages, it's still able to catch up. 14 func TestMessagesLost(t *testing.T) { 15 stopper := NewStopper(30, 0) 16 participantsData := createConsensusIdentities(t, 4) 17 rootSnapshot := createRootSnapshot(t, participantsData) 18 nodes, hub, runFor := createNodes(t, NewConsensusParticipants(participantsData), rootSnapshot, stopper) 19 20 hub.WithFilter(blockNodesFirstMessages(10, nodes[0])) 21 22 runFor(time.Minute) 23 24 allViews := allFinalizedViews(t, nodes) 25 assertSafety(t, allViews) 26 27 cleanupNodes(nodes) 28 } 29 30 // TestMessagesLostAcrossNetwork verifies if each receiver lost 10% messages, the network can still reach consensus. 31 func TestMessagesLostAcrossNetwork(t *testing.T) { 32 stopper := NewStopper(10, 0) 33 participantsData := createConsensusIdentities(t, 4) 34 rootSnapshot := createRootSnapshot(t, participantsData) 35 nodes, hub, runFor := createNodes(t, NewConsensusParticipants(participantsData), rootSnapshot, stopper) 36 37 hub.WithFilter(blockReceiverMessagesRandomly(0.1)) 38 39 runFor(time.Minute) 40 41 allViews := allFinalizedViews(t, nodes) 42 assertSafety(t, allViews) 43 44 cleanupNodes(nodes) 45 } 46 47 // TestDelay verifies that we still reach consensus even if _all_ messages are significantly 48 // delayed. Due to the delay, some proposals might be orphaned. The message delay is sampled 49 // for each message from the interval [0.1*hotstuffTimeout, 0.5*hotstuffTimeout]. 50 func TestDelay(t *testing.T) { 51 stopper := NewStopper(30, 0) 52 participantsData := createConsensusIdentities(t, 4) 53 rootSnapshot := createRootSnapshot(t, participantsData) 54 nodes, hub, runFor := createNodes(t, NewConsensusParticipants(participantsData), rootSnapshot, stopper) 55 56 hub.WithFilter(delayReceiverMessagesByRange(hotstuffTimeout/10, hotstuffTimeout/2)) 57 58 runFor(time.Minute) 59 60 allViews := allFinalizedViews(t, nodes) 61 assertSafety(t, allViews) 62 63 cleanupNodes(nodes) 64 } 65 66 // TestOneNodeBehind verifies that if one node (here node 0) consistently experiences a significant 67 // delay receiving messages beyond the hotstuff timeout, the committee still can reach consensus. 68 func TestOneNodeBehind(t *testing.T) { 69 stopper := NewStopper(30, 0) 70 participantsData := createConsensusIdentities(t, 3) 71 rootSnapshot := createRootSnapshot(t, participantsData) 72 nodes, hub, runFor := createNodes(t, NewConsensusParticipants(participantsData), rootSnapshot, stopper) 73 74 hub.WithFilter(func(channelID channels.Channel, event interface{}, sender, receiver *Node) (bool, time.Duration) { 75 if receiver == nodes[0] { 76 return false, hotstuffTimeout + time.Millisecond 77 } 78 // no block or delay to other nodes 79 return false, 0 80 }) 81 82 runFor(time.Minute) 83 84 allViews := allFinalizedViews(t, nodes) 85 assertSafety(t, allViews) 86 87 cleanupNodes(nodes) 88 } 89 90 // TestTimeoutRebroadcast drops 91 // * all proposals at view 5 92 // * the first timeout object per view for _every_ sender 93 // In this configuration, the _initial_ broadcast is insufficient for replicas to make 94 // progress in view 5 (neither in the happy path, because the proposal is always dropped 95 // nor on the unhappy path for the _first_ attempt to broadcast timeout objects). We 96 // expect that replica will eventually broadcast its timeout object again. 97 func TestTimeoutRebroadcast(t *testing.T) { 98 stopper := NewStopper(5, 0) 99 participantsData := createConsensusIdentities(t, 4) 100 rootSnapshot := createRootSnapshot(t, participantsData) 101 nodes, hub, runFor := createNodes(t, NewConsensusParticipants(participantsData), rootSnapshot, stopper) 102 103 // nodeID -> view -> numTimeoutMessages 104 lock := new(sync.Mutex) 105 blockedTimeoutObjectsTracker := make(map[flow.Identifier]map[uint64]uint64) 106 hub.WithFilter(func(channelID channels.Channel, event interface{}, sender, receiver *Node) (bool, time.Duration) { 107 switch m := event.(type) { 108 case *messages.BlockProposal: 109 return m.Block.Header.View == 5, 0 // drop proposals only for view 5 110 case *messages.TimeoutObject: 111 // drop first timeout object for every sender for every view 112 lock.Lock() 113 blockedPerView, found := blockedTimeoutObjectsTracker[sender.id.NodeID] 114 if !found { 115 blockedPerView = make(map[uint64]uint64) 116 blockedTimeoutObjectsTracker[sender.id.NodeID] = blockedPerView 117 } 118 blocked := blockedPerView[m.View] + 1 119 blockedPerView[m.View] = blocked 120 lock.Unlock() 121 return blocked == 1, 0 122 } 123 // no block or delay to other nodes 124 return false, 0 125 }) 126 127 runFor(10 * time.Second) 128 129 allViews := allFinalizedViews(t, nodes) 130 assertSafety(t, allViews) 131 132 cleanupNodes(nodes) 133 }