feat: add Protocol enum in DomainConfig#3085
Conversation
934c7c3 to
76dac2d
Compare
Review - PR #3085: Add Protocol enumReviewed the full diff. This is a well-structured intermediate step for separating protocol from curve. Potential issues to consider:
Everything else (Borsh migration, JSON backward compat via ✅ Approved — the issues above are non-blocking given this is an intermediate step, but the |
76dac2d to
dffe2e9
Compare
0cfc4e1 to
46f9e95
Compare
46f9e95 to
1cccaff
Compare
Code ReviewNo critical issues found. This is a clean, well-structured intermediate step for adding the Verified:
The observations from the prior review (lossy ✅ Approved |
There was a problem hiding this comment.
Pull request overview
This PR introduces a new Protocol enum into the shared domain types and threads it through DomainConfig, contract migration code, and tests/examples so the codebase can start distinguishing protocol from curve ahead of the larger domain-separation refactor.
Changes:
- Added
Protocoltompc_primitives::domain, plus conversions betweenProtocolandCurve. - Extended
DomainConfigto carryprotocol, including JSON compatibility handling and v3.9.1 state migration logic. - Updated contract/node/e2e tests, sample configs, snapshots, and docs to populate the new field.
Reviewed changes
Copilot reviewed 34 out of 34 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| docs/localnet/args/add_domain.json | Updates localnet example domain payloads to include protocol. |
| crates/primitives/src/domain.rs | Adds Protocol enum, conversions, and unit tests. |
| crates/node/src/tests/resharing.rs | Fills protocol in resharing tests. |
| crates/node/src/tests/onboarding.rs | Fills protocol in onboarding tests. |
| crates/node/src/tests/multidomain.rs | Fills protocol in multidomain tests. |
| crates/node/src/tests/faulty.rs | Fills protocol in faulty-cluster tests. |
| crates/node/src/tests/changing_participant_details.rs | Fills protocol in participant-change tests. |
| crates/node/src/tests/basic_cluster.rs | Fills protocol in basic cluster tests. |
| crates/node/src/key_events.rs | Fills protocol in key event tests. |
| crates/near-mpc-contract-interface/src/types/state.rs | Adds protocol to DomainConfig with JSON compat deserialization. |
| crates/near-mpc-contract-interface/src/lib.rs | Re-exports Protocol from public interface types. |
| crates/e2e-tests/tests/request_lifecycle.rs | Fills protocol in request lifecycle test config. |
| crates/e2e-tests/tests/request_during_resharing.rs | Fills protocol in resharing request tests. |
| crates/e2e-tests/tests/parallel_sign_calls.rs | Fills protocol in parallel request test config. |
| crates/e2e-tests/tests/key_resharing.rs | Fills protocol in key resharing tests. |
| crates/e2e-tests/tests/foreign_chain_tx_validation.rs | Fills protocol in foreign-tx validation setup. |
| crates/e2e-tests/src/cluster.rs | Adds default protocols to cluster domain defaults. |
| crates/devnet/src/mpc.rs | Populates protocol when building add-domain proposals. |
| crates/contract/tests/snapshots/abi__abi_has_not_changed.snap | Updates ABI snapshot for new protocol field/type. |
| crates/contract/tests/sandbox/vote.rs | Fills protocol in sandbox vote tests. |
| crates/contract/tests/sandbox/upgrade_to_current_contract.rs | Fills protocol in upgrade sandbox tests. |
| crates/contract/tests/sandbox/update_votes_cleanup_after_resharing.rs | Fills protocol in vote-cleanup test data. |
| crates/contract/tests/sandbox/participants_gas.rs | Fills protocol in gas-measurement setup. |
| crates/contract/tests/sandbox/common.rs | Fills protocol across shared sandbox builders/helpers. |
| crates/contract/tests/inprocess/attestation_submission.rs | Fills protocol in in-process attestation tests. |
| crates/contract/src/v3_9_1_state.rs | Adds legacy-domain migration shims for old on-chain state. |
| crates/contract/src/state/running.rs | Updates running-state tests for the new field. |
| crates/contract/src/snapshots/mpc_contract__tests__mpc_contract_borsh_schema_has_not_changed.snap | Updates Borsh schema snapshot for Protocol. |
| crates/contract/src/primitives/test_utils.rs | Generates test domains with protocol. |
| crates/contract/src/primitives/domain.rs | Adds curve/protocol consistency validation and updates registry/test helpers. |
| crates/contract/src/lib.rs | Updates contract tests to construct domains with protocol. |
| crates/contract/src/errors.rs | Adds error variant for inconsistent curve/protocol pairs. |
| crates/contract/README.md | Updates contract docs/examples to include protocol. |
| crates/backup-cli/assets/contract_state.json | Updates sample backup state with protocol. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| let mut new_registry = self.clone(); | ||
| for domain in domains { | ||
| let new_domain_id = new_registry.add_domain(domain.curve, domain.purpose); | ||
| validate_curve_protocol_consistency(&domain)?; |
There was a problem hiding this comment.
Makes sense, but better to do it inside the curve protocol consistency
| #[serde(from = "DomainConfigCompat")] | ||
| pub struct DomainConfig { | ||
| pub id: DomainId, | ||
| pub curve: Curve, | ||
| pub protocol: Protocol, | ||
| pub purpose: DomainPurpose, | ||
| } | ||
|
|
||
| // `Deserialize` is implemented manually via this compat struct so that JSON | ||
| // emitted by older contracts (pre-`protocol` field) still deserializes: | ||
| // the missing `protocol` is inferred from `curve`. | ||
| #[derive(Deserialize)] | ||
| struct DomainConfigCompat { |
There was a problem hiding this comment.
I think this is fine, as the compact struct is just transitional, to be removed in the next release
| /// Validates that `domain.curve` matches the curve derived from | ||
| /// `domain.protocol`. Once dispatch is rewired to read `protocol` directly, | ||
| /// every entry point must reject inconsistent pairs so that stored state is | ||
| /// authoritative. | ||
| /// | ||
| /// The legacy `Curve::V2Secp256k1` value is accepted as a stand-in for | ||
| /// `(Secp256k1, DamgardEtAl)`. | ||
| // TODO(#2442): drop the V2Secp256k1 carve-out once that variant is removed | ||
| // from `Curve` in the next PR. | ||
| pub fn validate_curve_protocol_consistency(domain: &DomainConfig) -> Result<(), Error> { | ||
| let expected = Curve::from(domain.protocol); | ||
| let consistent = domain.curve == expected | ||
| || (domain.curve == Curve::V2Secp256k1 && domain.protocol == Protocol::DamgardEtAl); | ||
| if !consistent { | ||
| return Err(DomainError::InconsistentCurveProtocol { | ||
| curve: domain.curve, | ||
| protocol: domain.protocol, | ||
| expected, | ||
| } | ||
| .into()); | ||
| } | ||
| Ok(()) | ||
| } | ||
|
|
There was a problem hiding this comment.
Small suggestion, not blocking — I’m not too familiar with this part of the code, but could we drop curve from DomainConfig entirely and just keep protocol, exposing curve as a derived accessor like domain.curve()?
IIUC, every protocol already maps to exactly one curve, so validate_curve_protocol_consistency and InconsistentCurveProtocol would just go away (and so would is_valid_curve_for_purpose).
I’m just trying to figure out a more idiomatic way to avoid extra runtime checks for config consistency.
There was a problem hiding this comment.
Yeah I think those would go away according to the design.
There was a problem hiding this comment.
Also related, I will change this a bit to address this comment
224a5f6 to
b383968
Compare
…m-to-mpc-primitives
Closes #3081
Notice that this is an intermediate step for #2673 , where curve and protocol are both in
DomainConfig. In the next PR that duplication will be removed