From dd266f701d4f095977236df8347bad294beee15c Mon Sep 17 00:00:00 2001 From: Xiangyi Zheng Date: Wed, 19 Nov 2025 13:06:19 +0800 Subject: [PATCH 1/5] release 1.11.0 (#596) Co-authored-by: Xiangyi Zheng --- Cargo.lock | 10 +++++----- Cargo.toml | 2 +- infra/scripts/generate_keys/Cargo.lock | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ee03404e..2f80744a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7379,7 +7379,7 @@ checksum = "1fafa6961cabd9c63bcd77a45d7e3b7f3b552b70417831fb0f56db717e72407e" [[package]] name = "mpc-contract" -version = "1.10.0" +version = "1.11.0" dependencies = [ "anyhow", "borsh 1.5.7", @@ -7401,7 +7401,7 @@ dependencies = [ [[package]] name = "mpc-crypto" -version = "1.10.0" +version = "1.11.0" dependencies = [ "alloy", "anyhow", @@ -7414,7 +7414,7 @@ dependencies = [ [[package]] name = "mpc-keys" -version = "1.10.0" +version = "1.11.0" dependencies = [ "borsh 1.5.7", "hex", @@ -7425,7 +7425,7 @@ dependencies = [ [[package]] name = "mpc-node" -version = "1.10.0" +version = "1.11.0" dependencies = [ "alloy", "alloy-dyn-abi", @@ -7504,7 +7504,7 @@ dependencies = [ [[package]] name = "mpc-primitives" -version = "1.10.0" +version = "1.11.0" dependencies = [ "borsh 1.5.7", "ciborium", diff --git a/Cargo.toml b/Cargo.toml index d014082f..1d859eeb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ exclude = ["infra/scripts/generate_keys"] resolver = "2" [workspace.package] -version = "1.10.0" +version = "1.11.0" [workspace.dependencies] alloy = { version = "=1.0.38", features = ["contract", "json"] } diff --git a/infra/scripts/generate_keys/Cargo.lock b/infra/scripts/generate_keys/Cargo.lock index b367da69..804bb754 100644 --- a/infra/scripts/generate_keys/Cargo.lock +++ b/infra/scripts/generate_keys/Cargo.lock @@ -2091,7 +2091,7 @@ dependencies = [ [[package]] name = "mpc-keys" -version = "1.9.1" +version = "1.11.0" dependencies = [ "borsh", "hex", From 9120780a08a041896675afbfe496d5196f44d64d Mon Sep 17 00:00:00 2001 From: Phuong Nguyen Date: Wed, 19 Nov 2025 18:40:11 -0800 Subject: [PATCH 2/5] Guard against empty triples/presignatures on sync (#601) --- chain-signatures/node/src/protocol/sync/mod.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/chain-signatures/node/src/protocol/sync/mod.rs b/chain-signatures/node/src/protocol/sync/mod.rs index ceef3e49..7bc67682 100644 --- a/chain-signatures/node/src/protocol/sync/mod.rs +++ b/chain-signatures/node/src/protocol/sync/mod.rs @@ -262,10 +262,18 @@ impl SyncUpdate { async fn process(self, triples: TripleStorage, presignatures: PresignatureStorage) { let start = Instant::now(); - let outdated_triples = triples.remove_outdated(self.from, &self.triples).await; - let outdated_presignatures = presignatures - .remove_outdated(self.from, &self.presignatures) - .await; + let outdated_triples = if !self.triples.is_empty() { + triples.remove_outdated(self.from, &self.triples).await + } else { + Vec::new() + }; + let outdated_presignatures = if !self.presignatures.is_empty() { + presignatures + .remove_outdated(self.from, &self.presignatures) + .await + } else { + Vec::new() + }; if !outdated_triples.is_empty() || !outdated_presignatures.is_empty() { tracing::info!( From 146df9480442e40359064fd6d8a78be681ebce62 Mon Sep 17 00:00:00 2001 From: Phuong Nguyen Date: Mon, 1 Dec 2025 18:16:22 -0800 Subject: [PATCH 3/5] feat: add protocol versioning (#606) * Add protocol versioning * Fix comment --- chain-signatures/node/src/lib.rs | 2 + chain-signatures/node/src/mesh/connection.rs | 19 +++++++-- chain-signatures/node/src/mesh/mod.rs | 45 ++++++++++++++++++++ chain-signatures/node/src/node_client.rs | 5 +-- chain-signatures/node/src/web/mock.rs | 26 +++++++++-- chain-signatures/node/src/web/mod.rs | 14 +++++- 6 files changed, 98 insertions(+), 13 deletions(-) diff --git a/chain-signatures/node/src/lib.rs b/chain-signatures/node/src/lib.rs index 35e32b3a..8afd629c 100644 --- a/chain-signatures/node/src/lib.rs +++ b/chain-signatures/node/src/lib.rs @@ -1,3 +1,5 @@ +pub const PROTOCOL_VERSION: u64 = 1; + pub mod backlog; pub mod checkpoint_consensus; pub mod cli; diff --git a/chain-signatures/node/src/mesh/connection.rs b/chain-signatures/node/src/mesh/connection.rs index c643abe1..9ed61ed5 100644 --- a/chain-signatures/node/src/mesh/connection.rs +++ b/chain-signatures/node/src/mesh/connection.rs @@ -106,7 +106,7 @@ impl NodeConnection { }); } _ = interval.tick() => { - let status = match client.status(&url).await { + let resp = match client.status(&url).await { Ok(status) => status, Err(err) => { tracing::warn!(?node, ?err, "checking /status failed"); @@ -117,10 +117,21 @@ impl NodeConnection { } }; - // note: borrowing and sending later on `status_tx` can potentially deadlock, - // but since we are copying the status, this is not the case. Change this carefully. + if resp.protocol_version != crate::PROTOCOL_VERSION { + tracing::warn!( + ?node, + our_version = crate::PROTOCOL_VERSION, + peer_version = resp.protocol_version, + "protocol version mismatch" + ); + status_tx.send_if_modified(|(status, _)| { + std::mem::replace(status, NodeStatus::Offline) != NodeStatus::Offline + }); + continue; + } + let old_status = status_tx.borrow().0; - let mut new_status = match status { + let mut new_status = match resp.status { OtherNodeStatus::Running { .. } => NodeStatus::Active, OtherNodeStatus::Resharing { .. } | OtherNodeStatus::Generating { .. } diff --git a/chain-signatures/node/src/mesh/mod.rs b/chain-signatures/node/src/mesh/mod.rs index 80422135..c890f6dd 100644 --- a/chain-signatures/node/src/mesh/mod.rs +++ b/chain-signatures/node/src/mesh/mod.rs @@ -202,6 +202,23 @@ mod tests { const PING_INTERVAL: Duration = Duration::from_millis(10); + async fn expect_status( + watcher: &mut connection::ConnectionWatcher, + participant: Participant, + expected: NodeStatus, + ) { + for _ in 0..20 { + if let Ok((p, status, _info)) = + tokio::time::timeout(Duration::from_millis(500), watcher.next()).await + { + if p == participant && status == expected { + return; + } + } + } + panic!("timed out waiting for {participant:?} to become {expected:?}"); + } + #[test(tokio::test)] async fn test_pool_update() { let num_nodes = 3; @@ -440,4 +457,32 @@ mod tests { mesh_task.abort(); } + + #[test(tokio::test)] + async fn test_protocol_version_mismatch_marks_offline() { + let mut servers = MockServers::run(2).await; + let participants = servers.participants(); + let my_id = servers[0].account_id().clone(); + + let mut pool = Pool::new(&servers.client(), &my_id, PING_INTERVAL); + let mut watcher = pool.watch(); + pool.connect_nodes(&participants, &mut HashSet::new()).await; + + let remote_id = servers[1].id(); + + expect_status(&mut watcher, remote_id, NodeStatus::Syncing).await; + pool.report_node_synced(remote_id).await; + expect_status(&mut watcher, remote_id, NodeStatus::Active).await; + + servers[1].set_protocol_version(None).await; + expect_status(&mut watcher, remote_id, NodeStatus::Offline).await; + + servers[1].make_online().await; + expect_status(&mut watcher, remote_id, NodeStatus::Syncing).await; + pool.report_node_synced(remote_id).await; + expect_status(&mut watcher, remote_id, NodeStatus::Active).await; + + servers[1].set_protocol_version(Some(0)).await; + expect_status(&mut watcher, remote_id, NodeStatus::Offline).await; + } } diff --git a/chain-signatures/node/src/node_client.rs b/chain-signatures/node/src/node_client.rs index ec3673e8..9157f934 100644 --- a/chain-signatures/node/src/node_client.rs +++ b/chain-signatures/node/src/node_client.rs @@ -1,9 +1,8 @@ use crate::backlog::Checkpoint; use crate::protocol::message::cbor_to_bytes; -use crate::protocol::state::NodeStatus; use crate::protocol::sync::SyncUpdate; use crate::protocol::Chain; -use crate::web::StateView; +use crate::web::{StateView, StatusResponse}; use hyper::StatusCode; use mpc_keys::hpke::Ciphered; @@ -152,7 +151,7 @@ impl NodeClient { Ok(resp.json::().await?) } - pub async fn status(&self, base: impl IntoUrl) -> Result { + pub async fn status(&self, base: impl IntoUrl) -> Result { let mut url = base.into_url()?; url.set_path("status"); diff --git a/chain-signatures/node/src/web/mock.rs b/chain-signatures/node/src/web/mock.rs index 6f47afef..1371c2ee 100644 --- a/chain-signatures/node/src/web/mock.rs +++ b/chain-signatures/node/src/web/mock.rs @@ -5,6 +5,8 @@ use near_sdk::AccountId; use crate::{ node_client::NodeClient, protocol::{contract::primitives::Participants, state::NodeStatus, ParticipantInfo}, + web::StatusResponse, + PROTOCOL_VERSION, }; use super::StateView; @@ -77,11 +79,15 @@ impl MockServer { } pub async fn make_online(&mut self) { + self.set_protocol_version(Some(PROTOCOL_VERSION)).await; + } + + pub async fn set_protocol_version(&mut self, protocol_version: Option) { self.server .mock("GET", "/status") .with_status(201) .with_header("content-type", "application/json") - .with_body(default_status_body(self.id)) + .with_body(status_body(self.id, protocol_version)) .create_async() .await; } @@ -166,11 +172,23 @@ fn default_state_body() -> Vec { } fn default_status_body(id: u32) -> Vec { - serde_json::to_vec(&NodeStatus::Running { + status_body(id, Some(PROTOCOL_VERSION)) +} + +fn status_body(id: u32, version: Option) -> Vec { + let status = NodeStatus::Running { me: Participant::from(id), participants: vec![Participant::from(0)], ongoing_triple_gen: 0, ongoing_presignature_gen: 0, - }) - .unwrap() + }; + + match version { + Some(protocol_version) => serde_json::to_vec(&StatusResponse { + protocol_version, + status: status.clone(), + }) + .unwrap(), + None => serde_json::to_vec(&status).unwrap(), + } } diff --git a/chain-signatures/node/src/web/mod.rs b/chain-signatures/node/src/web/mod.rs index 9731caa6..29919d2a 100644 --- a/chain-signatures/node/src/web/mod.rs +++ b/chain-signatures/node/src/web/mod.rs @@ -214,9 +214,19 @@ async fn state(Extension(web): Extension>) -> Result>) -> Json { - Json(web.node.status()) +async fn status(Extension(web): Extension>) -> Json { + Json(StatusResponse { + status: web.node.status(), + protocol_version: crate::PROTOCOL_VERSION, + }) } #[tracing::instrument(level = "debug", skip_all)] From edcb67c7b67b682600571c7e992759e354a330ca Mon Sep 17 00:00:00 2001 From: Xiangyi Zheng Date: Wed, 3 Dec 2025 09:39:00 +0800 Subject: [PATCH 4/5] release 1.12.0 --- Cargo.lock | 10 +++++----- Cargo.toml | 2 +- infra/scripts/generate_keys/Cargo.lock | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2f80744a..e55cec3c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7379,7 +7379,7 @@ checksum = "1fafa6961cabd9c63bcd77a45d7e3b7f3b552b70417831fb0f56db717e72407e" [[package]] name = "mpc-contract" -version = "1.11.0" +version = "1.12.0" dependencies = [ "anyhow", "borsh 1.5.7", @@ -7401,7 +7401,7 @@ dependencies = [ [[package]] name = "mpc-crypto" -version = "1.11.0" +version = "1.12.0" dependencies = [ "alloy", "anyhow", @@ -7414,7 +7414,7 @@ dependencies = [ [[package]] name = "mpc-keys" -version = "1.11.0" +version = "1.12.0" dependencies = [ "borsh 1.5.7", "hex", @@ -7425,7 +7425,7 @@ dependencies = [ [[package]] name = "mpc-node" -version = "1.11.0" +version = "1.12.0" dependencies = [ "alloy", "alloy-dyn-abi", @@ -7504,7 +7504,7 @@ dependencies = [ [[package]] name = "mpc-primitives" -version = "1.11.0" +version = "1.12.0" dependencies = [ "borsh 1.5.7", "ciborium", diff --git a/Cargo.toml b/Cargo.toml index 1d859eeb..fa0081fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ exclude = ["infra/scripts/generate_keys"] resolver = "2" [workspace.package] -version = "1.11.0" +version = "1.12.0" [workspace.dependencies] alloy = { version = "=1.0.38", features = ["contract", "json"] } diff --git a/infra/scripts/generate_keys/Cargo.lock b/infra/scripts/generate_keys/Cargo.lock index 804bb754..d4d2eeb7 100644 --- a/infra/scripts/generate_keys/Cargo.lock +++ b/infra/scripts/generate_keys/Cargo.lock @@ -2091,7 +2091,7 @@ dependencies = [ [[package]] name = "mpc-keys" -version = "1.11.0" +version = "1.12.0" dependencies = [ "borsh", "hex", From 02cd25e4493b064073988eae95853eb188ba2cc3 Mon Sep 17 00:00:00 2001 From: Xiangyi Zheng Date: Wed, 3 Dec 2025 10:03:39 +0800 Subject: [PATCH 5/5] 1.11.1 --- Cargo.lock | 10 +++++----- Cargo.toml | 2 +- infra/scripts/generate_keys/Cargo.lock | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e55cec3c..db42c0c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7379,7 +7379,7 @@ checksum = "1fafa6961cabd9c63bcd77a45d7e3b7f3b552b70417831fb0f56db717e72407e" [[package]] name = "mpc-contract" -version = "1.12.0" +version = "1.11.1" dependencies = [ "anyhow", "borsh 1.5.7", @@ -7401,7 +7401,7 @@ dependencies = [ [[package]] name = "mpc-crypto" -version = "1.12.0" +version = "1.11.1" dependencies = [ "alloy", "anyhow", @@ -7414,7 +7414,7 @@ dependencies = [ [[package]] name = "mpc-keys" -version = "1.12.0" +version = "1.11.1" dependencies = [ "borsh 1.5.7", "hex", @@ -7425,7 +7425,7 @@ dependencies = [ [[package]] name = "mpc-node" -version = "1.12.0" +version = "1.11.1" dependencies = [ "alloy", "alloy-dyn-abi", @@ -7504,7 +7504,7 @@ dependencies = [ [[package]] name = "mpc-primitives" -version = "1.12.0" +version = "1.11.1" dependencies = [ "borsh 1.5.7", "ciborium", diff --git a/Cargo.toml b/Cargo.toml index fa0081fb..6f46386f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ exclude = ["infra/scripts/generate_keys"] resolver = "2" [workspace.package] -version = "1.12.0" +version = "1.11.1" [workspace.dependencies] alloy = { version = "=1.0.38", features = ["contract", "json"] } diff --git a/infra/scripts/generate_keys/Cargo.lock b/infra/scripts/generate_keys/Cargo.lock index d4d2eeb7..ccbf75aa 100644 --- a/infra/scripts/generate_keys/Cargo.lock +++ b/infra/scripts/generate_keys/Cargo.lock @@ -2091,7 +2091,7 @@ dependencies = [ [[package]] name = "mpc-keys" -version = "1.12.0" +version = "1.11.1" dependencies = [ "borsh", "hex",