Blocks and consensus¶
Block structure¶
Every block in WaveLedger has the following fields:
| Field | Type | Notes |
|---|---|---|
index | uint | Block height. Genesis = 0. |
timestamp | float | Unix epoch (seconds, float). |
transactions | list | Ordered; first tx is always the coinbase. |
previous_hash | hex string | SHA3-512 of the previous block. |
merkle_root | hex string | SHA3-512 Merkle root of the tx list. |
nonce | uint | PoW nonce. |
hash | hex string | SHA3-512 of the block header (computed last). |
difficulty | uint | Number of required leading hex zeros in hash. |
miner | string (20-byte hex) | The miner's address; receives the coinbase. |
quantum_signature | object | null | QRNG attestation envelope (see Entropy). |
quantum_verified | bool | True when quantum_signature is present + valid. |
Genesis is the only block with difficulty = 0 and no PoW.
Consensus rules¶
A block is valid iff:
previous_hashmatches the tip's hash.merkle_rootmatches a recomputed Merkle root oftransactions.hashmatches a recomputed SHA3-512 of the header.hashhas at leastdifficultyleading hex zeros.difficultymatches what the chain expects at this height.quantum_signatureis present and verifies against the block'squantum_seed(see Entropy).- The coinbase tx (
transactions[0]) hassender = "mining_reward",recipient = block.miner, andamount == subsidy + collected_feeswheresubsidyis the schedule-derived block reward at this height. - Every non-coinbase tx passes the standard tx validation rules (see Transaction format).
- Adding the coinbase would not push
total_supplyaboveMAX_SUPPLY.
Fork resolution¶
The canonical chain is the one with highest cumulative work, defined as $\sum 2^{\text{difficulty}_i}$ summed over every block.
If two blocks arrive at the same height with the same parent, the node keeps both until one chain extends. The longer-work chain wins; the other branch is reorged out and its non-coinbase txs are put back into the mempool.
Reorgs deeper than MAX_REORG_DEPTH (100 blocks) are rejected — a node that has been offline long enough to see a 100-block reorg must re-sync from peers, not from disk.
Difficulty adjustment¶
Difficulty is recalculated every DIFFICULTY_ADJUSTMENT_INTERVAL (10) blocks, at block boundaries only (not on every block). At each boundary:
- If the last interval took less than half the expected time →
+1 - If the last interval took more than 2× the expected time →
-1 - Otherwise hold
Mainnet bounds: [MIN_DIFFICULTY, MAX_DIFFICULTY] = [2, 8]. Testnet bounds: [2, 4] — performance-1x Fly VMs cap out at difficulty 4.
Expected time = BLOCK_TIME_TARGET * (DIFFICULTY_ADJUSTMENT_INTERVAL - 1) = 60s × 9 = 540s mainnet, 45s testnet.
Coinbase¶
The first transaction in every block is a "coinbase" — synthetic, no signature, sender = "mining_reward". Its amount is the schedule subsidy plus the sum of fees from all other txs in the block.
The subsidy is: $$ \text{subsidy}(h) = \frac{\text{INITIAL_BLOCK_REWARD}}{2^{\lfloor h / \text{HALVING_INTERVAL} \rfloor}} $$
with current values INITIAL_BLOCK_REWARD = 5 WAVE, HALVING_INTERVAL = 2,100,000 blocks. See Tokenomics for the full curve.
Mempool eligibility¶
To enter the mempool a tx must:
- Have a valid ML-DSA-87 signature
- Have fee
≥ MEMPOOL_MIN_FEE(0.0001 WAVE) - Have amount
≥ MIN_TRANSACTION_AMOUNT(0.01 WAVE), unless it is a contract deploy/call (recipient == "contract"ordata.type in ("deploy", "call")), which are exempt from the dust limit - Pass the balance check:
sender_balance - sum(pending_outflows) ≥ amount + fee - Not be a duplicate of a tx already pending
- Not exceed
MEMPOOL_MAX_PER_ADDRESSpending entries (50) from one sender
Mempool capacity is MEMPOOL_MAX_SIZE (5,000) with fee-priority eviction. Replace-by-fee is supported with a 10% minimum bump on the same (sender, nonce) pair.