Property-Based Testing
Overview
Bitcoin Commons uses property-based testing with Proptest to verify mathematical invariants across thousands of random inputs. The system includes property tests in the main test file and property test functions across all test files.
Property Test Categories
Economic Rules
prop_block_subsidy_halving_schedule- Verifies subsidy halves every 210,000 blocksprop_total_supply_monotonic_bounded- Verifies supply increases monotonically and is boundedprop_block_subsidy_non_negative_decreasing- Verifies subsidy is non-negative and decreasing
Proof of Work
prop_pow_target_expansion_valid_range- Verifies target expansion within valid rangeprop_target_expansion_deterministic- Verifies target expansion is deterministic
Transaction Validation
prop_transaction_output_value_bounded- Verifies output values are boundedprop_transaction_non_empty_inputs_outputs- Verifies transactions have inputs and outputsprop_transaction_size_bounded- Verifies transaction size is boundedprop_coinbase_script_sig_length- Verifies coinbase script sig length limitsprop_transaction_validation_deterministic- Verifies validation is deterministic
Script Execution
prop_script_execution_deterministic- Verifies script execution is deterministicprop_script_size_bounded- Verifies script size is boundedprop_script_execution_performance_bounded- Verifies script execution performance
Performance
prop_sha256_performance_bounded- Verifies SHA256 performanceprop_double_sha256_performance_bounded- Verifies double SHA256 performanceprop_transaction_validation_performance_bounded- Verifies transaction validation performanceprop_script_execution_performance_bounded- Verifies script execution performanceprop_block_subsidy_constant_time- Verifies block subsidy calculation is constant-timeprop_target_expansion_performance_bounded- Verifies target expansion performance
Deterministic Execution
prop_transaction_validation_deterministic- Verifies transaction validation determinismprop_block_subsidy_deterministic- Verifies block subsidy determinismprop_total_supply_deterministic- Verifies total supply determinismprop_target_expansion_deterministic- Verifies target expansion determinismprop_fee_calculation_deterministic- Verifies fee calculation determinism
Integer Overflow Safety
prop_fee_calculation_overflow_safety- Verifies fee calculation overflow safetyprop_output_value_overflow_safety- Verifies output value overflow safetyprop_total_supply_overflow_safety- Verifies total supply overflow safety
Temporal/State Transition
prop_supply_never_decreases_across_blocks- Verifies supply never decreasesprop_reorganization_preserves_supply- Verifies reorganization preserves supplyprop_supply_matches_expected_across_blocks- Verifies supply matches expected values
Compositional Verification
prop_connect_block_composition- Verifies block connection compositionprop_disconnect_connect_idempotency- Verifies disconnect/connect idempotency
SHA256 Correctness
sha256_matches_reference- Verifies SHA256 matches reference implementationdouble_sha256_matches_reference- Verifies double SHA256 matches referencesha256_idempotent- Verifies SHA256 idempotencysha256_deterministic- Verifies SHA256 determinismsha256_output_length- Verifies SHA256 output lengthdouble_sha256_output_length- Verifies double SHA256 output length
Location: blvm-consensus/tests/consensus_property_tests.rs
Proptest Integration
Basic Usage
#![allow(unused)]
fn main() {
use proptest::prelude::*;
proptest! {
#[test]
fn prop_function_invariant(input in strategy) {
let result = function_under_test(input);
prop_assert!(result.property_holds());
}
}
}
Strategy Generation
Proptest generates random inputs using strategies:
#![allow(unused)]
fn main() {
// Integer strategy
let height_strategy = 0u64..10_000_000;
// Vector strategy
let tx_strategy = prop::collection::vec(tx_strategy, 1..1000);
// Custom strategy
let block_strategy = (height_strategy, tx_strategy).prop_map(|(h, txs)| {
Block::new(h, txs)
});
}
Property Assertions
#![allow(unused)]
fn main() {
// Basic assertion
prop_assert!(condition);
// Assertion with message
prop_assert!(condition, "Property failed: {}", reason);
// Assertion with equality
prop_assert_eq!(actual, expected);
}
Property Test Patterns
Invariant Testing
Test that invariants hold across all inputs:
#![allow(unused)]
fn main() {
proptest! {
#[test]
fn prop_subsidy_non_negative(height in 0u64..10_000_000) {
let subsidy = get_block_subsidy(height);
prop_assert!(subsidy >= 0);
}
}
}
Round-Trip Properties
Test that operations are reversible:
#![allow(unused)]
fn main() {
proptest! {
#[test]
fn prop_serialization_round_trip(tx in tx_strategy()) {
let serialized = serialize(&tx);
let deserialized = deserialize(&serialized)?;
prop_assert_eq!(tx, deserialized);
}
}
}
Determinism Properties
Test that functions are deterministic:
#![allow(unused)]
fn main() {
proptest! {
#[test]
fn prop_deterministic(input in input_strategy()) {
let result1 = function(input.clone());
let result2 = function(input);
prop_assert_eq!(result1, result2);
}
}
}
Bounds Properties
Test that values stay within bounds:
#![allow(unused)]
fn main() {
proptest! {
#[test]
fn prop_value_bounded(value in 0i64..MAX_MONEY) {
let result = process_value(value);
prop_assert!(result >= 0 && result <= MAX_MONEY);
}
}
}
Additional Property Tests
Comprehensive Property Tests
Location: tests/unit/comprehensive_property_tests.rs
- Multiple proptest! blocks covering comprehensive scenarios
Script Opcode Property Tests
Location: tests/unit/script_opcode_property_tests.rs
- Multiple proptest! blocks for script opcode testing
SegWit/Taproot Property Tests
Location: tests/unit/segwit_taproot_property_tests.rs
- Multiple proptest! blocks for SegWit and Taproot
Edge Case Property Tests
Multiple files with edge case testing:
tests/unit/block_edge_cases.rs: Multiple proptest! blockstests/unit/economic_edge_cases.rs: Multiple proptest! blockstests/unit/reorganization_edge_cases.rs: Multiple proptest! blockstests/unit/transaction_edge_cases.rs: Multiple proptest! blockstests/unit/utxo_edge_cases.rs: Multiple proptest! blockstests/unit/difficulty_edge_cases.rs: Multiple proptest! blockstests/unit/mempool_edge_cases.rs: Multiple proptest! blocks
Cross-BIP Property Tests
Location: tests/cross_bip_property_tests.rs
- Multiple proptest! blocks for cross-BIP validation
Statistics
- Property Test Blocks: Multiple proptest! blocks across all test files
- Property Test Functions: Multiple prop_* functions across all test files
Running Property Tests
Run All Property Tests
cargo test --test consensus_property_tests
Run Specific Property Test
cargo test --test consensus_property_tests prop_block_subsidy_halving_schedule
Run with Verbose Output
cargo test --test consensus_property_tests -- --nocapture
Run with MIRI
cargo +nightly miri test --test consensus_property_tests
Shrinking
Proptest automatically shrinks failing inputs to minimal examples:
- Initial Failure: Large random input fails
- Shrinking: Proptest reduces input size
- Minimal Example: Smallest input that still fails
- Debugging: Minimal example is easier to debug
Configuration
Test Cases
Default: 256 test cases per property test
#![allow(unused)]
fn main() {
proptest! {
#![proptest_config(ProptestConfig::with_cases(1000))]
#[test]
fn prop_test(input in strategy) {
// ...
}
}
}
Max Shrink Iterations
Default: 65536 shrink iterations
#![allow(unused)]
fn main() {
proptest! {
#![proptest_config(ProptestConfig {
max_shrink_iters: 10000,
..ProptestConfig::default()
})]
#[test]
fn prop_test(input in strategy) {
// ...
}
}
}
Integration with Formal Verification
Property tests complement Z3 proofs:
- BLVM Specification Lock (Z3): Proves correctness for all inputs (bounded)
- Property Tests: Verifies invariants with random inputs (unbounded)
- Combined: Comprehensive verification coverage
Components
The property-based testing system includes:
- Property tests in main test file
- Property test blocks across all files
- Property test functions
- Proptest integration
- Strategy generation
- Automatic shrinking
- MIRI integration
Location: blvm-consensus/tests/consensus_property_tests.rs, blvm-consensus/tests/unit/
See Also
- Testing Infrastructure - Overview of all testing techniques
- Fuzzing Infrastructure - Automated bug discovery
- Differential Testing - Compare with Bitcoin Core
- Formal Verification - BLVM Specification Lock verification
- Contributing - Testing requirements for contributions