diff --git a/common/cosmwasm-smart-contracts/coconut-dkg/src/dealer.rs b/common/cosmwasm-smart-contracts/coconut-dkg/src/dealer.rs index 3e626a41ff..da00b9bf41 100644 --- a/common/cosmwasm-smart-contracts/coconut-dkg/src/dealer.rs +++ b/common/cosmwasm-smart-contracts/coconut-dkg/src/dealer.rs @@ -79,6 +79,17 @@ pub struct DealingResponse { pub dealing: Option, } +#[cw_serde] +pub struct DealingStatusResponse { + pub epoch_id: EpochId, + + pub dealer: Addr, + + pub dealing_index: DealingIndex, + + pub dealing_submitted: bool, +} + #[cw_serde] pub struct PagedDealingsResponse { pub epoch_id: EpochId, diff --git a/common/cosmwasm-smart-contracts/coconut-dkg/src/msg.rs b/common/cosmwasm-smart-contracts/coconut-dkg/src/msg.rs index afe1d23b2f..55884fd87f 100644 --- a/common/cosmwasm-smart-contracts/coconut-dkg/src/msg.rs +++ b/common/cosmwasm-smart-contracts/coconut-dkg/src/msg.rs @@ -10,7 +10,10 @@ use cosmwasm_std::Addr; #[cfg(feature = "schema")] use crate::{ - dealer::{DealerDetailsResponse, DealingResponse, PagedDealerResponse, PagedDealingsResponse}, + dealer::{ + DealerDetailsResponse, DealingResponse, DealingStatusResponse, PagedDealerResponse, + PagedDealingsResponse, + }, types::{Epoch, InitialReplacementData, State}, verification_key::PagedVKSharesResponse, }; @@ -87,6 +90,13 @@ pub enum QueryMsg { start_after: Option, }, + #[cfg_attr(feature = "schema", returns(DealingStatusResponse))] + GetDealingStatus { + epoch_id: EpochId, + dealer: String, + dealing_index: DealingIndex, + }, + #[cfg_attr(feature = "schema", returns(DealingResponse))] GetDealing { epoch_id: EpochId, diff --git a/contracts/coconut-dkg/src/contract.rs b/contracts/coconut-dkg/src/contract.rs index f1fff7e4cb..67ae62f303 100644 --- a/contracts/coconut-dkg/src/contract.rs +++ b/contracts/coconut-dkg/src/contract.rs @@ -5,7 +5,7 @@ use crate::dealers::queries::{ query_current_dealers_paged, query_dealer_details, query_past_dealers_paged, }; use crate::dealers::transactions::try_add_dealer; -use crate::dealings::queries::{query_dealing, query_dealings_paged}; +use crate::dealings::queries::{query_dealing, query_dealing_status, query_dealings_paged}; use crate::dealings::transactions::try_commit_dealings; use crate::epoch_state::queries::{ query_current_epoch, query_current_epoch_threshold, query_initial_dealers, @@ -113,6 +113,16 @@ pub fn query(deps: Deps<'_>, _env: Env, msg: QueryMsg) -> Result { to_binary(&query_past_dealers_paged(deps, start_after, limit)?)? } + QueryMsg::GetDealingStatus { + epoch_id, + dealer, + dealing_index, + } => to_binary(&query_dealing_status( + deps, + epoch_id, + dealer, + dealing_index, + )?)?, QueryMsg::GetDealing { epoch_id, dealer, diff --git a/contracts/coconut-dkg/src/dealings/queries.rs b/contracts/coconut-dkg/src/dealings/queries.rs index 9e9f86f05f..d78582aeee 100644 --- a/contracts/coconut-dkg/src/dealings/queries.rs +++ b/contracts/coconut-dkg/src/dealings/queries.rs @@ -5,9 +5,30 @@ use crate::dealings::storage; use crate::dealings::storage::StoredDealing; use cosmwasm_std::{Deps, StdResult}; use cw_storage_plus::Bound; -use nym_coconut_dkg_common::dealer::{DealingResponse, PagedDealingsResponse}; +use nym_coconut_dkg_common::dealer::{ + DealingResponse, DealingStatusResponse, PagedDealingsResponse, +}; use nym_coconut_dkg_common::types::{DealingIndex, EpochId}; +// this does almost the same as query_dealing but doesn't return the actual dealing to make it easier on the validator +// so it wouldn't need to deal with the deserialization +pub fn query_dealing_status( + deps: Deps<'_>, + epoch_id: EpochId, + dealer: String, + dealing_index: DealingIndex, +) -> StdResult { + let dealer = deps.api.addr_validate(&dealer)?; + let dealing_submitted = StoredDealing::exists(deps.storage, epoch_id, &dealer, dealing_index); + + Ok(DealingStatusResponse { + epoch_id, + dealer, + dealing_index, + dealing_submitted, + }) +} + pub fn query_dealing( deps: Deps<'_>, epoch_id: EpochId, @@ -108,6 +129,35 @@ pub(crate) mod tests { assert_eq!(retrieved.dealing.unwrap(), dealing.data); } + #[test] + fn test_query_dealing_status() { + let mut deps = init_contract(); + + let bad_address = "FOOMP".to_string(); + assert!(query_dealing_status(deps.as_ref(), 0, bad_address, 0).is_err()); + + let empty = query_dealing_status(deps.as_ref(), 0, "foo".to_string(), 0).unwrap(); + assert_eq!(empty.epoch_id, 0); + assert_eq!(empty.dealing_index, 0); + assert_eq!(empty.dealer, Addr::unchecked("foo")); + assert!(!empty.dealing_submitted); + + // insert the dealing + let dealing = partial_dealing_fixture(); + StoredDealing::save( + deps.as_mut().storage, + 0, + &Addr::unchecked("foo"), + dealing.clone(), + ); + + let retrieved = query_dealing_status(deps.as_ref(), 0, "foo".to_string(), 0).unwrap(); + assert_eq!(retrieved.epoch_id, 0); + assert_eq!(retrieved.dealing_index, dealing.index); + assert_eq!(retrieved.dealer, Addr::unchecked("foo")); + assert!(retrieved.dealing_submitted) + } + #[cfg(test)] mod query_dealings { use super::*;