Skip to content

bidirectional: target chain from event.caip2_id instead of dest#696

Open
ppca wants to merge 9 commits intodevelopfrom
xiangyi/use_caip2_id_not_dest
Open

bidirectional: target chain from event.caip2_id instead of dest#696
ppca wants to merge 9 commits intodevelopfrom
xiangyi/use_caip2_id_not_dest

Conversation

@ppca
Copy link
Copy Markdown
Contributor

@ppca ppca commented Mar 11, 2026

No description provided.

@ppca ppca requested a review from Copilot March 11, 2026 10:12
@ppca ppca changed the title target chain from event.caip2_id instead of dest bidirectional: target chain from event.caip2_id instead of dest Mar 11, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds Bitcoin as a recognized chain across the chain-signatures stack and introduces CAIP-2/deprecated chain-id parsing helpers to consistently derive target chains for bidirectional events.

Changes:

  • Extend mpc_primitives::Chain with Bitcoin plus associated timing/checkpoint config.
  • Add chain-id metadata + parsing helpers (from_caip2_chain_id, from_deprecated_chain_id) in mpc-crypto KDF and expose equivalent constructors in primitives.
  • Switch bidirectional event target-chain derivation from dest parsing to CAIP-2 parsing; add “bitcoin unsupported” handling in node RPC.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
chain-signatures/primitives/src/lib.rs Adds Chain::Bitcoin, timing/checkpoint defaults, and chain-id parsing constructors bridging to mpc_crypto::kdf::Chain.
chain-signatures/node/src/stream/ops.rs Introduces SignBidirectionalEvent::target_chain() (CAIP-2 based) and uses it during bidirectional respond processing.
chain-signatures/node/src/rpc.rs Adds Bitcoin match arms with “unsupported” behavior in publish flow and client selection.
chain-signatures/node/src/protocol/signature.rs Updates logging to reference event.target_chain() for bidirectional requests.
chain-signatures/crypto/src/kdf.rs Refactors chain-id metadata, adds CAIP-2/deprecated chain-id parsing helpers, and derives PartialEq/Eq for Chain.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

@ppca ppca requested a review from Copilot March 11, 2026 11:01
@ppca ppca force-pushed the xiangyi/use_caip2_id_not_dest branch from 920b7a3 to 7361463 Compare March 11, 2026 11:05
@ppca ppca force-pushed the xiangyi/use_caip2_id_not_dest branch from 7361463 to 706c370 Compare March 11, 2026 11:06
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

.find(|chain| chain.deprecated_chain_id() == chain_id)
}
}

Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New parsing helpers from_caip2_chain_id / from_deprecated_chain_id were added but aren’t covered by the existing unit tests in this module. Adding tests for expected mappings (and a negative case) would help prevent accidental regressions in chain-id strings and ensure the ALL list stays in sync with the enum variants.

Suggested change
#[cfg(test)]
mod tests {
use super::Chain;
#[test]
fn caip2_chain_id_mappings_are_correct() {
// Positive cases: ensure that each known CAIP-2 chain id maps back to the expected Chain.
assert_eq!(Chain::from_caip2_chain_id("near:mainnet"), Some(Chain::Near));
assert_eq!(Chain::from_caip2_chain_id("eip155:1"), Some(Chain::Ethereum));
assert_eq!(
Chain::from_caip2_chain_id("solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"),
Some(Chain::Solana)
);
assert_eq!(
Chain::from_caip2_chain_id("bip122:000000000019d6689c085ae165831e93"),
Some(Chain::Bitcoin)
);
assert_eq!(
Chain::from_caip2_chain_id("polkadot:2034"),
Some(Chain::Hydration)
);
// Negative case: unknown CAIP-2 chain id must not map to any Chain.
assert_eq!(Chain::from_caip2_chain_id("unknown:chain"), None);
}
#[test]
fn deprecated_chain_id_mappings_are_correct() {
// Positive cases: ensure that each known deprecated chain id maps back to the expected Chain.
assert_eq!(Chain::from_deprecated_chain_id("0x18d"), Some(Chain::Near));
assert_eq!(Chain::from_deprecated_chain_id("0x1"), Some(Chain::Ethereum));
assert_eq!(
Chain::from_deprecated_chain_id("0x800001f5"),
Some(Chain::Solana)
);
assert_eq!(
Chain::from_deprecated_chain_id("bip122:000000000019d6689c085ae165831e93"),
Some(Chain::Bitcoin)
);
assert_eq!(
Chain::from_deprecated_chain_id("polkadot:2034"),
Some(Chain::Hydration)
);
// Negative case: unknown deprecated chain id must not map to any Chain.
assert_eq!(Chain::from_deprecated_chain_id("0xdeadbeef"), None);
}
}

