Tier
Tier A · CRITICAL — Gas-efficient stateful aggregation.
Context
contracts/reputation/src/lib.rs compute_score iterates up to MAX_TRADES (200) sequential trades by calling get_trade_by_index + get_trade on the escrow contract for every single index. On a busy mainnet deployment this is ~200 cross-contract calls per compute_score. The score is recomputed from scratch every time, even when only one new trade changed.
Goal
Replace the linear scan with a Merkle-sum tree (MST) maintained by the escrow contract. Each leaf is a trade's (amount, status, timestamp). The root is updated atomically on release / refund / dispute_resolve. The reputation contract then validates a sparse Merkle proof (≤3 hashes) instead of scanning.
Non-goals
No off-chain indexer that feeds the tree (the root must be derivable purely from on-chain state).
No ZK proof for the score — the score is still computed in Solidity/Rust, just over a smaller tree.
No change to the external compute_score(address) API.
Data model
New types in contracts/reputation/src/lib.rs:
- ReputationLeaf: (trade_id_hash, amount, status_bits, counterparty_hash, ledger)
- ScoreProof: (leaf_index, sibling_hashes[..MAX_DEPTH], score_components)
New storage in contracts/escrow/src/lib.rs:
- ReputationRoot(BytesN<32>) — current MST root, updated on terminal trade state changes.
- ReputationLeaf(BytesN<32>) — leaf data for each completed/refunded trade.
Implementation plan
- Add MerkleSumTree module to contracts/escrow/src/lib.rs (or a shared htlc-core crate). Leaf hash = H(amount || status || counterparty_hash || ledger).
- In release, refund, batch_release, resolve_dispute, and fallback_after_timeout, update the MST root after flipping state. Use a helper update_reputation_root(env, trade_id, old_status, new_status, amount).
- Add a new read-only escrow contract method get_reputation_root() -> BytesN<32> and get_reputation_proof(address, max_trades) -> ScoreProof.
- Rewrite contracts/reputation/src/lib.rs compute_score to accept a ScoreProof from the caller (or fetch it via cross-contract call if the caller is the contract itself). Verify the MST path matches ReputationRoot.
- Add compute_score_incremental that only touches new leaves since the last cached score.
- Write contracts/reputation/src/mst_test.rs with randomized insertion/deletion/verification property tests.
Thresholds
- MAX_TRADES can increase to 10,000 because MST verification is O(log n).
- DECAY_TABLE index must be derived from the MST leaf's ledger field, not a global scan.
Acceptance criteria
- compute_score executes in <500k instructions for 10,000 trades (benchmark under cargo test).
- A proof with a single altered leaf fails MST verification.
- Escrow terminal-state transitions still publish the same events; released / refunded / disp_res / disp_exp events are unchanged.
- Existing get_score and get_score_breakdown read methods continue to work; they internally fetch and verify the MST proof.
Related files
- contracts/reputation/src/lib.rs
- contracts/escrow/src/lib.rs
- contracts/htlc-core/src/lib.rs
- contracts/reputation/src/test.rs
- contracts/reputation/src/benchmarks.rs
- packages/shared/src/index.ts
Contributor notes
A Merkle-sum tree is strictly better than a Merkle tree here because score math is additive. Reuse the Htlc trait's terminal-state transition points to keep MST updates atomic. Benchmark before and after — the gas delta is the selling point for mainnet.
Tier
Tier A · CRITICAL — Gas-efficient stateful aggregation.
Context
contracts/reputation/src/lib.rs compute_score iterates up to MAX_TRADES (200) sequential trades by calling get_trade_by_index + get_trade on the escrow contract for every single index. On a busy mainnet deployment this is ~200 cross-contract calls per compute_score. The score is recomputed from scratch every time, even when only one new trade changed.
Goal
Replace the linear scan with a Merkle-sum tree (MST) maintained by the escrow contract. Each leaf is a trade's (amount, status, timestamp). The root is updated atomically on release / refund / dispute_resolve. The reputation contract then validates a sparse Merkle proof (≤3 hashes) instead of scanning.
Non-goals
No off-chain indexer that feeds the tree (the root must be derivable purely from on-chain state).
No ZK proof for the score — the score is still computed in Solidity/Rust, just over a smaller tree.
No change to the external compute_score(address) API.
Data model
New types in contracts/reputation/src/lib.rs:
New storage in contracts/escrow/src/lib.rs:
Implementation plan
Thresholds
Acceptance criteria
Related files
Contributor notes
A Merkle-sum tree is strictly better than a Merkle tree here because score math is additive. Reuse the Htlc trait's terminal-state transition points to keep MST updates atomic. Benchmark before and after — the gas delta is the selling point for mainnet.