Merge branch 'release/v1.1.4' of https://github.com/nymtech/nym into feature/wallet-tests

This commit is contained in:
benedettadavico
2022-12-21 17:13:01 +01:00
323 changed files with 18872 additions and 3977 deletions
+1 -1
View File
@@ -3,7 +3,7 @@
[package]
name = "nym-validator-api"
version = "1.1.2"
version = "1.1.4"
authors = [
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
"Jędrzej Stuczyński <andrew@nymtech.net>",
+2
View File
@@ -8,6 +8,7 @@ use coconut_dkg_common::types::{EncodedBTEPublicKeyWithProof, EpochState};
use coconut_dkg_common::verification_key::{ContractVKShare, VerificationKeyShare};
use contracts_common::dealings::ContractSafeBytes;
use cw3::ProposalResponse;
use dkg::Threshold;
use validator_client::nymd::cosmwasm_client::types::ExecuteResult;
use validator_client::nymd::{AccountId, Fee, TxResponse};
@@ -22,6 +23,7 @@ pub trait Client {
blinded_serial_number: String,
) -> Result<SpendCredentialResponse>;
async fn get_current_epoch_state(&self) -> Result<EpochState>;
async fn get_current_epoch_threshold(&self) -> Result<Option<Threshold>>;
async fn get_self_registered_dealer_details(&self) -> Result<DealerDetailsResponse>;
async fn get_current_dealers(&self) -> Result<Vec<DealerDetails>>;
async fn get_dealings(&self, idx: usize) -> Result<Vec<ContractDealing>>;
+7
View File
@@ -8,6 +8,7 @@ use coconut_dkg_common::types::{EncodedBTEPublicKeyWithProof, EpochState, NodeIn
use coconut_dkg_common::verification_key::{ContractVKShare, VerificationKeyShare};
use contracts_common::dealings::ContractSafeBytes;
use cw3::ProposalResponse;
use dkg::Threshold;
use validator_client::nymd::cosmwasm_client::logs::{find_attribute, NODE_INDEX};
use validator_client::nymd::cosmwasm_client::types::ExecuteResult;
use validator_client::nymd::AccountId;
@@ -45,6 +46,12 @@ impl DkgClient {
ret
}
pub(crate) async fn get_current_epoch_threshold(
&self,
) -> Result<Option<Threshold>, CoconutError> {
self.inner.get_current_epoch_threshold().await
}
pub(crate) async fn get_self_registered_dealer_details(
&self,
) -> Result<DealerDetailsResponse, CoconutError> {
+3 -1
View File
@@ -1,7 +1,9 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
#[derive(Debug, Eq, PartialEq)]
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub(crate) enum ComplaintReason {
MalformedBTEPublicKey,
InvalidBTEPublicKey,
+17 -2
View File
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
use crate::coconut::dkg::client::DkgClient;
use crate::coconut::dkg::state::{ConsistentState, State};
use crate::coconut::dkg::state::{ConsistentState, PersistentState, State};
use crate::coconut::dkg::verification_key::{
verification_key_finalization, verification_key_validation,
};
@@ -63,12 +63,20 @@ impl<R: RngCore + Clone> DkgController<R> {
)) {
coconut_keypair.set(coconut_keypair_value).await;
}
let persistent_state =
PersistentState::load_from_file(config.persistent_state_path()).unwrap_or_default();
Ok(DkgController {
dkg_client: DkgClient::new(nymd_client),
secret_key_path: config.secret_key_path(),
verification_key_path: config.verification_key_path(),
state: State::new(config.get_announce_address(), dkg_keypair, coconut_keypair),
state: State::new(
config.persistent_state_path(),
persistent_state,
config.get_announce_address(),
dkg_keypair,
coconut_keypair,
),
rng,
polling_rate: config.get_dkg_contract_polling_rate(),
})
@@ -114,6 +122,13 @@ impl<R: RngCore + Clone> DkgController<R> {
};
if let Err(e) = ret {
warn!("Could not handle this iteration for the epoch state: {}", e);
} else if epoch_state != EpochState::InProgress {
let persistent_state = PersistentState::from(&self.state);
if let Err(e) =
persistent_state.save_to_file(self.state.persistent_state_path())
{
warn!("Could not backup the state for this iteration: {}", e);
}
}
}
}
+14 -6
View File
@@ -20,9 +20,7 @@ pub(crate) async fn dealing_exchange(
}
let dealers = dkg_client.get_current_dealers().await?;
// note: ceiling in integer division can be achieved via q = (x + y - 1) / y;
let threshold = (2 * dealers.len() as u64 + 3 - 1) / 3;
let threshold = dkg_client.get_current_epoch_threshold().await?;
state.set_dealers(dealers);
state.set_threshold(threshold);
let receivers = state.current_dealers_by_idx();
@@ -36,7 +34,7 @@ pub(crate) async fn dealing_exchange(
rng.clone(),
&params,
dealer_index,
threshold,
state.threshold()?,
&receivers,
None,
);
@@ -55,6 +53,7 @@ pub(crate) async fn dealing_exchange(
pub(crate) mod tests {
use super::*;
use crate::coconut::dkg::complaints::ComplaintReason;
use crate::coconut::dkg::state::PersistentState;
use crate::coconut::tests::DummyClient;
use crate::coconut::KeyPair;
use coconut_dkg_common::dealer::DealerDetails;
@@ -63,6 +62,7 @@ pub(crate) mod tests {
use dkg::bte::Params;
use rand::rngs::OsRng;
use std::collections::HashMap;
use std::path::PathBuf;
use std::str::FromStr;
use std::sync::{Arc, RwLock};
use url::Url;
@@ -103,13 +103,17 @@ pub(crate) mod tests {
let self_index = 2;
let dealer_details_db = Arc::new(RwLock::new(HashMap::new()));
let dealings_db = Arc::new(RwLock::new(HashMap::new()));
let threshold_db = Arc::new(RwLock::new(Some(2)));
let dkg_client = DkgClient::new(
DummyClient::new(AccountId::from_str(TEST_VALIDATORS_ADDRESS[0]).unwrap())
.with_dealer_details(&dealer_details_db)
.with_dealings(&dealings_db),
.with_dealings(&dealings_db)
.with_threshold(&threshold_db),
);
let params = setup();
let mut state = State::new(
PathBuf::default(),
PersistentState::default(),
Url::parse("localhost:8000").unwrap(),
DkgKeyPair::new(&params, OsRng),
KeyPair::new(),
@@ -156,13 +160,17 @@ pub(crate) mod tests {
let self_index = 2;
let dealer_details_db = Arc::new(RwLock::new(HashMap::new()));
let dealings_db = Arc::new(RwLock::new(HashMap::new()));
let threshold_db = Arc::new(RwLock::new(Some(2)));
let dkg_client = DkgClient::new(
DummyClient::new(AccountId::from_str(TEST_VALIDATORS_ADDRESS[0]).unwrap())
.with_dealer_details(&dealer_details_db)
.with_dealings(&dealings_db),
.with_dealings(&dealings_db)
.with_threshold(&threshold_db),
);
let params = setup();
let mut state = State::new(
PathBuf::default(),
PersistentState::default(),
Url::parse("localhost:8000").unwrap(),
DkgKeyPair::new(&params, OsRng),
KeyPair::new(),
@@ -34,10 +34,12 @@ pub(crate) async fn public_key_submission(
#[cfg(test)]
pub(crate) mod tests {
use super::*;
use crate::coconut::dkg::state::PersistentState;
use crate::coconut::tests::DummyClient;
use crate::coconut::KeyPair;
use dkg::bte::keys::KeyPair as DkgKeyPair;
use rand::rngs::OsRng;
use std::path::PathBuf;
use std::str::FromStr;
use url::Url;
use validator_client::nymd::AccountId;
@@ -51,6 +53,8 @@ pub(crate) mod tests {
AccountId::from_str(TEST_VALIDATOR_ADDRESS).unwrap(),
));
let mut state = State::new(
PathBuf::default(),
PersistentState::default(),
Url::parse("localhost:8000").unwrap(),
DkgKeyPair::new(&dkg::bte::setup(), OsRng),
KeyPair::new(),
+114 -25
View File
@@ -9,13 +9,33 @@ use coconut_dkg_common::types::EpochState;
use cosmwasm_std::Addr;
use dkg::bte::{keys::KeyPair as DkgKeyPair, PublicKey, PublicKeyWithProof};
use dkg::{NodeIndex, RecoveredVerificationKeys, Threshold};
use serde::de::Error;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::collections::BTreeMap;
use std::path::PathBuf;
use url::Url;
fn bte_pk_serialize<S: Serializer>(
val: &PublicKeyWithProof,
serializer: S,
) -> Result<S::Ok, S::Error> {
val.to_bytes().serialize(serializer)
}
fn bte_pk_deserialize<'de, D>(deserializer: D) -> Result<PublicKeyWithProof, D::Error>
where
D: Deserializer<'de>,
{
let vec: Vec<u8> = Deserialize::deserialize(deserializer)?;
PublicKeyWithProof::try_from_bytes(&vec).map_err(|err| Error::custom(format_args!("{:?}", err)))
}
// note: each dealer is also a receiver which simplifies some logic significantly
#[derive(Debug)]
#[derive(Clone, Deserialize, Debug, Serialize)]
pub(crate) struct DkgParticipant {
pub(crate) _address: Addr,
#[serde(serialize_with = "bte_pk_serialize")]
#[serde(deserialize_with = "bte_pk_deserialize")]
pub(crate) bte_public_key_with_proof: PublicKeyWithProof,
pub(crate) assigned_index: NodeIndex,
}
@@ -71,20 +91,6 @@ pub(crate) trait ConsistentState {
}
}
pub(crate) struct State {
announce_address: Url,
dkg_keypair: DkgKeyPair,
coconut_keypair: CoconutKeyPair,
node_index: Option<NodeIndex>,
dealers: BTreeMap<Addr, Result<DkgParticipant, ComplaintReason>>,
receiver_index: Option<usize>,
threshold: Option<Threshold>,
recovered_vks: Vec<RecoveredVerificationKeys>,
proposal_id: Option<u64>,
voted_vks: bool,
executed_proposal: bool,
}
#[async_trait]
impl ConsistentState for State {
fn node_index_value(&self) -> Result<NodeIndex, CoconutError> {
@@ -131,27 +137,110 @@ impl ConsistentState for State {
}
}
fn vks_serialize<S: Serializer>(
val: &[RecoveredVerificationKeys],
serializer: S,
) -> Result<S::Ok, S::Error> {
let vec: Vec<Vec<u8>> = val.iter().map(|vk| vk.to_bytes()).collect();
vec.serialize(serializer)
}
fn vks_deserialize<'de, D>(deserializer: D) -> Result<Vec<RecoveredVerificationKeys>, D::Error>
where
D: Deserializer<'de>,
{
let vec: Vec<Vec<u8>> = Deserialize::deserialize(deserializer)?;
vec.into_iter()
.map(|b| {
RecoveredVerificationKeys::try_from_bytes(&b)
.map_err(|err| D::Error::custom(format_args!("{:?}", err)))
})
.collect()
}
#[derive(Default, Deserialize, Serialize)]
pub(crate) struct PersistentState {
node_index: Option<NodeIndex>,
dealers: BTreeMap<Addr, Result<DkgParticipant, ComplaintReason>>,
receiver_index: Option<usize>,
threshold: Option<Threshold>,
#[serde(serialize_with = "vks_serialize")]
#[serde(deserialize_with = "vks_deserialize")]
recovered_vks: Vec<RecoveredVerificationKeys>,
proposal_id: Option<u64>,
voted_vks: bool,
executed_proposal: bool,
}
impl From<&State> for PersistentState {
fn from(s: &State) -> Self {
PersistentState {
node_index: s.node_index,
dealers: s.dealers.clone(),
receiver_index: s.receiver_index,
threshold: s.threshold,
recovered_vks: s.recovered_vks.clone(),
proposal_id: s.proposal_id,
voted_vks: s.voted_vks,
executed_proposal: s.executed_proposal,
}
}
}
impl PersistentState {
pub fn save_to_file(&self, path: PathBuf) -> Result<(), CoconutError> {
std::fs::write(path, serde_json::to_string(self)?)?;
Ok(())
}
pub fn load_from_file(path: PathBuf) -> Result<Self, CoconutError> {
Ok(serde_json::from_str(&std::fs::read_to_string(path)?)?)
}
}
pub(crate) struct State {
persistent_state_path: PathBuf,
announce_address: Url,
dkg_keypair: DkgKeyPair,
coconut_keypair: CoconutKeyPair,
node_index: Option<NodeIndex>,
dealers: BTreeMap<Addr, Result<DkgParticipant, ComplaintReason>>,
receiver_index: Option<usize>,
threshold: Option<Threshold>,
recovered_vks: Vec<RecoveredVerificationKeys>,
proposal_id: Option<u64>,
voted_vks: bool,
executed_proposal: bool,
}
impl State {
pub fn new(
persistent_state_path: PathBuf,
persistent_state: PersistentState,
announce_address: Url,
dkg_keypair: DkgKeyPair,
coconut_keypair: CoconutKeyPair,
) -> Self {
State {
persistent_state_path,
announce_address,
dkg_keypair,
coconut_keypair,
node_index: None,
dealers: BTreeMap::new(),
receiver_index: None,
threshold: None,
recovered_vks: vec![],
proposal_id: None,
voted_vks: false,
executed_proposal: false,
node_index: persistent_state.node_index,
dealers: persistent_state.dealers,
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,
}
}
pub fn persistent_state_path(&self) -> PathBuf {
self.persistent_state_path.clone()
}
pub fn announce_address(&self) -> &Url {
&self.announce_address
}
@@ -244,8 +333,8 @@ impl State {
self.receiver_index = receiver_index;
}
pub fn set_threshold(&mut self, threshold: Threshold) {
self.threshold = Some(threshold);
pub fn set_threshold(&mut self, threshold: Option<Threshold>) {
self.threshold = threshold;
}
pub fn set_proposal_id(&mut self, proposal_id: u64) {
+79 -188
View File
@@ -249,6 +249,7 @@ pub(crate) mod tests {
use super::*;
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;
use coconut_dkg_common::dealer::DealerDetails;
@@ -259,36 +260,55 @@ pub(crate) mod tests {
use rand::Rng;
use std::collections::HashMap;
use std::env::temp_dir;
use std::path::PathBuf;
use std::str::FromStr;
use std::sync::{Arc, RwLock};
use url::Url;
use validator_client::nymd::AccountId;
struct MockContractDb {
dealer_details_db: Arc<RwLock<HashMap<String, DealerDetails>>>,
dealings_db: Arc<RwLock<HashMap<String, Vec<ContractSafeBytes>>>>,
proposal_db: Arc<RwLock<HashMap<u64, ProposalResponse>>>,
verification_share_db: Arc<RwLock<HashMap<String, ContractVKShare>>>,
threshold_db: Arc<RwLock<Option<Threshold>>>,
}
impl MockContractDb {
pub fn new() -> Self {
MockContractDb {
dealer_details_db: Arc::new(Default::default()),
dealings_db: Arc::new(Default::default()),
proposal_db: Arc::new(Default::default()),
verification_share_db: Arc::new(Default::default()),
threshold_db: Arc::new(RwLock::new(Some(2))),
}
}
}
const TEST_VALIDATORS_ADDRESS: [&str; 3] = [
"n1aq9kakfgwqcufr23lsv644apavcntrsqsk4yus",
"n1s9l3xr4g0rglvk4yctktmck3h4eq0gp6z2e20v",
"n19kl4py32vsk297dm93ezem992cdyzdy4zuc2x6",
];
async fn prepare_clients_and_states(
dealer_details_db: &Arc<RwLock<HashMap<String, DealerDetails>>>,
dealings_db: &Arc<RwLock<HashMap<String, Vec<ContractSafeBytes>>>>,
proposal_db: &Arc<RwLock<HashMap<u64, ProposalResponse>>>,
verification_share_db: &Arc<RwLock<HashMap<String, ContractVKShare>>>,
) -> Vec<(DkgClient, State)> {
async fn prepare_clients_and_states(db: &MockContractDb) -> Vec<(DkgClient, State)> {
let params = setup();
let mut clients_and_states = vec![];
for addr in TEST_VALIDATORS_ADDRESS {
let dkg_client = DkgClient::new(
DummyClient::new(AccountId::from_str(addr).unwrap())
.with_dealer_details(dealer_details_db)
.with_dealings(dealings_db)
.with_proposal_db(proposal_db)
.with_verification_share(verification_share_db),
.with_dealer_details(&db.dealer_details_db)
.with_dealings(&db.dealings_db)
.with_proposal_db(&db.proposal_db)
.with_verification_share(&db.verification_share_db)
.with_threshold(&db.threshold_db),
);
let keypair = DkgKeyPair::new(&params, OsRng);
let state = State::new(
PathBuf::default(),
PersistentState::default(),
Url::parse("localhost:8000").unwrap(),
keypair,
KeyPair::new(),
@@ -305,18 +325,9 @@ pub(crate) mod tests {
}
async fn prepare_clients_and_states_with_submission(
dealer_details_db: &Arc<RwLock<HashMap<String, DealerDetails>>>,
dealings_db: &Arc<RwLock<HashMap<String, Vec<ContractSafeBytes>>>>,
proposal_db: &Arc<RwLock<HashMap<u64, ProposalResponse>>>,
verification_share_db: &Arc<RwLock<HashMap<String, ContractVKShare>>>,
db: &MockContractDb,
) -> Vec<(DkgClient, State)> {
let mut clients_and_states = prepare_clients_and_states(
dealer_details_db,
dealings_db,
proposal_db,
verification_share_db,
)
.await;
let mut clients_and_states = prepare_clients_and_states(db).await;
for (dkg_client, state) in clients_and_states.iter_mut() {
let random_file: usize = OsRng.gen();
let private_key_path = temp_dir().join(format!("private{}.pem", random_file));
@@ -332,18 +343,9 @@ pub(crate) mod tests {
}
async fn prepare_clients_and_states_with_validation(
dealer_details_db: &Arc<RwLock<HashMap<String, DealerDetails>>>,
dealings_db: &Arc<RwLock<HashMap<String, Vec<ContractSafeBytes>>>>,
proposal_db: &Arc<RwLock<HashMap<u64, ProposalResponse>>>,
verification_share_db: &Arc<RwLock<HashMap<String, ContractVKShare>>>,
db: &MockContractDb,
) -> Vec<(DkgClient, State)> {
let mut clients_and_states = prepare_clients_and_states_with_submission(
dealer_details_db,
dealings_db,
proposal_db,
verification_share_db,
)
.await;
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)
.await
@@ -353,18 +355,9 @@ pub(crate) mod tests {
}
async fn prepare_clients_and_states_with_finalization(
dealer_details_db: &Arc<RwLock<HashMap<String, DealerDetails>>>,
dealings_db: &Arc<RwLock<HashMap<String, Vec<ContractSafeBytes>>>>,
proposal_db: &Arc<RwLock<HashMap<u64, ProposalResponse>>>,
verification_share_db: &Arc<RwLock<HashMap<String, ContractVKShare>>>,
db: &MockContractDb,
) -> Vec<(DkgClient, State)> {
let mut clients_and_states = prepare_clients_and_states_with_validation(
dealer_details_db,
dealings_db,
proposal_db,
verification_share_db,
)
.await;
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)
.await
@@ -376,17 +369,8 @@ pub(crate) mod tests {
#[tokio::test]
#[ignore] // expensive test
async fn check_dealers_filter_all_good() {
let dealer_details_db = Arc::new(RwLock::new(HashMap::new()));
let dealings_db = Arc::new(RwLock::new(HashMap::new()));
let proposal_db = Arc::new(RwLock::new(HashMap::new()));
let verification_share_db = Arc::new(RwLock::new(HashMap::new()));
let mut clients_and_states = prepare_clients_and_states(
&dealer_details_db,
&dealings_db,
&proposal_db,
&verification_share_db,
)
.await;
let db = MockContractDb::new();
let mut clients_and_states = prepare_clients_and_states(&db).await;
for (dkg_client, state) in clients_and_states.iter_mut() {
let filtered = deterministic_filter_dealers(dkg_client, state, 2)
.await
@@ -401,20 +385,11 @@ pub(crate) mod tests {
#[tokio::test]
#[ignore] // expensive test
async fn check_dealers_filter_one_bad_dealing() {
let dealer_details_db = Arc::new(RwLock::new(HashMap::new()));
let dealings_db = Arc::new(RwLock::new(HashMap::new()));
let proposal_db = Arc::new(RwLock::new(HashMap::new()));
let verification_share_db = Arc::new(RwLock::new(HashMap::new()));
let mut clients_and_states = prepare_clients_and_states(
&dealer_details_db,
&dealings_db,
&proposal_db,
&verification_share_db,
)
.await;
let db = MockContractDb::new();
let mut clients_and_states = prepare_clients_and_states(&db).await;
// corrupt just one dealing
dealings_db
db.dealings_db
.write()
.unwrap()
.entry(TEST_VALIDATORS_ADDRESS[0].to_string())
@@ -442,20 +417,11 @@ pub(crate) mod tests {
#[tokio::test]
#[ignore] // expensive test
async fn check_dealers_filter_all_bad_dealings() {
let dealer_details_db = Arc::new(RwLock::new(HashMap::new()));
let dealings_db = Arc::new(RwLock::new(HashMap::new()));
let proposal_db = Arc::new(RwLock::new(HashMap::new()));
let verification_share_db = Arc::new(RwLock::new(HashMap::new()));
let mut clients_and_states = prepare_clients_and_states(
&dealer_details_db,
&dealings_db,
&proposal_db,
&verification_share_db,
)
.await;
let db = MockContractDb::new();
let mut clients_and_states = prepare_clients_and_states(&db).await;
// corrupt all dealings of one address
dealings_db
db.dealings_db
.write()
.unwrap()
.entry(TEST_VALIDATORS_ADDRESS[0].to_string())
@@ -486,20 +452,11 @@ pub(crate) mod tests {
#[tokio::test]
#[ignore] // expensive test
async fn check_dealers_filter_malformed_dealing() {
let dealer_details_db = Arc::new(RwLock::new(HashMap::new()));
let dealings_db = Arc::new(RwLock::new(HashMap::new()));
let proposal_db = Arc::new(RwLock::new(HashMap::new()));
let verification_share_db = Arc::new(RwLock::new(HashMap::new()));
let mut clients_and_states = prepare_clients_and_states(
&dealer_details_db,
&dealings_db,
&proposal_db,
&verification_share_db,
)
.await;
let db = MockContractDb::new();
let mut clients_and_states = prepare_clients_and_states(&db).await;
// corrupt just one dealing
dealings_db
db.dealings_db
.write()
.unwrap()
.entry(TEST_VALIDATORS_ADDRESS[0].to_string())
@@ -532,20 +489,11 @@ pub(crate) mod tests {
#[tokio::test]
#[ignore] // expensive test
async fn check_dealers_filter_dealing_verification_error() {
let dealer_details_db = Arc::new(RwLock::new(HashMap::new()));
let dealings_db = Arc::new(RwLock::new(HashMap::new()));
let proposal_db = Arc::new(RwLock::new(HashMap::new()));
let verification_share_db = Arc::new(RwLock::new(HashMap::new()));
let mut clients_and_states = prepare_clients_and_states(
&dealer_details_db,
&dealings_db,
&proposal_db,
&verification_share_db,
)
.await;
let db = MockContractDb::new();
let mut clients_and_states = prepare_clients_and_states(&db).await;
// corrupt just one dealing
dealings_db
db.dealings_db
.write()
.unwrap()
.entry(TEST_VALIDATORS_ADDRESS[0].to_string())
@@ -579,17 +527,8 @@ pub(crate) mod tests {
#[tokio::test]
#[ignore] // expensive test
async fn partial_keypair_derivation() {
let dealer_details_db = Arc::new(RwLock::new(HashMap::new()));
let dealings_db = Arc::new(RwLock::new(HashMap::new()));
let proposal_db = Arc::new(RwLock::new(HashMap::new()));
let verification_share_db = Arc::new(RwLock::new(HashMap::new()));
let mut clients_and_states = prepare_clients_and_states(
&dealer_details_db,
&dealings_db,
&proposal_db,
&verification_share_db,
)
.await;
let db = MockContractDb::new();
let mut clients_and_states = prepare_clients_and_states(&db).await;
for (dkg_client, state) in clients_and_states.iter_mut() {
let filtered = deterministic_filter_dealers(dkg_client, state, 2)
.await
@@ -601,20 +540,11 @@ pub(crate) mod tests {
#[tokio::test]
#[ignore] // expensive test
async fn partial_keypair_derivation_with_threshold() {
let dealer_details_db = Arc::new(RwLock::new(HashMap::new()));
let dealings_db = Arc::new(RwLock::new(HashMap::new()));
let proposal_db = Arc::new(RwLock::new(HashMap::new()));
let verification_share_db = Arc::new(RwLock::new(HashMap::new()));
let mut clients_and_states = prepare_clients_and_states(
&dealer_details_db,
&dealings_db,
&proposal_db,
&verification_share_db,
)
.await;
let db = MockContractDb::new();
let mut clients_and_states = prepare_clients_and_states(&db).await;
// corrupt just one dealing
dealings_db
db.dealings_db
.write()
.unwrap()
.entry(TEST_VALIDATORS_ADDRESS[0].to_string())
@@ -635,20 +565,12 @@ pub(crate) mod tests {
#[tokio::test]
#[ignore] // expensive test
async fn submit_verification_key() {
let dealer_details_db = Arc::new(RwLock::new(HashMap::new()));
let dealings_db = Arc::new(RwLock::new(HashMap::new()));
let proposal_db = Arc::new(RwLock::new(HashMap::new()));
let verification_share_db = Arc::new(RwLock::new(HashMap::new()));
let mut clients_and_states = prepare_clients_and_states_with_submission(
&dealer_details_db,
&dealings_db,
&proposal_db,
&verification_share_db,
)
.await;
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() {
assert!(proposal_db
assert!(db
.proposal_db
.read()
.unwrap()
.contains_key(&state.proposal_id_value().unwrap()));
@@ -659,19 +581,11 @@ pub(crate) mod tests {
#[tokio::test]
#[ignore] // expensive test
async fn validate_verification_key() {
let dealer_details_db = Arc::new(RwLock::new(HashMap::new()));
let dealings_db = Arc::new(RwLock::new(HashMap::new()));
let proposal_db = Arc::new(RwLock::new(HashMap::new()));
let verification_share_db = Arc::new(RwLock::new(HashMap::new()));
let mut clients_and_states = prepare_clients_and_states_with_validation(
&dealer_details_db,
&dealings_db,
&proposal_db,
&verification_share_db,
)
.await;
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() {
let proposal = proposal_db
let proposal = db
.proposal_db
.read()
.unwrap()
.get(&state.proposal_id_value().unwrap())
@@ -684,19 +598,10 @@ pub(crate) mod tests {
#[tokio::test]
#[ignore] // expensive test
async fn validate_verification_key_malformed_share() {
let dealer_details_db = Arc::new(RwLock::new(HashMap::new()));
let dealings_db = Arc::new(RwLock::new(HashMap::new()));
let proposal_db = Arc::new(RwLock::new(HashMap::new()));
let verification_share_db = Arc::new(RwLock::new(HashMap::new()));
let mut clients_and_states = prepare_clients_and_states_with_submission(
&dealer_details_db,
&dealings_db,
&proposal_db,
&verification_share_db,
)
.await;
let db = MockContractDb::new();
let mut clients_and_states = prepare_clients_and_states_with_submission(&db).await;
verification_share_db
db.verification_share_db
.write()
.unwrap()
.entry(TEST_VALIDATORS_ADDRESS[0].to_string())
@@ -709,7 +614,8 @@ pub(crate) mod tests {
}
for (idx, (_, state)) in clients_and_states.iter().enumerate() {
let proposal = proposal_db
let proposal = db
.proposal_db
.read()
.unwrap()
.get(&state.proposal_id_value().unwrap())
@@ -726,26 +632,18 @@ pub(crate) mod tests {
#[tokio::test]
#[ignore] // expensive test
async fn validate_verification_key_unpaired_share() {
let dealer_details_db = Arc::new(RwLock::new(HashMap::new()));
let dealings_db = Arc::new(RwLock::new(HashMap::new()));
let proposal_db = Arc::new(RwLock::new(HashMap::new()));
let verification_share_db = Arc::new(RwLock::new(HashMap::new()));
let mut clients_and_states = prepare_clients_and_states_with_submission(
&dealer_details_db,
&dealings_db,
&proposal_db,
&verification_share_db,
)
.await;
let db = MockContractDb::new();
let mut clients_and_states = prepare_clients_and_states_with_submission(&db).await;
let second_share = verification_share_db
let second_share = db
.verification_share_db
.write()
.unwrap()
.get(TEST_VALIDATORS_ADDRESS[1])
.unwrap()
.share
.clone();
verification_share_db
db.verification_share_db
.write()
.unwrap()
.entry(TEST_VALIDATORS_ADDRESS[0].to_string())
@@ -758,7 +656,8 @@ pub(crate) mod tests {
}
for (idx, (_, state)) in clients_and_states.iter().enumerate() {
let proposal = proposal_db
let proposal = db
.proposal_db
.read()
.unwrap()
.get(&state.proposal_id_value().unwrap())
@@ -775,20 +674,12 @@ pub(crate) mod tests {
#[tokio::test]
#[ignore] // expensive test
async fn finalize_verification_key() {
let dealer_details_db = Arc::new(RwLock::new(HashMap::new()));
let dealings_db = Arc::new(RwLock::new(HashMap::new()));
let proposal_db = Arc::new(RwLock::new(HashMap::new()));
let verification_share_db = Arc::new(RwLock::new(HashMap::new()));
let clients_and_states = prepare_clients_and_states_with_finalization(
&dealer_details_db,
&dealings_db,
&proposal_db,
&verification_share_db,
)
.await;
let db = MockContractDb::new();
let clients_and_states = prepare_clients_and_states_with_finalization(&db).await;
for (_, state) in clients_and_states.iter() {
let proposal = proposal_db
let proposal = db
.proposal_db
.read()
.unwrap()
.get(&state.proposal_id_value().unwrap())
+3
View File
@@ -23,6 +23,9 @@ pub enum CoconutError {
#[error("{0}")]
IOError(#[from] std::io::Error),
#[error("{0}")]
SerdeJsonError(#[from] serde_json::Error),
#[error("Could not parse Ed25519 data")]
Ed25519ParseError(#[from] Ed25519RecoveryError),
+13 -1
View File
@@ -45,6 +45,7 @@ use coconut_dkg_common::verification_key::{ContractVKShare, VerificationKeyShare
use contracts_common::dealings::ContractSafeBytes;
use crypto::asymmetric::{encryption, identity};
use cw3::ProposalResponse;
use dkg::Threshold;
use rand_07::rngs::OsRng;
use rand_07::Rng;
use rocket::http::Status;
@@ -67,6 +68,7 @@ pub(crate) struct DummyClient {
epoch_state: Arc<RwLock<EpochState>>,
dealer_details: Arc<RwLock<HashMap<String, DealerDetails>>>,
threshold: Arc<RwLock<Option<Threshold>>>,
dealings: Arc<RwLock<HashMap<String, Vec<ContractSafeBytes>>>>,
verification_share: Arc<RwLock<HashMap<String, ContractVKShare>>>,
}
@@ -80,6 +82,7 @@ impl DummyClient {
spent_credential_db: Arc::new(RwLock::new(HashMap::new())),
epoch_state: Arc::new(RwLock::new(EpochState::default())),
dealer_details: Arc::new(RwLock::new(HashMap::new())),
threshold: Arc::new(RwLock::new(None)),
dealings: Arc::new(RwLock::new(HashMap::new())),
verification_share: Arc::new(RwLock::new(HashMap::new())),
}
@@ -119,6 +122,11 @@ impl DummyClient {
self
}
pub fn with_threshold(mut self, threshold: &Arc<RwLock<Option<Threshold>>>) -> Self {
self.threshold = Arc::clone(threshold);
self
}
pub fn with_dealings(
mut self,
dealings: &Arc<RwLock<HashMap<String, Vec<ContractSafeBytes>>>>,
@@ -184,6 +192,10 @@ impl super::client::Client for DummyClient {
Ok(*self.epoch_state.read().unwrap())
}
async fn get_current_epoch_threshold(&self) -> Result<Option<Threshold>> {
Ok(*self.threshold.read().unwrap())
}
async fn get_self_registered_dealer_details(&self) -> Result<DealerDetailsResponse> {
Ok(DealerDetailsResponse {
details: self
@@ -270,7 +282,7 @@ impl super::client::Client for DummyClient {
self.dealer_details.write().unwrap().insert(
self.validator_address.to_string(),
DealerDetails {
address: Addr::unchecked(&self.validator_address.to_string()),
address: Addr::unchecked(self.validator_address.to_string()),
bte_public_key_with_proof,
announce_address,
assigned_index,
+18 -1
View File
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
use crate::config::template::config_template;
use config::defaults::mainnet::MIXNET_CONTRACT_ADDRESS;
use config::defaults::DEFAULT_VALIDATOR_API_PORT;
use config::NymConfig;
use serde::{Deserialize, Serialize};
@@ -119,7 +120,7 @@ impl Default for Base {
id: String::default(),
local_validator: default_validator,
announce_address: default_announce_address,
mixnet_contract_address: String::default(),
mixnet_contract_address: MIXNET_CONTRACT_ADDRESS.to_string(),
mnemonic: "exact antique hybrid width raise anchor puzzle degree fee quit long crack net vague hip despair write put useless civil mechanic broom music day".to_string(),
}
}
@@ -282,6 +283,9 @@ pub struct CoconutSigner {
/// Specifies whether rewarding service is enabled in this process.
enabled: bool,
/// Path to a JSON file where state is persisted between different stages of DKG.
dkg_persistent_state_path: PathBuf,
/// Path to the coconut verification key.
verification_key_path: PathBuf,
@@ -299,6 +303,7 @@ pub struct CoconutSigner {
}
impl CoconutSigner {
pub const DKG_PERSISTENT_STATE_FILE: &'static str = "dkg_persistent_state.json";
pub const DKG_DECRYPTION_KEY_FILE: &'static str = "dkg_decryption_key.pem";
pub const DKG_PUBLIC_KEY_WITH_PROOF_FILE: &'static str = "dkg_public_key_with_proof.pem";
pub const COCONUT_VERIFICATION_KEY_FILE: &'static str = "coconut_verification_key.pem";
@@ -312,6 +317,10 @@ impl CoconutSigner {
Config::default_data_directory(None).join(Self::COCONUT_SECRET_KEY_FILE)
}
fn default_dkg_persistent_state_path() -> PathBuf {
Config::default_data_directory(None).join(Self::DKG_PERSISTENT_STATE_FILE)
}
fn default_dkg_decryption_key_path() -> PathBuf {
Config::default_data_directory(None).join(Self::DKG_DECRYPTION_KEY_FILE)
}
@@ -325,6 +334,7 @@ impl Default for CoconutSigner {
fn default() -> Self {
Self {
enabled: Default::default(),
dkg_persistent_state_path: CoconutSigner::default_dkg_persistent_state_path(),
verification_key_path: CoconutSigner::default_coconut_verification_key_path(),
secret_key_path: CoconutSigner::default_coconut_secret_key_path(),
decryption_key_path: CoconutSigner::default_dkg_decryption_key_path(),
@@ -345,6 +355,8 @@ impl Config {
Config::default_data_directory(Some(id)).join(NodeStatusAPI::DB_FILE);
self.network_monitor.credentials_database_path =
Config::default_data_directory(Some(id)).join(NetworkMonitor::DB_FILE);
self.coconut_signer.dkg_persistent_state_path =
Config::default_data_directory(Some(id)).join(CoconutSigner::DKG_PERSISTENT_STATE_FILE);
self.coconut_signer.verification_key_path = Config::default_data_directory(Some(id))
.join(CoconutSigner::COCONUT_VERIFICATION_KEY_FILE);
self.coconut_signer.secret_key_path =
@@ -509,6 +521,11 @@ impl Config {
self.node_status_api.database_path.clone()
}
#[cfg(feature = "coconut")]
pub fn persistent_state_path(&self) -> PathBuf {
self.coconut_signer.dkg_persistent_state_path.clone()
}
#[cfg(feature = "coconut")]
pub fn verification_key_path(&self) -> PathBuf {
self.coconut_signer.verification_key_path.clone()
+3 -3
View File
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
use nymsphinx::forwarding::packet::MixPacket;
use nymsphinx::message::NymMessage;
use nymsphinx::{
acknowledgements::AckKey, addressing::clients::Recipient, preparer::MessagePreparer,
};
@@ -52,10 +53,9 @@ impl Chunker {
) -> Vec<MixPacket> {
let ack_key: AckKey = AckKey::new(&mut self.rng);
let (split_message, _reply_keys) = self
let split_message = self
.message_preparer
.prepare_and_split_message(message, false, topology)
.expect("failed to split the message");
.pad_and_split_message(NymMessage::new_plain(message));
let mut mix_packets = Vec::with_capacity(split_message.len());
for message_chunk in split_message {
@@ -1,4 +1,4 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::network_monitor::gateways_reader::GatewayMessages;
@@ -68,27 +68,30 @@ struct ReceivedProcessorInner {
}
impl ReceivedProcessorInner {
fn on_message(&mut self, message: Vec<u8>) -> Result<(), ProcessingError> {
fn on_message(&mut self, mut message: Vec<u8>) -> Result<(), ProcessingError> {
// if the nonce is none it means the packet was received during the 'waiting' for the
// next test run
if self.test_nonce.is_none() {
return Err(ProcessingError::ReceivedOutsideTestRun);
}
let encrypted_bytes = self
let plaintext = self
.message_receiver
.recover_plaintext(self.client_encryption_keypair.private_key(), message)
.recover_plaintext_from_regular_packet(
self.client_encryption_keypair.private_key(),
&mut message,
)
.map_err(|_| ProcessingError::MalformedPacketReceived)?;
let fragment = self
.message_receiver
.recover_fragment(&encrypted_bytes)
.recover_fragment(plaintext)
.map_err(|_| ProcessingError::MalformedPacketReceived)?;
let (recovered, _) = self
.message_receiver
.insert_new_fragment(fragment)
.map_err(|_| ProcessingError::MalformedPacketReceived)?
.ok_or(ProcessingError::NonTestPacketReceived)?; // if it's a test packet it MUST BE reconstructed with single fragment
let test_packet = TestPacket::try_from_bytes(&recovered.message)
let test_packet = TestPacket::try_from_bytes(&recovered.into_inner_data())
.map_err(|_| ProcessingError::MalformedPacketReceived)?;
// we know nonce is NOT none
+12
View File
@@ -333,6 +333,18 @@ where
Ok(self.0.read().await.nymd.get_current_epoch_state().await?)
}
async fn get_current_epoch_threshold(
&self,
) -> crate::coconut::error::Result<Option<dkg::Threshold>> {
Ok(self
.0
.read()
.await
.nymd
.get_current_epoch_threshold()
.await?)
}
async fn get_self_registered_dealer_details(
&self,
) -> crate::coconut::error::Result<DealerDetailsResponse> {
@@ -114,7 +114,7 @@ impl MixNodeBondAnnotated {
}
}
#[derive(Deserialize, JsonSchema)]
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
pub struct ComputeRewardEstParam {
pub performance: Option<Performance>,
pub active_in_rewarded_set: Option<bool>,