The GenLayer Fee Distribution Simulator is a comprehensive Python-based system for modeling and testing fee distribution mechanisms in the GenLayer blockchain validator network. It uses a path-based approach to exhaustively test all possible transaction scenarios, ensuring correctness through rigorous invariant checking.
To understand how this works, one should understand how does the voting process at genlayer works, and how appeals work, etc. So here are the docs for that.
The simulator follows a deterministic flow: TRANSITIONS_GRAPH → Path → TransactionRoundResults → Round Labels → Fee Distribution, where each step is purely functional and content-based rather than index-based.
- Path-Based Testing: Generates all valid transaction paths from TRANSITIONS_GRAPH for exhaustive testing
- Content-Based Round Detection: Identifies round types by analyzing vote patterns, not indices
- 22 Invariants: Comprehensive invariant checking ensures correctness (conservation of value, non-negative balances, etc.)
- Role-Based Fee Distribution: Allocates fees based on participant roles (Leader, Validator, Sender, Appealant)
- Appeal Mechanisms: Handles leader and validator appeals with proper bond calculations
- Special Pattern Recognition: Automatically transforms round labels based on transaction patterns
- Visualization Tools: Rich formatted tables for transaction results and fee distributions
- Path JSON Export: Generate compressed JSON files for all paths for external verification
- Modular Architecture: Clean separation between path generation, transaction processing, and fee distribution
src/
└── fee_simulator/
├── core/ # Core logic
│ ├── round_fee_distribution/ # Fee distribution strategies
│ │ ├── normal_round.py
│ │ ├── appeal_*_successful.py
│ │ ├── appeal_*_unsuccessful.py
│ │ ├── leader_timeout_*.py
│ │ └── split_previous_appeal_bond.py
│ ├── path_to_transaction.py # Path → Transaction converter
│ ├── round_labeling.py # Content-based round type detection
│ ├── transaction_processing.py # Main processing pipeline
│ ├── bond_computing.py # Appeal bond calculations
│ ├── majority.py # Vote outcome determination
│ └── refunds.py # Sender refund logic
├── protocol/ # Protocol definitions
│ ├── models.py # Data structures (immutable)
│ ├── constants.py # NORMAL_ROUND_SIZES, APPEAL_ROUND_SIZES
│ └── types.py # Type definitions
├── specification/ # Formal specification
│ ├── invariants/ # System invariants
│ │ ├── checker.py # Main invariant checker
│ │ └── definitions/ # 22 invariant implementations
│ └── state_machine/ # State machine specification
│ ├── graph.py # TRANSACTION_GRAPH definition
│ └── path_analysis/ # Path analysis tools
│ ├── path_generator.py
│ ├── path_counter.py
│ └── path_filter.py
├── display/ # Visualization utilities
├── metrics/ # Metrics and aggregations
└── utils.py # Utility functions
tests/
├── round_combinations/ # Path generation tests
├── round_labeling/ # Round detection tests
├── fee_distributions/ # Fee distribution tests
│ ├── simple_round_types_tests/
│ └── check_invariants/ # Invariant testing
└── slashing/ # Idleness and violation tests
scripts/ # Utility scripts
├── 01_generate_test_vectors.py # Generate compressed JSON files for all paths
├── 02_decode_test_vector.py # Decode and visualize JSON path files
├── 03_analyze_incentives.py # Analyze incentive structures
└── 04_interactive_simulator.py # Interactive path builder and simulator
examples/ # Example scenarios
├── 01_basic_transaction.py # Simple majority agreement
├── 02_validator_appeal.py # Successful validator appeal
├── 03_leader_timeout.py # Leader timeout scenario
└── 04_complex_path.py # Multiple appeals example
1. TRANSITIONS_GRAPH defines valid state transitions
↓
2. Path Generator creates sequences like:
["START", "LEADER_RECEIPT_MAJORITY_AGREE", "APPEAL_VALIDATOR_SUCCESSFUL", "END"]
↓
3. Path-to-Transaction converter creates TransactionRoundResults with appropriate votes
↓
4. Round Labeling analyzes vote patterns (content-based, not index-based):
- All NA votes → Leader Appeal
- LEADER_TIMEOUT → Leader Timeout
- AGREE/DISAGREE without leader → Validator Appeal
↓
5. Fee Distribution based on labels:
- NORMAL_ROUND → Leader and majority validators earn
- APPEAL_*_SUCCESSFUL → Appealant earns bond
- Special patterns trigger transformations
↓
6. Invariant Checking ensures correctness
Rounds are identified by their vote patterns, not their position:
- Leader Appeals: All participants vote "NA"
- Validator Appeals: No LEADER_RECEIPT, validators vote AGREE/DISAGREE
- Normal Rounds: Have LEADER_RECEIPT or LEADER_TIMEOUT
- Special Patterns: e.g., successful appeal makes previous round SKIP_ROUND
-
Vote Types:
LEADER_RECEIPT: Leader submitted resultLEADER_TIMEOUT: Leader failed to respondAGREE/DISAGREE/TIMEOUT: Validator votesNA: Not applicable (appeals)
-
Round Sizes:
- Normal rounds: [5, 11, 23, 47, 95, 191, 383, 767, 1000]
- Appeal rounds: [7, 13, 25, 49, 97, 193, 385, 769, 1000]
-
Fee Distribution:
- Leader earns: leader_timeout + validator_timeout (if majority)
- Validators earn: validator_timeout (if in majority)
- Penalties: PENALTY_REWARD_COEFFICIENT * validator_timeout
-
Clone the repository:
git clone <repository_url> cd genlayer-fee-distribution-simulator
-
Set up the conda environment:
# Activate miniconda source ~/opt/miniconda3/bin/activate # Create and activate the consensus-simulator environment conda create -n consensus-simulator python=3.9 conda activate consensus-simulator
-
Install dependencies:
pip install -r requirements.txt
To run the entire test suite:
pytestTo run tests with full output logging:
pytest -s --verbose-output --debug-output > tests.txt To run a specific test with verbose and debug output (displays formatted tables):
pytest tests/fee_distributions/simple_round_types_tests/test_normal_round.py -s --verbose-output --debug-outputTo run round labeling tests with property-based testing:
pytest tests/round_labeling/test_round_labeling_properties.py -sTo run exhaustive path testing (can take hours for long paths):
python tests/round_labeling/run_path_tests.pyGenerate compressed JSON files for all possible paths (useful for external verification):
# Generate all paths up to length 7 (484 paths)
python scripts/01_generate_test_vectors.py --max-length 7
# Generate paths up to length 17 (~113M paths, requires significant time and storage)
python scripts/01_generate_test_vectors.py --max-length 17
# Test mode (generates only 10 paths per length)
python scripts/01_generate_test_vectors.py --max-length 7 --test-mode
# Specify custom output directory
python scripts/01_generate_test_vectors.py --max-length 7 --output-dir custom_outputThe generated files will be organized in directories by path length:
path_jsons/
├── lookup_tables.json # Decoding tables for compressed format
├── length_03/ # Paths of length 3
│ ├── 02-0cd0354f.json
│ └── ...
├── length_04/ # Paths of length 4
│ └── ...
└── ...
Decode compressed JSON files and visualize the transaction:
# Show compressed data summary and summary table (default)
python scripts/02_decode_test_vector.py path_jsons/length_03/02-0cd0354f.json
# Show all visualizations
python scripts/02_decode_test_vector.py path_jsons/length_03/02-0cd0354f.json --show-all
# Show specific visualizations
python scripts/02_decode_test_vector.py path_jsons/length_03/02-0cd0354f.json -t -f
# -c: compressed data summary
# -t: transaction results
# -f: fee distribution details
# -s: summary table
# -a: all visualizations
# Use custom path_jsons directory
python scripts/02_decode_test_vector.py custom_output/length_03/02-0cd0354f.json --json-dir custom_outputAnalyze different validator strategies and their financial outcomes:
# Analyze incentive structures for different path lengths
python scripts/03_analyze_incentives.py --max-length 7
# Generate detailed table of outcomes
python scripts/03_analyze_incentives.py --max-length 5 --show-detailsUse the interactive simulator to build custom transaction paths and see all outputs:
# Run the interactive simulator
python scripts/04_interactive_simulator.pyFeatures:
- Build custom paths: Interactively select nodes to create your transaction path
- Predefined examples: Quick access to simple, appeal, and complex scenarios
- Full visualization: See transaction details, fee distribution, and summary tables
- Invariant verification: Automatically checks all 24 invariants
- Parameter customization: Set custom leader and validator timeout values
The interactive simulator provides a menu-driven interface where you can:
- Build paths step-by-step with valid node suggestions
- Use predefined example paths
- Customize simulation parameters
- View comprehensive results with all tables and visualizations
The examples/ directory contains ready-to-run scripts demonstrating various transaction scenarios:
# 1. Basic transaction with majority agreement
python examples/01_basic_transaction.py
# 2. Successful validator appeal
python examples/02_validator_appeal.py
# 3. Leader timeout scenario
python examples/03_leader_timeout.py
# 4. Complex path with multiple appeals
python examples/04_complex_path.pyEach example script:
- Shows a specific transaction scenario
- Displays all visualization tables (transaction details, fee distribution, summary)
- Verifies all 24 invariants
- Provides detailed explanations of the outcomes
When you run an example, you'll see:
- Transaction Details: Round-by-round vote breakdown
- Fee Distribution: Detailed fee events for each participant
- Summary Table: Consolidated view of all participants' earnings and costs
- Invariant Verification: Confirmation that all 24 invariants pass
- Outcome Explanation: Clear description of what happened and why
These examples are perfect for:
- Understanding how the fee distribution system works
- Testing different scenarios
- Learning the impact of appeals and timeouts
- Demonstrating the system to others
You can create and simulate custom transaction scenarios programmatically:
from src.fee_simulator.protocol.models import TransactionBudget, TransactionRoundResults, Round, Rotation
from src.fee_simulator.core.transaction_processing import process_transaction
from src.fee_simulator.core.round_labeling import label_rounds
from src.fee_simulator.utils import generate_random_eth_address
from src.fee_simulator.display import display_summary_table, display_transaction_results
# Generate addresses
addresses = [generate_random_eth_address() for _ in range(6)]
# Define budget
budget = TransactionBudget(
leaderTimeout=100,
validatorsTimeout=200,
appealRounds=0,
rotations=[0],
senderAddress=addresses[5],
appeals=[],
staking_distribution="constant"
)
# Define transaction results
rotation = Rotation(
votes={
addresses[0]: ["LEADER_RECEIPT", "AGREE"],
addresses[1]: "AGREE",
addresses[2]: "AGREE",
addresses[3]: "AGREE",
addresses[4]: "DISAGREE"
}
)
results = TransactionRoundResults(rounds=[Round(rotations=[rotation])])
# Get round labels
round_labels = label_rounds(results)
# Process transaction
fee_events, _ = process_transaction(addresses, results, budget)
# Display results
display_summary_table(fee_events, results, budget, round_labels)
display_transaction_results(results, round_labels)The test suite covers:
- Unit Tests: Validate individual components (e.g., budget calculations, refunds)
- Scenario-Based Tests: Test specific round types (e.g., normal rounds, successful/unsuccessful appeals)
- Property-Based Tests: Use Hypothesis to generate test cases for round labeling
- Path-Based Tests: Exhaustively test all paths through TRANSITIONS_GRAPH
- Invariant Tests: Verify 24 invariants for every test case
- Slashing Tests: Verify slashing for idleness and deterministic violations
- Edge Cases: Handle empty rounds, undetermined majorities, and consecutive appeals
The system maintains 24 invariants that are checked for every test:
- Conservation of value - Total in = Total out
- Appeal bond coverage - Bonds fully distributed
- Majority/minority consistency - Vote counts accurate
- Sequential processing - Rounds processed in order
- Appeal follows normal - Appeals only after normal rounds
- Round label validity - Only valid labels used
- Appellant consistency - Appellant role properly assigned
- Burn non-negativity - Burns are non-negative
- No double penalties - Single penalty per violation
- Bounded slashing impact - Slashing within reasonable bounds
- No profit from griefing - Can't profit from attacks
- Cost of contention - Contention has economic cost
- Griefing amplification - Attack costs scale appropriately
- Progress monotonicity - System makes forward progress
- Resource pool integrity - Resource pools remain consistent
- Irreversibility of finality - Finalized decisions are permanent
- Temporal event consistency - Events ordered in time
- Refund non-negativity - Refunds are non-negative
- Vote consistency - Votes match transaction data
- Idle slashing - Idle validators properly penalized
- Deterministic violation slashing - Hash mismatches penalized
- Leader timeout earning - Bounded leader earnings
- Appeal bond consistency - Bond amounts match round sizes
- Round size consistency - Sizes follow NORMAL/APPEAL arrays
- Economic Analysis: Evaluate the incentive structure of the GenLayer protocol
- Protocol Validation: Simulate fee distribution before deploying protocol changes
- Consensus Verification: Generate test data for consensus algorithm implementations
- Education: Understand blockchain consensus and fee mechanics
- Development: Test and refine fee distribution algorithms
This project is licensed under the MIT License. See the LICENSE file for details.