feat: implement related contracts mechanism (depth=1)#3650
feat: implement related contracts mechanism (depth=1)#3650
Conversation
|
The existing Rule Review: One INFO finding — duplicate safety checksRules checked: WarningsNone. Info
Everything else looks well-implemented:
Advisory review against |
| } | ||
| continue; | ||
| // Validate with depth=1 related contract resolution | ||
| let result = self |
There was a problem hiding this comment.
should document here for future reference to protect against depth requests
There was a problem hiding this comment.
Added a detailed depth protection comment at this call site documenting all the safety mechanisms: depth=1 limit, one-round-only, self-reference rejection, max 10 contracts, and timeout. Points to the constants for reference.
[AI-assisted - Claude]
When a contract's validate_state returns RequestRelated(ids), the executor now fetches those contracts locally and re-calls validate_state with the populated RelatedContracts map. This enables contracts to validate their state against other contracts' state (e.g., membership gates). Design decisions: - Depth=1 only: related contracts cannot request their own related contracts - One round: if second validate_state also returns RequestRelated, it's an error - Limits: max 10 related contracts, 10s timeout, no self-reference - Network inbound path deferred (sending node already validated) Key changes: - Add fetch_related_for_validation helper with abuse prevention - Simplify verify_and_store_contract from 100-iteration loop to depth=1 flow - Fix 4 code paths: new PUT, post-merge, perform_contract_put, get_updated_state - Extend MockWasmRuntime with configurable validate_overrides for testing - Add 10 unit tests covering success, rejection, and edge cases Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove dead code paths for RequestRelated after fetch_related_for_validation (which resolves it internally), consolidate validation_error helper, clean up test comments, and remove redundant .into_owned() call. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace unreachable!() with proper error returns (no panics in production) - Add init_tracker.fail_initialization cleanup when validation errors - Merge initial_related with fetched data on retry call - Replace unreachable! in validation_error with defensive error logging - Fix docs inconsistency about network inbound behavior - Add boundary test (exactly 10 related contracts) - Add multi-contract test (3 distinct related contracts) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add detailed comment at verify_and_store_contract documenting all depth=1 safety mechanisms per Nacho's review feedback. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Codex review found two issues: P1: fetch_related_for_validation only did local lookups, breaking first-time publishes that depend on contracts not yet stored locally. Added fetch_related_for_validation_network on Executor<Runtime> that uses local_state_or_from_network. The Executor<Runtime>-specific paths (verify_and_store_contract, perform_contract_put, get_updated_state) now use this network-aware version while the bridged generic impl keeps local-only lookups. P2: validation_error always returned ContractError::Update, but PUT paths should return StdContractError::Put. Added validation_error_put for PUT paths to preserve correct error semantics. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
02ab734 to
2d1542f
Compare
Problem
Related contracts allow a contract's
validate_stateto returnRequestRelated(contract_ids)requesting other contracts' state for validation. This enables use cases like River room membership gates (contract B validates against contract A's state) and Bitcoin header verification. The mechanism was partially wired up but had broken code paths, no safety limits, no real tests, and a buggy recursive validation flow withDEPENDENCY_CYCLE_LIMIT_GUARD = 100.Approach
Depth=1 only, one round. When
validate_statereturnsRequestRelated(ids), we fetch those contracts locally and re-callvalidate_stateexactly once. If the second call also returnsRequestRelated, that's an error. This prevents amplification attacks where a malicious contract requests new contracts on every retry.Key design decisions:
fetch_related_for_validationhelper useslookup_key+state_store.get()(available on all executor types). Network fetch happens automatically via GET auto-subscribe when contracts are first retrievedRequestRelatedstill errors — the sending node already validated. Filing a separate issue for thisAbuse prevention:
RequestRelated(vec![])rejectedRequestRelatedafter providing data → error (depth>1 not supported)Changes
fetch_related_for_validationhelper — shared validation logic with all safety checksverify_and_store_contract— replaced 100-iteration loop with clean depth=1 flowperform_contract_put,get_updated_stateMockWasmRuntime—ValidateOverrideenum enables per-contract validation behavior in tests.claude/rules/contracts.md— documented depth=1 design decisionsTesting
10 new unit tests covering all paths and edge cases:
test_put_with_related_succeedstest_put_with_gate_closedtest_put_self_reference_rejectedtest_put_too_many_related_rejectedtest_put_missing_related_errorstest_depth_exceeded_rejectedAlwaysRequestRelated→ depth>1 errortest_empty_request_relatedtest_duplicate_ids_dedupedtest_existing_contract_put_with_relatedtest_update_with_related_succeedsFull test suite: 2108 passed, 0 failures, clippy clean, fmt clean.
[AI-assisted - Claude]