@@ -3294,3 +3294,62 @@ def compare_unfinished_blocks(block1: UnfinishedBlock, block2: UnfinishedBlock)
3294
3294
# Final assertion to check the entire block
3295
3295
assert block1 == block2 , "The entire block objects are not identical"
3296
3296
return True
3297
+
3298
+
3299
+ @pytest .mark .anyio
3300
+ @pytest .mark .parametrize (
3301
+ "condition, error" ,
3302
+ [
3303
+ (ConditionOpcode .ASSERT_HEIGHT_RELATIVE , "ASSERT_HEIGHT_RELATIVE_FAILED" ),
3304
+ (ConditionOpcode .ASSERT_HEIGHT_ABSOLUTE , "ASSERT_HEIGHT_ABSOLUTE_FAILED" ),
3305
+ ],
3306
+ )
3307
+ async def test_pending_tx_cache_retry_on_new_peak (
3308
+ condition : ConditionOpcode , error : str , blockchain_constants : ConsensusConstants , caplog : pytest .LogCaptureFixture
3309
+ ) -> None :
3310
+ """
3311
+ Covers PendingTXCache items that are placed there due to unmet relative or
3312
+ absolute height conditions, to make sure those items get retried at peak
3313
+ post processing when those conditions are met.
3314
+ """
3315
+ async with setup_simulators_and_wallets (1 , 0 , blockchain_constants ) as new :
3316
+ full_node_api = new .simulators [0 ].peer_api
3317
+ bt = new .bt
3318
+ wallet = WalletTool (test_constants )
3319
+ ph = wallet .get_new_puzzlehash ()
3320
+ blocks = bt .get_consecutive_blocks (
3321
+ 3 , guarantee_transaction_block = True , farmer_reward_puzzle_hash = ph , pool_reward_puzzle_hash = ph
3322
+ )
3323
+ for block in blocks :
3324
+ await full_node_api .full_node .add_block (block )
3325
+ peak = full_node_api .full_node .blockchain .get_peak ()
3326
+ assert peak is not None
3327
+ current_height = peak .height
3328
+ # Create a transaction with a height condition that makes it pending
3329
+ coin = blocks [- 1 ].get_included_reward_coins ()[0 ]
3330
+ if condition == ConditionOpcode .ASSERT_HEIGHT_RELATIVE :
3331
+ condition_height = 1
3332
+ else :
3333
+ condition_height = current_height + 1
3334
+ condition_dic = {condition : [ConditionWithArgs (condition , [int_to_bytes (condition_height )])]}
3335
+ sb = wallet .generate_signed_transaction (uint64 (42 ), ph , coin , condition_dic )
3336
+ sb_name = sb .name ()
3337
+ # Send the transaction
3338
+ res = await full_node_api .send_transaction (SendTransaction (sb ))
3339
+ assert res is not None
3340
+ assert ProtocolMessageTypes (res .type ) == ProtocolMessageTypes .transaction_ack
3341
+ transaction_ack = TransactionAck .from_bytes (res .data )
3342
+ assert transaction_ack .status == MempoolInclusionStatus .PENDING .value
3343
+ assert transaction_ack .error == error
3344
+ # Make sure it ends up in the pending cache, not the mempool
3345
+ assert full_node_api .full_node .mempool_manager .get_mempool_item (sb_name , include_pending = False ) is None
3346
+ assert full_node_api .full_node .mempool_manager .get_mempool_item (sb_name , include_pending = True ) is not None
3347
+ # Advance peak to meet the asserted height condition
3348
+ with caplog .at_level (logging .DEBUG ):
3349
+ blocks = bt .get_consecutive_blocks (2 , block_list_input = blocks , guarantee_transaction_block = True )
3350
+ for block in blocks :
3351
+ await full_node_api .full_node .add_block (block )
3352
+ # This should trigger peak post processing with the added transaction
3353
+ assert f"Added transaction to mempool: { sb_name } \n " in caplog .text
3354
+ # Make sure the transaction was retried and got added to the mempool
3355
+ assert full_node_api .full_node .mempool_manager .get_mempool_item (sb_name , include_pending = False ) is not None
0 commit comments