datahaven/operator
Steve Degosserie 67f375860b
feat: Performance-Based Validator Rewards and Inflation Scaling (#306)
## Summary

Building on #304, this PR implements two complementary mechanisms to
improve validator incentives and network performance:

1. **Performance-Based Validator Rewards** (session-level)
2. **Inflation Scaling** (era-level)

## Reward Model Comparison

### Old Model (main branch) vs New Model

| Metric | Old Model (20 pts/block) | New Model (320 pts/block pool) |
|--------|--------------------------|--------------------------------|
| **Per Block** | Author: 20 pts, Others: 0 | Author: ~196 pts, Others:
~4 pts each |
| **Formula** | Direct author reward | 60% authoring + 30% liveness +
10% base |
| **Per Session** (600 blocks, 32 validators) | 12,000 total pts |
192,000 total pts |
| **Per Validator/Session** (uniform) | ~375 pts | ~6,000 pts |
| **Per Validator/Era** (6 sessions) | ~2,250 pts | ~36,000 pts |
| **Offline Validator** | 0 pts | ~600 pts/session (base only) |
| **Over-performer (150% blocks)** | 150% of fair share | Up to 130%
reward (soft cap) |

### Key Differences
- **Pool-based**: New model adds 320 points to a shared pool per block,
distributed via formula
- **Liveness rewarded**: 30% of rewards go to validators who are online
(heartbeat OR block authorship)
- **Base guarantee**: 10% ensures all active validators receive minimum
rewards
- **Soft cap**: Prevents extreme over-performance rewards (max 150% of
fair share credited)

## Performance-Based Validator Rewards

Introduces a **60/30/10 reward formula** that rewards validators based
on their contribution during each session:

- **60%** based on block production (with soft cap allowing up to 150%
of fair share)
- **30%** based on liveness (ImOnline heartbeat OR block authorship)
- **10%** guaranteed base reward for all active validators

### Key Features
- Tracks individual validator block authorship per session
- Calculates fair share dynamically: `fair_share = total_blocks /
total_validator_count`
- Fair share uses **total** validator count (including whitelisted)
since all validators occupy block slots
- **Soft cap**: Over-performers can earn credit up to 150% of their fair
share (configurable via `OperatorRewardsFairShareCap` at 50%)
- With 60% BlockAuthoringWeight, this gives over-performers up to **30%
bonus reward**
- **BasePointsPerBlock**: Defines points added to pool per block
produced (default: 320)
- Integrates with SessionManager for automatic point awards at session
end
- Excludes whitelisted validators from rewards (but includes them in
fair share calculation)
- Slashing check disabled but hook retained for future use
- Points accumulate across sessions within an era

### Dynamic Parameters (Governance-Adjustable)
- `OperatorRewardsBlockAuthoringWeight`: Weight for block authoring
(default: 60%)
- `OperatorRewardsLivenessWeight`: Weight for liveness (default: 30%)
- `OperatorRewardsFairShareCap`: Soft cap percentage above fair share
(default: 50%)

## Inflation Scaling

Implements **dynamic inflation scaling** that adjusts total inflation
based on network block production:

- **Minimum**: 20% of base inflation (network halt protection)
- **Maximum**: 100% of base inflation (caps at expected blocks)
- **Linear scaling** between minimum and maximum based on performance

### Scaling Examples
- 0% blocks produced → 20% inflation (safety floor)
- 50% blocks produced → 60% inflation  
- 100% blocks produced → 100% inflation
- >100% blocks produced → capped at 100%

### Configuration
- **ExpectedBlocksPerEra**: Computed as `SessionsPerEra ×
EpochDurationInBlocks`
- **MinInflationPercent**: 20%
- **MaxInflationPercent**: 100%

## Combined Effect

These mechanisms work together to create a comprehensive incentive
structure:

1. **Session rewards** encourage individual validator performance and
uptime
2. **Era inflation scaling** incentivizes collective network health
3. **Minimum inflation floor** protects against network halt
4. **Soft cap** allows over-performers to earn up to 30% bonus while
preventing extreme centralization

## Implementation Details

### Pallet Changes
- Add `BlocksAuthoredInSession` storage for per-validator tracking
- Add `BlocksProducedInEra` storage for total network tracking (cleaned
up with HistoryDepth)
- Add `note_block_author()` function called on block production
- Add `award_session_performance_points()` function with configurable
60/30/10 formula
- Add `calculate_scaled_inflation()` function for era-level scaling
- Update `on_era_end()` to use scaled inflation
- Integrate with SessionManager via wrapper types
- Defensive weight validation: proportionally scales if sum > 100%

### Configuration Parameters
- `ValidatorSet`: Provides active validator list
- `LivenessCheck`: Uses `ImOnline::is_online()` (heartbeat OR block
authorship)
- `SlashingCheck`: Integration with slashing pallet (currently disabled)
- `BasePointsPerBlock`: Points added to pool per block (default: 320)
- `BlockAuthoringWeight`: Dynamic parameter (60%)
- `LivenessWeight`: Dynamic parameter (30%)
- `FairShareCap`: Dynamic parameter (50%)
- `ExpectedBlocksPerEra`: Computed from session/epoch config
- `MinInflationPercent`: 20%
- `MaxInflationPercent`: 100%

### Runtime Updates
- Full configuration added to mainnet, testnet, and stagenet runtimes
- Dynamic parameters added to `runtime_params.rs` for governance control
- Uses `prod_or_fast!()` macro for environment-specific parameters
- `ValidatorIsOnline` uses `ImOnline::is_online()` for accurate liveness
detection

## Testing

- **76 tests passing** 
- Comprehensive coverage of both mechanisms

### Test Coverage
- Inflation scaling at 0%, 25%, 50%, 75%, 100%, >100% blocks
- Session performance with 60/30/10 formula
- Fair share calculations with soft cap (150%)
- Whitelisted validator exclusion from rewards (with correct fair share
using total count)
- Total points verification (sum of individual = total)
- Whitelisted over-producer scenarios
- Overflow protection (large block counts, near-u32::MAX)
- End-to-end session to era flow
- MockLivenessCheck mirrors ImOnline behavior (block authorship =
online)
- Multiple eras with different performance levels
- Edge cases (zero participation, single validator, large numbers)
- BlocksProducedInEra cleanup on era start

## ⚠️ Breaking Changes ⚠️

### Reward Distribution

Previously, rewards were distributed equally among all validators
regardless of their contribution. Now:

- **Performance-based**: Validators earn rewards proportional to their
block production (60%), liveness (30%), and a guaranteed base (10%)
- **Pool-based**: `BasePointsPerBlock` defines points added to pool per
block (320), distributed via formula
- **Fair share uses total validators**: Ensures non-whitelisted aren't
penalized for whitelisted validators' block slots
- **Soft cap**: Block production rewards allow up to 150% of fair share
(50% cap = 30% bonus with 60% weight)
- **Slashing check disabled**: Hook retained for future use, but
currently not applied

### Inflation Mechanism

Previously, the full calculated inflation was minted each era. Now:

- **Scaled by performance**: Total inflation scales between 20%-100%
based on actual blocks produced vs expected
- **Safety floor**: Even with zero blocks, 20% of inflation is still
minted to prevent complete halt
- **Network incentive**: Collective block production directly impacts
total rewards available

### Pallet Configuration

The `pallet-external-validators-rewards` Config now requires additional
types:
- `BlockAuthoringWeight`, `LivenessWeight`, `FairShareCap` for reward
formula
- `ValidatorSet`, `LivenessCheck`, `SlashingCheck` for validator
tracking
- `ExpectedBlocksPerEra`, `MinInflationPercent`, `MaxInflationPercent`
for inflation scaling

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Ahmad Kaouk <56095276+ahmadkaouk@users.noreply.github.com>
2025-12-16 16:27:03 +01:00
..
benchmarking fix: pallet collective weights aliases (#337) 2025-12-05 14:22:52 +01:00
node build: 🔨 Optimize node dependencies by feature-gating benchmarking (#341) 2025-12-09 12:26:05 +01:00
pallets feat: Performance-Based Validator Rewards and Inflation Scaling (#306) 2025-12-16 16:27:03 +01:00
precompiles feat: Add datahaven native transfer precompile (#309) 2025-12-02 13:57:40 +01:00
primitives fix: 🛡️ Check origin for validator set messages (#343) 2025-12-15 14:11:08 +01:00
runtime feat: Performance-Based Validator Rewards and Inflation Scaling (#306) 2025-12-16 16:27:03 +01:00
scripts Revert "feat: statically build binary (#292)" (#330) 2025-12-02 15:42:43 +01:00
.dockerignore refactor: 🐳 Improve docker caching (again) (#86) 2025-05-27 16:14:15 +00:00
.gitignore test: Native token transfer e2e tests (#120) 2025-08-22 18:27:14 +02:00
Cargo.lock feat: Performance-Based Validator Rewards and Inflation Scaling (#306) 2025-12-16 16:27:03 +01:00
Cargo.toml build: ⬆️ Upgrade to StorageHub version 0.2.6 (#357) 2025-12-16 11:22:33 +01:00
DOCKER-COMPOSE.md feat: Add Docker Compose setup for local DataHaven network (#314) 2025-11-22 14:07:46 +01:00
docker-compose.yml feat: Add Docker Compose setup for local DataHaven network (#314) 2025-11-22 14:07:46 +01:00
Dockerfile feat: Add Docker Compose setup for local DataHaven network (#314) 2025-11-22 14:07:46 +01:00
README.md doc: Fix fast-runtime documentation (#311) 2025-11-19 17:23:10 +00:00
rust-toolchain.toml fix: 🔧 Add revision number to rust toolchain channel version to match with srtool image version (#209) 2025-10-07 11:34:21 +02:00

DataHaven Operator (Substrate Node) 🫎

The DataHaven operator is a Substrate-based blockchain node that serves as an EigenLayer AVS operator. It combines Substrate's modular framework with EVM compatibility (via Frontier) and cross-chain capabilities (via Snowbridge).

Overview

Built on the polkadot-sdk-solochain-template, this node implements:

  • EVM Compatibility: Full Ethereum compatibility via Frontier pallets
  • EigenLayer Integration: Operator registration and management via AVS contracts
  • External Validators: Dynamic validator set controlled by EigenLayer registry
  • Cross-chain Communication: Token and message passing via Snowbridge
  • Rewards System: Performance-based validator rewards from Ethereum

Project Structure

operator/
├── node/                          # Node implementation
│   ├── src/
│   │   ├── chain_spec.rs         # Chain specification & genesis config
│   │   ├── cli.rs                # CLI interface
│   │   ├── command.rs            # Command handlers
│   │   ├── rpc.rs                # RPC configuration
│   │   └── service.rs            # Node service setup
├── pallets/                       # Custom pallets
│   ├── external-validators/      # EigenLayer validator set management
│   ├── native-transfer/          # Cross-chain token transfers
│   └── rewards/                   # Validator rewards distribution
├── runtime/                       # Runtime configurations
│   ├── mainnet/                  # Mainnet runtime
│   ├── stagenet/                 # Stagenet runtime
│   └── testnet/                  # Testnet runtime (with fast-runtime feature)
└── scripts/                       # Utility scripts
    └── run-benchmarks.sh         # Runtime benchmarking automation

Prerequisites

Building

Development Build (Fast Runtime)

For local development with shorter epochs and eras:

cargo build --release --features fast-runtime

This switches runtime parameters to the fast variants (1-minute epochs, 3 sessions per era) while the block time remains 6 seconds.

Production Build

For production or stagenet deployments:

cargo build --release

Running Tests

# Run all tests
cargo test

# Run tests for specific pallet
cargo test -p pallet-external-validators

# Run with output
cargo test -- --nocapture

Code Quality

# Format code
cargo fmt

# Lint with clippy
cargo clippy --all-targets --all-features

Benchmarking

DataHaven uses runtime benchmarking to generate accurate weight calculations for all pallets. The benchmarking process is automated using frame-omni-bencher.

Requirements

  • Latest Rust stable version
  • frame-omni-bencher: Install with cargo install frame-omni-bencher --profile=production

Running Benchmarks

Execute from the operator directory:

# Benchmark all pallets for testnet runtime (default)
./scripts/run-benchmarks.sh

# Benchmark specific runtime
./scripts/run-benchmarks.sh mainnet

# Custom steps and repetitions
./scripts/run-benchmarks.sh testnet 100 50

The script will:

  1. Discover all available pallets
  2. Build runtime WASM with runtime-benchmarks feature
  3. Generate weight files in runtime/{runtime}/src/weights/
  4. Provide summary of results

Parameters:

  • runtime: Runtime to benchmark (testnet, stagenet, mainnet). Default: testnet
  • steps: Number of steps. Default: 50
  • repeat: Number of repetitions. Default: 20

Zombienet Testing

Zombienet provides local multi-validator network testing.

Setup

  1. Install Zombienet:

    # Download binary from releases
    # Or install via npm
    npm install -g @zombienet/cli
    
  2. Spawn local network with four validators:

    zombienet -p native spawn test/config/zombie-datahaven-local.toml
    

This launches a local solochain with BABE consensus for testing validator coordination.

Docker Image

Build local Docker image for testing:

cd ../test
bun build:docker:operator

This creates datahavenxyz/datahaven:local using optimized caching:

  • sccache: Rust build caching
  • cargo-chef: Dependency layer caching
  • BuildKit cache mounts: External cache restoration

Type Generation

After runtime changes, regenerate Polkadot-API TypeScript types:

cd ../test
bun generate:types           # Production runtime
bun generate:types:fast      # Fast runtime (development)

Integration Testing

For full network integration tests with Ethereum, Snowbridge, and contracts:

cd ../test
bun cli launch               # Interactive launcher
bun test:e2e                 # Run E2E test suite

See the test directory for comprehensive testing documentation.

Custom Pallets

External Validators

Manages the dynamic validator set based on EigenLayer operator registry. Syncs validator changes from Ethereum to the Substrate consensus layer.

Location: pallets/external-validators/

Native Transfer

Handles cross-chain token transfers between Ethereum and DataHaven via Snowbridge messaging.

Location: pallets/native-transfer/

Rewards

Distributes performance-based rewards to validators, processing reward messages from the Ethereum RewardsRegistry contract.

Location: pallets/rewards/

Each pallet includes its own tests and benchmarks. See pallet-specific README files for details.