ParaloomPARALOOM

Consensus

Reputation-gated BFT for withdrawal approval and compute verification, with on-chain slashing.

Consensus

Paraloom uses Byzantine fault-tolerant consensus among a small validator cohort to verify zk-SNARK withdrawal proofs and compute job results. Validators are verify-only — they do not produce proofs. Voting weight is gated by on-chain reputation, and bad behaviour is recorded as on-chain slashing evidence.

Parameters

DefaultSource
Threshold7 of 10configurable per network in Settings
Verification windowtunableper-message timeout
Heartbeat interval5 scoordinator HA
Min validator stake1 SOLenforced on-chain (MIN_VALIDATOR_STAKE)
Initial reputation1000new validators start neutral

The threshold lives in consensus::ConsensusThreshold; the on-chain stake minimum lives in programs/paraloom/src/lib.rs:

pub const MIN_VALIDATOR_STAKE: u64 = 1_000_000_000; // 1 SOL

Two consensus jobs, one cohort

The same BFT cohort handles both:

UseThresholdWhat's voted on
Withdrawal approval7 / 10 (default)Validity of a Groth16 withdrawal proof
Compute result agreement7 / 10 (configurable, lower for stable subsets)Hash equality of WASM execution outputs

Withdrawal flow lives in src/consensus/withdrawal.rs; compute consensus uses the same WithdrawalVerificationCoordinator-style aggregation in src/compute/distribution.rs.

Reputation gating

Withdrawal voting is gated by reputation — a validator below the gate threshold cannot vote on withdrawals. New validators start at neutral; reputation moves with observed behaviour.

The reputation tracker (ReputationTracker in src/consensus/reputation.rs) updates per round:

EventReputation delta
Correct vote on agreed outcome+
Vote in line with majority on slashable evidence+
Disagreement with majority (no equivocation)small −
Equivocation (conflicting signed votes at same height)recorded as slashing evidence
Persistent unavailability (N missed heartbeats over a window)recorded as slashing evidence

The exact deltas are tunable per network and intentionally not advertised as a fixed table — they're consensus parameters, not protocol invariants.

Slashing evidence

Two kinds of evidence are recorded in protocol:

Equivocation

Two valid signatures from the same validator on conflicting messages at the same consensus height. Cryptographic proof of fault — slashable on-chain.

Persistent unavailability

A validator that misses heartbeats / votes for longer than a configurable window without proper unregistration. Aggregated evidence is signed by the cohort and submitted on-chain.

Evidence catalog and tracker live in src/consensus/slashing.rs. Slashing is executed by the slash_validator instruction in the Anchor program — stake is transferred from the validator's PDA to the bridge vault, and the times_slashed counter increments.

// programs/paraloom/src/lib.rs (extract)
pub fn slash_validator(
    ctx: Context<SlashValidator>,
    validator: Pubkey,
    slash_percentage: u8, // 1-100
) -> Result<()> {
    let slash_amount = (validator_account.stake_amount as u128
                       * slash_percentage as u128 / 100) as u64;
    validator_account.stake_amount =
        validator_account.stake_amount.saturating_sub(slash_amount);
    validator_account.times_slashed += 1;
    // … transfer slash_amount from validator account to bridge_vault …
}

Withdrawal flow (from a vote's perspective)

The chain re-verifies the proof and enforces nullifier uniqueness independently of the cohort — even a fully malicious 10/10 cohort cannot approve an invalid withdrawal. The cohort can only delay or refuse.

Coordinator role

A single coordinator drives round mechanics (collecting votes, computing the threshold, submitting the on-chain tx). It is not a single trust point — its decisions are still verified by the cohort and the on-chain program. But it is a single coordination point. Active/passive HA ensures a primary crash doesn't pause the network: details in Coordinator HA.

Configuration

[consensus]
threshold        = 7        # of total_validators
total_validators = 10
heartbeat_secs   = 5

# Reputation gate — validators below this are not counted
reputation_gate = 500       # of 10000

[network]
# bootstrap peers are read from on-chain validator registry — no manual seeds needed

Tests

End-to-end consensus scenarios — happy path, equivocation evidence, persistent unavailability, gating — live in tests/consensus_integration_test.rs. The reputation gating + slashing work landed in v0.4.0 (issue #62).

On this page