fixed nym-api tests

This commit is contained in:
Jędrzej Stuczyński
2024-02-15 20:19:46 +00:00
parent be3dd2c250
commit 646f522142
3 changed files with 389 additions and 309 deletions
+24 -10
View File
@@ -286,7 +286,7 @@ impl<R: RngCore + CryptoRng> DkgController<R> {
// it could be outdated and we can't use it for resharing
let previous = epoch_id.saturating_sub(1);
if old_keypair.issued_for_epoch != previous {
warn!("our existing coconut keypair has been generated for an distant epoch ({} vs expected {previous} for resharing)", old_keypair.issued_for_epoch);
warn!("our existing coconut keypair has been generated for a distant epoch ({} vs expected {previous} for resharing)", old_keypair.issued_for_epoch);
// don't participate in resharing
return Ok(());
}
@@ -475,6 +475,7 @@ pub(crate) mod tests {
};
use crate::coconut::tests::helpers::unchecked_decode_bte_key;
use nym_coconut::{ttp_keygen, Parameters};
use nym_coconut_dkg_common::types::DealerRegistrationDetails;
use nym_dkg::bte::PublicKeyWithProof;
#[tokio::test]
@@ -615,7 +616,7 @@ pub(crate) mod tests {
let dealers = dealers_fixtures(&mut rng, 4);
let self_dealer = dealers[0].clone();
let epoch = 0;
let epoch = 1;
let mut keys = ttp_keygen(&Parameters::new(4).unwrap(), 3, 4).unwrap();
let coconut_keypair = KeyPair::new();
@@ -672,29 +673,42 @@ pub(crate) mod tests {
let dealers = dealers_fixtures(&mut rng, 4);
let self_dealer = dealers[0].clone();
let epoch = 0;
let epoch = 1;
let mut keys = ttp_keygen(&Parameters::new(4).unwrap(), 3, 4).unwrap();
let coconut_keypair = KeyPair::new();
coconut_keypair
.set(KeyPairWithEpoch::new(keys.pop().unwrap(), epoch))
.set(KeyPairWithEpoch::new(keys.pop().unwrap(), epoch - 1))
.await;
let initial_dealers = InitialReplacementData {
initial_dealers: vec![self_dealer.address.clone()],
initial_height: 100,
};
let mut controller = TestingDkgControllerBuilder::default()
.with_threshold(3)
.with_dealers(dealers.clone())
.with_as_dealer(self_dealer.clone())
.with_keypair(coconut_keypair)
.with_initial_epoch_id(epoch)
.with_initial_dealers(initial_dealers)
.build()
.await;
let chain = controller.chain_state.clone();
// TODO: put that functionality in the builder
chain
.lock()
.unwrap()
.dkg_contract
.dealers
.entry(epoch - 1)
.or_default()
.insert(
self_dealer.address.to_string(),
DealerRegistrationDetails {
bte_public_key_with_proof: self_dealer.bte_public_key_with_proof.clone(),
ed25519_identity: self_dealer.ed25519_identity.clone(),
announce_address: self_dealer.announce_address.clone(),
},
);
let key_size = controller.dkg_client.get_contract_state().await?.key_size;
let res = controller.dealing_exchange(epoch, true).await;
+27 -18
View File
@@ -10,7 +10,8 @@ use crate::coconut::keys::KeyPair;
use crate::coconut::tests::{DummyClient, SharedFakeChain};
use cosmwasm_std::Addr;
use nym_coconut::VerificationKey;
use nym_coconut_dkg_common::types::{DealerDetails, EpochId, InitialReplacementData};
use nym_coconut_dkg_common::dealer::DealerRegistrationDetails;
use nym_coconut_dkg_common::types::{DealerDetails, EpochId};
use nym_crypto::asymmetric::identity;
use nym_dkg::bte::keys::KeyPair as DkgKeyPair;
use nym_dkg::{NodeIndex, Threshold};
@@ -81,7 +82,6 @@ pub struct TestingDkgControllerBuilder {
threshold: Option<Threshold>,
self_dealer: Option<DealerDetails>,
dealers: Vec<DealerDetails>,
initial_dealers: Option<InitialReplacementData>,
}
impl TestingDkgControllerBuilder {
@@ -127,11 +127,6 @@ impl TestingDkgControllerBuilder {
self
}
pub fn with_initial_dealers(mut self, initial_dealers: InitialReplacementData) -> Self {
self.initial_dealers = Some(initial_dealers);
self
}
#[allow(dead_code)]
pub fn with_address(mut self, address: impl Into<String>) -> Self {
let addr = address.into();
@@ -181,20 +176,34 @@ impl TestingDkgControllerBuilder {
// insert initial data into the chain state
{
let mut state_guard = chain_state.lock().unwrap();
if let Some(threshold) = self.threshold {
state_guard.dkg_contract.threshold = Some(threshold)
}
for dealer in self.dealers {
state_guard
.dkg_contract
.dealers
.insert(dealer.assigned_index, dealer);
}
if let Some(epoch_id) = self.epoch_id {
state_guard.dkg_contract.epoch.epoch_id = epoch_id;
}
if let Some(initial_dealers) = self.initial_dealers {
state_guard.dkg_contract.initial_dealers = Some(initial_dealers)
if let Some(threshold) = self.threshold {
state_guard.dkg_contract.threshold = Some(threshold)
}
let epoch_id = state_guard.dkg_contract.epoch.epoch_id;
for dealer in self.dealers {
let epoch_dealers = state_guard
.dkg_contract
.dealers
.entry(epoch_id)
.or_default();
epoch_dealers.insert(
dealer.address.to_string(),
DealerRegistrationDetails {
bte_public_key_with_proof: dealer.bte_public_key_with_proof,
ed25519_identity: dealer.ed25519_identity,
announce_address: dealer.announce_address,
},
);
state_guard
.dkg_contract
.dealer_indices
.insert(dealer.address.to_string(), dealer.assigned_index);
}
}
+338 -281
View File
@@ -21,15 +21,17 @@ use nym_coconut_bandwidth_contract_common::events::{
DEPOSIT_VALUE,
};
use nym_coconut_bandwidth_contract_common::spend_credential::SpendCredentialResponse;
use nym_coconut_dkg_common::dealer::{DealerDetails, DealerDetailsResponse, DealerType};
use nym_coconut_dkg_common::dealer::{
DealerDetails, DealerDetailsResponse, DealerType, RegisteredDealerDetails,
};
use nym_coconut_dkg_common::dealing::{
DealerDealingsStatusResponse, DealingChunkInfo, DealingMetadata, DealingStatus,
DealingStatusResponse, PartialContractDealing,
};
use nym_coconut_dkg_common::event_attributes::{DKG_PROPOSAL_ID, NODE_INDEX};
use nym_coconut_dkg_common::types::{
ChunkIndex, DealingIndex, EncodedBTEPublicKeyWithProof, Epoch, EpochId, EpochState,
PartialContractDealingData, State as ContractState,
ChunkIndex, DealerRegistrationDetails, DealingIndex, EncodedBTEPublicKeyWithProof, Epoch,
EpochId, EpochState, PartialContractDealingData, State as ContractState,
};
use nym_coconut_dkg_common::verification_key::{ContractVKShare, VerificationKeyShare};
use nym_coconut_interface::VerificationKey;
@@ -38,7 +40,6 @@ use nym_contracts_common::IdentityKey;
use nym_credentials::coconut::bandwidth::BandwidthVoucher;
use nym_crypto::asymmetric::{encryption, identity};
use nym_dkg::{NodeIndex, Threshold};
use nym_mixnet_contract_common::BlockHeight;
use nym_validator_client::nym_api::routes::{
API_VERSION, BANDWIDTH, COCONUT_BLIND_SIGN, COCONUT_ROUTES,
};
@@ -53,7 +54,6 @@ use rand_07::RngCore;
use rocket::http::Status;
use rocket::local::asynchronous::Client;
use std::collections::{BTreeMap, HashMap};
use std::mem;
use std::ops::Deref;
use std::str::FromStr;
use std::sync::atomic::{AtomicU64, Ordering};
@@ -138,6 +138,10 @@ pub(crate) struct FakeDkgContractState {
// pub(crate) dealers: HashMap<NodeIndex, DealerDetails>,
// pub(crate) past_dealers: HashMap<NodeIndex, DealerDetails>,
// pub(crate) initial_dealers: Option<InitialReplacementData>,
pub(crate) dealer_indices: HashMap<String, NodeIndex>,
// map of epoch id -> dealer -> info
pub(crate) dealers: HashMap<EpochId, HashMap<String, DealerRegistrationDetails>>,
// map of epoch id -> dealer -> dealings
pub(crate) dealings: HashMap<EpochId, HashMap<String, HashMap<DealingIndex, Dealing>>>,
@@ -151,41 +155,84 @@ pub(crate) struct FakeDkgContractState {
}
impl FakeDkgContractState {
pub(crate) fn verified_dealers(&self) -> Vec<Addr> {
let epoch_id = self.epoch.epoch_id;
let Some(shares) = self.verification_shares.get(&epoch_id) else {
return Vec::new();
};
shares
.values()
.filter(|s| s.verified)
.map(|s| s.owner.clone())
.collect()
}
// pub(crate) fn verified_dealers(&self) -> Vec<Addr> {
// let epoch_id = self.epoch.epoch_id;
// let Some(shares) = self.verification_shares.get(&epoch_id) else {
// return Vec::new();
// };
//
// shares
// .values()
// .filter(|s| s.verified)
// .map(|s| s.owner.clone())
// .collect()
// }
fn reset_dkg_state(&mut self) {
self.threshold = None;
let dealers = mem::take(&mut self.dealers);
for (index, details) in dealers {
self.past_dealers.insert(index, details);
}
}
pub(crate) fn reset_epoch_in_reshare_mode(&mut self, block_height: BlockHeight) {
if let Some(initial_dealers) = self.initial_dealers.as_mut() {
initial_dealers.initial_height = block_height;
} else {
self.initial_dealers = Some(InitialReplacementData {
initial_dealers: self.verified_dealers(),
initial_height: block_height,
})
}
pub(crate) fn reset_epoch_in_reshare_mode(&mut self) {
self.reset_dkg_state();
self.epoch.state = EpochState::PublicKeySubmission { resharing: true };
self.epoch.epoch_id += 1;
}
pub(crate) fn reset_dkg(&mut self) {
self.reset_dkg_state();
self.epoch.state = EpochState::PublicKeySubmission { resharing: false };
self.epoch.epoch_id += 1;
}
pub(crate) fn get_registration_details(
&self,
addr: &str,
epoch_id: EpochId,
) -> Option<DealerRegistrationDetails> {
self.dealers.get(&epoch_id)?.get(addr).cloned()
}
pub(crate) fn get_dealer_details(
&self,
addr: &str,
epoch_id: EpochId,
) -> Option<DealerDetails> {
let registration_details = self.get_registration_details(addr, epoch_id)?;
let assigned_index = self.get_dealer_index(addr)?;
Some(DealerDetails {
address: Addr::unchecked(addr),
bte_public_key_with_proof: registration_details.bte_public_key_with_proof,
ed25519_identity: registration_details.ed25519_identity,
announce_address: registration_details.announce_address,
assigned_index,
})
}
// implementation copied from our contract
pub(crate) fn query_dealer_details(&self, addr: &str) -> DealerDetailsResponse {
let current_epoch_id = self.epoch.epoch_id;
// if the address has registration data for the current epoch, it means it's an active dealer
if let Some(dealer_details) = self.get_dealer_details(addr, current_epoch_id) {
let assigned_index = dealer_details.assigned_index;
return DealerDetailsResponse::new(
Some(dealer_details),
DealerType::Current { assigned_index },
);
}
// and if has had an assigned index it must have been a dealer at some point in the past
if let Some(assigned_index) = self.get_dealer_index(addr) {
return DealerDetailsResponse::new(None, DealerType::Past { assigned_index });
}
DealerDetailsResponse::new(None, DealerType::Unknown)
}
pub(crate) fn get_dealer_index(&self, addr: &str) -> Option<NodeIndex> {
self.dealer_indices.get(addr).copied()
}
}
#[derive(Debug)]
@@ -274,8 +321,8 @@ impl Default for FakeChainState {
dkg_contract: FakeDkgContractState {
address: dkg_contract.as_ref().parse().unwrap(),
dealer_indices: Default::default(),
dealers: HashMap::new(),
past_dealers: Default::default(),
epoch: Epoch::default(),
contract_state: ContractState {
@@ -287,7 +334,6 @@ impl Default for FakeChainState {
dealings: HashMap::new(),
verification_shares: HashMap::new(),
threshold: None,
initial_dealers: None,
},
group_contract: FakeGroupContractState {
address: group_contract,
@@ -307,6 +353,18 @@ impl Default for FakeChainState {
}
impl FakeChainState {
pub(crate) fn get_or_assign_dealer(&mut self, addr: &str) -> NodeIndex {
if let Some(index) = self.dkg_contract.dealer_indices.get(addr) {
*index
} else {
let new = self._counters.next_node_index();
self.dkg_contract
.dealer_indices
.insert(addr.to_string(), new);
new
}
}
pub(crate) fn total_group_weight(&self) -> u64 {
self.group_contract.total_weight()
}
@@ -320,8 +378,12 @@ impl FakeChainState {
}
pub(crate) fn advance_epoch_in_reshare_mode(&mut self) {
self.dkg_contract
.reset_epoch_in_reshare_mode(self.block_info.height)
self.dkg_contract.reset_epoch_in_reshare_mode()
}
#[allow(unused)]
pub(crate) fn advance_epoch_in_reset_mode(&mut self) {
self.dkg_contract.reset_dkg()
}
// TODO: make it return a result
@@ -519,25 +581,25 @@ impl DummyClient {
// // self
// }
async fn get_dealer_by_address(&self, address: &str) -> Option<DealerDetails> {
let guard = self.state.lock().unwrap();
for dealer in guard.dkg_contract.dealers.values() {
if dealer.address.as_str() == address {
return Some(dealer.clone());
}
}
None
}
async fn get_past_dealer_by_address(&self, address: &str) -> Option<DealerDetails> {
let guard = self.state.lock().unwrap();
for dealer in guard.dkg_contract.past_dealers.values() {
if dealer.address.as_str() == address {
return Some(dealer.clone());
}
}
None
}
// async fn get_dealer_by_address(&self, address: &str) -> Option<DealerDetails> {
// let guard = self.state.lock().unwrap();
// for dealer in guard.dkg_contract.dealers.values() {
// if dealer.address.as_str() == address {
// return Some(dealer.clone());
// }
// }
// None
// }
//
// async fn get_past_dealer_by_address(&self, address: &str) -> Option<DealerDetails> {
// let guard = self.state.lock().unwrap();
// for dealer in guard.dkg_contract.past_dealers.values() {
// if dealer.address.as_str() == address {
// return Some(dealer.clone());
// }
// }
// None
// }
}
#[async_trait]
@@ -653,24 +715,74 @@ impl super::client::Client for DummyClient {
async fn get_self_registered_dealer_details(&self) -> Result<DealerDetailsResponse> {
let address = self.validator_address.as_ref();
Ok(self
.state
.lock()
.unwrap()
.dkg_contract
.query_dealer_details(address))
}
if let Some(details) = self.get_dealer_by_address(address).await {
return Ok(DealerDetailsResponse {
details: Some(details),
dealer_type: DealerType::Current,
async fn get_registered_dealer_details(
&self,
epoch_id: EpochId,
dealer: String,
) -> Result<RegisteredDealerDetails> {
let details = self
.state
.lock()
.unwrap()
.dkg_contract
.dealers
.get(&epoch_id)
.and_then(|dealers| dealers.get(&dealer))
.cloned();
Ok(RegisteredDealerDetails { details })
}
async fn get_dealer_dealings_status(
&self,
epoch_id: EpochId,
dealer: String,
) -> Result<DealerDealingsStatusResponse> {
let guard = self.state.lock().unwrap();
let key_size = guard.dkg_contract.contract_state.key_size;
let dealer_addr = Addr::unchecked(&dealer);
let Some(epoch_dealings) = guard.dkg_contract.dealings.get(&epoch_id) else {
return Ok(DealerDealingsStatusResponse {
epoch_id,
dealer: dealer_addr,
all_dealings_fully_submitted: false,
dealing_submission_status: Default::default(),
});
};
let Some(dealer_dealings) = epoch_dealings.get(&dealer) else {
return Ok(DealerDealingsStatusResponse {
epoch_id,
dealer: dealer_addr,
all_dealings_fully_submitted: false,
dealing_submission_status: Default::default(),
});
};
let mut dealing_submission_status: BTreeMap<DealingIndex, DealingStatus> = BTreeMap::new();
for dealing_index in 0..key_size {
let metadata = dealer_dealings
.get(&dealing_index)
.map(|d| d.metadata.clone());
dealing_submission_status.insert(dealing_index, metadata.into());
}
if let Some(details) = self.get_past_dealer_by_address(address).await {
return Ok(DealerDetailsResponse {
details: Some(details),
dealer_type: DealerType::Past,
});
}
Ok(DealerDetailsResponse {
details: None,
dealer_type: DealerType::Unknown,
Ok(DealerDealingsStatusResponse {
epoch_id,
dealer: Addr::unchecked(&dealer),
all_dealings_fully_submitted: dealing_submission_status
.values()
.all(|d| d.fully_submitted),
dealing_submission_status,
})
}
@@ -699,17 +811,75 @@ impl super::client::Client for DummyClient {
}
async fn get_current_dealers(&self) -> Result<Vec<DealerDetails>> {
Ok(self
.state
.lock()
.unwrap()
.dkg_contract
.dealers
.values()
.cloned()
let chain = self.state.lock().unwrap();
let current_epoch_id = chain.dkg_contract.epoch.epoch_id;
let Some(epoch_dealers) = chain.dkg_contract.dealers.get(&current_epoch_id) else {
return Ok(Vec::new());
};
Ok(epoch_dealers
.iter()
.map(|(address, details)| {
let assigned_index = chain.dkg_contract.get_dealer_index(address).unwrap();
DealerDetails {
address: Addr::unchecked(address),
bte_public_key_with_proof: details.bte_public_key_with_proof.clone(),
ed25519_identity: details.ed25519_identity.clone(),
announce_address: details.announce_address.clone(),
assigned_index,
}
})
.collect())
}
async fn get_dealing_metadata(
&self,
epoch_id: EpochId,
dealer: String,
dealing_index: DealingIndex,
) -> Result<Option<DealingMetadata>> {
let guard = self.state.lock().unwrap();
let Some(epoch_dealings) = guard.dkg_contract.dealings.get(&epoch_id) else {
return Ok(None);
};
let Some(dealer_dealings) = epoch_dealings.get(&dealer) else {
return Ok(None);
};
let Some(dealing) = dealer_dealings.get(&dealing_index) else {
return Ok(None);
};
Ok(Some(dealing.metadata.clone()))
}
async fn get_dealing_chunk(
&self,
epoch_id: EpochId,
dealer: &str,
dealing_index: DealingIndex,
chunk_index: ChunkIndex,
) -> Result<Option<PartialContractDealingData>> {
let guard = self.state.lock().unwrap();
let Some(epoch_dealings) = guard.dkg_contract.dealings.get(&epoch_id) else {
return Ok(None);
};
let Some(dealer_dealings) = epoch_dealings.get(dealer) else {
return Ok(None);
};
let Some(dealing) = dealer_dealings.get(&dealing_index) else {
return Ok(None);
};
Ok(dealing.chunks.get(&chunk_index).cloned())
}
async fn get_verification_key_share(
&self,
epoch_id: EpochId,
@@ -733,7 +903,6 @@ impl super::client::Client for DummyClient {
Some(epoch_shares) => Ok(epoch_shares.values().cloned().collect()),
}
}
async fn vote_proposal(
&self,
proposal_id: u64,
@@ -819,43 +988,23 @@ impl super::client::Client for DummyClient {
announce_address: String,
_resharing: bool,
) -> Result<ExecuteResult> {
let assigned_index = if let Some(already_registered) = self
.get_dealer_by_address(self.validator_address.as_ref())
.await
{
// current dealer
already_registered.assigned_index
} else if let Some(registered_in_the_past) = self
.get_past_dealer_by_address(self.validator_address.as_ref())
.await
{
// past dealer
let index = registered_in_the_past.assigned_index;
let mut guard = self.state.lock().unwrap();
guard
.dkg_contract
.dealers
.insert(index, registered_in_the_past);
index
} else {
// new dealer
let mut guard = self.state.lock().unwrap();
let assigned_index = guard._counters.next_node_index();
guard.dkg_contract.dealers.insert(
assigned_index,
DealerDetails {
address: Addr::unchecked(self.validator_address.to_string()),
bte_public_key_with_proof,
ed25519_identity: identity_key,
announce_address,
assigned_index,
},
);
assigned_index
};
let mut guard = self.state.lock().unwrap();
let assigned_index = guard.get_or_assign_dealer(self.validator_address.as_ref());
let epoch = guard.dkg_contract.epoch.epoch_id;
let dealer_details = DealerRegistrationDetails {
bte_public_key_with_proof,
ed25519_identity: identity_key,
announce_address,
};
let epoch_dealers = guard.dkg_contract.dealers.entry(epoch).or_default();
if !epoch_dealers.contains_key(self.validator_address.as_ref()) {
epoch_dealers.insert(self.validator_address.to_string(), dealer_details);
} else {
unimplemented!("already registered")
}
let transaction_hash = guard._counters.next_tx_hash();
Ok(ExecuteResult {
@@ -869,174 +1018,6 @@ impl super::client::Client for DummyClient {
gas_info: Default::default(),
})
}
async fn submit_verification_key_share(
&self,
share: VerificationKeyShare,
resharing: bool,
) -> Result<ExecuteResult> {
let address = self.validator_address.to_string();
let Some(dealer_details) = self.get_dealer_by_address(&address).await else {
// Just throw some error, not really the correct one
return Err(CoconutError::DepositEncrKeyNotFound);
};
let mut chain = self.state.lock().unwrap();
let dkg_contract = chain.dkg_contract.address.clone();
let epoch_id = chain.dkg_contract.epoch.epoch_id;
chain
.dkg_contract
.verification_shares
.entry(epoch_id)
.or_default()
.insert(
self.validator_address.to_string(),
ContractVKShare {
share,
announce_address: dealer_details.announce_address.clone(),
node_index: dealer_details.assigned_index,
owner: Addr::unchecked(&address),
epoch_id,
verified: false,
},
);
let proposal_id = chain._counters.next_proposal_id();
let verify_vk_share_req =
nym_coconut_dkg_common::msg::ExecuteMsg::VerifyVerificationKeyShare {
owner: address,
resharing,
};
let verify_vk_share_msg = CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: chain.dkg_contract.address.to_string(),
msg: to_binary(&verify_vk_share_req).unwrap(),
funds: vec![],
});
let proposal = Proposal {
title: String::new(),
description: String::new(),
msgs: vec![verify_vk_share_msg],
status: cw3::Status::Open,
expires: cw_utils::Expiration::Never {},
threshold: cw_utils::Threshold::AbsolutePercentage {
percentage: Decimal::from_ratio(2u32, 3u32),
},
total_weight: chain.total_group_weight(),
votes: Votes::yes(0),
proposer: Addr::unchecked(dkg_contract.as_ref()),
deposit: None,
start_height: 0,
};
chain
.multisig_contract
.proposals
.insert(proposal_id, proposal);
let transaction_hash = chain._counters.next_tx_hash();
Ok(ExecuteResult {
logs: vec![Log {
msg_index: 0,
events: vec![cosmwasm_std::Event::new("wasm")
.add_attribute(DKG_PROPOSAL_ID, proposal_id.to_string())],
}],
data: Default::default(),
transaction_hash,
gas_info: Default::default(),
})
}
async fn get_dealer_dealings_status(
&self,
epoch_id: EpochId,
dealer: String,
) -> Result<DealerDealingsStatusResponse> {
let guard = self.state.lock().unwrap();
let key_size = guard.dkg_contract.contract_state.key_size;
let dealer_addr = Addr::unchecked(&dealer);
let Some(epoch_dealings) = guard.dkg_contract.dealings.get(&epoch_id) else {
return Ok(DealerDealingsStatusResponse {
epoch_id,
dealer: dealer_addr,
all_dealings_fully_submitted: false,
dealing_submission_status: Default::default(),
});
};
let Some(dealer_dealings) = epoch_dealings.get(&dealer) else {
return Ok(DealerDealingsStatusResponse {
epoch_id,
dealer: dealer_addr,
all_dealings_fully_submitted: false,
dealing_submission_status: Default::default(),
});
};
let mut dealing_submission_status: BTreeMap<DealingIndex, DealingStatus> = BTreeMap::new();
for dealing_index in 0..key_size {
let metadata = dealer_dealings
.get(&dealing_index)
.map(|d| d.metadata.clone());
dealing_submission_status.insert(dealing_index, metadata.into());
}
Ok(DealerDealingsStatusResponse {
epoch_id,
dealer: Addr::unchecked(&dealer),
all_dealings_fully_submitted: dealing_submission_status
.values()
.all(|d| d.fully_submitted),
dealing_submission_status,
})
}
async fn get_dealing_metadata(
&self,
epoch_id: EpochId,
dealer: String,
dealing_index: DealingIndex,
) -> Result<Option<DealingMetadata>> {
let guard = self.state.lock().unwrap();
let Some(epoch_dealings) = guard.dkg_contract.dealings.get(&epoch_id) else {
return Ok(None);
};
let Some(dealer_dealings) = epoch_dealings.get(&dealer) else {
return Ok(None);
};
let Some(dealing) = dealer_dealings.get(&dealing_index) else {
return Ok(None);
};
Ok(Some(dealing.metadata.clone()))
}
async fn get_dealing_chunk(
&self,
epoch_id: EpochId,
dealer: &str,
dealing_index: DealingIndex,
chunk_index: ChunkIndex,
) -> Result<Option<PartialContractDealingData>> {
let guard = self.state.lock().unwrap();
let Some(epoch_dealings) = guard.dkg_contract.dealings.get(&epoch_id) else {
return Ok(None);
};
let Some(dealer_dealings) = epoch_dealings.get(dealer) else {
return Ok(None);
};
let Some(dealing) = dealer_dealings.get(&dealing_index) else {
return Ok(None);
};
Ok(dealing.chunks.get(&chunk_index).cloned())
}
async fn submit_dealing_metadata(
&self,
@@ -1104,6 +1085,82 @@ impl super::client::Client for DummyClient {
gas_info: Default::default(),
})
}
async fn submit_verification_key_share(
&self,
share: VerificationKeyShare,
resharing: bool,
) -> Result<ExecuteResult> {
let mut chain = self.state.lock().unwrap();
let address = self.validator_address.to_string();
let epoch_id = chain.dkg_contract.epoch.epoch_id;
let Some(dealer_details) = chain.dkg_contract.get_dealer_details(&address, epoch_id) else {
// Just throw some error, not really the correct one
return Err(CoconutError::DepositEncrKeyNotFound);
};
let dkg_contract = chain.dkg_contract.address.clone();
chain
.dkg_contract
.verification_shares
.entry(epoch_id)
.or_default()
.insert(
self.validator_address.to_string(),
ContractVKShare {
share,
announce_address: dealer_details.announce_address.clone(),
node_index: dealer_details.assigned_index,
owner: Addr::unchecked(&address),
epoch_id,
verified: false,
},
);
let proposal_id = chain._counters.next_proposal_id();
let verify_vk_share_req =
nym_coconut_dkg_common::msg::ExecuteMsg::VerifyVerificationKeyShare {
owner: address,
resharing,
};
let verify_vk_share_msg = CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: chain.dkg_contract.address.to_string(),
msg: to_binary(&verify_vk_share_req).unwrap(),
funds: vec![],
});
let proposal = Proposal {
title: String::new(),
description: String::new(),
msgs: vec![verify_vk_share_msg],
status: cw3::Status::Open,
expires: cw_utils::Expiration::Never {},
threshold: cw_utils::Threshold::AbsolutePercentage {
percentage: Decimal::from_ratio(2u32, 3u32),
},
total_weight: chain.total_group_weight(),
votes: Votes::yes(0),
proposer: Addr::unchecked(dkg_contract.as_ref()),
deposit: None,
start_height: 0,
};
chain
.multisig_contract
.proposals
.insert(proposal_id, proposal);
let transaction_hash = chain._counters.next_tx_hash();
Ok(ExecuteResult {
logs: vec![Log {
msg_index: 0,
events: vec![cosmwasm_std::Event::new("wasm")
.add_attribute(DKG_PROPOSAL_ID, proposal_id.to_string())],
}],
data: Default::default(),
transaction_hash,
gas_info: Default::default(),
})
}
}
#[derive(Clone, Debug)]