iuna

iuna - experimental devnet protocol
git clone https://iuna.jhx.app/git/iuna.git
Log | Files | Refs | README | LICENSE

commit 15ded2b144f71ce971dd2a037b6d52189663350c
parent 8840d73382f1c8af915bafe3885fb91c44e34719
Author: Joris Hartog <jorishartog@hotmail.com>
Date:   Fri,  7 Aug 2026 15:29:46 +0200

Increase fallback finalizer slot delay

Diffstat:
Mdocs/protocol.md | 6+++---
Msrc/app.rs | 4++--
Msrc/domain.rs | 9+++++++--
3 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/docs/protocol.md b/docs/protocol.md @@ -69,8 +69,8 @@ Fallback finalizers use more VDF work: rank `0` uses the base rounds, rank `1` u VDF rounds alone are not the fallback gate. Faster hardware could otherwise finish a lower-ranked VDF before a slower primary finalizer. iuna therefore also uses rank time slots: - rank `0` blocks are valid as soon as their timestamp is greater than the parent timestamp; -- rank `1` blocks are valid from `parent timestamp + 1 * target block time`; -- rank `2` blocks are valid from `parent timestamp + 2 * target block time`; +- rank `1` blocks are valid from `parent timestamp + 2 * target block time`; +- rank `2` blocks are valid from `parent timestamp + 4 * target block time`; - and so on. If a fallback finalizer finishes the VDF early, it must wait until its slot opens before publishing. Rank `0` does not wait on a rank slot; that keeps the primary path useful as the clean VDF-speed signal for retargeting. If a rank `0` finalizer finishes late, the block timestamp should reflect that later completion/publication time so VDF retargeting can observe slow rounds. Other nodes reject fallback blocks whose timestamp is before their rank slot. @@ -84,7 +84,7 @@ Rank slots depend on block timestamps, so timestamps are constrained by consensu - it must not be too far in the future relative to the validating node's network-adjusted clock; - for fallback ticket blocks, it must be at or after the finalizer rank slot. -The future drift limit is `2 minutes`. A finalizer can lie within that small margin, but cannot skip an entire `5 minute` rank slot by claiming a far-future timestamp. P2P treats too-early future/slot blocks as temporal errors rather than peer-banning evidence. +The future drift limit is `2 minutes`. A finalizer can lie within that small margin, but cannot skip an entire `10 minute` fallback rank slot by claiming a far-future timestamp. P2P treats too-early future/slot blocks as temporal errors rather than peer-banning evidence. ## Recovery Blocks diff --git a/src/app.rs b/src/app.rs @@ -3466,7 +3466,7 @@ mod tests { let work = plan.work.expect("fallback work should be prepared"); let vdf_output = run_vdf(work.vdf_seed(), work.vdf_rounds()); let block = node - .complete_prepared_block_at(work, vdf_output, VDF_TARGET_BLOCK_MS) + .complete_prepared_block_at(work, vdf_output, VDF_TARGET_BLOCK_MS * 2) .unwrap(); assert_eq!(block.finalizer_rank, 1); @@ -3578,7 +3578,7 @@ mod tests { let vdf_output = run_vdf(work.vdf_seed(), work.vdf_rounds()); let mut peer_ledger = node.clone_ledger(); let block = node - .complete_prepared_block_at(work, vdf_output, VDF_TARGET_BLOCK_MS) + .complete_prepared_block_at(work, vdf_output, VDF_TARGET_BLOCK_MS * 2) .unwrap(); assert!(block.transactions.iter().any(Transaction::is_burn)); assert!( diff --git a/src/domain.rs b/src/domain.rs @@ -4021,6 +4021,8 @@ fn vdf_rounds_for_finalizer_rank(base_rounds: u64, rank: u32) -> Result<u64> { fn finalizer_rank_slot_delay_ms(rank: u32) -> Result<u64> { VDF_TARGET_BLOCK_MS + .checked_mul(2) + .context("finalizer rank time slot overflow")? .checked_mul(u64::from(rank)) .context("finalizer rank time slot overflow") } @@ -6623,7 +6625,10 @@ mod tests { .prepare_next_block(fallback.address(), parent_timestamp + 1) .unwrap(); - assert_eq!(work.timestamp_ms(), parent_timestamp + VDF_TARGET_BLOCK_MS); + assert_eq!( + work.timestamp_ms(), + parent_timestamp + VDF_TARGET_BLOCK_MS * 2 + ); assert_eq!(work.vdf_rounds(), ledger.vdf_rounds() * 2); } @@ -6698,7 +6703,7 @@ mod tests { .prepare_next_block(fallback.address(), parent_timestamp + 1) .unwrap(); let mut block = work.finish(fallback, "preverified-vdf".to_string()); - block.timestamp_ms = parent_timestamp + VDF_TARGET_BLOCK_MS - 1; + block.timestamp_ms = parent_timestamp + VDF_TARGET_BLOCK_MS * 2 - 1; block.hash = block.compute_hash(); let error = ledger