Skip to content

Commit 45e94f5

Browse files
authored
Testing: Correct an off by one, and retry instead of fail with bad accounts (#6217)
1 parent df0613a commit 45e94f5

File tree

2 files changed

+34
-15
lines changed

2 files changed

+34
-15
lines changed

test/e2e-go/features/incentives/challenge_test.go

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package suspension
1818

1919
import (
20-
"fmt"
2120
"path/filepath"
2221
"testing"
2322
"time"
@@ -47,10 +46,17 @@ func eligible(address string) bool {
4746
func TestChallenges(t *testing.T) {
4847
partitiontest.PartitionTest(t)
4948
defer fixtures.ShutdownSynchronizedTest(t)
50-
51-
t.Parallel()
5249
a := require.New(fixtures.SynchronizedTest(t))
5350

51+
retry := true
52+
for retry {
53+
retry = testChallengesOnce(t, a)
54+
}
55+
}
56+
57+
// testChallengesOnce is the core of TestChallenges, but is allowed to bail out
58+
// if the random accounts aren't suitable. TestChallenges will try again.
59+
func testChallengesOnce(t *testing.T, a *require.Assertions) (retry bool) {
5460
// Overview of this test:
5561
// Use a consensus protocol with challenge interval=50, grace period=10, bits=2.
5662
// Start a three-node network. One relay, two nodes with 4 accounts each
@@ -79,7 +85,7 @@ func TestChallenges(t *testing.T) {
7985
accounts, err := fixture.GetNodeWalletsSortedByBalance(c)
8086
a.NoError(err)
8187
a.Len(accounts, 8)
82-
fmt.Printf("Client %s has %v\n", name, accounts)
88+
t.Logf("Client %s has %v\n", name, accounts)
8389
return c, accounts
8490
}
8591

@@ -114,6 +120,7 @@ func TestChallenges(t *testing.T) {
114120
// 100 = 40 + 32 + (50-22) = 72 + 28
115121
lastPossible := current + lookback
116122
challengeRound := lastPossible + (interval - lastPossible%interval)
123+
t.Logf("current %d lastPossible %d challengeRound %d", current, lastPossible, challengeRound)
117124

118125
// Advance to challenge round, check the blockseed
119126
err = fixture.WaitForRoundWithTimeout(challengeRound)
@@ -130,29 +137,33 @@ func TestChallenges(t *testing.T) {
130137
address, err := basics.UnmarshalChecksumAddress(account.Address)
131138
a.NoError(err)
132139
if address[0]&mask == challenge {
133-
fmt.Printf("%v of node 1 was challenged %v by %v\n", address, address[0], challenge)
140+
t.Logf("%v of node 1 was challenged %v by %v\n", address, address[0], challenge)
134141
match1.Add(address)
135142
if eligible(address.String()) {
136143
eligible1.Add(address)
137144
}
138145
}
139146
}
140-
require.NotEmpty(t, match1, "rerun the test") // TODO: remove.
147+
if match1.Empty() {
148+
return true
149+
}
141150

142151
match2 := util.MakeSet[basics.Address]()
143152
eligible2 := util.MakeSet[basics.Address]() // matched AND eligible
144153
for _, account := range accounts2 {
145154
address, err := basics.UnmarshalChecksumAddress(account.Address)
146155
a.NoError(err)
147156
if address[0]&mask == challenge {
148-
fmt.Printf("%v of node 2 was challenged %v by %v\n", address, address[0], challenge)
157+
t.Logf("%v of node 2 was challenged %v by %v\n", address, address[0], challenge)
149158
match2.Add(address)
150159
if eligible(address.String()) {
151160
eligible2.Add(address)
152161
}
153162
}
154163
}
155-
require.NotEmpty(t, match2, "rerun the test") // TODO: remove.
164+
if match2.Empty() {
165+
return true
166+
}
156167

157168
allMatches := util.Union(match1, match2)
158169

@@ -176,18 +187,19 @@ func TestChallenges(t *testing.T) {
176187

177188
// In the second half of the grace period, Node 2 should heartbeat for its eligible accounts
178189
beated := util.MakeSet[basics.Address]()
179-
fixture.WithEveryBlock(challengeRound+grace/2, challengeRound+grace, func(block bookkeeping.Block) {
190+
fixture.WithEveryBlock(challengeRound+grace/2+1, challengeRound+grace, func(block bookkeeping.Block) {
191+
t.Logf("2nd half Block %d\n", block.Round())
180192
if eligible2.Contains(block.Proposer()) {
181193
lucky.Add(block.Proposer())
182194
}
183195
for i, txn := range block.Payset {
184196
hb := txn.Txn.HeartbeatTxnFields
185-
fmt.Printf("Heartbeat txn %v in position %d round %d\n", hb, i, block.Round())
186-
a.True(match2.Contains(hb.HbAddress)) // only Node 2 is alive
187-
a.True(eligible2.Contains(hb.HbAddress)) // only eligible accounts get heartbeat
188-
a.False(beated.Contains(hb.HbAddress)) // beat only once
197+
t.Logf("Heartbeat txn %v in position %d round %d\n", hb, i, block.Round())
198+
a.Contains(match2, hb.HbAddress, hb.HbAddress) // only Node 2 is alive
199+
a.Contains(eligible2, hb.HbAddress, hb.HbAddress) // only eligible accounts get heartbeat
200+
a.NotContains(beated, hb.HbAddress, "rebeat %s", hb.HbAddress) // beat only once
189201
beated.Add(hb.HbAddress)
190-
a.False(lucky.Contains(hb.HbAddress)) // we should not see a heartbeat from an account that proposed
202+
a.NotContains(lucky, hb.HbAddress, "unneeded %s", hb.HbAddress) // we should not see a heartbeat from an account that proposed
191203
}
192204
a.Empty(block.AbsentParticipationAccounts) // nobody suspended during grace
193205
})
@@ -202,7 +214,8 @@ func TestChallenges(t *testing.T) {
202214
data, err := c2.AccountData(address.String())
203215
a.NoError(err)
204216
if eligible1.Contains(address) {
205-
a.Equal(basics.Offline, data.Status, address)
217+
a.Equal(basics.Offline, data.Status, "%v was not offline in round %d. (%d and %d)",
218+
address, challengeRound+grace+1, data.LastHeartbeat, data.LastProposed)
206219
} else {
207220
a.Equal(basics.Online, data.Status, address) // not eligible, so not suspended
208221
}
@@ -219,4 +232,5 @@ func TestChallenges(t *testing.T) {
219232
a.Equal(data.IncentiveEligible, eligible(address.String()))
220233
}
221234

235+
return false // no need to retry
222236
}

util/set.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ func MakeSet[T comparable](elems ...T) Set[T] {
3535
return make(Set[T]).Add(elems...)
3636
}
3737

38+
// Empty returns true if the set is empty.
39+
func (s Set[T]) Empty() bool {
40+
return len(s) == 0
41+
}
42+
3843
// Contains checks the membership of an element in the set.
3944
func (s Set[T]) Contains(elem T) (exists bool) {
4045
_, exists = s[elem]

0 commit comments

Comments
 (0)