Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
e5d6db9
do not treat failed syncs as successfull
volovyks Feb 24, 2026
abcbd99
broadcast_sync refactor, bug fixes, dummy storage layer sync processing
volovyks Feb 24, 2026
5840d53
remove sync unit tests (tmp)
volovyks Feb 24, 2026
97bb642
naive prune and bidyrectional sync test implementation
volovyks Feb 26, 2026
a33b416
refactor helpers, remove old sync test
volovyks Feb 26, 2026
aab9394
e2e sync integration test
volovyks Feb 26, 2026
78a46c4
clippy
volovyks Feb 26, 2026
7c5fa6e
Merge branch 'develop' into serhii/sync-to-active-fix
volovyks Feb 27, 2026
432e33b
Merge branch 'develop' into serhii/sync-to-active-fix
volovyks Mar 2, 2026
d5bb994
use Redis to manage holders
volovyks Mar 2, 2026
e5f1dc3
distinguish participands and holders
volovyks Mar 2, 2026
69db15c
clippy
volovyks Mar 2, 2026
c5412ca
Merge branch 'develop' into serhii/sync-to-active-fix
volovyks Mar 3, 2026
d93b951
set holders in tets
volovyks Mar 3, 2026
847e369
return Result on fetch_owned
volovyks Mar 3, 2026
46b1d6d
define type for sync response
volovyks Mar 3, 2026
55a5004
do not recycle presignatures, add a guard on active participants
volovyks Mar 4, 2026
37851a5
Merge branch 'develop' into serhii/sync-to-active-fix
volovyks Mar 5, 2026
0af3865
Merge branch 'develop' into serhii/sync-to-active-fix
volovyks Mar 6, 2026
24c373d
do not add reserved to owned during sync
volovyks Mar 9, 2026
52138a8
Revert "do not recycle presignatures, add a guard on active participa…
volovyks Mar 12, 2026
8dc0c3a
Merge branch 'develop' into serhii/sync-to-active-fix
volovyks Mar 12, 2026
1b207be
Merge branch 'develop' into serhii/sync-to-active-fix
volovyks Mar 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
.direnv
.DS_Store
.idea
.vscode

tmp
*.log
Expand Down
16 changes: 14 additions & 2 deletions chain-signatures/node/src/protocol/presignature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::protocol::contract::primitives::intersect_vec;
use crate::protocol::posit::PositInternalAction;
use crate::protocol::MpcSignProtocol;
use crate::storage::presignature_storage::{PresignatureSlot, PresignatureStorage};
use crate::storage::protocol_storage::ProtocolArtifact;
use crate::storage::triple_storage::{TriplesTaken, TriplesTakenDropper};
use crate::storage::TripleStorage;
use crate::types::{PresignatureProtocol, SecretKeyShare};
Expand Down Expand Up @@ -56,14 +57,18 @@ impl FullPresignatureId {
pub struct Presignature {
pub id: PresignatureId,
pub output: PresignOutput<Secp256k1>,
/// Original protocol participants
pub participants: Vec<Participant>,
/// Nodes still holding their share of the artifact
pub holders: Option<Vec<Participant>>,
Comment on lines +60 to +63
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.

Why do we need to track these separately? Could we not just remove non-holders from the participants list?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We absolutely can. But I wanted to distinguish holders and participants. Mostly for debugging and storage analysis. Also, holders are not a part of the serialized object to avoid deserialization/serailzation of each artifact.

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.

Okay, it just seemed like a lot of extra complexity with the separate tracking in Redis. But if you see enough value in having it, I have no problem with it.

}

impl fmt::Debug for Presignature {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Presignature")
.field("id", &self.id)
.field("participants", &self.participants)
.field("holders", &self.holders)
.finish()
}
}
Expand Down Expand Up @@ -106,6 +111,7 @@ impl<'de> Deserialize<'de> for Presignature {
k: fields.output_k,
sigma: fields.output_sigma,
},
holders: None,
participants: fields.participants,
})
}
Expand Down Expand Up @@ -262,6 +268,7 @@ impl PresignatureGenerator {
id: self.id,
output,
participants: self.participants.clone(),
holders: Some(self.participants.clone()),
};
if self.owner == me {
tracing::info!(id = self.id, "assigning presignature to myself");
Expand Down Expand Up @@ -478,8 +485,12 @@ impl PresignatureSpawner {
};

let pair_id = triples.artifact.id;
// note: only one of the pair's participants is needed since they are the same.
let participants = intersect_vec(&[active, &triples.artifact.triple0.public.participants]);
// use holders (not original participants) since some nodes may have lost the artifact.
let Some(holders) = triples.artifact.holders() else {
tracing::error!(?pair_id, "holders not set on taken triple pair");
return;
};
let participants = intersect_vec(&[active, holders]);
if participants.len() < self.threshold {
tracing::warn!(
?pair_id,
Expand Down Expand Up @@ -875,6 +886,7 @@ mod tests {
sigma: <Secp256k1 as CurveArithmetic>::Scalar::ONE,
},
participants: vec![Participant::from(1), Participant::from(2)],
holders: None,
};

// Serialize Presignature to JSON
Expand Down
16 changes: 12 additions & 4 deletions chain-signatures/node/src/protocol/signature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use crate::protocol::presignature::PresignatureId;
use crate::protocol::Chain;
use crate::rpc::{ContractStateWatcher, RpcChannel};
use crate::storage::presignature_storage::{PresignatureTaken, PresignatureTakenDropper};
use crate::storage::protocol_storage::ProtocolArtifact;
use crate::storage::PresignatureStorage;
use crate::types::SignatureProtocol;
use crate::util::{AffinePointExt, JoinMap, TimeoutBudget};
Expand Down Expand Up @@ -277,7 +278,14 @@ impl SignOrganizer {
let fetch = tokio::time::timeout(remaining, async {
loop {
if let Some(taken) = ctx.presignatures.take_mine(ctx.me).await {
let participants = intersect_vec(&[&taken.artifact.participants, &active]);
let Some(holders) = taken.artifact.holders() else {
tracing::error!(
id = taken.artifact.id,
"holders not set on taken presignature"
);
continue;
};
let participants = intersect_vec(&[holders, &active]);
if participants.len() < ctx.threshold {
recycle.push(taken);
continue;
Expand Down Expand Up @@ -700,7 +708,7 @@ impl SignGenerating {
);

let presignature_pending = if let Some(taken) = self.presignature.take() {
PendingPresignature::Available(taken)
PendingPresignature::Available(Box::new(taken))
} else {
PendingPresignature::InStorage(
self.presignature_id,
Expand Down Expand Up @@ -1394,7 +1402,7 @@ impl Drop for SignatureSpawnerTask {
}

enum PendingPresignature {
Available(PresignatureTaken),
Available(Box<PresignatureTaken>),
InStorage(PresignatureId, Participant, PresignatureStorage),
}

Expand All @@ -1408,7 +1416,7 @@ impl PendingPresignature {

pub async fn fetch(self, timeout: Duration) -> Option<PresignatureTaken> {
let (id, storage, owner) = match self {
PendingPresignature::Available(taken) => return Some(taken),
PendingPresignature::Available(taken) => return Some(*taken),
PendingPresignature::InStorage(id, owner, storage) => (id, storage, owner),
};

Expand Down
Loading
Loading