Skip to content
Bitcoin Roots

v29.4-roots.3 · Commit 3: [PATCH 03/30] policy: restore conservative relay and network controls

test/functional/p2p_compactblocks_extratxs.py

Before: /dev/null · After: test/functional/p2p_compactblocks_extratxs.py

File metadata
new file mode 100755
index 0000000000000000000000000000000000000000..156c0785e9460c176b4e77e5d790ff5efb8fd8b0

Download original patch · Release notes

Diff rows 401–513 of 513. Line numbers refer to the original before/after files.

+ Added− RemovedUnmarked lines are context.

Scroll the code area horizontally to read long lines. Before is on the left; after is on the right. Unified view fits narrow screens more easily.

test/functional/p2p_compactblocks_extratxs.py ADDED
@@ -0,0 +1,513 @@ (continued)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
401
+ test_count = 100
402
+ rejected_txs = self.populate_extra_pool(test_count, target_size=20000)
403
+
404
+ indices = list(range(test_count))
405
+ result = self.send_compact_block(rejected_txs, indices)
406
+
407
+ # Find the boundary - how many fit vs how many were evicted
408
+ num_evicted = len(result["missing_indices"])
409
+ num_fit = test_count - num_evicted
410
+
411
+ # Now restart and add exactly the number that fit
412
+ self.restart_node_with_limit(memory_mb=limit_mb)
413
+ rejected_txs = self.populate_extra_pool(num_fit, target_size=20000)
414
+
415
+ # Verify all fit
416
+ indices = list(range(num_fit))
417
+ result = self.send_compact_block(rejected_txs, indices)
418
+ assert result["missing_indices"] == [], f"Expected all {num_fit} transactions to fit at boundary"
419
+
420
+ # Add one more transaction - should evict exactly one
421
+ self.log.info("Adding one more transaction at the boundary...")
422
+ self.populate_extra_pool(1, target_size=20000)
423
+
424
+ # Check original transactions again
425
+ result2 = self.send_compact_block(rejected_txs, indices)
426
+ assert len(result2["missing_indices"]) == 1, "Expected exactly 1 eviction at boundary"
427
+ assert result2["missing_indices"] == [0], "Expected oldest transaction (0) to be evicted"
428
+
429
+ self.log.info("Size limit boundary behavior verified - one transaction evicted when limit exceeded")
430
+
431
+ def test_extratxnsize_small_limit(self):
432
+ """Test extra transaction pool with very small size limit (0.1 MB)."""
433
+ self.log.info("Testing extra transaction pool with 0.1 MB size limit...")
434
+
435
+ limit_mb = 0.1
436
+ self.restart_node_with_limit(memory_mb=limit_mb)
437
+
438
+ test_count = 100
439
+ rejected_txs = self.populate_extra_pool(test_count, target_size=2000)
440
+ indices = list(range(test_count))
441
+ result = self.send_compact_block(rejected_txs, indices)
442
+
443
+ # Find the boundary - how many fit vs how many were evicted
444
+ num_evicted = len(result["missing_indices"])
445
+ num_fit = test_count - num_evicted
446
+
447
+ # fill exact capacity
448
+ self.restart_node_with_limit(memory_mb=limit_mb)
449
+ rejected_txs = self.populate_extra_pool(num_fit, target_size=2000)
450
+
451
+ indices = list(range(num_fit))
452
+ result = self.send_compact_block(rejected_txs, indices)
453
+ assert result["missing_indices"] == [], f"Expected all {num_fit} transactions to fit at boundary"
454
+
455
+ # Add one more transaction - should evict exactly one
456
+ self.log.info("Adding one more transaction at the boundary...")
457
+ self.populate_extra_pool(1, target_size=2000)
458
+
459
+ # Check original transactions again
460
+ result = self.send_compact_block(rejected_txs, indices)
461
+ assert len(result["missing_indices"]) == 1, "Expected exactly 1 eviction at boundary"
462
+ assert result["missing_indices"] == [0], "Expected oldest transaction (0) to be evicted"
463
+
464
+ self.log.info("Small size limit boundary behavior verified - one transaction evicted when limit exceeded")
465
+
466
+ def test_extratxnsize_large_transaction_exceeds_limit(self):
467
+ """Test that a transaction larger than the entire size limit is rejected."""
468
+ self.log.info("Testing large transaction that exceeds size limit...")
469
+
470
+ limit_mb = 0.5 # 0.5 MB/500KB
471
+ self.restart_node_with_limit(memory_mb=limit_mb)
472
+
473
+ # Create a 600KB transaction (larger than 500KB limit)
474
+ # This should be rejected from mempool AND not stored in extra pool
475
+ rejected_txs = self.populate_extra_pool(1, target_size=600000) # 600 KB
476
+
477
+ # try block reconstruction
478
+ result = self.send_compact_block(rejected_txs, [0])
479
+
480
+ # Verify the transaction is NOT available (was not stored in extra pool)
481
+ assert len(result["missing_indices"]) == 1, "Large transaction should not be stored in extra pool"
482
+
483
+ def run_test(self):
484
+ self.wallet = MiniWallet(self.nodes[0])
485
+
486
+ # Setup the p2p connection
487
+ self.segwit_node = self.nodes[0].add_p2p_connection(TestP2PConn())
488
+
489
+ # Create UTXOs for testing
490
+ self.make_utxos()
491
+
492
+ # Ensure segwit is active
493
+ assert softfork_active(self.nodes[0], "segwit")
494
+
495
+ # Test policy rejection types first
496
+ self.test_policy_rejection_types()
497
+
498
+ # Extra Txn capacity tests
499
+ self.test_extratxnpool_disabled()
500
+ self.test_extratxnpool_capacity_and_wraparound()
501
+ self.test_single_extratxnpool_capacity()
502
+ self.test_extratxn_invalid_parameters()
503
+
504
+ # Extra Txn size tests
505
+ self.test_extratxnsize_zero_limit()
506
+ self.test_extratxnsize_eviction()
507
+ self.test_extratxnsize_boundary()
508
+ self.test_extratxnsize_small_limit()
509
+ self.test_extratxnsize_large_transaction_exceeds_limit()
510
+
511
+
512
+ if __name__ == '__main__':
513
+ CompactBlocksBlockReconstructionLimitTest(__file__).main()