# Waves: Block Finality
# Overview
Waves protocol introduces deterministic block finality: a mechanism that makes confirmed blocks irreversible without manual intervention. Prior to this feature, Waves offered only probabilistic finality — a hidden chain with a larger cumulative generating balance could theoretically be published and cause a reorganization, reversing previously confirmed transactions.
The new finality mechanism works by having validators explicitly commit to participation in block generation, then endorse key-blocks by signing the parent block. Once the cumulative balance of a block's endorsers reaches 2/3 of the total active generating balance, the block is considered final and cannot be rolled back.
The mechanism is supplementary and backward-compatible: if the Generator Set is empty, the node continues operating with probabilistic finality and no disruption to block production.
# Key Concepts
# Generator Set
The Generator Set is the explicitly known list of validators participating in block generation for a given generation period (a fixed number of blocks). Membership requires submitting a CommitToGeneration transaction in advance; it is not possible to join the current period retroactively.
Each account may hold at most two active commitments: one for the current period and one for the next. At the start of each new block, the node recalculates the generating balance of every generator in the set and updates the total.
A generator is excluded from the set if:
- Its generating balance falls below the minimum threshold (1,000 WAVES) — exclusion takes effect in the block following the one where the balance dropped.
- It submits a conflicting endorsement — exclusion is immediate, in the same block where the conflict is detected.
Network parameters:
| Parameter | Mainnet | Testnet | Stagenet |
|---|---|---|---|
| Period duration (blocks) | 10,000 | 3,000 | 1,000 |
| Max endorsements per block | 128 | 64 | 32 |
| Max rollback depth | 100 | 100 | 100 |
# Finality Calculation
A block becomes final when:
3 × endorsedBalance ≥ 2 × totalGeneratingBalance
The endorsed balance is the sum of the block generator's balance plus all valid endorser balances collected in that block's micro-blocks. Only endorsements collected at height N+1 count toward finalizing block N — votes from later heights do not carry back. This is intentional: carrying forward descendant votes would prevent branches from being merged after a network split and reunion.
The miner's own balance always counts toward the endorsed balance implicitly. If the miner's balance alone meets the 2/3 threshold, the parent block finalizes without any explicit endorsements, even if the block is empty.
Finality of block N is calculated upon receiving key-block N+2, which contains the micro-blocks with votes collected at height N+1. A finalized block cannot be reorganized out of the chain.
If the Generator Set is empty, finality can only be advanced via the minimum rollback depth constraint — the finalized height is treated as current_height − maxRollback, the same behavior as before the feature was activated.
# CommitToGeneration Transaction
A new transaction type through which an account registers its intent to participate in the next generation period.
Fields:
| Field | Description |
|---|---|
generation_period_start | Block height at which the next period begins |
endorser_public_key | BLS public key used to sign endorsements |
commitment_signature | BLS proof-of-possession: signature over endorser_public_key || generation_period_start |
Validation rules:
- Can only target the next period start height; retroactive or far-future commitments are rejected.
- Only one commitment per account per period is accepted.
- The sender's generating balance (after deducting the deposit and fee) must be ≥ 1,000 WAVES.
endorser_public_keymust be a valid BLS public key.commitment_signaturemust be a valid BLS proof-of-possession signature (protects against Rogue Key attacks).
Fees and deposit:
- Fee: minimum 0.1 WAVES
- Deposit: 100 WAVES (locked for the duration of the period)
The deposit is returned in the first block of the period that follows the committed period, provided the generator behaved honestly. It is fully slashed for malicious behavior (conflicting endorsement).
# Endorsement Mechanism
After receiving and validating a key-block, every active generator in the Generator Set sends an endorsement directly to the key-block's generator. The key-block generator does not send an explicit endorsement — producing the block is itself an implicit vote for the parent block.
# Endorsement Message Fields
| Field | Description |
|---|---|
endorser_index | Index of the endorser within the Generator Set |
endorsed_block_id | ID of the block being endorsed (the parent of the current key-block) |
finalized_block_id | ID of the locally finalized block at the time of endorsement |
finalized_block_height | Height of the locally finalized block |
signature | BLS signature over finalized_block_id || finalized_block_height || endorsed_block_id |
The finalized_block_id and finalized_block_height fields are used to detect conflicting endorsements (see Punishments below).
# Micro-block Packaging
The key-block generator collects endorsements and packs a minimal snapshot into micro-blocks:
- A snapshot of valid endorser indexes and the aggregated BLS signature — but only once the 2/3 quorum has been reached. Before that threshold, endorser indexes are not included (there is no finalization to record yet, and omitting them saves space).
- Any new conflicting endorsements discovered since the last micro-block.
Voting data is only included in a micro-block when there is an update (a new valid or conflicting endorsement arrived). Crucially, micro-blocks are only produced when transactions are available — the miner does not emit empty micro-blocks solely to carry endorsements. In a low-traffic network, this means finality may be delayed until the next transaction-bearing micro-block is produced.
# BLS Cryptography
Endorsement signatures use BLS12-381 (via the blst library). Aggregated BLS signatures allow the entire endorsement set to be verified in a single operation, keeping block overhead minimal.
- Compressed public keys: 48 bytes
- Signatures: 96 bytes
- Aggregated signature size: identical to a single signature (96 bytes regardless of endorser count)
The proof-of-possession scheme in CommitToGeneration prevents Rogue Key attacks. The blst library automatically validates group membership for signatures; public keys must be checked for subgroup membership on receipt.
# Block and Micro-block Structure Changes
A new field finalization_voting is added to both block and micro-block headers:
finalization_voting:
endorser_indexes – list of valid endorser indexes
finalized_block_height – height of the finalized block these votes reference
aggregated_endorsement_signature – aggregated BLS signature
conflict_endorsements – list of conflicting endorsement proofs
This field is covered by the micro-block header signature.
Validation rules for endorsements in a block:
- A block cannot endorse an already-finalized block or any earlier block.
- The aggregated BLS signature must be valid against the listed endorser public keys.
- Each endorser must be present in the Generator Set.
- A block generator cannot include their own endorsement.
- An endorser can appear at most once (either as valid or conflicting, not both).
- The number of valid endorsers cannot exceed the configured maximum.
- In a challenge block (see Waves 1.5), the finalization header must be empty.
# Punishments
Conflicting endorsements are punishable. An endorsement is considered conflicting when its finalized_block_height is less than or equal to the miner's current finalized height, but the finalized_block_id at that height differs from the miner's. This proves the endorser could not have switched to the miner's chain — they were irrevocably on a different fork.
Upon including a conflicting endorsement in a block or micro-block, the following penalties are applied:
- Exclusion from the Generator Set for the remainder of the current period (immediate, at the same height).
- Full deposit slash: the 100 WAVES deposit is burned at the start of the next block.
The excluded generator cannot mine blocks or participate in endorsements until the period ends.
Note for node operators: Running multiple backup instances of the same generating account on a split network may result in unintentional conflicting endorsements and trigger slashing. Only one active instance per key pair should be operated at any time.
# Empty Generator Set
The Generator Set can be empty for several reasons: no generators have committed for the current period, or all committed generators have had their balances drop below 1,000 WAVES, or all have been excluded for conflicting endorsements.
When this happens:
Block production is unaffected. A block is accepted if the miner is in the Generator Set, or if the Generator Set is empty. Mining continues without interruption regardless of why the set is empty.
Deterministic finality is suspended. With no active generators, endorsement-based finality is impossible. The finalized height falls back to current_height − maxRollback (100 blocks), identical to pre-activation behavior. Deterministic finality resumes automatically once generators commit for the next period.
This means the feature degrades gracefully — the network never halts, it simply loses the stronger finality guarantees temporarily.
# Chain Synchronization Change
After activation, when a node requests an extension from a peer:
- Before activation: the last 100 block signatures are returned.
- After activation: only blocks above the last finalized block are returned.
This means a node can no longer automatically roll back past the last finalized block.
# RIDE Changes
CommitToGenerationis added as a recognized transaction type and all its fields are accessible in RIDE scripts.BalanceDetails.availablereflects the locked deposit.- The finalized block height is not exposed as a RIDE function because finality is a local node property, not a consensus-level blockchain property.
- BLS cryptographic primitives and the
depositfield are not added toBalanceDetails.
# Activation
The feature activates at a specific block height (ActivationHeight). Before that height, all received endorsements are ignored and the finalized height is treated as height − maxRollback.
The first generation period starts GenerationPeriod blocks after activation:
First period: [ActivationHeight + GenerationPeriod + 1 ; ActivationHeight + 2 × GenerationPeriod]
Second period: [ActivationHeight + 2 × GenerationPeriod + 1 ; ActivationHeight + 3 × GenerationPeriod]
Generators wishing to participate in the first period must submit their CommitToGeneration transaction before the period start height.