github.com/koko1123/flow-go-1@v0.29.6/consensus/hotstuff/integration/integration_test.go (about) 1 package integration 2 3 import ( 4 "errors" 5 "sync" 6 "testing" 7 "time" 8 9 "github.com/stretchr/testify/assert" 10 "github.com/stretchr/testify/require" 11 12 "github.com/koko1123/flow-go-1/consensus/hotstuff/pacemaker/timeout" 13 "github.com/koko1123/flow-go-1/utils/unittest" 14 ) 15 16 // a pacemaker timeout to wait for proposals. Usually 10 ms is enough, 17 // but for slow environment like CI, a longer one is needed. 18 const safeTimeout = 2 * time.Second 19 20 const safeDecreaseFactor = 0.85 21 22 func TestSingleInstance(t *testing.T) { 23 24 // set up a single instance to run 25 // NOTE: currently, the HotStuff logic will infinitely call back on itself 26 // with a single instance, leading to a boundlessly growing call stack, 27 // which slows down the mocks significantly due to splitting the callstack 28 // to find the calling function name; we thus keep it low for now 29 finalView := uint64(10) 30 in := NewInstance(t, 31 WithStopCondition(ViewFinalized(finalView)), 32 ) 33 34 // run the event handler until we reach a stop condition 35 err := in.Run() 36 require.ErrorIs(t, err, errStopCondition, "should run until stop condition") 37 38 // check if forks and pacemaker are in expected view state 39 assert.Equal(t, finalView, in.forks.FinalizedView(), "finalized view should be three lower than current view") 40 } 41 42 func TestThreeInstances(t *testing.T) { 43 // test parameters 44 // NOTE: block finalization seems to be rather slow on CI at the moment, 45 // needing around 1 minute on Travis for 1000 blocks and 10 minutes on 46 // TeamCity for 1000 blocks; in order to avoid test timeouts, we keep the 47 // number low here 48 num := 3 49 finalView := uint64(100) 50 51 // generate three hotstuff participants 52 participants := unittest.IdentityListFixture(num) 53 root := DefaultRoot() 54 timeouts, err := timeout.NewConfig(safeTimeout, safeTimeout, 0.5, 1.5, safeDecreaseFactor, 0) 55 require.NoError(t, err) 56 57 // set up three instances that are exactly the same 58 instances := make([]*Instance, 0, num) 59 for n := 0; n < num; n++ { 60 in := NewInstance(t, 61 WithRoot(root), 62 WithParticipants(participants), 63 WithLocalID(participants[n].NodeID), 64 WithTimeouts(timeouts), 65 WithStopCondition(ViewFinalized(finalView)), 66 ) 67 instances = append(instances, in) 68 } 69 70 // connect the communicators of the instances together 71 Connect(instances) 72 73 // start the instances and wait for them to finish 74 var wg sync.WaitGroup 75 for _, in := range instances { 76 wg.Add(1) 77 go func(in *Instance) { 78 err := in.Run() 79 require.True(t, errors.Is(err, errStopCondition), "should run until stop condition") 80 wg.Done() 81 }(in) 82 } 83 wg.Wait() 84 85 // check that all instances have the same finalized block 86 in1 := instances[0] 87 in2 := instances[1] 88 in3 := instances[2] 89 // verify progress has been made 90 assert.GreaterOrEqual(t, in1.forks.FinalizedBlock().View, finalView, "the first instance 's finalized view should be four lower than current view") 91 // verify same progresses have been made 92 assert.Equal(t, in1.forks.FinalizedBlock(), in2.forks.FinalizedBlock(), "second instance should have same finalized block as first instance") 93 assert.Equal(t, in1.forks.FinalizedBlock(), in3.forks.FinalizedBlock(), "third instance should have same finalized block as first instance") 94 assert.Equal(t, FinalizedViews(in1), FinalizedViews(in2)) 95 assert.Equal(t, FinalizedViews(in1), FinalizedViews(in3)) 96 } 97 98 func TestSevenInstances(t *testing.T) { 99 // test parameters 100 // NOTE: block finalization seems to be rather slow on CI at the moment, 101 // needing around 1 minute on Travis for 1000 blocks and 10 minutes on 102 // TeamCity for 1000 blocks; in order to avoid test timeouts, we keep the 103 // number low here 104 numPass := 5 105 numFail := 2 106 107 // When using 100 as finalView, I often saw this tests fail on CI, because it only made to around 64-86 108 // so using 30 will still check that it's making progress and give enough buffer. 109 finalView := uint64(30) 110 111 // generate the seven hotstuff participants 112 participants := unittest.IdentityListFixture(numPass + numFail) 113 instances := make([]*Instance, 0, numPass+numFail) 114 root := DefaultRoot() 115 timeouts, err := timeout.NewConfig(safeTimeout, safeTimeout, 0.5, 1.5, safeDecreaseFactor, 0) 116 require.NoError(t, err) 117 118 // set up five instances that work fully 119 for n := 0; n < numPass; n++ { 120 in := NewInstance(t, 121 WithRoot(root), 122 WithParticipants(participants), 123 WithLocalID(participants[n].NodeID), 124 WithTimeouts(timeouts), 125 WithStopCondition(ViewFinalized(finalView)), 126 ) 127 instances = append(instances, in) 128 } 129 130 // set up two instances which can't vote 131 for n := numPass; n < numPass+numFail; n++ { 132 in := NewInstance(t, 133 WithRoot(root), 134 WithParticipants(participants), 135 WithLocalID(participants[n].NodeID), 136 WithTimeouts(timeouts), 137 WithStopCondition(ViewFinalized(finalView)), 138 WithOutgoingVotes(BlockAllVotes), 139 ) 140 instances = append(instances, in) 141 } 142 143 // connect the communicators of the instances together 144 Connect(instances) 145 146 // start all seven instances and wait for them to wrap up 147 var wg sync.WaitGroup 148 for _, in := range instances { 149 wg.Add(1) 150 go func(in *Instance) { 151 err := in.Run() 152 require.True(t, errors.Is(err, errStopCondition), "should run until stop condition") 153 wg.Done() 154 }(in) 155 } 156 wg.Wait() 157 158 // check that all instances have the same finalized block 159 ref := instances[0] 160 assert.Less(t, finalView-uint64(2*numPass+numFail), ref.forks.FinalizedBlock().View, "expect instance 0 should made enough progress, but didn't") 161 finalizedViews := FinalizedViews(ref) 162 for i := 1; i < numPass; i++ { 163 assert.Equal(t, ref.forks.FinalizedBlock(), instances[i].forks.FinalizedBlock(), "instance %d should have same finalized block as first instance") 164 assert.Equal(t, finalizedViews, FinalizedViews(instances[i]), "instance %d should have same finalized view as first instance") 165 } 166 }