Skip to content

fix: pos exit proof non power of 2 merkle#908

Merged
leovct merged 2 commits intomainfrom
fix/pos-exit-proof-non-power-of-2-merkle
Apr 29, 2026
Merged

fix: pos exit proof non power of 2 merkle#908
leovct merged 2 commits intomainfrom
fix/pos-exit-proof-non-power-of-2-merkle

Conversation

@leovct
Copy link
Copy Markdown
Member

@leovct leovct commented Apr 29, 2026

leovct added 2 commits April 29, 2026 09:27
Polygon's matic-js MerkleTree (and the pos-contracts / pos-portal test
helpers it mirrors) builds a complete fixed-depth binary tree by padding
the leaf layer with zero hashes to the next power of 2. The on-chain
verifier (pos-contracts/contracts/common/lib/Merkle.sol checkMembership)
requires that exact shape — it asserts index < 2^proofHeight and walks
a fixed-depth tree.

merkleProof was instead duplicating the last node per layer when an odd
count was reached. That coincidentally matches matic-js when the leaf
count is already a power of 2 (mainnet's 128-block checkpoints), so the
bug never surfaced in production. On a fast-cadence devnet validators
sometimes submit checkpoint ranges that aren't powers of 2 (e.g. 40
blocks), and the resulting tree root differs from L1's stored
headerRoot — startExitWithBurntTokens then reverts with
WITHDRAW_BLOCK_NOT_A_PART_OF_SUBMITTED_HEADER.

Pad once at the leaf layer to the next power of 2 with zero hashes, then
build cleanly. Adds cmd_test.go with an independent reproduction of the
on-chain verifier and a regression case at 40 leaves.
@leovct leovct requested a review from a team April 29, 2026 08:08
@sonarqubecloud
Copy link
Copy Markdown

@leovct leovct merged commit c98ee8f into main Apr 29, 2026
16 checks passed
@leovct leovct deleted the fix/pos-exit-proof-non-power-of-2-merkle branch April 29, 2026 08:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants