Skip to content

Commit dedd30c

Browse files
authored
Wait for block proposal (#89)
* added timeout based on wal * timeout after 1 min * add stop * remove Time()
1 parent f88ddc6 commit dedd30c

File tree

2 files changed

+38
-36
lines changed

2 files changed

+38
-36
lines changed

epoch_failover_test.go

Lines changed: 17 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -16,26 +16,17 @@ import (
1616
)
1717

1818
func TestEpochLeaderFailover(t *testing.T) {
19-
timeoutDetected := make(chan struct{})
20-
2119
l := testutil.MakeLogger(t, 1)
22-
l.Intercept(func(entry zapcore.Entry) error {
23-
if entry.Message == `Timed out on block agreement` {
24-
close(timeoutDetected)
25-
}
26-
return nil
27-
})
2820

2921
bb := &testBlockBuilder{out: make(chan *testBlock, 1), blockShouldBeBuilt: make(chan struct{}, 1)}
3022
storage := newInMemStorage()
3123

3224
nodes := []NodeID{{1}, {2}, {3}, {4}}
3325
quorum := Quorum(len(nodes))
3426

35-
start := time.Now()
36-
3727
wal := newTestWAL(t)
3828

29+
start := time.Now()
3930
conf := EpochConfig{
4031
MaxProposalWait: DefaultMaxProposalWaitTime,
4132
StartTime: start,
@@ -67,8 +58,8 @@ func TestEpochLeaderFailover(t *testing.T) {
6758

6859
bb.blockShouldBeBuilt <- struct{}{}
6960

70-
waitForEvent(t, start, e, timeoutDetected)
71-
61+
waitForBlockProposerTimeout(t, e, start)
62+
7263
lastBlock, _, ok := storage.Retrieve(storage.Height() - 1)
7364
require.True(t, ok)
7465

@@ -97,7 +88,7 @@ func TestEpochLeaderFailover(t *testing.T) {
9788
walContent, err := wal.ReadAll()
9889
require.NoError(t, err)
9990
wal.lock.Unlock()
100-
91+
10192
rawEmptyVote, rawEmptyNotarization := walContent[len(walContent)-2], walContent[len(walContent)-1]
10293
emptyVote, err := ParseEmptyVoteRecord(rawEmptyVote)
10394
require.NoError(t, err)
@@ -141,10 +132,9 @@ func TestEpochLeaderFailoverAfterProposal(t *testing.T) {
141132
nodes := []NodeID{{1}, {2}, {3}, {4}}
142133
quorum := Quorum(len(nodes))
143134

144-
start := time.Now()
145-
146135
wal := newTestWAL(t)
147136

137+
start := time.Now()
148138
conf := EpochConfig{
149139
MaxProposalWait: DefaultMaxProposalWaitTime,
150140
StartTime: start,
@@ -194,7 +184,7 @@ func TestEpochLeaderFailoverAfterProposal(t *testing.T) {
194184

195185
bb.blockShouldBeBuilt <- struct{}{}
196186

197-
waitForEvent(t, start, e, timeoutDetected)
187+
waitForBlockProposerTimeout(t, e, start)
198188

199189
for i := 1; i < quorum; i++ {
200190
// Skip the vote of the block proposer
@@ -204,7 +194,7 @@ func TestEpochLeaderFailoverAfterProposal(t *testing.T) {
204194
injectTestVote(t, e, block, nodes[i])
205195
}
206196

207-
waitForEvent(t, start, e, alreadyTimedOut)
197+
waitForBlockProposerTimeout(t, e, start)
208198

209199
lastBlock, _, ok := storage.Retrieve(storage.Height() - 1)
210200
require.True(t, ok)
@@ -254,27 +244,17 @@ func TestEpochLeaderFailoverAfterProposal(t *testing.T) {
254244
}
255245

256246
func TestEpochLeaderFailoverTwice(t *testing.T) {
257-
timeoutDetected := make(chan struct{})
258-
259247
l := testutil.MakeLogger(t, 1)
260-
l.Intercept(func(entry zapcore.Entry) error {
261-
if entry.Message == `Timed out on block agreement` {
262-
close(timeoutDetected)
263-
timeoutDetected = make(chan struct{})
264-
}
265-
return nil
266-
})
267248

268249
bb := &testBlockBuilder{out: make(chan *testBlock, 1), blockShouldBeBuilt: make(chan struct{}, 1)}
269250
storage := newInMemStorage()
270251

271252
nodes := []NodeID{{1}, {2}, {3}, {4}}
272253
quorum := Quorum(len(nodes))
273254

274-
start := time.Now()
275-
276255
wal := newTestWAL(t)
277256

257+
start := time.Now()
278258
conf := EpochConfig{
279259
MaxProposalWait: DefaultMaxProposalWaitTime,
280260
StartTime: start,
@@ -302,7 +282,7 @@ func TestEpochLeaderFailoverTwice(t *testing.T) {
302282

303283
bb.blockShouldBeBuilt <- struct{}{}
304284

305-
waitForEvent(t, start, e, timeoutDetected)
285+
waitForBlockProposerTimeout(t, e, start)
306286

307287
lastBlock, _, ok := storage.Retrieve(storage.Height() - 1)
308288
require.True(t, ok)
@@ -331,7 +311,7 @@ func TestEpochLeaderFailoverTwice(t *testing.T) {
331311

332312
bb.blockShouldBeBuilt <- struct{}{}
333313

334-
waitForEvent(t, start, e, timeoutDetected)
314+
waitForBlockProposerTimeout(t, e, start)
335315

336316
md = ProtocolMetadata{
337317
Round: 3,
@@ -387,17 +367,18 @@ func createEmptyVote(md ProtocolMetadata, signer NodeID) *EmptyVote {
387367
return emptyVoteFrom2
388368
}
389369

390-
func waitForEvent(t *testing.T, start time.Time, e *Epoch, events chan struct{}) {
391-
now := start
370+
func waitForBlockProposerTimeout(t *testing.T, e *Epoch, startTime time.Time) {
371+
startRound := e.Metadata().Round
392372
timeout := time.NewTimer(time.Minute)
393373
defer timeout.Stop()
394374

395375
for {
396-
now = now.Add(e.EpochConfig.MaxProposalWait / 5)
397-
e.AdvanceTime(now)
398-
select {
399-
case <-events:
376+
if e.WAL.(*testWAL).containsEmptyVote(startRound) {
400377
return
378+
}
379+
startTime = startTime.Add(e.EpochConfig.MaxProposalWait / 5)
380+
e.AdvanceTime(startTime)
381+
select {
401382
case <-time.After(time.Millisecond * 10):
402383
continue
403384
case <-timeout.C:

epoch_multinode_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,27 @@ func (tw *testWAL) assertNotarization(round uint64) {
208208

209209
}
210210

211+
func (tw *testWAL) containsEmptyVote(round uint64) bool {
212+
tw.lock.Lock()
213+
defer tw.lock.Unlock()
214+
215+
rawRecords, err := tw.WriteAheadLog.ReadAll()
216+
require.NoError(tw.t, err)
217+
218+
for _, rawRecord := range rawRecords {
219+
if binary.BigEndian.Uint16(rawRecord[:2]) == record.EmptyVoteRecordType {
220+
vote, err := ParseEmptyVoteRecord(rawRecord)
221+
require.NoError(tw.t, err)
222+
223+
if vote.Round == round {
224+
return true
225+
}
226+
}
227+
}
228+
229+
return false
230+
}
231+
211232
type testComm struct {
212233
from NodeID
213234
net *inMemNetwork

0 commit comments

Comments
 (0)