Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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 chain-signatures/contract-sol/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ pub struct SignatureRespondedEvent {
}

#[event]
#[derive(Clone)]
pub struct RespondBidirectionalEvent {
pub request_id: [u8; 32],
pub responder: Pubkey,
Expand Down
77 changes: 47 additions & 30 deletions chain-signatures/node/src/protocol/signature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ use crate::protocol::posit::{PositAction, SinglePositCounter};
use crate::protocol::presignature::PresignatureId;
use crate::protocol::{Chain, ProtocolState};
use crate::rpc::{ContractStateWatcher, GovernanceInfo, RpcChannel};
use crate::storage::presignature_storage::{PresignatureTaken, PresignatureTakenDropper};
use crate::storage::protocol_storage::ProtocolArtifact;
use crate::storage::presignature_storage::{
PresignatureReserved, PresignatureTaken, PresignatureTakenDropper,
};
use crate::storage::PresignatureStorage;
use crate::stream::ops::SignBidirectionalEvent;
use crate::types::SignatureProtocol;
Expand Down Expand Up @@ -54,7 +55,10 @@ const ORGANIZE_POSIT_TIMEOUT: Duration = Duration::from_secs(if cfg!(feature = "
///
/// Use shorter time for tests, as network delays are much smaller.
const ACCEPT_POSIT_TIMEOUT: Duration = Duration::from_millis(if cfg!(feature = "test-feature") {
100
// TODO(#793): This should work with lower values. But
// `test_sign_no_presignature_waste` becomes unstable when this is too low.
// This should work if we handle non-participants better.
300
} else {
500
});
Expand Down Expand Up @@ -212,7 +216,7 @@ struct SignPositor {
proposer: Participant,
active: BTreeSet<Participant>,
presignature_id: PresignatureId,
presignature: Option<PresignatureTaken>,
presignature: Option<PresignatureReserved>,
}

struct SignGenerating {
Expand Down Expand Up @@ -353,34 +357,27 @@ impl SignOrganizer {
let remaining = state.budget.remaining();
let fetch = tokio::time::timeout(remaining, async {
loop {
if let Some(taken) = ctx.presignatures.take_mine().await {
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 let Some(reserved) = ctx.presignatures.reserve_mine().await {
let participants = intersect_vec(&[&reserved.holders, &active]);
if participants.len() < ctx.governance.threshold {
tracing::warn!(
?sign_id,
id = taken.artifact.id,
?holders,
id = reserved.id,
holders = ?reserved.holders,
?active,
"discarding presignature due to inactive participants"
"releasing reserved presignature due to inactive participants"
);
// drop(reserved) releases the mine-key entry
continue;
}

break (taken, participants);
break (reserved, participants);
}
tokio::time::sleep(Duration::from_millis(500)).await;
}
})
.await;

let (taken, participants) = match fetch {
let (reserved, participants) = match fetch {
Ok(value) => value,
Err(_) => {
tracing::warn!(
Expand All @@ -393,7 +390,7 @@ impl SignOrganizer {
}
};

let presignature_id = taken.artifact.id;
let presignature_id = reserved.id;

tracing::info!(?sign_id, ?presignature_id, "proposer got presignature");

Expand All @@ -417,7 +414,7 @@ impl SignOrganizer {

// Update active to only include participants that are in both the presignature and active set
let active = participants.into_iter().collect::<BTreeSet<_>>();
(presignature_id, Some(taken), active)
(presignature_id, Some(reserved), active)
} else {
(PresignatureId::default(), None, active)
};
Expand Down Expand Up @@ -704,12 +701,10 @@ impl SignPositor {
if !counter.process_action(from, &action) {
continue;
}

if counter.enough_rejects(ctx.governance.threshold) {
tracing::warn!(?sign_id, ?round, ?from, "received enough REJECTs, reorganizing");
if let Some(_taken) = presignature {
tracing::warn!(?sign_id, "discarding presignature due to REJECTs");
}
// drop(reserved) releases the mine-key entry
let released = presignature.map(|reserved|reserved.id);
tracing::warn!(?sign_id, ?round, ?from, ?released, "received enough REJECTs, reorganizing");
state.bump_round();
return SignPhase::Organizing(SignOrganizer);
}
Expand Down Expand Up @@ -738,16 +733,16 @@ impl SignPositor {
}
_ = &mut posit_deadline => {
if is_proposer {
// drop(reserved) releases the mine-key entry
let released = presignature.map(|reserved|reserved.id);
tracing::warn!(
?sign_id,
accepts = counter.accepts.len(),
threshold = ctx.governance.threshold,
?round,
?released,
"proposer posit deadline reached, expiring round"
);
if let Some(_taken) = presignature {
tracing::warn!(?sign_id, "discarding presignature due to proposer timeout");
}
} else {
tracing::warn!(?sign_id, me=?ctx.governance.me, ?proposer, "deliberator posit timeout waiting for Start, reorganizing");
}
Expand All @@ -772,10 +767,27 @@ impl SignPositor {
}
};

// Proposer: Now that posit succeeded, fetch and delete the presignature
// atomically. This shouldn't fail outside of corrupted db problems.
let presignature_taken = match presignature {
Some(reserved) => match reserved.commit(&ctx.presignatures).await {
Some(taken) => Some(taken),
None => {
tracing::warn!(
?sign_id,
"failed to commit reserved presignature, reorganizing"
);
state.bump_round();
return SignPhase::Organizing(SignOrganizer);
}
},
None => None,
};

SignPhase::Generating(SignGenerating {
proposer,
presignature_id,
presignature,
presignature: presignature_taken,
accepted_participants,
})
}
Expand Down Expand Up @@ -1556,6 +1568,11 @@ impl PendingPresignature {
}
}

#[cfg(feature = "test-feature")]
pub fn organize_posit_timeout() -> Duration {
ORGANIZE_POSIT_TIMEOUT
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
11 changes: 1 addition & 10 deletions chain-signatures/node/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1830,8 +1830,6 @@ use signet_program::accounts::Respond as SolanaRespondAccount;
use signet_program::accounts::RespondBidirectional as SolanaRespondBidirectionalAccount;
use signet_program::instruction::Respond as SolanaRespond;
use signet_program::instruction::RespondBidirectional as SolanaRespondBidirectional;
use signet_program::AffinePoint as SolanaContractAffinePoint;
use signet_program::Signature as SolanaContractSignature;
use solana_sdk::signature::Signer as SolanaSigner;
async fn try_publish_sol(
sol: &SolanaClient,
Expand All @@ -1844,14 +1842,7 @@ async fn try_publish_sol(
let sign_id = action.indexed.id;
let request_ids = vec![action.indexed.id.request_id];
let big_r = signature.big_r.to_encoded_point(false);
let signature = SolanaContractSignature {
big_r: SolanaContractAffinePoint {
x: big_r.as_bytes()[1..33].try_into().unwrap(),
y: big_r.as_bytes()[33..65].try_into().unwrap(),
},
s: signature.s.to_bytes().into(),
recovery_id: signature.recovery_id,
};
let signature = crate::util::mpc_to_sol_signature(signature, big_r);

tracing::debug!(
?sign_id,
Expand Down
5 changes: 4 additions & 1 deletion chain-signatures/node/src/storage/presignature_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ use redis::{FromRedisValue, RedisError, RedisWrite, ToRedisArgs};

use cait_sith::protocol::Participant;

use super::protocol_storage::{ArtifactSlot, ArtifactTaken, ArtifactTakenDropper, ProtocolStorage};
use super::protocol_storage::{
ArtifactReserved, ArtifactSlot, ArtifactTaken, ArtifactTakenDropper, ProtocolStorage,
};
use crate::protocol::presignature::{Presignature, PresignatureId};
use crate::storage::protocol_storage::ProtocolArtifact;

pub type PresignatureStorage = ProtocolStorage<Presignature>;
pub type PresignatureSlot = ArtifactSlot<Presignature>;
pub type PresignatureTaken = ArtifactTaken<Presignature>;
pub type PresignatureTakenDropper = ArtifactTakenDropper<Presignature>;
pub type PresignatureReserved = ArtifactReserved<Presignature>;

impl Presignature {
pub fn storage(pool: &Pool, account_id: &AccountId) -> PresignatureStorage {
Expand Down
Loading
Loading