13
13
// See the License for the specific language governing permissions and
14
14
// limitations under the License.
15
15
16
+ use rstest:: rstest;
17
+
16
18
use chainstate_test_framework:: { empty_witness, TransactionBuilder } ;
17
- use common:: { chain:: signature:: inputsig:: InputWitness , primitives:: H256 } ;
19
+ use common:: {
20
+ chain:: { signature:: inputsig:: InputWitness , timelock:: OutputTimeLock , OrderData } ,
21
+ primitives:: H256 ,
22
+ } ;
18
23
use randomness:: Rng ;
19
- use rstest:: rstest;
20
24
use test_utils:: random:: { make_seedable_rng, Seed } ;
21
25
22
26
use super :: * ;
@@ -48,6 +52,10 @@ fn diamond_unconfirmed_descendants(#[case] seed: Seed) {
48
52
OutputValue :: Coin ( Amount :: from_atoms ( rng. gen ( ) ) ) ,
49
53
Destination :: AnyoneCanSpend ,
50
54
) )
55
+ . add_output ( TxOutput :: Transfer (
56
+ OutputValue :: Coin ( Amount :: from_atoms ( rng. gen ( ) ) ) ,
57
+ Destination :: AnyoneCanSpend ,
58
+ ) )
51
59
. build ( ) ;
52
60
let tx_a_id = tx_a. transaction ( ) . get_id ( ) ;
53
61
output_cache
@@ -79,7 +87,7 @@ fn diamond_unconfirmed_descendants(#[case] seed: Seed) {
79
87
// C
80
88
let tx_c = TransactionBuilder :: new ( )
81
89
. add_input (
82
- TxInput :: from_utxo ( tx_a_id. into ( ) , 0 ) ,
90
+ TxInput :: from_utxo ( tx_a_id. into ( ) , 1 ) ,
83
91
empty_witness ( & mut rng) ,
84
92
)
85
93
. add_output ( TxOutput :: Transfer (
@@ -140,7 +148,7 @@ fn diamond_unconfirmed_descendants(#[case] seed: Seed) {
140
148
assert ! ( output_cache. unconfirmed_descendants. is_empty( ) ) ;
141
149
}
142
150
143
- // Create 2 unconfirmed txs B and C that spends tokens:
151
+ // Create 2 unconfirmed txs B and C that spend tokens:
144
152
//
145
153
// /-->B-->C
146
154
// A
@@ -151,7 +159,7 @@ fn diamond_unconfirmed_descendants(#[case] seed: Seed) {
151
159
#[ rstest]
152
160
#[ trace]
153
161
#[ case( Seed :: from_entropy( ) ) ]
154
- fn conflict_parent_and_child ( #[ case] seed : Seed ) {
162
+ fn update_conflicting_txs_parent_and_child ( #[ case] seed : Seed ) {
155
163
let mut rng = make_seedable_rng ( seed) ;
156
164
157
165
let mut output_cache = OutputCache :: empty ( ) ;
@@ -245,3 +253,148 @@ fn conflict_parent_and_child(#[case] seed: Seed) {
245
253
]
246
254
) ;
247
255
}
256
+
257
+ // Create unconfirmed txs Bi that use a token in their outputs only:
258
+ // a) by transferring zero amount of the token (a legit situation which doesn't require the token
259
+ // to be present in the inputs);
260
+ // b) creating an order that asks for the token.
261
+ //
262
+ // /-->Bi
263
+ // A
264
+ // \-->C
265
+ //
266
+ // Freeze token in C.
267
+ // Check that Bi got marked as conflicted.
268
+ #[ rstest]
269
+ #[ trace]
270
+ #[ case( Seed :: from_entropy( ) ) ]
271
+ fn update_conflicting_txs_frozen_token_only_in_outputs ( #[ case] seed : Seed ) {
272
+ let mut rng = make_seedable_rng ( seed) ;
273
+
274
+ let mut output_cache = OutputCache :: empty ( ) ;
275
+ let token_id = TokenId :: random_using ( & mut rng) ;
276
+
277
+ let genesis_tx_id = Id :: < Transaction > :: new ( H256 :: random_using ( & mut rng) ) ;
278
+ let tx_a = TransactionBuilder :: new ( )
279
+ . add_input (
280
+ TxInput :: from_utxo ( genesis_tx_id. into ( ) , 0 ) ,
281
+ InputWitness :: NoSignature ( None ) ,
282
+ )
283
+ // Note: only coin outputs here
284
+ . add_output ( TxOutput :: Transfer (
285
+ OutputValue :: Coin ( Amount :: from_atoms ( rng. gen ( ) ) ) ,
286
+ Destination :: AnyoneCanSpend ,
287
+ ) )
288
+ . add_output ( TxOutput :: Transfer (
289
+ OutputValue :: Coin ( Amount :: from_atoms ( rng. gen ( ) ) ) ,
290
+ Destination :: AnyoneCanSpend ,
291
+ ) )
292
+ . add_output ( TxOutput :: Transfer (
293
+ OutputValue :: Coin ( Amount :: from_atoms ( rng. gen ( ) ) ) ,
294
+ Destination :: AnyoneCanSpend ,
295
+ ) )
296
+ . build ( ) ;
297
+ let tx_a_id = tx_a. transaction ( ) . get_id ( ) ;
298
+ output_cache
299
+ . add_tx (
300
+ tx_a_id. into ( ) ,
301
+ WalletTx :: Tx ( TxData :: new (
302
+ tx_a,
303
+ TxState :: Confirmed ( BlockHeight :: zero ( ) , BlockTimestamp :: from_int_seconds ( 0 ) , 0 ) ,
304
+ ) ) ,
305
+ )
306
+ . unwrap ( ) ;
307
+
308
+ // Transfer zero amount
309
+ let tx_b1 = TransactionBuilder :: new ( )
310
+ . add_input (
311
+ TxInput :: from_utxo ( tx_a_id. into ( ) , 0 ) ,
312
+ empty_witness ( & mut rng) ,
313
+ )
314
+ . add_output ( TxOutput :: Transfer (
315
+ OutputValue :: TokenV1 ( token_id, Amount :: ZERO ) ,
316
+ Destination :: AnyoneCanSpend ,
317
+ ) )
318
+ . build ( ) ;
319
+ let tx_b1_id = tx_b1. transaction ( ) . get_id ( ) ;
320
+ output_cache
321
+ . add_tx (
322
+ tx_b1_id. into ( ) ,
323
+ WalletTx :: Tx ( TxData :: new ( tx_b1. clone ( ) , TxState :: Inactive ( 0 ) ) ) ,
324
+ )
325
+ . unwrap ( ) ;
326
+
327
+ // LockThenTransfer zero amount
328
+ let tx_b2 = TransactionBuilder :: new ( )
329
+ . add_input (
330
+ TxInput :: from_utxo ( tx_a_id. into ( ) , 1 ) ,
331
+ empty_witness ( & mut rng) ,
332
+ )
333
+ . add_output ( TxOutput :: LockThenTransfer (
334
+ OutputValue :: TokenV1 ( token_id, Amount :: ZERO ) ,
335
+ Destination :: AnyoneCanSpend ,
336
+ OutputTimeLock :: ForBlockCount ( 1 ) ,
337
+ ) )
338
+ . build ( ) ;
339
+ let tx_b2_id = tx_b2. transaction ( ) . get_id ( ) ;
340
+ output_cache
341
+ . add_tx (
342
+ tx_b2_id. into ( ) ,
343
+ WalletTx :: Tx ( TxData :: new ( tx_b2. clone ( ) , TxState :: Inactive ( 0 ) ) ) ,
344
+ )
345
+ . unwrap ( ) ;
346
+
347
+ let tx_b3 = TransactionBuilder :: new ( )
348
+ . add_input (
349
+ TxInput :: from_utxo ( tx_a_id. into ( ) , 2 ) ,
350
+ empty_witness ( & mut rng) ,
351
+ )
352
+ . add_output ( TxOutput :: CreateOrder ( Box :: new ( OrderData :: new (
353
+ Destination :: AnyoneCanSpend ,
354
+ OutputValue :: TokenV1 ( token_id, Amount :: from_atoms ( rng. gen ( ) ) ) ,
355
+ OutputValue :: Coin ( Amount :: from_atoms ( rng. gen ( ) ) ) ,
356
+ ) ) ) )
357
+ . build ( ) ;
358
+ let tx_b3_id = tx_b3. transaction ( ) . get_id ( ) ;
359
+ output_cache
360
+ . add_tx (
361
+ tx_b3_id. into ( ) ,
362
+ WalletTx :: Tx ( TxData :: new ( tx_b3. clone ( ) , TxState :: Inactive ( 0 ) ) ) ,
363
+ )
364
+ . unwrap ( ) ;
365
+
366
+ let tx_d = TransactionBuilder :: new ( )
367
+ . add_input (
368
+ TxInput :: AccountCommand (
369
+ AccountNonce :: new ( 0 ) ,
370
+ AccountCommand :: FreezeToken ( token_id, IsTokenUnfreezable :: No ) ,
371
+ ) ,
372
+ empty_witness ( & mut rng) ,
373
+ )
374
+ . build ( ) ;
375
+
376
+ let block_id = Id :: < GenBlock > :: new ( H256 :: random_using ( & mut rng) ) ;
377
+ let result = output_cache
378
+ . update_conflicting_txs ( tx_d. transaction ( ) , block_id)
379
+ . unwrap ( )
380
+ . into_iter ( )
381
+ . collect :: < BTreeMap < _ , _ > > ( ) ;
382
+
383
+ assert_eq ! (
384
+ result,
385
+ BTreeMap :: from( [
386
+ (
387
+ tx_b1_id,
388
+ WalletTx :: Tx ( TxData :: new( tx_b1, TxState :: Conflicted ( block_id) ) )
389
+ ) ,
390
+ (
391
+ tx_b2_id,
392
+ WalletTx :: Tx ( TxData :: new( tx_b2, TxState :: Conflicted ( block_id) ) )
393
+ ) ,
394
+ (
395
+ tx_b3_id,
396
+ WalletTx :: Tx ( TxData :: new( tx_b3, TxState :: Conflicted ( block_id) ) )
397
+ ) ,
398
+ ] )
399
+ ) ;
400
+ }
0 commit comments