actually working happy path with a unit test

This commit is contained in:
Jędrzej Stuczyński
2024-01-22 16:55:04 +00:00
parent ac3830e677
commit 605176551b
13 changed files with 1277 additions and 1096 deletions
+4 -1
View File
@@ -17,7 +17,7 @@ use crate::epoch_state::transactions::{
use crate::error::ContractError;
use crate::state::queries::query_state;
use crate::state::storage::{DKG_ADMIN, MULTISIG, STATE};
use crate::verification_key_shares::queries::query_vk_shares_paged;
use crate::verification_key_shares::queries::{query_vk_share, query_vk_shares_paged};
use crate::verification_key_shares::transactions::try_commit_verification_key_share;
use crate::verification_key_shares::transactions::try_verify_verification_key_share;
use cosmwasm_std::{
@@ -159,6 +159,9 @@ pub fn query(deps: Deps<'_>, _env: Env, msg: QueryMsg) -> Result<QueryResponse,
start_after,
limit,
)?)?,
QueryMsg::GetVerificationKey { owner, epoch_id } => {
to_binary(&query_vk_share(deps, owner, epoch_id)?)?
}
QueryMsg::GetVerificationKeys {
epoch_id,
limit,
@@ -1,4 +1,4 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2022-2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::verification_key_shares::storage;
@@ -6,7 +6,23 @@ use crate::verification_key_shares::storage::vk_shares;
use cosmwasm_std::{Deps, Order, StdResult};
use cw_storage_plus::Bound;
use nym_coconut_dkg_common::types::EpochId;
use nym_coconut_dkg_common::verification_key::PagedVKSharesResponse;
use nym_coconut_dkg_common::verification_key::{PagedVKSharesResponse, VkShareResponse};
// TODO: unit tests
pub fn query_vk_share(
deps: Deps<'_>,
owner: String,
epoch_id: EpochId,
) -> StdResult<VkShareResponse> {
let owner = deps.api.addr_validate(&owner)?;
let share = vk_shares().may_load(deps.storage, (&owner, epoch_id))?;
Ok(VkShareResponse {
owner,
epoch_id,
share,
})
}
pub fn query_vk_shares_paged(
deps: Deps<'_>,
@@ -1,7 +1,5 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::constants::{VK_SHARES_EPOCH_ID_IDX_NAMESPACE, VK_SHARES_PK_NAMESPACE};
use crate::epoch_state::storage::CURRENT_EPOCH;
+4 -1
View File
@@ -58,7 +58,10 @@ pub async fn post_blind_sign(
// check if we have the signing key available
debug!("checking if we actually have coconut keys derived...");
let keypair_guard = state.coconut_keypair.get().await;
let maybe_keypair_guard = state.coconut_keypair.get().await;
let Some(keypair_guard) = maybe_keypair_guard.as_ref() else {
return Err(CoconutError::KeyPairNotDerivedYet);
};
let Some(signing_key) = keypair_guard.as_ref() else {
return Err(CoconutError::KeyPairNotDerivedYet);
};
+2 -1
View File
@@ -302,10 +302,11 @@ impl DkgController {
rng: rand_chacha::ChaCha20Rng,
dkg_client: DkgClient,
state: State,
coconut_key_path: PathBuf,
) -> DkgController<rand_chacha::ChaCha20Rng> {
DkgController {
dkg_client,
coconut_key_path: Default::default(),
coconut_key_path,
state,
rng,
polling_rate: Default::default(),
+24 -7
View File
@@ -234,13 +234,6 @@ impl<R: RngCore + CryptoRng> DkgController<R> {
) -> Result<(), CoconutError> {
let dealing_state = self.state.dealing_exchange_state(epoch_id)?;
// TODO:
/*
let receiver_index = receivers
.keys()
.position(|node_index| *node_index == dealer_index);
*/
// check if we have already submitted the dealings
if dealing_state.completed() {
// the only way this could be a false positive is if the chain forked and blocks got reverted,
@@ -277,6 +270,30 @@ impl<R: RngCore + CryptoRng> DkgController<R> {
self.state.dkg_state_mut(epoch_id)?.set_dealers(dealers);
// obtain our dealer index to correctly set receiver index (used for share decryption)
let dealer_index = self.state.assigned_index(epoch_id)?;
// update internally used threshold value which should have been available after all dealers registered
let Some(threshold) = self.dkg_client.get_current_epoch_threshold().await? else {
// TODO: if we're in the dealing exchange phase, the threshold must have been already established
todo!("yell at me clippy")
};
self.state
.key_derivation_state_mut(epoch_id)?
.expected_threshold = Some(threshold);
// establish our receiver index
let sorted_dealers = &self.state.dkg_state(epoch_id)?.dealers;
let Some(receiver_index) = sorted_dealers.keys().position(|idx| idx == &dealer_index)
else {
// this branch should be impossible as `dealing_exchange` should never be called unless we're actually a dealer
error!("could not establish receiver index for epoch {epoch_id} even though we're a dealer!");
return Err(CoconutError::UnavailableReceiverIndex { epoch_id });
};
self.state
.dealing_exchange_state_mut(epoch_id)?
.receiver_index = Some(receiver_index);
// get the expected key size which will determine the number of dealings we need to construct
let contract_state = self.dkg_client.get_contract_state().await?;
let expected_key_size = contract_state.key_size;
File diff suppressed because it is too large Load Diff
+27 -8
View File
@@ -16,7 +16,7 @@ use nym_coconut_dkg_common::types::{
};
use nym_crypto::asymmetric::identity;
use nym_dkg::bte::{keys::KeyPair as DkgKeyPair, PublicKey, PublicKeyWithProof};
use nym_dkg::{Dealing, NodeIndex, RecoveredVerificationKeys, Threshold};
use nym_dkg::{bte, Dealing, NodeIndex, RecoveredVerificationKeys, Threshold};
use nym_validator_client::nyxd::{tx, Hash};
use serde::de::Error;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
@@ -43,6 +43,13 @@ impl ParticipantState {
matches!(self, ParticipantState::VerifiedKey(..))
}
pub fn public_key(&self) -> Option<bte::PublicKey> {
match self {
ParticipantState::Invalid(_) => None,
ParticipantState::VerifiedKey(key_with_proof) => Some(*key_with_proof.public_key()),
}
}
fn from_raw_encoded_key(raw: EncodedBTEPublicKeyWithProof) -> Self {
// TODO: include more error information
let Ok(bytes) = bs58::decode(raw).into_vec() else {
@@ -353,7 +360,7 @@ impl State {
}
/// Obtain the list of dealers for the provided epoch that have submitted valid public keys.
pub fn valid_epoch_dealers(
pub fn valid_epoch_receivers(
&self,
epoch_id: EpochId,
) -> Result<Vec<(Addr, NodeIndex)>, CoconutError> {
@@ -371,6 +378,18 @@ impl State {
.collect())
}
pub fn valid_epoch_receivers_keys(
&self,
epoch_id: EpochId,
) -> Result<BTreeMap<NodeIndex, bte::PublicKey>, CoconutError> {
Ok(self
.dkg_state(epoch_id)?
.dealers
.values()
.filter_map(|d| d.state.public_key().map(|k| (d.assigned_index, k)))
.collect())
}
pub fn dkg_state(&self, epoch_id: EpochId) -> Result<&DkgState, CoconutError> {
self.dkg_instances
.get(&epoch_id)
@@ -449,11 +468,11 @@ impl State {
.ok_or(CoconutError::UnavailableThreshold { epoch_id })
}
// pub fn assigned_index(&self, epoch_id: EpochId) -> Result<NodeIndex, CoconutError> {
// self.registration_state(epoch_id)?
// .assigned_index
// .ok_or(CoconutError::UnavailableAssignedIndex { epoch_id })
// }
pub fn assigned_index(&self, epoch_id: EpochId) -> Result<NodeIndex, CoconutError> {
self.registration_state(epoch_id)?
.assigned_index
.ok_or(CoconutError::UnavailableAssignedIndex { epoch_id })
}
pub fn receiver_index(&self, epoch_id: EpochId) -> Result<usize, CoconutError> {
self.dealing_exchange_state(epoch_id)?
@@ -509,7 +528,7 @@ impl State {
pub async fn coconut_keypair(
&self,
) -> tokio::sync::RwLockReadGuard<'_, Option<KeyPairWithEpoch>> {
) -> Option<tokio::sync::RwLockReadGuard<'_, Option<KeyPairWithEpoch>>> {
self.coconut_keypair.get().await
}
+3 -3
View File
@@ -142,14 +142,14 @@ pub enum CoconutError {
MissingDkgState { epoch_id: EpochId },
#[error(
"the node index value for {epoch_id} is not available - are you sure we are a dealer?"
"the node index value for epoch {epoch_id} is not available - are you sure we are a dealer?"
)]
UnavailableAssignedIndex { epoch_id: EpochId },
#[error("the receiver index value for {epoch_id} is not available - are you sure we are a receiver?")]
#[error("the receiver index value for epoch {epoch_id} is not available - are you sure we are a receiver?")]
UnavailableReceiverIndex { epoch_id: EpochId },
#[error("the threshold value for {epoch_id} is not available")]
#[error("the threshold value for epoch {epoch_id} is not available")]
UnavailableThreshold { epoch_id: EpochId },
#[error("insufficient number of dealings provided to derive the key")]
+13 -7
View File
@@ -50,22 +50,28 @@ impl KeyPair {
self.keys.write().await.take()
}
pub async fn get(&self) -> RwLockReadGuard<'_, Option<KeyPairWithEpoch>> {
todo!()
// self.keys.read().await
pub async fn get(&self) -> Option<RwLockReadGuard<'_, Option<KeyPairWithEpoch>>> {
if self.is_valid() {
Some(self.keys.read().await)
} else {
None
}
}
pub async fn set(&self, keypair: KeyPairWithEpoch) {
todo!()
// let mut w_lock = self.keys.write().await;
// *w_lock = Some(keypair);
let mut w_lock = self.keys.write().await;
*w_lock = Some(keypair);
}
pub fn is_valid(&self) -> bool {
self.valid.load(Ordering::SeqCst)
}
pub fn invalidate(&self) {
pub fn enable(&self) {
self.valid.store(true, Ordering::SeqCst);
}
pub fn invalidate(&self) {
self.valid.store(false, Ordering::SeqCst);
}
}
+25 -5
View File
@@ -19,6 +19,7 @@ use rand_chacha::{
};
use std::ops::{Deref, DerefMut};
use std::sync::{Arc, Mutex};
use tempfile::{tempdir, TempDir};
pub fn test_rng(seed: [u8; 32]) -> ChaCha20Rng {
ChaCha20Rng::from_seed(seed)
@@ -73,6 +74,8 @@ pub struct TestingDkgControllerBuilder {
address: Option<AccountId>,
threshold: Option<Threshold>,
chain_state: Option<Arc<Mutex<FakeChainState>>>,
self_dealer: Option<DealerDetails>,
dealers: Vec<DealerDetails>,
}
@@ -88,6 +91,11 @@ impl TestingDkgControllerBuilder {
self
}
pub fn with_shared_chain_state(mut self, fake_chain: Arc<Mutex<FakeChainState>>) -> Self {
self.chain_state = Some(fake_chain);
self
}
pub fn with_as_dealer(mut self, dealer_details: DealerDetails) -> Self {
self.self_dealer = Some(dealer_details);
self
@@ -141,8 +149,11 @@ impl TestingDkgControllerBuilder {
}
});
let dummy_client = DummyClient::new(self_dealer.address.to_string().parse().unwrap());
let chain_state = dummy_client.chain_state();
let chain_state = self.chain_state.unwrap_or_default();
let dummy_client = DummyClient::new(
self_dealer.address.to_string().parse().unwrap(),
chain_state.clone(),
);
// insert initial data into the chain state
let mut state_guard = chain_state.lock().unwrap();
@@ -153,13 +164,14 @@ impl TestingDkgControllerBuilder {
state_guard.dealers.insert(dealer.assigned_index, dealer);
}
let epoch = state_guard.epoch.epoch_id;
let epoch = state_guard.dkg_epoch.epoch_id;
drop(state_guard);
let dummy_client = DkgClient::new(dummy_client);
let tmp_dir = tempdir().unwrap();
let mut state = State::new(
Default::default(),
tmp_dir.path().join("persistent_state.json"),
Default::default(),
self_dealer.announce_address.parse().unwrap(),
// TODO: we might need to fix up the key here
@@ -176,8 +188,14 @@ impl TestingDkgControllerBuilder {
}
TestingDkgController {
controller: DkgController::test_mock_new(rng, dummy_client, state),
controller: DkgController::test_mock_new(
rng,
dummy_client,
state,
tmp_dir.path().join("coconut_keypair.pem"),
),
chain_state,
_tmp_dir: tmp_dir,
}
}
}
@@ -190,6 +208,8 @@ pub(crate) struct TestingDkgController {
pub(crate) controller: DkgController<ChaCha20Rng>,
pub(crate) chain_state: Arc<Mutex<FakeChainState>>,
_tmp_dir: TempDir,
}
impl Deref for TestingDkgController {
+122
View File
@@ -1,10 +1,132 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::coconut::dkg::controller::DkgController;
use crate::coconut::dkg::key_derivation::{
verification_key_finalization, verification_key_validation,
};
use crate::coconut::tests::fixtures::{TestingDkgController, TestingDkgControllerBuilder};
use crate::coconut::tests::FakeChainState;
use nym_coconut_dkg_common::types::EpochState;
use nym_crypto::aes::cipher::crypto_common::rand_core::OsRng;
use nym_dkg::bte::PublicKeyWithProof;
use nym_dkg::Dealing;
use std::env::temp_dir;
use std::sync::{Arc, Mutex};
pub(crate) fn unchecked_decode_bte_key(raw: &str) -> PublicKeyWithProof {
let bytes = bs58::decode(raw).into_vec().unwrap();
PublicKeyWithProof::try_from_bytes(&bytes).unwrap()
}
pub(crate) type SharedChainState = Arc<Mutex<FakeChainState>>;
pub(crate) fn init_chain() -> SharedChainState {
Default::default()
}
pub(crate) fn initialise_controllers(amount: usize) -> Vec<TestingDkgController> {
let chain = init_chain();
let mut controllers = Vec::with_capacity(amount);
assert!(amount <= u8::MAX as usize);
for rng_seed in 0..amount {
let controller = TestingDkgControllerBuilder::default()
.with_shared_chain_state(chain.clone())
.with_magic_seed_val(rng_seed as u8)
.build();
controllers.push(controller)
}
controllers
}
pub(crate) fn initialise_dkg(controllers: &mut [TestingDkgController], resharing: bool) {
assert_eq!(
controllers[0].chain_state.lock().unwrap().dkg_epoch.state,
EpochState::WaitingInitialisation
);
controllers[0].chain_state.lock().unwrap().dkg_epoch.state =
EpochState::PublicKeySubmission { resharing }
}
pub(crate) async fn submit_public_keys(controllers: &mut [TestingDkgController], resharing: bool) {
let epoch = controllers[0]
.chain_state
.lock()
.unwrap()
.dkg_epoch
.epoch_id;
for controller in controllers.iter_mut() {
controller
.public_key_submission(epoch, resharing)
.await
.unwrap();
}
let threshold = (2 * controllers.len() as u64 + 3 - 1) / 3;
let mut guard = controllers[0].chain_state.lock().unwrap();
guard.dkg_epoch.state = EpochState::DealingExchange { resharing };
guard.threshold = Some(threshold)
}
pub(crate) async fn exchange_dealings(controllers: &mut [TestingDkgController], resharing: bool) {
let epoch = controllers[0]
.chain_state
.lock()
.unwrap()
.dkg_epoch
.epoch_id;
for controller in controllers.iter_mut() {
controller.dealing_exchange(epoch, resharing).await.unwrap();
}
let mut guard = controllers[0].chain_state.lock().unwrap();
guard.dkg_epoch.state = EpochState::VerificationKeySubmission { resharing };
}
pub(crate) async fn derive_keypairs(controllers: &mut [TestingDkgController], resharing: bool) {
let epoch = controllers[0]
.chain_state
.lock()
.unwrap()
.dkg_epoch
.epoch_id;
for controller in controllers.iter_mut() {
controller
.verification_key_submission(epoch, resharing)
.await
.unwrap();
}
let mut guard = controllers[0].chain_state.lock().unwrap();
guard.dkg_epoch.state = EpochState::VerificationKeyValidation { resharing }
}
pub(crate) async fn validate_keys(controllers: &mut [TestingDkgController], resharing: bool) {
todo!()
// let mut clients_and_states = derive_keypairs(db).await;
// for controller in clients_and_states.iter_mut() {
// verification_key_validation(&controller.dkg_client, &mut controller.state, false)
// .await
// .unwrap();
// }
// clients_and_states
}
pub(crate) async fn finalize(controllers: &mut [TestingDkgController], resharing: bool) {
todo!()
// let mut clients_and_states = validate_keys(db).await;
// for controller in clients_and_states.iter_mut() {
// verification_key_finalization(&controller.dkg_client, &mut controller.state, false)
// .await
// .unwrap();
// }
// clients_and_states
}
+215 -172
View File
@@ -64,46 +64,47 @@ const TEST_REWARDING_VALIDATOR_ADDRESS: &str = "n19lc9u84cz0yz3fww5283nucc9yvr8g
#[derive(Debug)]
pub(crate) struct FakeChainState {
// new
pub(crate) dealers: HashMap<NodeIndex, DealerDetails>,
pub(crate) past_dealers: HashMap<NodeIndex, DealerDetails>,
pub(crate) dealings: HashMap<EpochId, HashMap<String, Vec<PartialContractDealing>>>,
pub(crate) verification_shares: HashMap<EpochId, HashMap<String, ContractVKShare>>,
pub(crate) dkg_epoch: Epoch,
pub(crate) dkg_contract_state: ContractState,
pub(crate) threshold: Option<Threshold>,
pub(crate) node_index_counter: NodeIndex,
pub(crate) proposals: HashMap<u64, ProposalResponse>,
// old
txs: HashMap<Hash, TxResponse>,
proposals: HashMap<u64, ProposalResponse>,
spent_credentials: HashMap<String, SpendCredentialResponse>,
epoch: Epoch,
contract_state: ContractState,
old_dealers: HashMap<String, (DealerDetails, bool)>,
threshold: Option<Threshold>,
verification_shares: HashMap<String, ContractVKShare>,
group: HashMap<String, MemberResponse>,
initial_dealers: Option<InitialReplacementData>,
// txs: HashMap<Hash, TxResponse>,
// spent_credentials: HashMap<String, SpendCredentialResponse>,
//
// old_dealers: HashMap<String, (DealerDetails, bool)>,
//
// group: HashMap<String, MemberResponse>,
// initial_dealers: Option<InitialReplacementData>,
}
impl Default for FakeChainState {
fn default() -> Self {
FakeChainState {
dealers: HashMap::new(),
past_dealers: Default::default(),
txs: HashMap::new(),
proposals: HashMap::new(),
spent_credentials: HashMap::new(),
epoch: Epoch::default(),
contract_state: ContractState {
dkg_epoch: Epoch::default(),
dkg_contract_state: ContractState {
mix_denom: TEST_COIN_DENOM.to_string(),
multisig_addr: Addr::unchecked("dummy address"),
group_addr: Cw4Contract::new(Addr::unchecked("dummy cw4")),
key_size: 5,
},
old_dealers: HashMap::new(),
threshold: None,
dealings: HashMap::new(),
verification_shares: HashMap::new(),
group: HashMap::new(),
initial_dealers: None,
threshold: None,
node_index_counter: 0,
proposals: Default::default(),
}
}
}
@@ -116,10 +117,10 @@ pub(crate) struct DummyClient {
}
impl DummyClient {
pub fn new(validator_address: AccountId) -> Self {
pub fn new(validator_address: AccountId, state: Arc<Mutex<FakeChainState>>) -> Self {
Self {
validator_address,
state: Arc::new(Mutex::new(FakeChainState::default())),
state,
}
}
@@ -219,6 +220,26 @@ impl DummyClient {
// self.initial_dealers_db = Arc::clone(initial_dealers);
// self
}
async fn get_dealer_by_address(&self, address: &str) -> Option<DealerDetails> {
let guard = self.state.lock().unwrap();
for dealer in guard.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.past_dealers.values() {
if dealer.address.as_str() == address {
return Some(dealer.clone());
}
}
None
}
}
#[async_trait]
@@ -228,71 +249,76 @@ impl super::client::Client for DummyClient {
}
async fn get_tx(&self, tx_hash: Hash) -> Result<TxResponse> {
Ok(self
.state
.lock()
.unwrap()
.txs
.get(&tx_hash)
.cloned()
.unwrap())
todo!()
// Ok(self
// .state
// .lock()
// .unwrap()
// .txs
// .get(&tx_hash)
// .cloned()
// .unwrap())
}
async fn get_proposal(&self, proposal_id: u64) -> Result<ProposalResponse> {
self.state
.lock()
.unwrap()
.proposals
.get(&proposal_id)
.cloned()
.ok_or(CoconutError::IncorrectProposal {
reason: String::from("proposal not found"),
})
todo!()
// self.state
// .lock()
// .unwrap()
// .proposals
// .get(&proposal_id)
// .cloned()
// .ok_or(CoconutError::IncorrectProposal {
// reason: String::from("proposal not found"),
// })
}
async fn list_proposals(&self) -> Result<Vec<ProposalResponse>> {
Ok(self
.state
.lock()
.unwrap()
.proposals
.values()
.cloned()
.collect())
todo!()
// Ok(self
// .state
// .lock()
// .unwrap()
// .proposals
// .values()
// .cloned()
// .collect())
}
async fn get_spent_credential(
&self,
blinded_serial_number: String,
) -> Result<SpendCredentialResponse> {
self.state
.lock()
.unwrap()
.spent_credentials
.get(&blinded_serial_number)
.cloned()
.ok_or(CoconutError::InvalidCredentialStatus {
status: String::from("spent credential not found"),
})
todo!()
// self.state
// .lock()
// .unwrap()
// .spent_credentials
// .get(&blinded_serial_number)
// .cloned()
// .ok_or(CoconutError::InvalidCredentialStatus {
// status: String::from("spent credential not found"),
// })
}
async fn contract_state(&self) -> Result<ContractState> {
Ok(self.state.lock().unwrap().contract_state.clone())
Ok(self.state.lock().unwrap().dkg_contract_state.clone())
}
async fn get_current_epoch(&self) -> Result<Epoch> {
Ok(self.state.lock().unwrap().epoch)
Ok(self.state.lock().unwrap().dkg_epoch)
}
async fn group_member(&self, addr: String) -> Result<MemberResponse> {
Ok(self
.state
.lock()
.unwrap()
.group
.get(&addr)
.cloned()
.unwrap_or(MemberResponse { weight: None }))
todo!()
// Ok(self
// .state
// .lock()
// .unwrap()
// .group
// .get(&addr)
// .cloned()
// .unwrap_or(MemberResponse { weight: None }))
}
async fn get_current_epoch_threshold(&self) -> Result<Option<Threshold>> {
@@ -300,30 +326,30 @@ impl super::client::Client for DummyClient {
}
async fn get_initial_dealers(&self) -> Result<Option<InitialReplacementData>> {
Ok(self.state.lock().unwrap().initial_dealers.clone())
todo!()
// Ok(self.state.lock().unwrap().initial_dealers.clone())
}
async fn get_self_registered_dealer_details(&self) -> Result<DealerDetailsResponse> {
let (details, dealer_type) = if let Some((details, current)) = self
.state
.lock()
.unwrap()
.old_dealers
.get(self.validator_address.as_ref())
.cloned()
{
let dealer_type = if current {
DealerType::Current
} else {
DealerType::Past
};
(Some(details), dealer_type)
} else {
(None, DealerType::Unknown)
};
let address = self.validator_address.as_ref();
if let Some(details) = self.get_dealer_by_address(address).await {
return Ok(DealerDetailsResponse {
details: Some(details),
dealer_type: DealerType::Current,
});
}
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,
dealer_type,
details: None,
dealer_type: DealerType::Unknown,
})
}
@@ -332,7 +358,7 @@ impl super::client::Client for DummyClient {
epoch_id: EpochId,
dealer: String,
dealing_index: DealingIndex,
) -> crate::coconut::error::Result<DealingStatusResponse> {
) -> Result<DealingStatusResponse> {
let dealings = self.get_dealings(epoch_id, &dealer).await?;
Ok(DealingStatusResponse {
epoch_id,
@@ -371,18 +397,28 @@ impl super::client::Client for DummyClient {
.unwrap_or_default())
}
async fn get_verification_key_shares(
async fn get_verification_key_share(
&self,
_epoch_id: EpochId,
) -> Result<Vec<ContractVKShare>> {
Ok(self
.state
.lock()
.unwrap()
.verification_shares
.values()
.cloned()
.collect())
epoch_id: EpochId,
dealer: String,
) -> Result<Option<ContractVKShare>> {
let guard = self.state.lock().unwrap();
let epoch_shares = guard.verification_shares.get(&epoch_id);
match epoch_shares {
None => Ok(None),
Some(epoch_shares) => Ok(epoch_shares.get(&dealer).cloned()),
}
}
async fn get_verification_key_shares(&self, epoch_id: EpochId) -> Result<Vec<ContractVKShare>> {
let guard = self.state.lock().unwrap();
let epoch_shares = guard.verification_shares.get(&epoch_id);
match epoch_shares {
None => Ok(Vec::new()),
Some(epoch_shares) => Ok(epoch_shares.values().cloned().collect()),
}
}
async fn vote_proposal(
@@ -391,29 +427,31 @@ impl super::client::Client for DummyClient {
vote_yes: bool,
_fee: Option<Fee>,
) -> Result<()> {
if let Some(proposal) = self.state.lock().unwrap().proposals.get_mut(&proposal_id) {
// for now, just suppose that every vote is honest
if !vote_yes {
proposal.status = cw3::Status::Rejected;
} else if vote_yes && proposal.status == cw3::Status::Open {
proposal.status = cw3::Status::Passed;
}
}
Ok(())
todo!()
// if let Some(proposal) = self.state.lock().unwrap().proposals.get_mut(&proposal_id) {
// // for now, just suppose that every vote is honest
// if !vote_yes {
// proposal.status = cw3::Status::Rejected;
// } else if vote_yes && proposal.status == cw3::Status::Open {
// proposal.status = cw3::Status::Passed;
// }
// }
// Ok(())
}
async fn execute_proposal(&self, proposal_id: u64) -> Result<()> {
self.state
.lock()
.unwrap()
.proposals
.entry(proposal_id)
.and_modify(|prop| {
if prop.status == cw3::Status::Passed {
prop.status = cw3::Status::Executed
}
});
Ok(())
todo!()
// self.state
// .lock()
// .unwrap()
// .proposals
// .entry(proposal_id)
// .and_modify(|prop| {
// if prop.status == cw3::Status::Passed {
// prop.status = cw3::Status::Executed
// }
// });
// Ok(())
}
async fn advance_epoch_state(&self) -> Result<()> {
@@ -427,33 +465,39 @@ impl super::client::Client for DummyClient {
announce_address: String,
_resharing: bool,
) -> Result<ExecuteResult> {
let mut guard = self.state.lock().unwrap();
let assigned_index = if let Some((details, active)) =
guard.old_dealers.get_mut(self.validator_address.as_ref())
let assigned_index = if let Some(already_registered) = self
.get_dealer_by_address(self.validator_address.as_ref())
.await
{
*active = true;
details.assigned_index
// 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.dealers.insert(index, registered_in_the_past);
index
} else {
// new dealer
let mut guard = self.state.lock().unwrap();
// let assigned_index = OsRng.gen();
let assigned_index = guard
.old_dealers
.values()
.map(|(d, _)| d.assigned_index)
.max()
.unwrap_or(0)
+ 1;
guard.old_dealers.insert(
self.validator_address.to_string(),
(
DealerDetails {
address: Addr::unchecked(self.validator_address.to_string()),
bte_public_key_with_proof,
ed25519_identity: identity_key,
announce_address,
assigned_index,
},
true,
),
guard.node_index_counter += 1;
let assigned_index = guard.node_index_counter;
guard.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
};
@@ -475,7 +519,7 @@ impl super::client::Client for DummyClient {
_resharing: bool,
) -> Result<ExecuteResult> {
let mut guard = self.state.lock().unwrap();
let current_epoch = guard.epoch.epoch_id;
let current_epoch = guard.dkg_epoch.epoch_id;
let epoch_dealings = guard.dealings.entry(current_epoch).or_default();
let existing_dealings = epoch_dealings
@@ -496,33 +540,36 @@ impl super::client::Client for DummyClient {
share: VerificationKeyShare,
resharing: bool,
) -> Result<ExecuteResult> {
let (dealer_details, active) = self
.state
.lock()
.unwrap()
.old_dealers
.get(self.validator_address.as_ref())
.unwrap()
.clone();
if !active {
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);
}
self.state.lock().unwrap().verification_shares.insert(
self.validator_address.to_string(),
ContractVKShare {
share,
announce_address: dealer_details.announce_address.clone(),
node_index: dealer_details.assigned_index,
owner: Addr::unchecked(self.validator_address.to_string()),
epoch_id: 0,
verified: false,
},
);
};
let mut guard = self.state.lock().unwrap();
let epoch_id = guard.dkg_epoch.epoch_id;
guard
.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 = OsRng.gen();
let verify_vk_share_req =
nym_coconut_dkg_common::msg::ExecuteMsg::VerifyVerificationKeyShare {
owner: Addr::unchecked(self.validator_address.as_ref()),
owner: Addr::unchecked(&address),
resharing,
};
let verify_vk_share_msg = CosmosMsg::Wasm(WasmMsg::Execute {
@@ -544,11 +591,7 @@ impl super::client::Client for DummyClient {
proposer: Addr::unchecked(self.validator_address.as_ref()),
deposit: None,
};
self.state
.lock()
.unwrap()
.proposals
.insert(proposal_id, proposal);
guard.proposals.insert(proposal_id, proposal);
Ok(ExecuteResult {
logs: vec![Log {
msg_index: 0,