nym-api updates

This commit is contained in:
Jędrzej Stuczyński
2024-02-15 14:39:48 +00:00
parent 914b8a6dc2
commit da70ae70a5
11 changed files with 149 additions and 86 deletions
@@ -11,6 +11,7 @@ use cosmwasm_std::Addr;
use nym_coconut_dkg_common::types::{ChunkIndex, NodeIndex};
use serde::Deserialize;
use nym_coconut_dkg_common::dealer::RegisteredDealerDetails;
pub use nym_coconut_dkg_common::{
dealer::{DealerDetailsResponse, PagedDealerIndexResponse, PagedDealerResponse},
dealing::{
@@ -44,6 +45,18 @@ pub trait DkgQueryClient {
self.query_dkg_contract(request).await
}
async fn get_registered_dealer_details(
&self,
address: &AccountId,
epoch_id: Option<EpochId>,
) -> Result<RegisteredDealerDetails, NyxdError> {
let request = DkgQueryMsg::GetRegisteredDealer {
dealer_address: address.to_string(),
epoch_id,
};
self.query_dkg_contract(request).await
}
async fn get_dealer_details(
&self,
address: &AccountId,
@@ -235,6 +248,12 @@ mod tests {
DkgQueryMsg::GetCurrentEpochThreshold {} => {
client.get_current_epoch_threshold().ignore()
}
DkgQueryMsg::GetRegisteredDealer {
dealer_address,
epoch_id,
} => client
.get_registered_dealer_details(&dealer_address.parse().unwrap(), epoch_id)
.ignore(),
DkgQueryMsg::GetDealerDetails { dealer_address } => client
.get_dealer_details(&dealer_address.parse().unwrap())
.ignore(),
@@ -35,6 +35,11 @@ impl DealerType {
}
}
#[cw_serde]
pub struct RegisteredDealerDetails {
pub details: Option<DealerRegistrationDetails>,
}
#[cw_serde]
pub struct DealerDetailsResponse {
pub details: Option<DealerDetails>,
@@ -11,7 +11,10 @@ use cosmwasm_schema::cw_serde;
#[cfg(feature = "schema")]
use crate::{
dealer::{DealerDetailsResponse, PagedDealerIndexResponse, PagedDealerResponse},
dealer::{
DealerDetailsResponse, PagedDealerIndexResponse, PagedDealerResponse,
RegisteredDealerDetails,
},
dealing::{
DealerDealingsStatusResponse, DealingChunkResponse, DealingChunkStatusResponse,
DealingMetadataResponse, DealingStatusResponse,
@@ -86,6 +89,12 @@ pub enum QueryMsg {
#[cfg_attr(feature = "schema", returns(u64))]
GetCurrentEpochThreshold {},
#[cfg_attr(feature = "schema", returns(RegisteredDealerDetails))]
GetRegisteredDealer {
dealer_address: String,
epoch_id: Option<EpochId>,
},
#[cfg_attr(feature = "schema", returns(DealerDetailsResponse))]
GetDealerDetails { dealer_address: String },
+9
View File
@@ -3,6 +3,7 @@
use crate::dealers::queries::{
query_current_dealers_paged, query_dealer_details, query_dealers_indices_paged,
query_registered_dealer_details,
};
use crate::dealers::transactions::try_add_dealer;
use crate::dealings::queries::{
@@ -130,6 +131,14 @@ pub fn query(deps: Deps<'_>, _env: Env, msg: QueryMsg) -> Result<QueryResponse,
QueryMsg::GetCurrentEpochThreshold {} => {
to_binary(&query_current_epoch_threshold(deps.storage)?)?
}
QueryMsg::GetRegisteredDealer {
dealer_address,
epoch_id,
} => to_binary(&query_registered_dealer_details(
deps,
dealer_address,
epoch_id,
)?)?,
QueryMsg::GetDealerDetails { dealer_address } => {
to_binary(&query_dealer_details(deps, dealer_address)?)?
}
+21 -2
View File
@@ -2,15 +2,34 @@
// SPDX-License-Identifier: Apache-2.0
use crate::dealers::storage::{
self, get_dealer_details, get_dealer_index, DEALERS_INDICES, EPOCH_DEALERS_MAP,
self, get_dealer_details, get_dealer_index, get_registration_details, DEALERS_INDICES,
EPOCH_DEALERS_MAP,
};
use crate::epoch_state::storage::CURRENT_EPOCH;
use cosmwasm_std::{Deps, Order, StdResult};
use cw_storage_plus::Bound;
use nym_coconut_dkg_common::dealer::{
DealerDetailsResponse, DealerType, PagedDealerIndexResponse, PagedDealerResponse,
RegisteredDealerDetails,
};
use nym_coconut_dkg_common::types::DealerDetails;
use nym_coconut_dkg_common::types::{DealerDetails, EpochId};
pub fn query_registered_dealer_details(
deps: Deps<'_>,
dealer_address: String,
epoch_id: Option<EpochId>,
) -> StdResult<RegisteredDealerDetails> {
let addr = deps.api.addr_validate(&dealer_address)?;
let epoch_id = match epoch_id {
Some(epoch_id) => epoch_id,
None => CURRENT_EPOCH.load(deps.storage)?.epoch_id,
};
Ok(RegisteredDealerDetails {
details: get_registration_details(deps.storage, &addr, epoch_id).ok(),
})
}
pub fn query_dealer_details(
deps: Deps<'_>,
+11 -9
View File
@@ -5,13 +5,15 @@ use crate::coconut::error::Result;
use cw3::{ProposalResponse, VoteResponse};
use cw4::MemberResponse;
use nym_coconut_bandwidth_contract_common::spend_credential::SpendCredentialResponse;
use nym_coconut_dkg_common::dealer::{DealerDetails, DealerDetailsResponse};
use nym_coconut_dkg_common::dealer::{
DealerDetails, DealerDetailsResponse, RegisteredDealerDetails,
};
use nym_coconut_dkg_common::dealing::{
DealerDealingsStatusResponse, DealingChunkInfo, DealingMetadata, DealingStatusResponse,
PartialContractDealing,
};
use nym_coconut_dkg_common::types::{
ChunkIndex, DealingIndex, EncodedBTEPublicKeyWithProof, Epoch, EpochId, InitialReplacementData,
ChunkIndex, DealingIndex, EncodedBTEPublicKeyWithProof, Epoch, EpochId,
PartialContractDealingData, State,
};
use nym_coconut_dkg_common::verification_key::{ContractVKShare, VerificationKeyShare};
@@ -47,10 +49,14 @@ pub trait Client {
async fn get_current_epoch_threshold(&self) -> Result<Option<Threshold>>;
async fn get_initial_dealers(&self) -> Result<Option<InitialReplacementData>>;
async fn get_self_registered_dealer_details(&self) -> Result<DealerDetailsResponse>;
async fn get_registered_dealer_details(
&self,
epoch_id: EpochId,
dealer: String,
) -> Result<RegisteredDealerDetails>;
async fn get_dealer_dealings_status(
&self,
epoch_id: EpochId,
@@ -111,11 +117,7 @@ pub trait Client {
resharing: bool,
) -> Result<ExecuteResult>;
async fn submit_dealing_chunk(
&self,
chunk: PartialContractDealing,
resharing: bool,
) -> Result<ExecuteResult>;
async fn submit_dealing_chunk(&self, chunk: PartialContractDealing) -> Result<ExecuteResult>;
async fn submit_verification_key_share(
&self,
+14 -10
View File
@@ -10,8 +10,8 @@ use nym_coconut_dkg_common::dealing::{
DealerDealingsStatusResponse, DealingChunkInfo, PartialContractDealing,
};
use nym_coconut_dkg_common::types::{
ChunkIndex, DealingIndex, EncodedBTEPublicKeyWithProof, Epoch, EpochId, InitialReplacementData,
NodeIndex, PartialContractDealingData, State as ContractState,
ChunkIndex, DealingIndex, EncodedBTEPublicKeyWithProof, Epoch, EpochId, NodeIndex,
PartialContractDealingData, State as ContractState,
};
use nym_coconut_dkg_common::verification_key::{ContractVKShare, VerificationKeyShare};
use nym_contracts_common::IdentityKey;
@@ -62,18 +62,23 @@ impl DkgClient {
self.inner.get_current_epoch_threshold().await
}
pub(crate) async fn get_initial_dealers(
&self,
) -> Result<Option<InitialReplacementData>, CoconutError> {
self.inner.get_initial_dealers().await
}
pub(crate) async fn get_self_registered_dealer_details(
&self,
) -> Result<DealerDetailsResponse, CoconutError> {
self.inner.get_self_registered_dealer_details().await
}
pub(crate) async fn dealer_in_epoch(
&self,
epoch_id: EpochId,
dealer: String,
) -> Result<bool, CoconutError> {
self.inner
.get_registered_dealer_details(epoch_id, dealer)
.await
.map(|d| d.details.is_some())
}
pub(crate) async fn get_current_dealers(&self) -> Result<Vec<DealerDetails>, CoconutError> {
self.inner.get_current_dealers().await
}
@@ -190,9 +195,8 @@ impl DkgClient {
pub(crate) async fn submit_dealing_chunk(
&self,
chunk: PartialContractDealing,
resharing: bool,
) -> Result<(), CoconutError> {
self.inner.submit_dealing_chunk(chunk, resharing).await?;
self.inner.submit_dealing_chunk(chunk).await?;
Ok(())
}
+17 -18
View File
@@ -209,9 +209,7 @@ impl<R: RngCore + CryptoRng> DkgController<R> {
.remove(chunk_index)
.expect("chunking specification has changed mid-exchange!");
debug!("[dealing {dealing_index}]: resubmitting chunk index {chunk_index}");
self.dkg_client
.submit_dealing_chunk(chunk, resharing)
.await?;
self.dkg_client.submit_dealing_chunk(chunk).await?;
}
}
Ok(())
@@ -243,26 +241,28 @@ impl<R: RngCore + CryptoRng> DkgController<R> {
let human_index = chunk_index + 1;
debug!("[dealing {dealing_index}]: submitting chunk index {chunk_index} ({human_index}/{total_chunks})");
self.dkg_client
.submit_dealing_chunk(chunk, resharing)
.await?;
self.dkg_client.submit_dealing_chunk(chunk).await?;
}
Ok(())
}
/// Check whether this dealer can participate in the resharing
/// by looking into the contract and ensuring it's in the list of initial dealers for this epoch
async fn can_reshare(&self) -> Result<bool, DealingGenerationError> {
let Some(initial_data) = self.dkg_client.get_initial_dealers().await? else {
return Ok(false);
};
/// by looking into the contract and ensuring it's been a dealer in the previous epoch
async fn can_reshare(&self, epoch_id: EpochId) -> Result<bool, DealingGenerationError> {
// SAFETY:
// it's impossible for the contract to trigger resharing for the 0th epoch
// otherwise some serious invariants have been broken
#[allow(clippy::expect_used)]
let previous_epoch_id = epoch_id
.checked_sub(1)
.expect("resharing epoch invariant has been broken");
let address = self.dkg_client.get_address().await;
Ok(initial_data
.initial_dealers
.iter()
.any(|d| d.as_str() == address.as_ref()))
Ok(self
.dkg_client
.dealer_in_epoch(previous_epoch_id, address.to_string())
.await?)
}
/// Deal with the dealing generation case where the system requests resharing
@@ -274,7 +274,7 @@ impl<R: RngCore + CryptoRng> DkgController<R> {
old_keypair: KeyPairWithEpoch,
) -> Result<(), DealingGenerationError> {
// make sure we're allowed to participate in resharing
if !self.can_reshare().await? {
if !self.can_reshare(epoch_id).await? {
// we have to wait for other dealers to give us the dealings (hopefully)
warn!("we we have an existing coconut keypair, but we're not allowed to participate in resharing");
return Ok(());
@@ -427,7 +427,7 @@ impl<R: RngCore + CryptoRng> DkgController<R> {
// sure, the if statements could be collapsed, but i prefer to explicitly repeat the block for readability
if resharing {
debug!("resharing + no prior key -> nothing to do");
if self.can_reshare().await? {
if self.can_reshare(epoch_id).await? {
warn!("this dealer was expected to participate in resharing but it doesn't have any prior keys to use");
}
} else {
@@ -475,7 +475,6 @@ 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::InitialReplacementData;
use nym_dkg::bte::PublicKeyWithProof;
#[tokio::test]
+20 -16
View File
@@ -186,7 +186,6 @@ impl<R: RngCore + CryptoRng> DkgController<R> {
epoch_id: EpochId,
dealer: &Addr,
resharing: bool,
initial_dealers: &[Addr],
) -> Result<Result<HashMap<DealingIndex, Vec<u8>>, DealerRejectionReason>, KeyDerivationError>
{
let dealing_statuses = self
@@ -208,11 +207,25 @@ impl<R: RngCore + CryptoRng> DkgController<R> {
));
}
// we might be in resharing mode and this dealer was not in "initial" set.
// in that case we don't expect any dealings
if resharing && !initial_dealers.contains(dealer) {
return Ok(Ok(HashMap::new()));
// if we're in the resharing mode and this dealer has not been a dealer in the previous epoch,
// we don't expect to have received anything from them
if resharing {
// SAFETY:
// it's impossible for the contract to trigger resharing for the 0th epoch
// otherwise some serious invariants have been broken
#[allow(clippy::expect_used)]
let previous_epoch_id = epoch_id
.checked_sub(1)
.expect("resharing epoch invariant has been broken");
if !self
.dkg_client
.dealer_in_epoch(previous_epoch_id, dealer.to_string())
.await?
{
return Ok(Ok(HashMap::new()));
}
}
return Ok(Err(DealerRejectionReason::NoDealingsProvided));
}
@@ -251,22 +264,13 @@ impl<R: RngCore + CryptoRng> DkgController<R> {
let mut valid_dealings: BTreeMap<_, BTreeMap<_, _>> = BTreeMap::new();
// given at MOST we'll have like 50 entries here, iterating over entire vector for lookup is fine
let initial_dealers = self
.dkg_client
.get_initial_dealers()
.await?
.map(|i| i.initial_dealers)
.unwrap_or_default();
// for every valid dealer in this epoch, obtain its dealings
for (dealer, dealer_index) in self.state.valid_epoch_receivers(epoch_id)? {
// note: if we're in resharing mode, the contract itself will forbid submission of dealings from
// parties that were not "initial" dealers, so we don't have to worry about it
// parties that were dealers in the previous epoch, so we don't have to worry about it
let raw_dealings = match self
.get_raw_dealings(epoch_id, &dealer, resharing, &initial_dealers)
.await?
{
let raw_dealings = match self.get_raw_dealings(epoch_id, &dealer, resharing).await? {
Ok(dealings) => dealings,
Err(rejection) => {
self.blacklist_dealer(epoch_id, dealer, rejection)?;
+5 -19
View File
@@ -29,7 +29,7 @@ use nym_coconut_dkg_common::dealing::{
use nym_coconut_dkg_common::event_attributes::{DKG_PROPOSAL_ID, NODE_INDEX};
use nym_coconut_dkg_common::types::{
ChunkIndex, DealingIndex, EncodedBTEPublicKeyWithProof, Epoch, EpochId, EpochState,
InitialReplacementData, PartialContractDealingData, State as ContractState,
PartialContractDealingData, State as ContractState,
};
use nym_coconut_dkg_common::verification_key::{ContractVKShare, VerificationKeyShare};
use nym_coconut_interface::VerificationKey;
@@ -135,9 +135,9 @@ impl Dealing {
pub(crate) struct FakeDkgContractState {
pub(crate) address: AccountId,
pub(crate) dealers: HashMap<NodeIndex, DealerDetails>,
pub(crate) past_dealers: HashMap<NodeIndex, DealerDetails>,
pub(crate) initial_dealers: Option<InitialReplacementData>,
// pub(crate) dealers: HashMap<NodeIndex, DealerDetails>,
// pub(crate) past_dealers: HashMap<NodeIndex, DealerDetails>,
// pub(crate) initial_dealers: Option<InitialReplacementData>,
// map of epoch id -> dealer -> dealings
pub(crate) dealings: HashMap<EpochId, HashMap<String, HashMap<DealingIndex, Dealing>>>,
@@ -651,16 +651,6 @@ impl super::client::Client for DummyClient {
Ok(self.state.lock().unwrap().dkg_contract.threshold)
}
async fn get_initial_dealers(&self) -> Result<Option<InitialReplacementData>> {
Ok(self
.state
.lock()
.unwrap()
.dkg_contract
.initial_dealers
.clone())
}
async fn get_self_registered_dealer_details(&self) -> Result<DealerDetailsResponse> {
let address = self.validator_address.as_ref();
@@ -1081,11 +1071,7 @@ impl super::client::Client for DummyClient {
})
}
async fn submit_dealing_chunk(
&self,
chunk: PartialContractDealing,
_resharing: bool,
) -> Result<ExecuteResult> {
async fn submit_dealing_chunk(&self, chunk: PartialContractDealing) -> Result<ExecuteResult> {
let mut guard = self.state.lock().unwrap();
let current_epoch = guard.dkg_contract.epoch.epoch_id;
let current_height = guard.block_info.height;
+18 -11
View File
@@ -14,9 +14,7 @@ use nym_coconut_dkg_common::dealing::{
PartialContractDealing,
};
use nym_coconut_dkg_common::msg::QueryMsg as DkgQueryMsg;
use nym_coconut_dkg_common::types::{
ChunkIndex, DealingIndex, InitialReplacementData, PartialContractDealingData, State,
};
use nym_coconut_dkg_common::types::{ChunkIndex, DealingIndex, PartialContractDealingData, State};
use nym_coconut_dkg_common::{
dealer::{DealerDetails, DealerDetailsResponse},
types::{EncodedBTEPublicKeyWithProof, Epoch, EpochId},
@@ -24,6 +22,7 @@ use nym_coconut_dkg_common::{
};
use nym_config::defaults::{ChainDetails, NymNetworkDetails};
use nym_coconut_dkg_common::dealer::RegisteredDealerDetails;
use nym_mixnet_contract_common::families::FamilyHead;
use nym_mixnet_contract_common::mixnode::MixNodeDetails;
use nym_mixnet_contract_common::reward_params::RewardingParams;
@@ -412,12 +411,6 @@ impl crate::coconut::client::Client for Client {
Ok(nyxd_query!(self, get_current_epoch_threshold().await?))
}
async fn get_initial_dealers(
&self,
) -> crate::coconut::error::Result<Option<InitialReplacementData>> {
Ok(nyxd_query!(self, get_initial_dealers().await?))
}
async fn get_self_registered_dealer_details(
&self,
) -> crate::coconut::error::Result<DealerDetailsResponse> {
@@ -425,6 +418,21 @@ impl crate::coconut::client::Client for Client {
Ok(nyxd_query!(self, get_dealer_details(self_address).await?))
}
async fn get_registered_dealer_details(
&self,
epoch_id: EpochId,
dealer: String,
) -> crate::coconut::error::Result<RegisteredDealerDetails> {
let dealer = dealer
.as_str()
.parse()
.map_err(|_| NyxdError::MalformedAccountAddress(dealer))?;
Ok(nyxd_query!(
self,
get_registered_dealer_details(&dealer, Some(epoch_id)).await?
))
}
async fn get_dealer_dealings_status(
&self,
epoch_id: EpochId,
@@ -547,11 +555,10 @@ impl crate::coconut::client::Client for Client {
async fn submit_dealing_chunk(
&self,
chunk: PartialContractDealing,
resharing: bool,
) -> Result<ExecuteResult, CoconutError> {
Ok(nyxd_signing!(
self,
submit_dealing_chunk(chunk, resharing, None).await?
submit_dealing_chunk(chunk, None).await?
))
}