99import com .algorand .algosdk .util .Digester ;
1010import com .algorand .algosdk .util .Encoder ;
1111import com .algorand .algosdk .v2 .client .Utils ;
12+ import com .algorand .algosdk .v2 .client .common .AlgodClient ;
1213import com .algorand .algosdk .v2 .client .common .Response ;
1314import com .algorand .algosdk .v2 .client .model .*;
1415import io .cucumber .java .en .Given ;
@@ -290,23 +291,25 @@ private static void assertSetOfByteArraysEqual(Set<byte[]> expected, Set<byte[]>
290291
291292 @ Then ("according to {string}, the current application should have the following boxes {string}." )
292293 public void checkAppBoxes (String fromClient , String encodedBoxesRaw ) throws Exception {
294+ final Set <byte []> expectedNames = new HashSet <>();
295+ if (!encodedBoxesRaw .isEmpty ()) {
296+ for (String s : encodedBoxesRaw .split (":" )) {
297+ expectedNames .add (Encoder .decodeFromBase64 (s ));
298+ }
299+ }
300+
293301 Response <BoxesResponse > r ;
294- if (fromClient .equals ("algod" ))
302+ if (fromClient .equals ("algod" )) {
303+ advanceChainAndWaitForBoxes (base .aclv2 , this .appId , this .transientAccount ,
304+ expectedNames .size ());
295305 r = base .aclv2 .GetApplicationBoxes (this .appId ).execute ();
296- else if (fromClient .equals ("indexer" ))
306+ } else if (fromClient .equals ("indexer" ))
297307 r = base .v2IndexerClient .searchForApplicationBoxes (this .appId ).execute ();
298308 else
299309 throw new IllegalArgumentException ("expecting algod or indexer, got " + fromClient );
300310
301311 Assert .assertTrue (r .isSuccessful ());
302312
303- final Set <byte []> expectedNames = new HashSet <>();
304- if (!encodedBoxesRaw .isEmpty ()) {
305- for (String s : encodedBoxesRaw .split (":" )) {
306- expectedNames .add (Encoder .decodeFromBase64 (s ));
307- }
308- }
309-
310313 final Set <byte []> actualNames = new HashSet <>();
311314 for (BoxDescriptor b : r .body ().boxes ) {
312315 actualNames .add (b .name );
@@ -315,6 +318,69 @@ else if (fromClient.equals("indexer"))
315318 assertSetOfByteArraysEqual (expectedNames , actualNames );
316319 }
317320
321+ /**
322+ * Advance the blockchain and wait for the expected number of application boxes to persist.
323+ *
324+ * @param algodClient Algod client for interacting with the blockchain.
325+ * @param appId Application ID to check for boxes.
326+ * @param sender Account sending dummy transactions.
327+ * @param expectedNumBoxes The expected number of boxes.
328+ * @throws Exception if the boxes do not persist within the specified attempts.
329+ */
330+ public static void advanceChainAndWaitForBoxes (
331+ AlgodClient algodClient ,
332+ long appId ,
333+ TransientAccount sender ,
334+ int expectedNumBoxes ) throws Exception {
335+
336+ int waitRounds = 5 ;
337+ int maxAttempts = 50 ;
338+ // Get the current round
339+ long currentRound = algodClient .GetStatus ().execute ().body ().lastRound ;
340+ long targetRound = currentRound + waitRounds ;
341+
342+ System .out .println ("Current round: " + currentRound + ", waiting for round: " + targetRound );
343+
344+ int attempts = 0 ;
345+ while (attempts < maxAttempts ) {
346+ // Send a dummy 0-Algo payment transaction to advance the blockchain
347+ TransactionParametersResponse params = algodClient .TransactionParams ().execute ().body ();
348+
349+ Transaction txn = Transaction .PaymentTransactionBuilder ()
350+ .sender (sender .transientAccount .getAddress ())
351+ .amount (0 )
352+ .receiver (sender .transientAccount .getAddress ())
353+ .suggestedParams (params )
354+ .noteUTF8 ("Advance round for box persistence" )
355+ .build ();
356+
357+ SignedTransaction stxn = sender .transientAccount .signTransaction (txn );
358+ String txId = algodClient .RawTransaction ().rawtxn (Encoder .encodeToMsgPack (stxn )).execute ().body ().txId ;
359+
360+ // Use Utils.waitForConfirmation to wait for the transaction to be confirmed
361+ Utils .waitForConfirmation (algodClient , txId , waitRounds );
362+ System .out .println ("Dummy transaction confirmed. TxID: " + txId );
363+
364+ // Check the number of boxes
365+ Response <BoxesResponse > boxResponse = algodClient .GetApplicationBoxes (appId ).execute ();
366+ List <BoxDescriptor > boxes = boxResponse .body ().boxes ;
367+
368+ int actualNumBoxes = boxes != null ? boxes .size () : 0 ;
369+ System .out .println ("Actual number of boxes: " + actualNumBoxes + ", Expected: " + expectedNumBoxes );
370+
371+ if (actualNumBoxes == expectedNumBoxes ) {
372+ System .out .println ("The expected number of boxes is now available." );
373+ return ; // Exit once the condition is met
374+ }
375+
376+ // Wait for a second before the next attempt
377+ Thread .sleep (1000 );
378+ attempts ++;
379+ }
380+
381+ throw new Exception ("Timeout waiting for " + expectedNumBoxes + " boxes to persist for application " + appId );
382+ }
383+
318384 @ Then ("according to {string}, with {long} being the parameter that limits results, the current application should have {int} boxes." )
319385 public void checkAppBoxesNum (String fromClient , Long limit , int expected_num ) throws Exception {
320386 Response <BoxesResponse > r ;
0 commit comments