mirror of
https://github.com/luxfi/consensus.git
synced 2026-09-24 00:26:58 +00:00
Finality's subject is (height, inner canonical) everywhere in this package. A cert binds the canonical block and the canonical parent; attestKey excludes the outer envelope on purpose, because the envelope carries the proposer and the timestamp and neither is part of what was decided. Two wrappers of one execution commit to one state transition. The ancestry walk compared outer ids. Arriving at the finalized height under a sibling wrapper of the tip therefore read as arriving on a losing branch, and a cert that does extend the frontier was refused for naming it differently. The asymmetry is what gives it away. When the peer's envelope is UNTRACKED the walk already substitutes a local wrapper of the same execution and finality advances -- so a node holding less data recovered where a node holding more refused. One rule, both arms: reaching the finalized height at the tip's execution is reaching the tip, and the child's parent link rebases onto the wrapper this node actually holds so the accept path and the reject-subtree walk agree on one envelope. decision() degrades an absent canonical to the outer id rather than to Empty, so a bare chain compares byte-for-byte as before: there, two blocks are the same decision only when they are the same block. The relaxation is keyed to the finalized height exactly -- an ancestor below it is never the frontier's alias -- and a divergent execution at that height still conflicts. Both halves are pinned by mutation: drop the height test and the below-frontier case finalizes; drop the canonical test and a fork finalizes. Co-authored-by: Hanzo Dev <[email protected]>