iuna

iuna

iuna - experimental mainnet-candidate protocol
git clone https://getiuna.org/git/iuna.git
Log | Files | Refs | README | LICENSE

commit 4377c85cd78611199bb4aace9234ea7873cfbb14
parent 700da7c158278af551822853674d4fc8956aa55d
Author: Joris Hartog <jorishartog@hotmail.com>
Date:   Tue,  1 Sep 2026 12:56:43 +0200

Extend post-activation burn E2E

Diffstat:
Me2e/README.md | 6+++++-
Me2e/iuna_e2e.py | 38+++++++++++++++++++++++++++++++++++++-
2 files changed, 42 insertions(+), 2 deletions(-)

diff --git a/e2e/README.md b/e2e/README.md @@ -59,7 +59,11 @@ blocks, network-health, peers, mempool, and wallet APIs on every node. `fallback-activation` crosses height 300 and checks that objective finality has not activated early. `objective-finality` crosses heights 1000 and 1001 and requires a certified checkpoint. `checkpoint-restart` proves that the certified -checkpoint survives a full six-node restart and that the chain keeps advancing. +checkpoint survives a full six-node restart, advances through height 1007, and +that block 1007 is finalized by a ticket derived from a burn included at height +1002 or later. At that height, the ticket maturity and expiry windows exclude +every pre-pipeline burn, so this covers a complete post-activation burn-to-block +lifecycle. Use `--keep` on `smoke` to leave a failed or successful network running. Stop a network without deleting its mutable data with: diff --git a/e2e/iuna_e2e.py b/e2e/iuna_e2e.py @@ -57,6 +57,7 @@ class Scenario: minimum_finalized_height: int | None = None canonical_height: int | None = None require_fixture_hash: bool = False + leader_burn_minimum_height: int | None = None SCENARIOS = { @@ -72,10 +73,11 @@ SCENARIOS = { ), "checkpoint-restart": Scenario( snapshot="first-objective-checkpoint", - through=1_002, + through=1_007, minimum_finalized_height=1_000, canonical_height=1_000, require_fixture_hash=True, + leader_burn_minimum_height=1_002, ), } @@ -245,6 +247,36 @@ def block_at_height(service: str, height: int) -> dict: return result[0] +def assert_leader_uses_burn_from_height( + block_height: int, minimum_height: int +) -> None: + block = block_at_height(SERVICES[0], block_height) + leader_proof = block.get("leader_proof") + if block.get("finalizer_mode") != "ticket" or not isinstance(leader_proof, dict): + raise E2EError(f"block {block_height} was not finalized by a burn ticket") + + ticket_id = leader_proof.get("ticket_id") + if not isinstance(ticket_id, str) or not ticket_id: + raise E2EError(f"block {block_height} has no valid leader ticket ID") + + for height in range(minimum_height, block_height): + source = block_at_height(SERVICES[0], height) + if any( + transaction.get("kind") == "burn" + and transaction.get("signature") == ticket_id + for transaction in source.get("transactions", []) + ): + print( + f"block {block_height} leader ticket comes from burn at height {height}" + ) + return + + raise E2EError( + f"block {block_height} leader ticket does not come from a burn at or after " + f"height {minimum_height}" + ) + + def assert_api_health(statuses: dict[str, dict], through: int) -> None: for service in SERVICES: blocks = node_json(service, "/api/blocks?limit=3") @@ -607,6 +639,10 @@ def run_scenario( assert_canonical_block( scenario.canonical_height, scenario.require_fixture_hash ) + if scenario.leader_burn_minimum_height is not None: + assert_leader_uses_burn_from_height( + scenario.through, scenario.leader_burn_minimum_height + ) assert_api_health(statuses, scenario.through) print(f"e2e scenario {name} passed") except Exception: