Feat/merkle proof scaling - #113
Open
nol4lej wants to merge 7 commits into
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Serving a Merkle proof was O(n):
get_merkle_pathloaded every leaf from storage and rebuilt all 20 levels per request (~90k reads + ~90k Poseidon hashes at current testnet size), and the RPC hard-rejected trees aboveMAX_RPC_LEAVES = 100_000— the spend path (transfer/unshield) would have gone down at ~10% of tree capacity. Implements Options A + B ofMERKLE_PROOF_SCALING_PLAN.md.What
Pallet (
pallet-shielded-pool0.10.1 → 0.11.0,STORAGE_VERSION0 → 1):MerkleNodes: StorageNMap<(tree_id, level, index), Hash>— theinsert_leaffrontier walk already computed every node on the insertion path and discarded them; they are now persisted (levels 1..=19; level 0 isMerkleLeaves, level 20 isPoseidonRoot).get_merkle_pathrewritten to 20 point reads, zero hashing. Missing siblings resolve to the canonical zero hash.get_all_leavesremoved.MigrateToV1: one-shot, idempotent backfill ofMerkleNodesfrom existing leaves, wired into the runtimeExecutive. try-runtimepre/post_upgradehooks verify the backfilled top nodes derivePoseidonRoot.(tree_id, level, index)— forest-ready perMULTI_TREE_FOREST_PLAN.md,tree_id = 0on the current single tree, so the future multi-tree migration needs no storage remapping.RPC (
fc-rpc-v2):privacy_getMerkleProof/privacy_getMerkleProofByCommitmentnow route through the runtime API: O(1) index lookup viaCommitmentToLeafIndex(kills the linear leaf scan) and O(depth) path reads. Root and path resolve at the same block hash — atomicity preserved.MAX_RPC_LEAVEScap and its error removed. Response shape unchanged — no client (ts-sdk / app / explorer) changes required.Runtime:
spec_version3 → 4 (consensus-affecting: new storage writes + migration).transaction_versionunchanged — no extrinsic signature changes.TryRuntimeAPI (was missing);build.rsskips the Poseidon host-function feature on try-runtime builds so the stock try-runtime CLI can execute the wasm.template/runtime/RUNTIME_VERSIONS.mdloggingRuntimeVersionhistory.Testing
post_upgraderoot check passes. Measured weight: ~3s ref_time with native host functions — the upgrade block runs overweight once (acceptable on a 6s-slot solochain; move to MBM if deployed above ~150k leaves).--steps 50 --repeat 20): leaf-inserting extrinsics now charge the node writes (shield13 → 32 writes; batch inserts dedupe shared ancestors). Known pre-existing gap: theunshieldbench exercises the no-change-note path.Deploy notes