@@ -902,3 +902,80 @@ func TestCycleInTx(gt *testing.T) {
902
902
unsafeHeadNumAfterReorg := targetNum - 1
903
903
reorgOutUnsafeAndConsolidateToSafe (t , actors , actors .ChainB , actors .ChainA , 0 , 0 , 1 , targetNum , unsafeHeadNumAfterReorg )
904
904
}
905
+
906
+ // TestCycleInBlock tests below scenario:
907
+ // Transaction executes message, then initiates it: cycle in block
908
+ // To elaborate, single block contains txs in below order:
909
+ // {exec message X tx, dummy tx, ..., dummy tx, init message X tx}
910
+ func TestCycleInBlock (gt * testing.T ) {
911
+ t := helpers .NewDefaultTesting (gt )
912
+ rng := rand .New (rand .NewSource (1234 ))
913
+ is := dsl .SetupInterop (t )
914
+ actors := is .CreateActors ()
915
+ actors .PrepareChainState (t )
916
+ alice := setupUser (t , is , actors .ChainA , 0 )
917
+
918
+ actors .ChainA .Sequencer .ActL2StartBlock (t )
919
+ deployOptsA , _ := DefaultTxOpts (t , setupUser (t , is , actors .ChainA , 1 ), actors .ChainA )
920
+ eventLoggerAddressA := DeployEventLogger (t , deployOptsA )
921
+
922
+ assertHeads (t , actors .ChainA , 1 , 0 , 0 , 0 )
923
+
924
+ // assume every tx including target exec message and init message land in block number 2
925
+ // all other txs are dummy tx to make block include multiple tx
926
+ targetTime := actors .ChainA .RollupCfg .Genesis .L2Time + actors .ChainA .RollupCfg .BlockTime * 2
927
+ targetNum := uint64 (2 )
928
+
929
+ // attempt to include multiple txs in a single L2 block
930
+ actors .ChainA .Sequencer .ActL2StartBlock (t )
931
+
932
+ nonce := uint64 (0 )
933
+
934
+ // speculatively build exec message by knowing necessary info to build Message
935
+ init := interop .RandomInitTrigger (rng , eventLoggerAddressA , 3 , 10 )
936
+ logIndexX := uint (0 )
937
+ exec , err := interop .ExecTriggerFromInitTrigger (init , logIndexX , targetNum , targetTime , actors .ChainA .ChainID )
938
+ require .NoError (t , err )
939
+
940
+ intents := []* txintent.IntentTx [txintent.Call , * txintent.InteropOutput ]{}
941
+ submitIntent := func (trigger txintent.Call , nonce uint64 ) {
942
+ opts , _ := DefaultTxOptsWithoutBlockSeal (t , alice , actors .ChainA , nonce )
943
+ intent := txintent.NewIntent [txintent.Call , * txintent.InteropOutput ](opts )
944
+ intent .Content .Set (trigger )
945
+ _ , err := intent .PlannedTx .Submitted .Eval (t .Ctx ())
946
+ require .NoError (t , err )
947
+ intents = append (intents , intent )
948
+ }
949
+ txCount := 2 + rng .Intn (15 )
950
+ // include exec message X tx first in block
951
+ {
952
+ submitIntent (exec , nonce )
953
+ nonce += 1
954
+ }
955
+ // include dummy txs in block
956
+ for range txCount - 2 {
957
+ randomInitTrigger := interop .RandomInitTrigger (rng , eventLoggerAddressA , 3 , 10 )
958
+ submitIntent (randomInitTrigger , nonce )
959
+ nonce += 1
960
+ }
961
+ // include init message X last in block
962
+ {
963
+ submitIntent (init , nonce )
964
+ // no need to increment nonce since this is the last tx
965
+ }
966
+ actors .ChainA .Sequencer .ActL2EndBlock (t )
967
+
968
+ // Make sure tx in block sealed at expected time
969
+ for _ , intent := range intents {
970
+ included , err := intent .PlannedTx .IncludedBlock .Eval (t .Ctx ())
971
+ require .NoError (t , err )
972
+ require .Equal (t , included .Time , targetTime )
973
+ require .Equal (t , included .Number , targetNum )
974
+ }
975
+
976
+ // Make batcher happy by advancing at least a single block
977
+ actors .ChainB .Sequencer .ActL2EmptyBlock (t )
978
+
979
+ unsafeHeadNumAfterReorg := targetNum - 1
980
+ reorgOutUnsafeAndConsolidateToSafe (t , actors , actors .ChainB , actors .ChainA , 0 , 0 , 1 , targetNum , unsafeHeadNumAfterReorg )
981
+ }
0 commit comments