Skip to content
Bitcoin Roots

v30.3-roots.1 · Commit 3: [PATCH 03/68] feat(policy): preserve Roots relay and network controls on Core 30.3

test/functional/p2p_compactblocks_extratxs.py

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

File metadata
new file mode 100755
index 0000000000000000000000000000000000000000..341071229b41da1f0a56c1a7bdb375c52bfd2f81

Download original patch · Release notes

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

+ Added− RemovedUnmarked lines are context.

Scroll the code area horizontally to read long lines. The two line-number columns refer to before and after.

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