From dc2a386cd60d8114e039273622ca66d15f2f7529 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Thu, 19 May 2022 17:36:49 +0100 Subject: [PATCH] Storing and retrieving epoch dealings commitments --- Cargo.lock | 1 + .../validator-client/src/client.rs | 32 +++++++++++++ .../src/nymd/traits/dkg_client.rs | 26 ++++++++++- .../coconut-dkg-contract/src/dealer.rs | 45 ++++++++++++++++++- .../coconut-dkg-contract/src/msg.rs | 9 +++- .../contracts-common/Cargo.toml | 1 + .../contracts-common/src/commitment.rs | 35 +++++++++++++-- contracts/Cargo.lock | 1 + .../coconut-dkg/src/dealers/transactions.rs | 18 +++----- contracts/coconut-dkg/src/dealings/queries.rs | 45 +++++++++++++++++++ contracts/coconut-dkg/src/dealings/storage.rs | 23 ++++++++++ .../coconut-dkg/src/dealings/transactions.rs | 45 +++++++++++++++++++ contracts/coconut-dkg/src/error.rs | 14 +++++- contracts/coconut-dkg/src/lib.rs | 14 +++++- contracts/coconut-dkg/src/support/tests.rs | 1 + nym-wallet/Cargo.lock | 1 + validator-api/src/nymd_client.rs | 15 ++++++- 17 files changed, 301 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 40198fbcaa..8d05f9fa09 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -733,6 +733,7 @@ name = "contracts-common" version = "0.1.0" dependencies = [ "blake3", + "bs58", "cosmwasm-std", "digest 0.10.3", "schemars", diff --git a/common/client-libs/validator-client/src/client.rs b/common/client-libs/validator-client/src/client.rs index 8ba3db4d2c..d71169b16c 100644 --- a/common/client-libs/validator-client/src/client.rs +++ b/common/client-libs/validator-client/src/client.rs @@ -23,6 +23,8 @@ use crate::nymd::{ #[cfg(feature = "dkg")] use crate::nymd::{traits::DkgClient, SigningCosmWasmClient}; +use coconut_dkg_common::dealer::ContractDealingCommitment; +use coconut_dkg_common::types::EpochId; #[cfg(feature = "dkg")] use coconut_dkg_common::types::{BlacklistedDealer, DealerDetails}; #[cfg(feature = "nymd-client")] @@ -846,4 +848,34 @@ where Ok(dealers) } + + pub async fn get_all_nymd_epoch_dealings_commitments( + &self, + epoch_id: EpochId, + ) -> Result, ValidatorClientError> + where + C: CosmWasmClient + Sync, + { + let mut commitments = Vec::new(); + let mut start_after = None; + loop { + let mut paged_response = self + .nymd + .get_epoch_dealings_commitments_paged( + epoch_id, + start_after.take(), + self.dealers_page_limit, + ) + .await?; + commitments.append(&mut paged_response.commitments); + + if let Some(start_after_res) = paged_response.start_next_after { + start_after = Some(start_after_res.into_string()) + } else { + break; + } + } + + Ok(commitments) + } } diff --git a/common/client-libs/validator-client/src/nymd/traits/dkg_client.rs b/common/client-libs/validator-client/src/nymd/traits/dkg_client.rs index ed0ae49aa5..98f7b76156 100644 --- a/common/client-libs/validator-client/src/nymd/traits/dkg_client.rs +++ b/common/client-libs/validator-client/src/nymd/traits/dkg_client.rs @@ -5,11 +5,11 @@ use crate::nymd::cosmwasm_client::types::ExecuteResult; use crate::nymd::error::NymdError; use crate::nymd::{cosmwasm_coin_to_cosmos_coin, Fee, NymdClient, SigningCosmWasmClient}; use async_trait::async_trait; -use coconut_dkg_common::dealer::DealerDetailsResponse; +use coconut_dkg_common::dealer::{DealerDetailsResponse, PagedCommitmentsResponse}; use coconut_dkg_common::msg::ExecuteMsg as DkgExecuteMsg; use coconut_dkg_common::msg::QueryMsg as DkgQueryMsg; use coconut_dkg_common::types::{ - BlacklistingResponse, EncodedBTEPublicKeyWithProof, EncodedEd25519PublicKey, Epoch, + BlacklistingResponse, EncodedBTEPublicKeyWithProof, EncodedEd25519PublicKey, Epoch, EpochId, MinimumDepositResponse, PagedBlacklistingResponse, PagedDealerResponse, }; use contracts_common::commitment::ContractSafeCommitment; @@ -41,6 +41,12 @@ pub trait DkgClient { async fn get_blacklisting(&self, dealer: String) -> Result; async fn get_deposit_amount(&self) -> Result; + async fn get_epoch_dealings_commitments_paged( + &self, + epoch: EpochId, + start_after: Option, + page_limit: Option, + ) -> Result; async fn register_dealer( &self, @@ -138,6 +144,22 @@ where .await } + async fn get_epoch_dealings_commitments_paged( + &self, + epoch: EpochId, + start_after: Option, + page_limit: Option, + ) -> Result { + let request = DkgQueryMsg::GetEpochDealingsCommitments { + limit: page_limit, + start_after, + epoch, + }; + self.client + .query_contract_smart(self.coconut_dkg_contract_address()?, &request) + .await + } + async fn register_dealer( &self, identity: EncodedEd25519PublicKey, diff --git a/common/cosmwasm-smart-contracts/coconut-dkg-contract/src/dealer.rs b/common/cosmwasm-smart-contracts/coconut-dkg-contract/src/dealer.rs index 2f2ce2b072..7d4b4e7b4d 100644 --- a/common/cosmwasm-smart-contracts/coconut-dkg-contract/src/dealer.rs +++ b/common/cosmwasm-smart-contracts/coconut-dkg-contract/src/dealer.rs @@ -1,7 +1,10 @@ // Copyright 2022 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::types::{BlockHeight, EncodedBTEPublicKeyWithProof, EncodedEd25519PublicKey, NodeIndex}; +use crate::types::{ + BlockHeight, EncodedBTEPublicKeyWithProof, EncodedEd25519PublicKey, EpochId, NodeIndex, +}; +use contracts_common::commitment::ContractSafeCommitment; use cosmwasm_std::Addr; use serde::{Deserialize, Serialize}; use std::fmt::{Display, Formatter}; @@ -206,3 +209,43 @@ impl BlacklistingResponse { .expect("dealer is not blacklisted") } } + +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +#[serde(rename_all = "snake_case")] +pub struct ContractDealingCommitment { + pub commitment: ContractSafeCommitment, + pub dealer: Addr, + pub epoch_id: EpochId, +} + +impl ContractDealingCommitment { + pub fn new(commitment: ContractSafeCommitment, dealer: Addr, epoch_id: EpochId) -> Self { + ContractDealingCommitment { + commitment, + dealer, + epoch_id, + } + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +#[serde(rename_all = "snake_case")] +pub struct PagedCommitmentsResponse { + pub commitments: Vec, + pub per_page: usize, + pub start_next_after: Option, +} + +impl PagedCommitmentsResponse { + pub fn new( + commitments: Vec, + per_page: usize, + start_next_after: Option, + ) -> Self { + PagedCommitmentsResponse { + commitments, + per_page, + start_next_after, + } + } +} diff --git a/common/cosmwasm-smart-contracts/coconut-dkg-contract/src/msg.rs b/common/cosmwasm-smart-contracts/coconut-dkg-contract/src/msg.rs index 22043a6676..7ea9112e00 100644 --- a/common/cosmwasm-smart-contracts/coconut-dkg-contract/src/msg.rs +++ b/common/cosmwasm-smart-contracts/coconut-dkg-contract/src/msg.rs @@ -1,7 +1,9 @@ // Copyright 2022 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::types::{BlockHeight, EncodedBTEPublicKeyWithProof, EncodedEd25519PublicKey, Threshold}; +use crate::types::{ + BlockHeight, EncodedBTEPublicKeyWithProof, EncodedEd25519PublicKey, EpochId, Threshold, +}; use contracts_common::commitment::ContractSafeCommitment; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -57,6 +59,11 @@ pub enum QueryMsg { dealer: String, }, GetDepositAmount {}, + GetEpochDealingsCommitments { + limit: Option, + start_after: Option, + epoch: EpochId, + }, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] diff --git a/common/cosmwasm-smart-contracts/contracts-common/Cargo.toml b/common/cosmwasm-smart-contracts/contracts-common/Cargo.toml index 4de97b8045..c4f9bc81af 100644 --- a/common/cosmwasm-smart-contracts/contracts-common/Cargo.toml +++ b/common/cosmwasm-smart-contracts/contracts-common/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +bs58 = "0.4.0" cosmwasm-std = "1.0.0-beta8" schemars = "0.8" serde = { version = "1.0.103", default-features = false, features = ["derive"] } diff --git a/common/cosmwasm-smart-contracts/contracts-common/src/commitment.rs b/common/cosmwasm-smart-contracts/contracts-common/src/commitment.rs index df565ac9f6..84edf2d839 100644 --- a/common/cosmwasm-smart-contracts/contracts-common/src/commitment.rs +++ b/common/cosmwasm-smart-contracts/contracts-common/src/commitment.rs @@ -4,7 +4,7 @@ #[cfg(feature = "committable_trait")] pub use digest::{Digest, Output}; use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::fmt::{Display, Formatter}; #[cfg(feature = "committable_trait")] use std::marker::PhantomData; @@ -16,9 +16,7 @@ pub const MAX_COMMITMENT_SIZE: usize = 128; // TODO: if we are to use commitments for different types, it might make sense to introduce something like // CommitmentTypeId field on the below for distinguishing different ones. it would somehow become part of the trait -#[derive( - Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Serialize, Deserialize, JsonSchema, -)] +#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, JsonSchema)] pub struct ContractSafeCommitment(Vec); impl Deref for ContractSafeCommitment { @@ -45,6 +43,35 @@ impl Display for ContractSafeCommitment { } } +// since cosmwasm stores everything with byte representation of stringified json, it's actually more efficient +// to serialize this as a string as opposed to keeping it as vector of bytes. +// for example vec![255,255] would have string representation of "[255,255]" and will be serialized to +// [91, 50, 53, 53, 44, 50, 53, 53, 93]. the equivalent base58 encoded string `"LUv"` will be serialized to +// [34, 76, 85, 118, 34] +// +// the difference between base58 and base64 is rather minimal and I've gone with base58 for consistency sake +impl Serialize for ContractSafeCommitment { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&bs58::encode(&self.0).into_string()) + } +} + +impl<'de> Deserialize<'de> for ContractSafeCommitment { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s = ::deserialize(deserializer)?; + let bytes = bs58::decode(&s) + .into_vec() + .map_err(serde::de::Error::custom)?; + Ok(ContractSafeCommitment(bytes)) + } +} + #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] pub struct UnsupportedCommitmentSize; diff --git a/contracts/Cargo.lock b/contracts/Cargo.lock index 1e419402b3..7a6ad964c7 100644 --- a/contracts/Cargo.lock +++ b/contracts/Cargo.lock @@ -277,6 +277,7 @@ checksum = "9d6f2aa4d0537bcc1c74df8755072bd31c1ef1a3a1b85a68e8404a8c353b7b8b" name = "contracts-common" version = "0.1.0" dependencies = [ + "bs58", "cosmwasm-std", "schemars", "serde", diff --git a/contracts/coconut-dkg/src/dealers/transactions.rs b/contracts/coconut-dkg/src/dealers/transactions.rs index 92d996af82..1e612da662 100644 --- a/contracts/coconut-dkg/src/dealers/transactions.rs +++ b/contracts/coconut-dkg/src/dealers/transactions.rs @@ -5,9 +5,8 @@ use crate::constants::{INVALID_ED25519_BLACKLISTING_EXPIRATION, MINIMUM_DEPOSIT} use crate::dealers::storage as dealers_storage; use crate::ContractError; use coconut_dkg_common::types::{ - BlacklistingReason, BlockHeight, ContractSafeCommitment, DealerDetails, - EncodedBTEPublicKeyWithProof, EncodedBTEPublicKeyWithProofRef, EncodedEd25519PublicKey, - EncodedEd25519PublicKeyRef, + BlacklistingReason, BlockHeight, DealerDetails, EncodedBTEPublicKeyWithProof, + EncodedBTEPublicKeyWithProofRef, EncodedEd25519PublicKey, EncodedEd25519PublicKeyRef, }; use config::defaults::STAKE_DENOM; use cosmwasm_std::{Addr, Coin, Deps, DepsMut, Env, MessageInfo, Response}; @@ -132,6 +131,9 @@ pub fn try_add_dealer( owner_signature: String, host: String, ) -> Result { + // TODO: check if we're in correct epoch state + + // check whether this sender is eligible to become a dealer verify_dealer(deps.branch(), env.block.height, &info.sender)?; @@ -190,13 +192,3 @@ pub fn try_add_dealer( Ok(Response::new().set_data(node_index.to_be_bytes())) } - -pub fn try_commit_dealing( - mut deps: DepsMut<'_>, - env: Env, - info: MessageInfo, - epoch_id: u32, - commitment: ContractSafeCommitment, -) -> Result { - todo!() -} diff --git a/contracts/coconut-dkg/src/dealings/queries.rs b/contracts/coconut-dkg/src/dealings/queries.rs index 87d5c392c8..7c2ccb3110 100644 --- a/contracts/coconut-dkg/src/dealings/queries.rs +++ b/contracts/coconut-dkg/src/dealings/queries.rs @@ -1,2 +1,47 @@ // Copyright 2022 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 + +use crate::dealings::storage; +use crate::dealings::storage::DEALING_COMMITMENTS; +use coconut_dkg_common::dealer::{ContractDealingCommitment, PagedCommitmentsResponse}; +use coconut_dkg_common::types::EpochId; +use cosmwasm_std::{Deps, Order, StdResult}; +use cw_storage_plus::Bound; + +pub fn query_epoch_dealings_commitments_paged( + deps: Deps<'_>, + epoch: EpochId, + start_after: Option, + limit: Option, +) -> StdResult { + let limit = limit + .unwrap_or(storage::COMMITMENTS_PAGE_DEFAULT_LIMIT) + .min(storage::COMMITMENTS_PAGE_MAX_LIMIT) as usize; + + let addr = start_after + .map(|addr| deps.api.addr_validate(&addr)) + .transpose()?; + + let start = addr.as_ref().map(Bound::exclusive); + + let commitments = DEALING_COMMITMENTS + .prefix(epoch) + .range(deps.storage, start, None, Order::Ascending) + .take(limit) + .map(|res| { + res.map(|(dealer, commitment)| { + ContractDealingCommitment::new(commitment, dealer, epoch) + }) + }) + .collect::>>()?; + + let start_next_after = commitments + .last() + .map(|commitment| commitment.dealer.clone()); + + Ok(PagedCommitmentsResponse::new( + commitments, + limit, + start_next_after, + )) +} diff --git a/contracts/coconut-dkg/src/dealings/storage.rs b/contracts/coconut-dkg/src/dealings/storage.rs index 87d5c392c8..d33134da20 100644 --- a/contracts/coconut-dkg/src/dealings/storage.rs +++ b/contracts/coconut-dkg/src/dealings/storage.rs @@ -1,2 +1,25 @@ // Copyright 2022 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 + +use coconut_dkg_common::types::{ContractSafeCommitment, EpochId}; +use cosmwasm_std::Addr; +use cw_storage_plus::Map; + +pub(crate) const COMMITMENTS_PAGE_MAX_LIMIT: u32 = 75; +pub(crate) const COMMITMENTS_PAGE_DEFAULT_LIMIT: u32 = 50; + +type CommitmentKey<'a> = (EpochId, &'a Addr); + +// Note to whoever is looking at this implementation and is thinking of using something similar +// for storing small commitments/hashes of data on chain: +// If there's a lot of entries you want to store thinking, "oh, this digest is only 32 bytes, it's not that much", +// the default cosmwasm' serializer will bloat it to around ~100B. So you really don't want to be using +// Buckets/Maps, etc. for that purpose. Instead you want to use `storage` directly (look into the actual implementation of +// `Map` or `Bucket` to see what I mean. Instead of using the `to_vec` method on serde_json_wasm, you'd +// provide your data directly yourself. +// but you must be extremely careful when doing so, as you might end up overwriting some existing data +// if you don't choose your prefixes wisely. +// I didn't have to do it here as I'm storing relatively little data and after just base58-encoding +// my bytes, I was fine with the json overhead. +pub(crate) const DEALING_COMMITMENTS: Map<'_, CommitmentKey<'_>, ContractSafeCommitment> = + Map::new("dcmt"); diff --git a/contracts/coconut-dkg/src/dealings/transactions.rs b/contracts/coconut-dkg/src/dealings/transactions.rs index 87d5c392c8..60f7d54639 100644 --- a/contracts/coconut-dkg/src/dealings/transactions.rs +++ b/contracts/coconut-dkg/src/dealings/transactions.rs @@ -1,2 +1,47 @@ // Copyright 2022 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 + +use crate::dealers::storage as dealers_storage; +use crate::dealings::storage::DEALING_COMMITMENTS; +use crate::epoch::storage as epoch_storage; +use crate::ContractError; +use coconut_dkg_common::types::ContractSafeCommitment; +use cosmwasm_std::{DepsMut, MessageInfo, Response}; + +pub fn try_commit_dealing( + deps: DepsMut<'_>, + info: MessageInfo, + epoch_id: u32, + commitment: ContractSafeCommitment, +) -> Result { + let current_epoch = epoch_storage::current_epoch(deps.storage)?; + // TODO: check if we're in correct epoch state (i.e. current_epoch.state) + + // ensure the sender is a dealer for the current epoch + if dealers_storage::current_dealers() + .may_load(deps.storage, &info.sender)? + .is_none() + { + return Err(ContractError::NotADealer); + } + + // make sure the dealer wants to submit commitment for THIS epoch + if current_epoch.id != epoch_id { + return Err(ContractError::MismatchedEpoch { + current: current_epoch.id, + request_for: epoch_id, + }); + } + + // check if this dealer has already committed to a dealing + // (we don't want to allow overwriting it as some receivers might already be using the commitment) + let storage_key = (epoch_id, &info.sender); + + if DEALING_COMMITMENTS.has(deps.storage, storage_key) { + return Err(ContractError::AlreadyCommitted); + } + + DEALING_COMMITMENTS.save(deps.storage, storage_key, &commitment)?; + + Ok(Response::new()) +} diff --git a/contracts/coconut-dkg/src/error.rs b/contracts/coconut-dkg/src/error.rs index 421f42d3d6..f059ed5eb5 100644 --- a/contracts/coconut-dkg/src/error.rs +++ b/contracts/coconut-dkg/src/error.rs @@ -1,7 +1,7 @@ // Copyright 2022 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use coconut_dkg_common::types::Blacklisting; +use coconut_dkg_common::types::{Blacklisting, EpochId}; use config::defaults::STAKE_DENOM; use cosmwasm_std::{Addr, StdError, VerificationError}; use thiserror::Error; @@ -55,4 +55,16 @@ pub enum ContractError { // explicitly declare it so that when we ultimate do see it, it's gonna be more informative over "normal" panic #[error("Somehow our validated address {address} is not using correct bech32 encoding")] InvalidValidatedAddress { address: Addr }, + + #[error("This sender is not a dealer for the current epoch")] + NotADealer, + + #[error("The current epoch does not match the one present in the request. Current: {current}, in request: {request_for}")] + MismatchedEpoch { + current: EpochId, + request_for: EpochId, + }, + + #[error("This dealer has already commited dealing for this epoch")] + AlreadyCommitted, } diff --git a/contracts/coconut-dkg/src/lib.rs b/contracts/coconut-dkg/src/lib.rs index 0bec70dae7..fde3474026 100644 --- a/contracts/coconut-dkg/src/lib.rs +++ b/contracts/coconut-dkg/src/lib.rs @@ -6,6 +6,7 @@ use crate::dealers::queries::{ query_blacklisted_dealers_paged, query_blacklisting, query_current_dealers_paged, query_dealer_details, query_past_dealers_paged, }; +use crate::dealings::queries::query_epoch_dealings_commitments_paged; use crate::epoch::queries::query_current_epoch; use crate::error::ContractError; use coconut_dkg_common::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}; @@ -88,7 +89,7 @@ pub fn execute( ExecuteMsg::CommitDealing { epoch_id, commitment, - } => dealers::transactions::try_commit_dealing(deps, env, info, epoch_id, commitment), + } => dealings::transactions::try_commit_dealing(deps, info, epoch_id, commitment), ExecuteMsg::UnsafeResetAll { init_msg } => reset_contract_state(deps, env, info, init_msg), } } @@ -151,6 +152,16 @@ pub fn query(deps: Deps<'_>, _env: Env, msg: QueryMsg) -> Result to_binary(&query_epoch_dealings_commitments_paged( + deps, + epoch, + start_after, + limit, + )?)?, }; Ok(response) @@ -174,6 +185,7 @@ mod tests { let env = mock_env(); let msg = InstantiateMsg { public_key_submission_end_height: env.block.height + 123, + system_threshold: None, }; let info = mock_info("creator", &[]); diff --git a/contracts/coconut-dkg/src/support/tests.rs b/contracts/coconut-dkg/src/support/tests.rs index 67c529ee91..7e01ad429b 100644 --- a/contracts/coconut-dkg/src/support/tests.rs +++ b/contracts/coconut-dkg/src/support/tests.rs @@ -13,6 +13,7 @@ pub mod helpers { let env = mock_env(); let msg = InstantiateMsg { public_key_submission_end_height: env.block.height + 123, + system_threshold: None, }; let info = mock_info("creator", &[]); instantiate(deps.as_mut(), env, info, msg).unwrap(); diff --git a/nym-wallet/Cargo.lock b/nym-wallet/Cargo.lock index a70b15747e..a0d726a620 100644 --- a/nym-wallet/Cargo.lock +++ b/nym-wallet/Cargo.lock @@ -725,6 +725,7 @@ checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" name = "contracts-common" version = "0.1.0" dependencies = [ + "bs58", "cosmwasm-std", "schemars", "serde", diff --git a/validator-api/src/nymd_client.rs b/validator-api/src/nymd_client.rs index 36ea2100be..b43b6a9e27 100644 --- a/validator-api/src/nymd_client.rs +++ b/validator-api/src/nymd_client.rs @@ -5,10 +5,10 @@ use crate::config::Config; use crate::rewarded_set_updater::error::RewardingError; #[cfg(feature = "coconut")] use async_trait::async_trait; -use coconut_dkg_common::dealer::DealerDetailsResponse; +use coconut_dkg_common::dealer::{ContractDealingCommitment, DealerDetailsResponse}; use coconut_dkg_common::types::{ BlacklistedDealer, BlacklistingResponse, Coin, DealerDetails, EncodedBTEPublicKeyWithProof, - EncodedEd25519PublicKey, Epoch as DkgEpoch, + EncodedEd25519PublicKey, Epoch as DkgEpoch, EpochId, }; use config::defaults::{DEFAULT_NETWORK, DEFAULT_VALIDATOR_API_PORT}; use contracts_common::commitment::ContractSafeCommitment; @@ -504,6 +504,17 @@ where .map(|res| res.amount) } + pub(crate) async fn get_epoch_dealings_commitments( + &self, + epoch_id: EpochId, + ) -> Result, ValidatorClientError> { + self.0 + .read() + .await + .get_all_nymd_epoch_dealings_commitments(epoch_id) + .await + } + pub(crate) async fn register_dealer( &self, identity: EncodedEd25519PublicKey,