Copilot uses AI. Check for mistakes.
Comment on lines +131 to +138
pub fn target_chain(&self) -> anyhow::Result<Chain> {
let event_caip2_id = self.caip2_id();
Chain::from_caip2_chain_id(&event_caip2_id).ok_or_else(|| {
anyhow::anyhow!(
"unable to parse target chain from event caip2_id field: {event_caip2_id}"
)
})
}
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SignBidirectionalEvent::target_chain currently clones the caip2_id String via self.caip2_id() just to parse it. This adds an avoidable allocation on a hot path (request processing). Consider returning a borrowed &str/Cow<'_, str> from caip2_id() (or matching on self in target_chain and borrowing the inner field) so parsing can operate on a reference.

Copilot uses AI. Check for mistakes.
@ppca ppca marked this pull request as ready for review March 16, 2026 04:35
@ppca ppca requested review from ChaoticTempest and volovyks March 16, 2026 04:35
Copy link
Copy Markdown
Contributor

@volovyks volovyks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not forget about docs. I was expecting that this PR would be mostly about documenting struct fields and flows.

}
}

pub fn target_chain(&self) -> anyhow::Result<Chain> {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returning Result<> here should not be required if we will parse string -> Cahin enum when constructing this Event.
It will reduce complexity (like event.target_chain()?;).

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 8 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +131 to +133
pub fn target_chain(&self) -> Chain {
// we can directly unwrap because we've checked that the chain id is valid during event deserialization in the indexer
Chain::from_caip2_chain_id(&self.caip2_id()).unwrap()
Comment on lines +244 to +256
pub fn from_caip2_chain_id(chain_id: &str) -> Result<Self, ChainFromError> {
Self::iter()
.into_iter()
.find(|chain| chain.caip2_chain_id() == chain_id)
.ok_or_else(|| ChainFromError::UnknownCaip2Id(chain_id.to_string()))
}

pub fn from_deprecated_chain_id(chain_id: &str) -> Result<Self, ChainFromError> {
Self::iter()
.into_iter()
.find(|chain| chain.deprecated_chain_id() == chain_id)
.ok_or_else(|| ChainFromError::UnknownDeprecatedId(chain_id.to_string()))
}
Comment on lines +261 to +266
/// The program ID of the Solana program that emitted this event.
///
/// Used by off-chain services (e.g., relayers, indexers) to filter and
/// verify events from the correct program.
///
/// MUST be provided and MUST match the deployed program ID.
@ppca ppca requested a review from volovyks March 17, 2026 10:14
Copy link
Copy Markdown
Contributor

@volovyks volovyks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we could rely a bit less on Copilot and address the suggestions from it before requesting a review 🙂

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 8 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +131 to +134
pub fn target_chain(&self) -> Result<Chain, mpc_primitives::ChainFromError> {
// we can directly unwrap because we've checked that the chain id is valid during event deserialization in the indexer
Chain::from_caip2_chain_id(&self.caip2_id())
}
Comment on lines +244 to +249
pub fn from_caip2_chain_id(chain_id: &str) -> Result<Self, ChainFromError> {
Self::iter()
.into_iter()
.find(|chain| chain.caip2_chain_id() == chain_id)
.ok_or_else(|| ChainFromError::UnknownCaip2Id(chain_id.to_string()))
}
Comment on lines +261 to +265
/// The program ID of the Solana program that emitted this event.
///
/// Used by MPC service to filter and verify events from the correct program.
///
/// MUST match the deployed program ID.
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.

3 participants