Consensus and blocks
The Velum chain produces blocks in turns among active full nodes, with a target of 2 seconds per slot. The actual pace is measured: the explorer and the home page show the recent average. Each epoch (1,800 blocks, about 1 hour30 blocks, about 60 seconds) nodes discover that epoch's VEL with their verified work.
Turns
Time is divided into 2 s slots (the target) since genesis (slot = floor((ts − genesis) / 2000)). For each slot, every node computes the same turn order:
active = registered full nodes with a heartbeat in the last 15 blocks
order = active sorted by sha256(previous_block_hash | slot | address)
- The first in the order (rank 0) proposes the block when the slot starts.
- Backups wait half a second per position (rank × 500 ms) before they can propose.
- A block signed before its turn is rejected.
The order changes with every block (it depends on the previous hash), so nobody knows in advance when it will be whose turn.
Heartbeats
Each node periodically signs a heartbeat (presence: node, height, time). Heartbeats go into blocks and define who is active. They also count towards uptime, one of the tier requirements.
The chain doesn't stop
If the active nodes all go offline at once, each empty slot moves everyone else up one position. Within a few slots, any registered node can keep producing. Light nodes never produce blocks: any block they sign is rejected.
Epochs
In the last block of each epoch:
- What there is to discover is added up: the epoch's issuance, the 80% of fees set aside and the 0.1% returned by the Network Reserve.
- 15% is discovered by those who produced and validated blocks, equally per block.
- 85% is discovered by those who opened bridges: verified deliveries × tier multiplier.
- Active token pools (
pool.fund) are released. - Difficulty (verified work / VEL issued) and the oracle price are published.
- Market orders whose
ttlhas passed expire.
A node's work isn't recorded receipt by receipt: each node publishes an aggregated claim (work.claim) with the Merkle root of its receipts, and the next epoch checks 16 random receipts (work.prove). See Run a node.
See The VEL coin for issuance and Run a node for tiers.
Fork choice and reorganizations
When two blocks compete for the same height, this rule decides:
best = the tallest chain; at equal height, the block with the lowest hash
A node that sees a better branch switches to it (a reorganization). Because of the turn design, reorganizations are short: usually one or two blocks, when two backups propose almost at the same time. The explorer's indexer keeps recent states to follow them and marks dropped blocks as "discarded branch".
Finality {#finalidad}
On {{chain}} finality is probabilistic: the more blocks on top of a block, the harder it is for it to be discarded.
| Use | Recommended confirmations | Approximate time |
|---|---|---|
| Messages, small payments between people | 1 | One block |
| Shops and payment gateways | 6 | A few seconds |
| Exchanges, normal amounts | 30 | ≈ 1 min at the target pace |
| Exchanges, large amounts | One epoch | ≈ 1 h on mainnet |
Instant finality with signatures from 2/3 of validators is on the mainnet roadmap.
Block structure
BlockHeader = { chain, height, prev, ts, slot, proposer, txRoot, receiptRoot, presenceRoot, stateRoot }
Block = { header, hash, sig, txs[], receipts[], presence[], rewards[], tokenRewards?[] }
hash = sha256(canonical JSON of header)
sig = proposer's ed25519 signature over hash
The roots are Merkle trees (SHA-256) of the transactions, receipts and heartbeats. stateRoot is the fingerprint of the full state after applying the block: two honest nodes always arrive at the same one.