Skip to content

Checkpoint count bound to published CIDs with an on-chain Merkle root - #68

Open
MarouaBoud wants to merge 7 commits into
mainfrom
claude/checkpoint-binding
Open

MarouaBoud wants to merge 7 commits into
mainfrom
claude/checkpoint-binding

Conversation

@MarouaBoud

Copy link
Copy Markdown
Member

Builds on #67; the diff reduces to the commits below once #67 is merged.

What changed

  • commitCheckpointBatch(bytes32 taskId, bytes32[] cids, bytes32 schemaHash) replaces the (count, merkleRoot, latestCID) form. The batch size is cids.length (1–1,000), the last CID becomes latestCheckpointCID, and the batch's Merkle root is computed on-chain: leaf i = keccak256(abi.encodePacked(cids[i], i)), pairs hashed with OpenZeppelin's commutative keccak256, an odd last node promoted. The checkpoint count that weights settlement therefore equals the number of CIDs published (H-5). The contract commits to the CIDs; it does not verify the content they reference.
  • verifyCheckpoint rejects leafIndex >= batchSize. A leaf and an internal node are both keccak256 of 64 bytes, so an internal node's sorted children could otherwise be presented as (cid, leafIndex) and verify as a checkpoint; test_InternalNodeAsLeaf_NotProvable reproduces this against the previous code.
  • Same changes in CairnCoreUpgradeable. Existing tests updated to the new signature; tests asserting caller-supplied roots now compare against an independently written reference root.

Verification

  • forge test: 458 passing, including CheckpointBinding.t.sol (count bounds, root parity fuzzed over 1–64 CIDs against a reference implementation, every leaf provable for sizes 2/5/8/13, unpublished CIDs and out-of-range indices not provable).
  • Coverage (lines): CairnCore 95.79%.
  • Gas (GasBenchmark.t.sol, execution only): 160,587 for 1 CID, 174,035 for 10, 228,381 for 50, 1,633,412 for 1,000 — about 1.4k gas per checkpoint over a ~159k base (previously ~158.5k independent of count). Calldata adds 512 gas per CID plus Base's L1 data fee.

MarouaBoud and others added 7 commits September 28, 2026 21:35
Co-Authored-By: Lagartha <ionanova22@gmail.com>
…ted cost

detectFailure records heartbeat-timeout or deadline-expiry evidence;
reportFailure records agent-attested evidence; reportCost feeds
B = (escrow - costAccrued) / escrow into both routers. Checkpoint count
no longer sets the failure class.

Co-Authored-By: Lagartha <ionanova22@gmail.com>
…detection

Co-Authored-By: Lagartha <ionanova22@gmail.com>
…hain root

commitCheckpointBatch takes the batch's CIDs; the count is their number
and the Merkle root is computed from them, so the count that weights
settlement cannot exceed what was committed (H-5).

Co-Authored-By: Lagartha <ionanova22@gmail.com>
Co-Authored-By: Lagartha <ionanova22@gmail.com>
An internal Merkle node's sorted children form the same 64-byte preimage
as a (cid, index) leaf, so without an index bound an internal node could
verify as a checkpoint. The index must now be below the batch size.

Co-Authored-By: Lagartha <ionanova22@gmail.com>
…uring recovery

Co-Authored-By: Lagartha <ionanova22@gmail.com>

This branch has not been deployed

No deployments
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.

1 participant