[wip]: improving error recovery during key submission phase

This commit is contained in:
Jędrzej Stuczyński
2024-01-05 17:34:36 +00:00
parent 9f1b89616a
commit 7a9b989db9
11 changed files with 1102 additions and 842 deletions
@@ -34,6 +34,8 @@ fn verify_dealer(deps: DepsMut<'_>, dealer: &Addr, resharing: bool) -> Result<()
Ok(())
}
// future optimisation:
// for a recurring dealer just let it refresh the keys without having to do all the storage operations
pub fn try_add_dealer(
mut deps: DepsMut<'_>,
info: MessageInfo,
+52 -3
View File
@@ -2,9 +2,11 @@
// SPDX-License-Identifier: GPL-3.0-only
use crate::support::config;
use anyhow::Context;
use anyhow::{anyhow, bail, Context};
use nym_coconut_dkg_common::types::EpochId;
use nym_dkg::bte::keys::KeyPair as DkgKeyPair;
use rand::{CryptoRng, RngCore};
use thiserror::__private::AsDisplay;
pub(crate) fn init_bte_keypair<R: RngCore + CryptoRng>(
rng: &mut R,
@@ -18,8 +20,8 @@ pub(crate) fn init_bte_keypair<R: RngCore + CryptoRng>(
&config.storage_paths.decryption_key_path,
&config.storage_paths.public_key_with_proof_path,
),
)?;
Ok(())
)
.context("DKG BTE keypair store failure")
}
pub(crate) fn load_bte_keypair(config: &config::CoconutSigner) -> anyhow::Result<DkgKeyPair> {
@@ -43,3 +45,50 @@ pub(crate) fn load_coconut_keypair_if_exists(
.context("coconut keypair load failure")
.map(Some)
}
pub(crate) fn persist_coconut_keypair(
keys: &nym_coconut_interface::KeyPair,
store_paths: &nym_pemstore::KeyPairPath,
) -> anyhow::Result<()> {
nym_pemstore::store_keypair(keys, store_paths).context("coconut keypair store failure")
}
pub(crate) fn archive_coconut_keypair(
store_paths: &nym_pemstore::KeyPairPath,
epoch_id: EpochId,
) -> anyhow::Result<()> {
if !store_paths.private_key_path.exists() {
bail!(
"private key does not exist at {}",
store_paths.private_key_path.as_display()
)
}
let dir = store_paths
.private_key_path
.parent()
.ok_or(anyhow!("the private key does not have a valid parent"))?;
let filename = store_paths
.private_key_path
.file_name()
.ok_or(anyhow!("the private key does not have a filename"))?
.to_str()
.ok_or(anyhow!("the key filename is not valid UTF8"))?;
let archive_path = dir.join(format!("epoch-{epoch_id}-{filename}.archived"));
std::fs::rename(&store_paths.private_key_path, archive_path)?;
let dir = store_paths
.public_key_path
.parent()
.ok_or(anyhow!("the public key does not have a valid parent"))?;
let filename = store_paths
.public_key_path
.file_name()
.ok_or(anyhow!("the public key does not have a filename"))?
.to_str()
.ok_or(anyhow!("the key filename is not valid UTF8"))?;
let archive_path = dir.join(format!("epoch-{epoch_id}-{filename}.archived"));
std::fs::rename(&store_paths.public_key_path, archive_path)?;
Ok(())
}
+36 -15
View File
@@ -8,8 +8,7 @@ use crate::coconut::dkg::verification_key::{
verification_key_finalization, verification_key_validation,
};
use crate::coconut::dkg::{
dealing::dealing_exchange, public_key::public_key_submission,
verification_key::verification_key_submission,
dealing::dealing_exchange, verification_key::verification_key_submission,
};
use crate::coconut::keypair::KeyPair as CoconutKeyPair;
use crate::nyxd;
@@ -19,6 +18,7 @@ use nym_coconut_dkg_common::types::{Epoch, EpochId, EpochState};
use nym_crypto::asymmetric::identity;
use nym_dkg::bte::keys::KeyPair as DkgKeyPair;
use nym_task::{TaskClient, TaskManager};
use rand::rngs::OsRng;
use rand::{CryptoRng, RngCore};
use std::path::PathBuf;
use std::time::Duration;
@@ -28,11 +28,11 @@ use tokio::time::interval;
mod error;
pub(crate) mod keys;
pub(crate) struct DkgController<R> {
dkg_client: DkgClient,
pub(crate) struct DkgController<R = OsRng> {
pub(crate) dkg_client: DkgClient,
secret_key_path: PathBuf,
verification_key_path: PathBuf,
state: State,
pub(crate) state: State,
rng: R,
polling_rate: Duration,
}
@@ -71,6 +71,10 @@ impl<R: RngCore + CryptoRng + Clone> DkgController<R> {
})
}
pub(crate) fn coconut_keypaths(&self) -> nym_pemstore::KeyPairPath {
nym_pemstore::KeyPairPath::new(&self.secret_key_path, &self.verification_key_path)
}
fn persist_state(&self) -> Result<(), DkgError> {
// if !self.state.coconut_keypair_is_some().await {
// // Delete the files just in case the process is killed before the new keys are generated
@@ -124,13 +128,17 @@ impl<R: RngCore + CryptoRng + Clone> DkgController<R> {
}
async fn handle_awaiting_initialisation(&mut self) -> Result<(), DkgError> {
info!("DKG hasn't been initialised yet");
return Ok(());
info!("DKG hasn't been initialised yet - nothing to do");
Ok(())
}
async fn handle_key_submission(&mut self, resharing: bool) -> Result<(), DkgError> {
async fn handle_key_submission(
&mut self,
epoch_id: EpochId,
resharing: bool,
) -> Result<(), DkgError> {
debug!("DKG: public key submission (resharing: {resharing})");
public_key_submission(&self.dkg_client, &mut self.state, resharing)
self.public_key_submission(epoch_id, resharing)
.await
.map_err(|source| DkgError::PublicKeySubmissionFailure { source })
}
@@ -152,12 +160,10 @@ impl<R: RngCore + CryptoRng + Clone> DkgController<R> {
epoch_id: EpochId,
resharing: bool,
) -> Result<(), DkgError> {
debug!("DKG: verification key sumbission (resharing: {resharing})");
debug!("DKG: verification key submission (resharing: {resharing})");
let keypair_path = nym_pemstore::KeyPairPath::new(
self.secret_key_path.clone(),
self.verification_key_path.clone(),
);
let keypair_path =
nym_pemstore::KeyPairPath::new(&self.secret_key_path, &self.verification_key_path);
verification_key_submission(
&self.dkg_client,
&mut self.state,
@@ -219,7 +225,8 @@ impl<R: RngCore + CryptoRng + Clone> DkgController<R> {
match epoch.state {
EpochState::WaitingInitialisation => self.handle_awaiting_initialisation().await?,
EpochState::PublicKeySubmission { resharing } => {
self.handle_key_submission(resharing).await?
self.handle_key_submission(epoch.epoch_id, resharing)
.await?
}
EpochState::DealingExchange { resharing } => {
self.handle_dealing_exchange(resharing).await?
@@ -294,3 +301,17 @@ impl<R: RngCore + CryptoRng + Clone> DkgController<R> {
Ok(())
}
}
#[cfg(test)]
impl DkgController {
pub(crate) fn test_mock(dkg_client: DkgClient, state: State) -> DkgController {
DkgController {
dkg_client,
secret_key_path: Default::default(),
verification_key_path: Default::default(),
state,
rng: OsRng,
polling_rate: Default::default(),
}
}
}
+14 -13
View File
@@ -47,18 +47,19 @@ pub(crate) async fn dealing_exchange(
let prior_resharing_secrets = if let Some(mut keypair) = state.take_coconut_keypair().await {
// Double check that we are in resharing mode
if resharing {
let sk = keypair.secret_key();
if sk.size() + 1 != expected_key_size as usize {
return Err(CoconutError::CorruptedCoconutKeyPair);
}
let (x, mut scalars) = sk.into_raw();
// We can now erase the keypair from memory
debug!("Removing coconut keypair from memory");
keypair.zeroize();
scalars.push(x);
scalars
todo!()
// let sk = keypair.secret_key();
// if sk.size() + 1 != expected_key_size as usize {
// return Err(CoconutError::CorruptedCoconutKeyPair);
// }
//
// let (x, mut scalars) = sk.into_raw();
//
// // We can now erase the keypair from memory
// debug!("Removing coconut keypair from memory");
// keypair.zeroize();
// scalars.push(x);
// scalars
} else {
log::warn!("Coconut key hasn't been reset in memory. The state might be corrupt");
vec![]
@@ -340,7 +341,7 @@ pub(crate) mod tests {
let params = dkg::params();
let mut keys = ttp_keygen(&Parameters::new(4).unwrap(), 3, 4).unwrap();
let coconut_keypair = KeyPair::new();
coconut_keypair.set(Some(keys.pop().unwrap())).await;
coconut_keypair.set(0, keys.pop().unwrap()).await;
let identity_keypair = identity::KeyPair::new(&mut thread_rng());
let mut state = State::new(
+67 -69
View File
@@ -1,74 +1,73 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2022-2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::coconut::dkg::client::DkgClient;
use crate::coconut::dkg::state::State;
use crate::coconut::dkg::controller::DkgController;
use crate::coconut::error::CoconutError;
use log::debug;
use nym_coconut_dkg_common::dealer::DealerType;
use nym_coconut_dkg_common::types::EpochId;
use rand::{CryptoRng, RngCore};
pub(crate) async fn public_key_submission(
dkg_client: &DkgClient,
state: &mut State,
resharing: bool,
) -> Result<(), CoconutError> {
if state.was_in_progress() {
let own_address = dkg_client.get_address().await.as_ref().to_string();
let is_initial_dealer = dkg_client
.get_initial_dealers()
.await?
.map(|data| data.initial_dealers.iter().any(|d| *d == own_address))
.unwrap_or(false);
let reset_coconut_keypair = !resharing || !is_initial_dealer;
debug!(
"Resetting state, with coconut keypair reset: {}",
reset_coconut_keypair
);
state.reset_persistent(reset_coconut_keypair).await;
}
if state.node_index().is_some() {
debug!("Node index was set previously, nothing to do");
return Ok(());
}
impl<R: RngCore + CryptoRng + Clone> DkgController<R> {
pub(crate) async fn public_key_submission(
&mut self,
epoch_id: EpochId,
resharing: bool,
) -> Result<(), CoconutError> {
self.state.init_dkg_state(epoch_id);
let registration_state = self.state.registration_state(epoch_id);
let bte_key = bs58::encode(&state.dkg_keypair().public_key().to_bytes()).into_string();
let dealer_details = dkg_client.get_self_registered_dealer_details().await?;
let index = if let Some(details) = dealer_details.details {
if dealer_details.dealer_type == DealerType::Past {
// If it was a dealer in a previous epoch, re-register it for this epoch
debug!("Registering for the current DKG round, with keys from a previous epoch");
dkg_client
.register_dealer(
bte_key,
state.identity_key().to_base58_string(),
state.announce_address().to_string(),
resharing,
)
.await?;
// check if we have already submitted the key
if registration_state.completed() {
// the only way this could be a false positive is if the chain forked and blocks got reverted,
// but I don't think we have to worry about that
debug!("we have already submitted the keys for this epoch");
return Ok(());
}
details.assigned_index
} else {
debug!("Registering for the first time to be a dealer");
// First time registration
dkg_client
.register_dealer(
bte_key,
state.identity_key().to_base58_string(),
state.announce_address().to_string(),
resharing,
)
.await?
};
state.set_node_index(Some(index));
info!("DKG: Using node index {}", index);
Ok(())
// if we have coconut keys available, it means we have already completed the DKG before (in previous epoch)
// in which case, archive and reset those keys
if let Some((old_epoch, _)) = self.state.take_coconut_keypair().await {
debug!("resetting and archiving old coconut keypair");
let store_path = self.coconut_keypaths();
// archive_coconut_keypair(&store_path, old_epoch)?
//
}
// FAILURE CASE:
// check if we have already sent the registration transaction, but it timed out or got stuck in the mempool and
// eventually got executed without us knowing about it
// in that case we MUST recover the assigned index since we won't be allowed to register again
let dealer_details = self.dkg_client.get_self_registered_dealer_details().await?;
if dealer_details.dealer_type.is_current() {
if let Some(details) = dealer_details.details {
// the tx did actually go through
self.state.registration_state_mut(epoch_id).assigned_index =
Some(details.assigned_index);
info!("DKG: recovered node index: {}", details.assigned_index);
return Ok(());
}
}
let bte_key = bs58::encode(&self.state.dkg_keypair().public_key().to_bytes()).into_string();
let identity_key = self.state.identity_key().to_base58_string();
let announce_address = self.state.announce_address().to_string();
let assigned_index = self
.dkg_client
.register_dealer(bte_key, identity_key, announce_address, resharing)
.await?;
self.state.registration_state_mut(epoch_id).assigned_index = Some(assigned_index);
info!("DKG: Using node index {assigned_index}");
Ok(())
}
}
#[cfg(test)]
pub(crate) mod tests {
use super::*;
use crate::coconut::dkg::state::PersistentState;
use crate::coconut::dkg::client::DkgClient;
use crate::coconut::dkg::state::{PersistentState, State};
use crate::coconut::tests::DummyClient;
use crate::coconut::KeyPair;
use nym_crypto::asymmetric::identity;
@@ -97,30 +96,29 @@ pub(crate) mod tests {
*identity_keypair.public_key(),
KeyPair::new(),
);
let mut controller = DkgController::test_mock(dkg_client, state);
assert!(dkg_client
assert!(controller
.dkg_client
.get_self_registered_dealer_details()
.await
.unwrap()
.details
.is_none());
public_key_submission(&dkg_client, &mut state, false)
.await
.unwrap();
let client_idx = dkg_client
controller.public_key_submission(0, false).await.unwrap();
let client_idx = controller
.dkg_client
.get_self_registered_dealer_details()
.await
.unwrap()
.details
.unwrap()
.assigned_index;
assert_eq!(state.node_index().unwrap(), client_idx);
assert_eq!(controller.state.node_index().unwrap(), client_idx);
// keeps the same index from chain, not calling register_dealer again
state.set_node_index(None);
public_key_submission(&dkg_client, &mut state, false)
.await
.unwrap();
assert_eq!(state.node_index().unwrap(), client_idx);
controller.state.set_node_index(None);
controller.public_key_submission(0, false).await.unwrap();
assert_eq!(controller.state.node_index().unwrap(), client_idx);
}
}
@@ -1,7 +1,10 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
mod registration;
use crate::coconut::dkg::complaints::ComplaintReason;
use crate::coconut::dkg::state::registration::RegistrationState;
use crate::coconut::error::CoconutError;
use crate::coconut::keypair::KeyPair as CoconutKeyPair;
use cosmwasm_std::Addr;
@@ -11,6 +14,8 @@ use nym_coconut_dkg_common::types::{DealingIndex, EpochId, EpochState};
use nym_crypto::asymmetric::identity;
use nym_dkg::bte::{keys::KeyPair as DkgKeyPair, PublicKey, PublicKeyWithProof};
use nym_dkg::{Dealing, NodeIndex, RecoveredVerificationKeys, Threshold};
use nym_validator_client::nyxd::{tx, Hash};
use rocket::form::validate::Contains;
use serde::de::Error;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::collections::{BTreeMap, HashMap};
@@ -271,8 +276,18 @@ impl PersistentState {
}
}
#[derive(Default)]
pub(crate) struct DkgState {
pub(crate) registration: RegistrationState,
}
pub(crate) struct State {
/// Path to the file containing the persistent state
persistent_state_path: PathBuf,
dkg_instances: HashMap<EpochId, DkgState>,
//
announce_address: Url,
identity_key: identity::PublicKey,
dkg_keypair: DkgKeyPair,
@@ -298,28 +313,33 @@ impl State {
identity_key: identity::PublicKey,
coconut_keypair: CoconutKeyPair,
) -> Self {
State {
persistent_state_path,
announce_address,
identity_key,
dkg_keypair,
coconut_keypair,
node_index: persistent_state.node_index,
dealers: persistent_state.dealers,
generated_dealings: persistent_state.generated_dealings,
receiver_index: persistent_state.receiver_index,
threshold: persistent_state.threshold,
recovered_vks: persistent_state.recovered_vks,
proposal_id: persistent_state.proposal_id,
voted_vks: persistent_state.voted_vks,
executed_proposal: persistent_state.executed_proposal,
was_in_progress: persistent_state.was_in_progress,
}
todo!()
// State {
// persistent_state_path,
// announce_address,
// identity_key,
// dkg_keypair,
// coconut_keypair,
// node_index: persistent_state.node_index,
// dealers: persistent_state.dealers,
// generated_dealings: persistent_state.generated_dealings,
// receiver_index: persistent_state.receiver_index,
// threshold: persistent_state.threshold,
// recovered_vks: persistent_state.recovered_vks,
// proposal_id: persistent_state.proposal_id,
// voted_vks: persistent_state.voted_vks,
// executed_proposal: persistent_state.executed_proposal,
// was_in_progress: persistent_state.was_in_progress,
// }
}
pub fn persist(&self) -> Result<(), CoconutError> {
PersistentState::from(self).save_to_file(self.persistent_state_path())
}
pub async fn reset_persistent(&mut self, reset_coconut_keypair: bool) {
if reset_coconut_keypair {
self.coconut_keypair.set(None).await;
self.coconut_keypair.invalidate().await;
}
self.node_index = Default::default();
self.dealers = Default::default();
@@ -332,6 +352,26 @@ impl State {
self.was_in_progress = Default::default();
}
pub fn init_dkg_state(&mut self, epoch_id: EpochId) {
if !self.dkg_instances.contains_key(&epoch_id) {
self.dkg_instances.insert(epoch_id, Default::default());
}
}
pub fn registration_state(&self, epoch_id: EpochId) -> &RegistrationState {
// safety: before any accessors are called, `init_dkg_state` is used at the beginning of submission handler
&self.dkg_instances[&epoch_id].registration
}
pub fn registration_state_mut(&mut self, epoch_id: EpochId) -> &mut RegistrationState {
// safety: before any accessors are called, `init_dkg_state` is used at the beginning of submission handler
&mut self.dkg_instances.get_mut(&epoch_id).unwrap().registration
}
pub fn already_registered(&self, epoch_id: EpochId) -> bool {
self.registration_state(epoch_id).completed()
}
pub fn persistent_state_path(&self) -> &Path {
self.persistent_state_path.as_path()
}
@@ -352,7 +392,7 @@ impl State {
self.coconut_keypair.get().await.is_some()
}
pub async fn take_coconut_keypair(&self) -> Option<nym_coconut::KeyPair> {
pub async fn take_coconut_keypair(&self) -> Option<(EpochId, nym_coconut::KeyPair)> {
self.coconut_keypair.take().await
}
@@ -438,9 +478,10 @@ impl State {
pub async fn set_coconut_keypair(
&mut self,
coconut_keypair: Option<nym_coconut_interface::KeyPair>,
epoch_id: EpochId,
coconut_keypair: nym_coconut_interface::KeyPair,
) {
self.coconut_keypair.set(coconut_keypair).await
self.coconut_keypair.set(epoch_id, coconut_keypair).await
}
pub fn set_node_index(&mut self, node_index: Option<NodeIndex>) {
@@ -0,0 +1,17 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use nym_dkg::NodeIndex;
use serde_derive::{Deserialize, Serialize};
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct RegistrationState {
pub(crate) assigned_index: Option<NodeIndex>,
}
impl RegistrationState {
/// Specifies whether this dealer has already registered in the particular DKG epoch
pub fn completed(&self) -> bool {
self.assigned_index.is_some()
}
}
+294 -178
View File
@@ -243,7 +243,7 @@ pub(crate) async fn verification_key_submission(
proposal_id
);
state.set_proposal_id(proposal_id);
state.set_coconut_keypair(Some(coconut_keypair)).await;
state.set_coconut_keypair(epoch_id, coconut_keypair).await;
info!("DKG: Submitted own verification key");
Ok(())
@@ -352,8 +352,8 @@ pub(crate) async fn verification_key_finalization(
#[cfg(test)]
pub(crate) mod tests {
use super::*;
use crate::coconut::dkg::controller::DkgController;
use crate::coconut::dkg::dealing::dealing_exchange;
use crate::coconut::dkg::public_key::public_key_submission;
use crate::coconut::dkg::state::PersistentState;
use crate::coconut::tests::DummyClient;
use crate::coconut::KeyPair;
@@ -405,7 +405,7 @@ pub(crate) mod tests {
"n1jfrs6cmw9t7dv0x8cgny6geunzjh56n2s89fkv",
];
async fn prepare_clients_and_states(db: &MockContractDb) -> Vec<(DkgClient, State)> {
async fn prepare_clients_and_states(db: &MockContractDb) -> Vec<DkgController> {
let params = dkg::params();
let mut clients_and_states = vec![];
let identity_keypair = identity::KeyPair::new(&mut thread_rng());
@@ -429,52 +429,50 @@ pub(crate) mod tests {
*identity_keypair.public_key(),
KeyPair::new(),
);
clients_and_states.push((dkg_client, state));
clients_and_states.push(DkgController::test_mock(dkg_client, state));
}
for (dkg_client, state) in clients_and_states.iter_mut() {
public_key_submission(dkg_client, state, false)
.await
.unwrap();
for controller in clients_and_states.iter_mut() {
controller.public_key_submission(0, false).await.unwrap();
}
clients_and_states
}
async fn prepare_clients_and_states_with_dealing(
db: &MockContractDb,
) -> Vec<(DkgClient, State)> {
async fn prepare_clients_and_states_with_dealing(db: &MockContractDb) -> Vec<DkgController> {
let mut clients_and_states = prepare_clients_and_states(db).await;
for (dkg_client, state) in clients_and_states.iter_mut() {
dealing_exchange(dkg_client, state, OsRng, false)
for controller in clients_and_states.iter_mut() {
dealing_exchange(&controller.dkg_client, &mut controller.state, OsRng, false)
.await
.unwrap();
}
clients_and_states
}
async fn prepare_clients_and_states_with_submission(
db: &MockContractDb,
) -> Vec<(DkgClient, State)> {
async fn prepare_clients_and_states_with_submission(db: &MockContractDb) -> Vec<DkgController> {
let mut clients_and_states = prepare_clients_and_states_with_dealing(db).await;
for (dkg_client, state) in clients_and_states.iter_mut() {
for controller in clients_and_states.iter_mut() {
let random_file: usize = OsRng.gen();
let private_key_path = temp_dir().join(format!("private{}.pem", random_file));
let public_key_path = temp_dir().join(format!("public{}.pem", random_file));
let keypair_path = KeyPairPath::new(private_key_path.clone(), public_key_path.clone());
verification_key_submission(dkg_client, state, 0, &keypair_path, false)
.await
.unwrap();
verification_key_submission(
&controller.dkg_client,
&mut controller.state,
0,
&keypair_path,
false,
)
.await
.unwrap();
std::fs::remove_file(private_key_path).unwrap();
std::fs::remove_file(public_key_path).unwrap();
}
clients_and_states
}
async fn prepare_clients_and_states_with_validation(
db: &MockContractDb,
) -> Vec<(DkgClient, State)> {
async fn prepare_clients_and_states_with_validation(db: &MockContractDb) -> Vec<DkgController> {
let mut clients_and_states = prepare_clients_and_states_with_submission(db).await;
for (dkg_client, state) in clients_and_states.iter_mut() {
verification_key_validation(dkg_client, state, false)
for controller in clients_and_states.iter_mut() {
verification_key_validation(&controller.dkg_client, &mut controller.state, false)
.await
.unwrap();
}
@@ -483,10 +481,10 @@ pub(crate) mod tests {
async fn prepare_clients_and_states_with_finalization(
db: &MockContractDb,
) -> Vec<(DkgClient, State)> {
) -> Vec<DkgController> {
let mut clients_and_states = prepare_clients_and_states_with_validation(db).await;
for (dkg_client, state) in clients_and_states.iter_mut() {
verification_key_finalization(dkg_client, state, false)
for controller in clients_and_states.iter_mut() {
verification_key_finalization(&controller.dkg_client, &mut controller.state, false)
.await
.unwrap();
}
@@ -498,12 +496,22 @@ pub(crate) mod tests {
async fn check_dealers_filter_all_good() {
let db = MockContractDb::new();
let mut clients_and_states = prepare_clients_and_states_with_dealing(&db).await;
let contract_state = clients_and_states[0].0.get_contract_state().await.unwrap();
let contract_state = clients_and_states[0]
.dkg_client
.get_contract_state()
.await
.unwrap();
for (dkg_client, state) in clients_and_states.iter_mut() {
let filtered = deterministic_filter_dealers(dkg_client, state, 0, 2, false)
.await
.unwrap();
for controller in clients_and_states.iter_mut() {
let filtered = deterministic_filter_dealers(
&controller.dkg_client,
&mut controller.state,
0,
2,
false,
)
.await
.unwrap();
assert_eq!(filtered.len(), contract_state.key_size as usize);
for mapping in filtered.iter() {
assert_eq!(mapping.len(), 4);
@@ -516,7 +524,11 @@ pub(crate) mod tests {
async fn check_dealers_filter_one_bad_dealing() {
let db = MockContractDb::new();
let mut clients_and_states = prepare_clients_and_states_with_dealing(&db).await;
let contract_state = clients_and_states[0].0.get_contract_state().await.unwrap();
let contract_state = clients_and_states[0]
.dkg_client
.get_contract_state()
.await
.unwrap();
// corrupt just one dealing
db.dealings_db
@@ -532,12 +544,19 @@ pub(crate) mod tests {
validator_dealings.push(last);
});
for (dkg_client, state) in clients_and_states.iter_mut().skip(1) {
let filtered = deterministic_filter_dealers(dkg_client, state, 0, 2, false)
.await
.unwrap();
for controller in clients_and_states.iter_mut().skip(1) {
let filtered = deterministic_filter_dealers(
&controller.dkg_client,
&mut controller.state,
0,
2,
false,
)
.await
.unwrap();
assert_eq!(filtered.len(), contract_state.key_size as usize);
let corrupted_status = state
let corrupted_status = controller
.state
.all_dealers()
.get(&Addr::unchecked(TEST_VALIDATORS_ADDRESS[0]))
.unwrap()
@@ -552,25 +571,36 @@ pub(crate) mod tests {
async fn check_dealers_resharing_filter_one_missing_dealing() {
let db = MockContractDb::new();
let mut clients_and_states = prepare_clients_and_states(&db).await;
let contract_state = clients_and_states[0].0.get_contract_state().await.unwrap();
let contract_state = clients_and_states[0]
.dkg_client
.get_contract_state()
.await
.unwrap();
// add all but the first dealing
for (dkg_client, state) in clients_and_states.iter_mut().skip(1) {
dealing_exchange(dkg_client, state, OsRng, true)
for controller in clients_and_states.iter_mut().skip(1) {
dealing_exchange(&controller.dkg_client, &mut controller.state, OsRng, true)
.await
.unwrap();
}
for (dkg_client, state) in clients_and_states.iter_mut().skip(1) {
for controller in clients_and_states.iter_mut().skip(1) {
*db.initial_dealers_db.write().unwrap() = Some(InitialReplacementData {
initial_dealers: vec![Addr::unchecked(TEST_VALIDATORS_ADDRESS[0])],
initial_height: 1,
});
let filtered = deterministic_filter_dealers(dkg_client, state, 0, 2, true)
.await
.unwrap();
let filtered = deterministic_filter_dealers(
&controller.dkg_client,
&mut controller.state,
0,
2,
true,
)
.await
.unwrap();
assert_eq!(filtered.len(), contract_state.key_size as usize);
let corrupted_status = state
let corrupted_status = controller
.state
.all_dealers()
.get(&Addr::unchecked(TEST_VALIDATORS_ADDRESS[0]))
.unwrap()
@@ -586,25 +616,36 @@ pub(crate) mod tests {
async fn check_dealers_resharing_filter_one_noninitial_missing_dealing() {
let db = MockContractDb::new();
let mut clients_and_states = prepare_clients_and_states(&db).await;
let contract_state = clients_and_states[0].0.get_contract_state().await.unwrap();
let contract_state = clients_and_states[0]
.dkg_client
.get_contract_state()
.await
.unwrap();
// add all but the first dealing
for (dkg_client, state) in clients_and_states.iter_mut().skip(1) {
dealing_exchange(dkg_client, state, OsRng, true)
for controller in clients_and_states.iter_mut().skip(1) {
dealing_exchange(&controller.dkg_client, &mut controller.state, OsRng, true)
.await
.unwrap();
}
for (dkg_client, state) in clients_and_states.iter_mut().skip(1) {
for controller in clients_and_states.iter_mut().skip(1) {
*db.initial_dealers_db.write().unwrap() = Some(InitialReplacementData {
initial_dealers: vec![],
initial_height: 1,
});
let filtered = deterministic_filter_dealers(dkg_client, state, 0, 2, true)
.await
.unwrap();
let filtered = deterministic_filter_dealers(
&controller.dkg_client,
&mut controller.state,
0,
2,
true,
)
.await
.unwrap();
assert_eq!(filtered.len(), contract_state.key_size as usize);
assert!(state
assert!(controller
.state
.all_dealers()
.get(&Addr::unchecked(TEST_VALIDATORS_ADDRESS[0]))
.unwrap()
@@ -618,7 +659,11 @@ pub(crate) mod tests {
async fn check_dealers_filter_all_bad_dealings() {
let db = MockContractDb::new();
let mut clients_and_states = prepare_clients_and_states_with_dealing(&db).await;
let contract_state = clients_and_states[0].0.get_contract_state().await.unwrap();
let contract_state = clients_and_states[0]
.dkg_client
.get_contract_state()
.await
.unwrap();
// corrupt all dealings of one address
db.dealings_db
@@ -634,15 +679,22 @@ pub(crate) mod tests {
});
});
for (dkg_client, state) in clients_and_states.iter_mut().skip(1) {
let filtered = deterministic_filter_dealers(dkg_client, state, 0, 2, false)
.await
.unwrap();
for controller in clients_and_states.iter_mut().skip(1) {
let filtered = deterministic_filter_dealers(
&controller.dkg_client,
&mut controller.state,
0,
2,
false,
)
.await
.unwrap();
assert_eq!(filtered.len(), contract_state.key_size as usize);
for mapping in filtered.iter() {
assert_eq!(mapping.len(), 3);
}
let corrupted_status = state
let corrupted_status = controller
.state
.all_dealers()
.get(&Addr::unchecked(TEST_VALIDATORS_ADDRESS[0]))
.unwrap()
@@ -657,7 +709,11 @@ pub(crate) mod tests {
async fn check_dealers_filter_malformed_dealing() {
let db = MockContractDb::new();
let mut clients_and_states = prepare_clients_and_states_with_dealing(&db).await;
let contract_state = clients_and_states[0].0.get_contract_state().await.unwrap();
let contract_state = clients_and_states[0]
.dkg_client
.get_contract_state()
.await
.unwrap();
// corrupt just one dealing
db.dealings_db
@@ -673,17 +729,30 @@ pub(crate) mod tests {
validator_dealings.push(last);
});
for (dkg_client, state) in clients_and_states.iter_mut().skip(1) {
deterministic_filter_dealers(dkg_client, state, 0, 2, false)
.await
.unwrap();
for controller in clients_and_states.iter_mut().skip(1) {
deterministic_filter_dealers(
&controller.dkg_client,
&mut controller.state,
0,
2,
false,
)
.await
.unwrap();
// second filter will leave behind the bad dealer and surface why it was left out
// in the first place
let filtered = deterministic_filter_dealers(dkg_client, state, 0, 2, false)
.await
.unwrap();
let filtered = deterministic_filter_dealers(
&controller.dkg_client,
&mut controller.state,
0,
2,
false,
)
.await
.unwrap();
assert_eq!(filtered.len(), contract_state.key_size as usize);
let corrupted_status = state
let corrupted_status = controller
.state
.all_dealers()
.get(&Addr::unchecked(TEST_VALIDATORS_ADDRESS[0]))
.unwrap()
@@ -698,7 +767,11 @@ pub(crate) mod tests {
async fn check_dealers_filter_dealing_verification_error() {
let db = MockContractDb::new();
let mut clients_and_states = prepare_clients_and_states_with_dealing(&db).await;
let contract_state = clients_and_states[0].0.get_contract_state().await.unwrap();
let contract_state = clients_and_states[0]
.dkg_client
.get_contract_state()
.await
.unwrap();
// corrupt just one dealing
db.dealings_db
@@ -719,17 +792,30 @@ pub(crate) mod tests {
validator_dealings.push(last);
});
for (dkg_client, state) in clients_and_states.iter_mut().skip(1) {
deterministic_filter_dealers(dkg_client, state, 0, 2, false)
.await
.unwrap();
for controller in clients_and_states.iter_mut().skip(1) {
deterministic_filter_dealers(
&controller.dkg_client,
&mut controller.state,
0,
2,
false,
)
.await
.unwrap();
// second filter will leave behind the bad dealer and surface why it was left out
// in the first place
let filtered = deterministic_filter_dealers(dkg_client, state, 0, 2, false)
.await
.unwrap();
let filtered = deterministic_filter_dealers(
&controller.dkg_client,
&mut controller.state,
0,
2,
false,
)
.await
.unwrap();
assert_eq!(filtered.len(), contract_state.key_size as usize);
let corrupted_status = state
let corrupted_status = controller
.state
.all_dealers()
.get(&Addr::unchecked(TEST_VALIDATORS_ADDRESS[0]))
.unwrap()
@@ -744,11 +830,17 @@ pub(crate) mod tests {
async fn partial_keypair_derivation() {
let db = MockContractDb::new();
let mut clients_and_states = prepare_clients_and_states_with_dealing(&db).await;
for (dkg_client, state) in clients_and_states.iter_mut() {
let filtered = deterministic_filter_dealers(dkg_client, state, 0, 2, false)
.await
.unwrap();
assert!(derive_partial_keypair(state, 2, filtered).is_ok());
for controller in clients_and_states.iter_mut() {
let filtered = deterministic_filter_dealers(
&controller.dkg_client,
&mut controller.state,
0,
2,
false,
)
.await
.unwrap();
assert!(derive_partial_keypair(&mut controller.state, 2, filtered).is_ok());
}
}
@@ -772,11 +864,17 @@ pub(crate) mod tests {
validator_dealings.push(last);
});
for (dkg_client, state) in clients_and_states.iter_mut().skip(1) {
let filtered = deterministic_filter_dealers(dkg_client, state, 0, 2, false)
.await
.unwrap();
assert!(derive_partial_keypair(state, 2, filtered).is_ok());
for controller in clients_and_states.iter_mut().skip(1) {
let filtered = deterministic_filter_dealers(
&controller.dkg_client,
&mut controller.state,
0,
2,
false,
)
.await
.unwrap();
assert!(derive_partial_keypair(&mut controller.state, 2, filtered).is_ok());
}
}
@@ -786,13 +884,13 @@ pub(crate) mod tests {
let db = MockContractDb::new();
let mut clients_and_states = prepare_clients_and_states_with_submission(&db).await;
for (_, state) in clients_and_states.iter_mut() {
for controller in clients_and_states.iter_mut() {
assert!(db
.proposal_db
.read()
.unwrap()
.contains_key(&state.proposal_id_value().unwrap()));
assert!(state.coconut_keypair_is_some().await);
.contains_key(&controller.state.proposal_id_value().unwrap()));
assert!(controller.state.coconut_keypair_is_some().await);
}
}
@@ -801,12 +899,12 @@ pub(crate) mod tests {
async fn validate_verification_key() {
let db = MockContractDb::new();
let mut clients_and_states = prepare_clients_and_states_with_validation(&db).await;
for (_, state) in clients_and_states.iter_mut() {
for controller in clients_and_states.iter_mut() {
let proposal = db
.proposal_db
.read()
.unwrap()
.get(&state.proposal_id_value().unwrap())
.get(&controller.state.proposal_id_value().unwrap())
.unwrap()
.clone();
assert_eq!(proposal.status, Status::Passed);
@@ -825,18 +923,18 @@ pub(crate) mod tests {
.entry(TEST_VALIDATORS_ADDRESS[0].to_string())
.and_modify(|share| share.share.push('x'));
for (dkg_client, state) in clients_and_states.iter_mut() {
verification_key_validation(dkg_client, state, false)
for controller in clients_and_states.iter_mut() {
verification_key_validation(&controller.dkg_client, &mut controller.state, false)
.await
.unwrap();
}
for (idx, (_, state)) in clients_and_states.iter().enumerate() {
for (idx, controller) in clients_and_states.iter().enumerate() {
let proposal = db
.proposal_db
.read()
.unwrap()
.get(&state.proposal_id_value().unwrap())
.get(&controller.state.proposal_id_value().unwrap())
.unwrap()
.clone();
if idx == 0 {
@@ -867,18 +965,18 @@ pub(crate) mod tests {
.entry(TEST_VALIDATORS_ADDRESS[0].to_string())
.and_modify(|share| share.share = second_share);
for (dkg_client, state) in clients_and_states.iter_mut() {
verification_key_validation(dkg_client, state, false)
for controller in clients_and_states.iter_mut() {
verification_key_validation(&controller.dkg_client, &mut controller.state, false)
.await
.unwrap();
}
for (idx, (_, state)) in clients_and_states.iter().enumerate() {
for (idx, controller) in clients_and_states.iter().enumerate() {
let proposal = db
.proposal_db
.read()
.unwrap()
.get(&state.proposal_id_value().unwrap())
.get(&controller.state.proposal_id_value().unwrap())
.unwrap()
.clone();
if idx == 0 {
@@ -895,12 +993,12 @@ pub(crate) mod tests {
let db = MockContractDb::new();
let clients_and_states = prepare_clients_and_states_with_finalization(&db).await;
for (_, state) in clients_and_states.iter() {
for controller in clients_and_states.iter() {
let proposal = db
.proposal_db
.read()
.unwrap()
.get(&state.proposal_id_value().unwrap())
.get(&controller.state.proposal_id_value().unwrap())
.unwrap()
.clone();
assert_eq!(proposal.status, Status::Executed);
@@ -912,21 +1010,22 @@ pub(crate) mod tests {
async fn reshare_preserves_keys() {
let db = MockContractDb::new();
let mut clients_and_states = prepare_clients_and_states_with_finalization(&db).await;
for (_, state) in clients_and_states.iter_mut() {
state.set_was_in_progress();
for controller in clients_and_states.iter_mut() {
controller.state.set_was_in_progress();
}
let mut vks = vec![];
let mut indices = vec![];
for (_, state) in clients_and_states.iter() {
let vk = state
for controller in clients_and_states.iter() {
let vk = controller
.state
.coconut_keypair()
.await
.as_ref()
.unwrap()
.verification_key()
.clone();
let index = state.node_index().unwrap();
let index = controller.state.node_index().unwrap();
vks.push(vk);
indices.push(index);
}
@@ -961,46 +1060,51 @@ pub(crate) mod tests {
*db.dealings_db.write().unwrap() = Default::default();
*db.verification_share_db.write().unwrap() = Default::default();
let mut initial_dealers = vec![];
for (dkg_client, _) in clients_and_states.iter() {
let client_address = Addr::unchecked(dkg_client.get_address().await.as_ref());
for controller in clients_and_states.iter() {
let client_address =
Addr::unchecked(controller.dkg_client.get_address().await.as_ref());
initial_dealers.push(client_address);
}
*db.initial_dealers_db.write().unwrap() = Some(InitialReplacementData {
initial_dealers,
initial_height: 1,
});
*clients_and_states.first_mut().unwrap() = (new_dkg_client, state);
*clients_and_states.first_mut().unwrap() = DkgController::test_mock(new_dkg_client, state);
for (dkg_client, state) in clients_and_states.iter_mut() {
public_key_submission(dkg_client, state, true)
for controller in clients_and_states.iter_mut() {
controller.public_key_submission(0, true).await.unwrap();
}
for controller in clients_and_states.iter_mut() {
dealing_exchange(&controller.dkg_client, &mut controller.state, OsRng, true)
.await
.unwrap();
}
for (dkg_client, state) in clients_and_states.iter_mut() {
dealing_exchange(dkg_client, state, OsRng, true)
.await
.unwrap();
}
for (dkg_client, state) in clients_and_states.iter_mut() {
for controller in clients_and_states.iter_mut() {
let random_file: usize = OsRng.gen();
let private_key_path = temp_dir().join(format!("private{}.pem", random_file));
let public_key_path = temp_dir().join(format!("public{}.pem", random_file));
let keypair_path = KeyPairPath::new(private_key_path.clone(), public_key_path.clone());
verification_key_submission(dkg_client, state, 0, &keypair_path, true)
.await
.unwrap();
verification_key_submission(
&controller.dkg_client,
&mut controller.state,
0,
&keypair_path,
true,
)
.await
.unwrap();
std::fs::remove_file(private_key_path).unwrap();
std::fs::remove_file(public_key_path).unwrap();
}
for (dkg_client, state) in clients_and_states.iter_mut() {
verification_key_validation(dkg_client, state, true)
for controller in clients_and_states.iter_mut() {
verification_key_validation(&controller.dkg_client, &mut controller.state, true)
.await
.unwrap();
}
for (dkg_client, state) in clients_and_states.iter_mut() {
verification_key_finalization(dkg_client, state, true)
for controller in clients_and_states.iter_mut() {
verification_key_finalization(&controller.dkg_client, &mut controller.state, true)
.await
.unwrap();
}
@@ -1013,15 +1117,16 @@ pub(crate) mod tests {
let mut vks = vec![];
let mut indices = vec![];
for (_, state) in clients_and_states.iter() {
let vk = state
for controller in clients_and_states.iter() {
let vk = controller
.state
.coconut_keypair()
.await
.as_ref()
.unwrap()
.verification_key()
.clone();
let index = state.node_index().unwrap();
let index = controller.state.node_index().unwrap();
vks.push(vk);
indices.push(index);
}
@@ -1034,8 +1139,8 @@ pub(crate) mod tests {
async fn reshare_after_reset() {
let db = MockContractDb::new();
let mut clients_and_states = prepare_clients_and_states_with_finalization(&db).await;
for (_, state) in clients_and_states.iter_mut() {
state.set_was_in_progress();
for controller in clients_and_states.iter_mut() {
controller.state.set_was_in_progress();
}
let new_dkg_client = DkgClient::new(
@@ -1088,39 +1193,43 @@ pub(crate) mod tests {
*db.dealings_db.write().unwrap() = Default::default();
*db.verification_share_db.write().unwrap() = Default::default();
clients_and_states.pop().unwrap();
let (initial_client2, initial_state2) = clients_and_states.pop().unwrap();
clients_and_states.push((new_dkg_client, state));
clients_and_states.push((new_dkg_client2, state2));
let controller2 = clients_and_states.pop().unwrap();
clients_and_states.push(DkgController::test_mock(new_dkg_client, state));
clients_and_states.push(DkgController::test_mock(new_dkg_client2, state2));
// DKG in reset mode
for (dkg_client, state) in clients_and_states.iter_mut() {
public_key_submission(dkg_client, state, false)
for controller in clients_and_states.iter_mut() {
controller.public_key_submission(0, false).await.unwrap();
}
for controller in clients_and_states.iter_mut() {
dealing_exchange(&controller.dkg_client, &mut controller.state, OsRng, false)
.await
.unwrap();
}
for (dkg_client, state) in clients_and_states.iter_mut() {
dealing_exchange(dkg_client, state, OsRng, false)
.await
.unwrap();
}
for (dkg_client, state) in clients_and_states.iter_mut() {
for controller in clients_and_states.iter_mut() {
let random_file: usize = OsRng.gen();
let private_key_path = temp_dir().join(format!("private{}.pem", random_file));
let public_key_path = temp_dir().join(format!("public{}.pem", random_file));
let keypair_path = KeyPairPath::new(private_key_path.clone(), public_key_path.clone());
verification_key_submission(dkg_client, state, 0, &keypair_path, false)
.await
.unwrap();
verification_key_submission(
&controller.dkg_client,
&mut controller.state,
0,
&keypair_path,
false,
)
.await
.unwrap();
std::fs::remove_file(private_key_path).unwrap();
std::fs::remove_file(public_key_path).unwrap();
}
for (dkg_client, state) in clients_and_states.iter_mut() {
verification_key_validation(dkg_client, state, false)
for controller in clients_and_states.iter_mut() {
verification_key_validation(&controller.dkg_client, &mut controller.state, false)
.await
.unwrap();
}
for (dkg_client, state) in clients_and_states.iter_mut() {
verification_key_finalization(dkg_client, state, false)
for controller in clients_and_states.iter_mut() {
verification_key_finalization(&controller.dkg_client, &mut controller.state, false)
.await
.unwrap();
}
@@ -1130,22 +1239,23 @@ pub(crate) mod tests {
.unwrap()
.values()
.all(|proposal| { proposal.status == Status::Executed }));
for (_, state) in clients_and_states.iter_mut() {
state.set_was_in_progress();
for controller in clients_and_states.iter_mut() {
controller.state.set_was_in_progress();
}
// DKG in reshare mode
let mut vks = vec![];
let mut indices = vec![];
for (_, state) in clients_and_states.iter() {
let vk = state
for controller in clients_and_states.iter() {
let vk = controller
.state
.coconut_keypair()
.await
.as_ref()
.unwrap()
.verification_key()
.clone();
let index = state.node_index().unwrap();
let index = controller.state.node_index().unwrap();
vks.push(vk);
indices.push(index);
}
@@ -1157,47 +1267,52 @@ pub(crate) mod tests {
*db.dealings_db.write().unwrap() = Default::default();
*db.verification_share_db.write().unwrap() = Default::default();
let mut initial_dealers = vec![];
for (dkg_client, _) in clients_and_states.iter() {
let client_address = Addr::unchecked(dkg_client.get_address().await.as_ref());
for controller in clients_and_states.iter() {
let client_address =
Addr::unchecked(controller.dkg_client.get_address().await.as_ref());
initial_dealers.push(client_address);
}
*db.initial_dealers_db.write().unwrap() = Some(InitialReplacementData {
initial_dealers,
initial_height: 1,
});
*clients_and_states.last_mut().unwrap() = (initial_client2, initial_state2);
*clients_and_states.last_mut().unwrap() = controller2;
for (dkg_client, state) in clients_and_states.iter_mut() {
public_key_submission(dkg_client, state, true)
for controller in clients_and_states.iter_mut() {
controller.public_key_submission(0, true).await.unwrap();
}
for controller in clients_and_states.iter_mut() {
dealing_exchange(&controller.dkg_client, &mut controller.state, OsRng, true)
.await
.unwrap();
}
for (dkg_client, state) in clients_and_states.iter_mut() {
dealing_exchange(dkg_client, state, OsRng, true)
.await
.unwrap();
}
for (dkg_client, state) in clients_and_states.iter_mut() {
for controller in clients_and_states.iter_mut() {
let random_file: usize = OsRng.gen();
let private_key_path = temp_dir().join(format!("private{}.pem", random_file));
let public_key_path = temp_dir().join(format!("public{}.pem", random_file));
let keypair_path = KeyPairPath::new(private_key_path.clone(), public_key_path.clone());
verification_key_submission(dkg_client, state, 0, &keypair_path, true)
.await
.unwrap();
verification_key_submission(
&controller.dkg_client,
&mut controller.state,
0,
&keypair_path,
true,
)
.await
.unwrap();
std::fs::remove_file(private_key_path).unwrap();
std::fs::remove_file(public_key_path).unwrap();
}
for (dkg_client, state) in clients_and_states.iter_mut() {
verification_key_validation(dkg_client, state, true)
for controller in clients_and_states.iter_mut() {
verification_key_validation(&controller.dkg_client, &mut controller.state, true)
.await
.unwrap();
}
for (dkg_client, state) in clients_and_states.iter_mut() {
verification_key_finalization(dkg_client, state, true)
for controller in clients_and_states.iter_mut() {
verification_key_finalization(&controller.dkg_client, &mut controller.state, true)
.await
.unwrap();
}
@@ -1210,15 +1325,16 @@ pub(crate) mod tests {
let mut vks = vec![];
let mut indices = vec![];
for (_, state) in clients_and_states.iter() {
let vk = state
for controller in clients_and_states.iter() {
let vk = controller
.state
.coconut_keypair()
.await
.as_ref()
.unwrap()
.verification_key()
.clone();
let index = state.node_index().unwrap();
let index = controller.state.node_index().unwrap();
vks.push(vk);
indices.push(index);
}
+18 -8
View File
@@ -1,31 +1,41 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use nym_coconut_dkg_common::types::EpochId;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::{RwLock, RwLockReadGuard};
#[derive(Clone, Debug)]
pub struct KeyPair {
inner: Arc<RwLock<Option<nym_coconut_interface::KeyPair>>>,
// keys: Arc<RwLock<HashMap<EpochId, nym_coconut_interface::KeyPair>>>,
keys: Arc<RwLock<Option<(EpochId, nym_coconut_interface::KeyPair)>>>,
// issued_for_epoch: Arc<AtomicU64>,
}
impl KeyPair {
pub fn new() -> Self {
Self {
inner: Arc::new(RwLock::new(None)),
keys: Arc::new(RwLock::new(None)),
}
}
pub async fn take(&self) -> Option<nym_coconut::KeyPair> {
self.inner.write().await.take()
pub async fn take(&self) -> Option<(EpochId, nym_coconut::KeyPair)> {
self.keys.write().await.take()
}
pub async fn get(&self) -> RwLockReadGuard<'_, Option<nym_coconut::KeyPair>> {
self.inner.read().await
todo!()
// self.keys.read().await
}
pub async fn set(&self, keypair: Option<nym_coconut_interface::KeyPair>) {
let mut w_lock = self.inner.write().await;
*w_lock = keypair;
pub async fn set(&self, epoch_id: EpochId, keypair: nym_coconut_interface::KeyPair) {
todo!()
// let mut w_lock = self.keys.write().await;
// *w_lock = Some(keypair);
}
pub async fn invalidate(&self) {
*self.keys.write().await = None
}
}
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -73,7 +73,8 @@ async fn start_nym_api_tasks(config: Config) -> anyhow::Result<ShutdownHandles>
// if the keypair doesnt exist (because say this API is running in the caching mode), nothing will happen
if let Some(loaded_keys) = load_coconut_keypair_if_exists(&config.coconut_signer)? {
coconut_keypair_wrapper.set(Some(loaded_keys)).await
todo!()
// coconut_keypair_wrapper.set(loaded_keys).await
}
let identity_keypair = config.base.storage_paths.load_identity()?;