1717package suspension
1818
1919import (
20- "fmt"
2120 "path/filepath"
2221 "testing"
2322 "time"
@@ -47,10 +46,17 @@ func eligible(address string) bool {
4746func 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}
0 commit comments