@@ -79,53 +79,145 @@ func TestStaleTransactions1(t *testing.T) {
7979 assert .True (t , errors .As (err , & ConsistencyError {}), "err: %v" , err )
8080}
8181
82- func TestKeyRegistrationApplicationTxn (t * testing.T ) {
82+ // TestAllClearedFields verifies that all fields that should be reset during a rewind are properly cleared
83+ func TestAllClearedFields (t * testing.T ) {
8384 var a sdk.Address
8485 a [0 ] = 'a'
8586
86- // Set up account with participation and app state
87+ // Helper functions for pointer values
88+ uint64Ptr := func (v uint64 ) * uint64 { return & v }
89+ boolPtr := func (v bool ) * bool { return & v }
90+ bytesPtr := func (v []byte ) * []byte { return & v }
91+ stringPtr := func (v string ) * string { return & v }
92+
93+ // Create an account with ALL fields populated
8794 account := models.Account {
8895 Address : a .String (),
89- Amount : 100 ,
90- AmountWithoutPendingRewards : 100 ,
91- Round : 8 ,
96+ Amount : 1000 ,
97+ AmountWithoutPendingRewards : 980 ,
98+ PendingRewards : 20 ,
99+ Rewards : 100 ,
100+ Round : 10 ,
101+ Status : "Online" ,
102+ MinBalance : 200 ,
103+
104+ // Keyreg-related fields
92105 Participation : & models.AccountParticipation {
93- VoteFirstValid : 100 , VoteLastValid : 200 , VoteKeyDilution : 10000 ,
106+ VoteFirstValid : 100 ,
107+ VoteLastValid : 200 ,
108+ VoteKeyDilution : 10000 ,
109+ VoteParticipationKey : []byte ("votepk" ),
110+ SelectionParticipationKey : []byte ("selpk" ),
111+ StateProofKey : bytesPtr ([]byte ("stpk" )),
94112 },
95- AppsLocalState : & []models.ApplicationLocalState {{Id : 123 }},
96- CreatedApps : & []models.Application {{Id : 456 }},
113+
114+ // App-related fields
115+ AppsLocalState : & []models.ApplicationLocalState {{Id : 123 }},
116+ AppsTotalExtraPages : uint64Ptr (2 ),
117+ AppsTotalSchema : & models.ApplicationStateSchema {NumByteSlice : 10 , NumUint : 10 },
118+ CreatedApps : & []models.Application {{Id : 456 }},
119+ TotalAppsOptedIn : 5 ,
120+ TotalBoxBytes : 1000 ,
121+ TotalBoxes : 10 ,
122+ TotalCreatedApps : 3 ,
123+
124+ // Asset-related fields
125+ Assets : & []models.AssetHolding {{AssetId : 789 , Amount : 50 }},
126+ CreatedAssets : & []models.Asset {{Index : 999 }},
127+ TotalAssetsOptedIn : 2 ,
128+ TotalCreatedAssets : 1 ,
129+
130+ // Fields set at account creation/deletion
131+ ClosedAtRound : uint64Ptr (500 ),
132+ CreatedAtRound : uint64Ptr (1 ),
133+ Deleted : boolPtr (false ),
134+
135+ // Incentive fields
136+ IncentiveEligible : boolPtr (true ),
137+ LastHeartbeat : uint64Ptr (7 ),
138+ LastProposed : uint64Ptr (6 ),
139+
140+ // Auth fields
141+ AuthAddr : stringPtr ("authaddr" ),
142+ SigType : (* models .AccountSigType )(stringPtr (string (models .AccountSigTypeSig ))),
97143 }
98144
99- // Create test transactions - one KeyReg and one AppCall
100- keyregTxn := idb.TxnRow {
101- Round : 7 ,
102- Txn : & sdk.SignedTxnWithAD {SignedTxn : sdk.SignedTxn {
103- Txn : sdk.Transaction {Type : sdk .KeyRegistrationTx , Header : sdk.Header {Sender : a }},
104- }}}
105-
106- appCallTxn := idb.TxnRow {
107- Round : 8 ,
108- Txn : & sdk.SignedTxnWithAD {SignedTxn : sdk.SignedTxn {
109- Txn : sdk.Transaction {Type : sdk .ApplicationCallTx , Header : sdk.Header {Sender : a }},
110- }}}
111-
112- // Send both transactions to the mock DB
113- ch := make (chan idb.TxnRow , 2 )
114- ch <- appCallTxn
115- ch <- keyregTxn
145+ // Create various transaction types for testing
146+ txns := []idb.TxnRow {
147+ { // Application call
148+ Round : 10 ,
149+ Txn : & sdk.SignedTxnWithAD {SignedTxn : sdk.SignedTxn {
150+ Txn : sdk.Transaction {Type : sdk .ApplicationCallTx , Header : sdk.Header {Sender : a }},
151+ }},
152+ },
153+ { // Key registration
154+ Round : 9 ,
155+ Txn : & sdk.SignedTxnWithAD {SignedTxn : sdk.SignedTxn {
156+ Txn : sdk.Transaction {Type : sdk .KeyRegistrationTx , Header : sdk.Header {Sender : a }},
157+ }},
158+ },
159+ { // Payment
160+ Round : 8 ,
161+ Txn : & sdk.SignedTxnWithAD {SignedTxn : sdk.SignedTxn {
162+ Txn : sdk.Transaction {
163+ Type : sdk .PaymentTx ,
164+ Header : sdk.Header {Sender : a },
165+ PaymentTxnFields : sdk.PaymentTxnFields {Amount : 10 },
166+ },
167+ }},
168+ },
169+ }
170+
171+ // Set up mock DB
172+ ch := make (chan idb.TxnRow , len (txns ))
173+ for _ , txn := range txns {
174+ ch <- txn
175+ }
116176 close (ch )
117177 var outCh <- chan idb.TxnRow = ch
118178
119179 db := & mocks.IndexerDb {}
120180 db .On ("GetSpecialAccounts" , mock .Anything ).Return (types.SpecialAddresses {}, nil )
121- db .On ("Transactions" , mock .Anything , mock .Anything ).Return (outCh , uint64 (8 ))
181+ db .On ("Transactions" , mock .Anything , mock .Anything ).Return (outCh , uint64 (10 ))
122182
123183 // Run the rewind
124- result , err := AccountAtRound (context .Background (), account , 6 , db )
184+ result , err := AccountAtRound (context .Background (), account , 5 , db )
125185 assert .NoError (t , err )
126186
127- // Verify that both participation and app state fields are nil after rewind
128- assert .Nil (t , result .Participation , "Participation should be nil after rewinding KeyRegistration transaction" )
129- assert .Nil (t , result .AppsLocalState , "AppsLocalState should be nil after rewinding ApplicationCall transaction" )
130- assert .Nil (t , result .CreatedApps , "CreatedApps should be nil after rewinding ApplicationCall transaction" )
187+ // Verify all fields that should be reset or zeroed out
188+
189+ // Fields that should be preserved/changed correctly
190+ assert .Equal (t , a .String (), result .Address , "Address should be preserved" )
191+
192+ // Fields that are explicitly zeroed out
193+ assert .Equal (t , uint64 (0 ), result .Rewards , "Rewards should be 0" )
194+ assert .Equal (t , uint64 (0 ), result .PendingRewards , "PendingRewards should be 0" )
195+ assert .Equal (t , uint64 (0 ), result .MinBalance , "MinBalance should be 0" )
196+
197+ // Fields that are explicitly set to nil
198+ assert .Nil (t , result .ClosedAtRound , "ClosedAtRound should be nil" )
199+
200+ // Fields nulled out by KeyRegistrationTx
201+ assert .Nil (t , result .Participation , "Participation should be nil" )
202+
203+ // Fields nulled out by ApplicationCallTx
204+ assert .Nil (t , result .AppsLocalState , "AppsLocalState should be nil" )
205+ assert .Nil (t , result .AppsTotalExtraPages , "AppsTotalExtraPages should be nil" )
206+ assert .Nil (t , result .AppsTotalSchema , "AppsTotalSchema should be nil" )
207+ assert .Nil (t , result .CreatedApps , "CreatedApps should be nil" )
208+ assert .Equal (t , uint64 (0 ), result .TotalAppsOptedIn , "TotalAppsOptedIn should be 0" )
209+ assert .Equal (t , uint64 (0 ), result .TotalBoxBytes , "TotalBoxBytes should be 0" )
210+ assert .Equal (t , uint64 (0 ), result .TotalBoxes , "TotalBoxes should be 0" )
211+ assert .Equal (t , uint64 (0 ), result .TotalCreatedApps , "TotalCreatedApps should be 0" )
212+
213+ // Incentive fields explicitly set to nil
214+ assert .Nil (t , result .IncentiveEligible , "IncentiveEligible should be nil" )
215+ assert .Nil (t , result .LastHeartbeat , "LastHeartbeat should be nil" )
216+ assert .Nil (t , result .LastProposed , "LastProposed should be nil" )
217+
218+ // Assets should be preserved (although updated with AssetConfigTx/AssetTransferTx)
219+ assert .NotNil (t , result .Assets , "Assets should not be nil" )
220+
221+ // Round should be set to the target round
222+ assert .Equal (t , uint64 (5 ), result .Round , "Round should be set to target round" )
131223}
0 commit comments