updated dealings queries

This commit is contained in:
Jędrzej Stuczyński
2024-01-03 12:22:23 +00:00
parent db36f72200
commit 13f8449dc8
9 changed files with 204 additions and 120 deletions
@@ -70,7 +70,7 @@ pub trait DkgQueryClient {
start_after: Option<String>,
limit: Option<u32>,
) -> Result<PagedDealingsResponse, NyxdError> {
let request = DkgQueryMsg::GetDealing {
let request = DkgQueryMsg::GetDealings {
idx,
limit,
start_after,
@@ -165,7 +165,7 @@ mod tests {
DkgQueryMsg::GetPastDealers { limit, start_after } => {
client.get_past_dealers_paged(start_after, limit).ignore()
}
DkgQueryMsg::GetDealing {
DkgQueryMsg::GetDealings {
idx,
limit,
start_after,
@@ -1,7 +1,10 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::types::{ContractSafeBytes, EncodedBTEPublicKeyWithProof, NodeIndex};
use crate::types::{
ContractDealing, DealingIndex, EncodedBTEPublicKeyWithProof, EpochId, NodeIndex,
PartialContractDealing,
};
use cosmwasm_schema::cw_serde;
use cosmwasm_std::Addr;
@@ -65,37 +68,40 @@ impl PagedDealerResponse {
}
}
#[deprecated]
#[cw_serde]
pub struct ContractDealing {
pub dealing: ContractSafeBytes,
pub dealer: Addr,
}
pub struct DealingResponse {
pub epoch_id: EpochId,
impl ContractDealing {
pub fn new(dealing: ContractSafeBytes, dealer: Addr) -> Self {
ContractDealing { dealing, dealer }
}
pub dealer: Addr,
pub dealing_index: DealingIndex,
pub dealing: Option<ContractDealing>,
}
#[cw_serde]
pub struct PagedDealingsResponse {
pub dealings: Vec<ContractDealing>,
pub per_page: usize,
pub epoch_id: EpochId,
pub dealer: Addr,
pub dealings: Vec<PartialContractDealing>,
/// Field indicating paging information for the following queries if the caller wishes to get further entries.
pub start_next_after: Option<Addr>,
pub start_next_after: Option<DealingIndex>,
}
impl PagedDealingsResponse {
pub fn new(
dealings: Vec<ContractDealing>,
per_page: usize,
start_next_after: Option<Addr>,
epoch_id: EpochId,
dealer: Addr,
dealings: Vec<PartialContractDealing>,
start_next_after: Option<DealingIndex>,
) -> Self {
PagedDealingsResponse {
epoch_id,
dealer,
dealings,
per_page,
start_next_after,
}
}
@@ -1,14 +1,16 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::types::{PartialContractDealing, EncodedBTEPublicKeyWithProof, EpochId, TimeConfiguration};
use crate::types::{
DealingIndex, EncodedBTEPublicKeyWithProof, EpochId, PartialContractDealing, TimeConfiguration,
};
use crate::verification_key::VerificationKeyShare;
use cosmwasm_schema::cw_serde;
use cosmwasm_std::Addr;
#[cfg(feature = "schema")]
use crate::{
dealer::{DealerDetailsResponse, PagedDealerResponse, PagedDealingsResponse},
dealer::{DealerDetailsResponse, DealingResponse, PagedDealerResponse, PagedDealingsResponse},
types::{Epoch, InitialReplacementData},
verification_key::PagedVKSharesResponse,
};
@@ -82,11 +84,19 @@ pub enum QueryMsg {
start_after: Option<String>,
},
#[cfg_attr(feature = "schema", returns(PagedDealingsResponse))]
#[cfg_attr(feature = "schema", returns(DealingResponse))]
GetDealing {
idx: u64,
epoch_id: EpochId,
dealer: String,
dealing_index: DealingIndex,
},
#[cfg_attr(feature = "schema", returns(PagedDealingsResponse))]
GetDealings {
epoch_id: EpochId,
dealer: String,
limit: Option<u32>,
start_after: Option<String>,
start_after: Option<DealingIndex>,
},
#[cfg_attr(feature = "schema", returns(PagedVKSharesResponse))]
@@ -14,6 +14,7 @@ pub type EncodedBTEPublicKeyWithProofRef<'a> = &'a str;
pub type NodeIndex = u64;
pub type EpochId = u64;
pub type DealingIndex = u32;
pub type ContractDealing = ContractSafeBytes;
// 2 public attributes, 2 private attributes, 1 fixed for coconut credential
pub const TOTAL_DEALINGS: usize = 2 + 2 + 1;
@@ -21,7 +22,7 @@ pub const TOTAL_DEALINGS: usize = 2 + 2 + 1;
#[cw_serde]
pub struct PartialContractDealing {
pub index: u32,
pub data: ContractSafeBytes,
pub data: ContractDealing,
}
#[cw_serde]
+15 -3
View File
@@ -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_dealings_paged;
use crate::dealings::queries::{query_dealing, 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,
@@ -112,10 +112,22 @@ pub fn query(deps: Deps<'_>, _env: Env, msg: QueryMsg) -> Result<QueryResponse,
to_binary(&query_past_dealers_paged(deps, start_after, limit)?)?
}
QueryMsg::GetDealing {
idx,
epoch_id,
dealer,
dealing_index,
} => to_binary(&query_dealing(deps, epoch_id, dealer, dealing_index)?)?,
QueryMsg::GetDealings {
epoch_id,
dealer,
limit,
start_after,
} => to_binary(&query_dealings_paged(deps, idx, start_after, limit)?)?,
} => to_binary(&query_dealings_paged(
deps,
epoch_id,
dealer,
limit,
start_after,
)?)?,
QueryMsg::GetVerificationKeys {
epoch_id,
limit,
+31 -23
View File
@@ -2,44 +2,52 @@
// SPDX-License-Identifier: Apache-2.0
use crate::dealings::storage;
use crate::dealings::storage::DEALINGS_BYTES;
use cosmwasm_std::{Deps, Order, StdResult};
use crate::dealings::storage::StoredDealing;
use cosmwasm_std::{Deps, StdResult};
use cw_storage_plus::Bound;
use nym_coconut_dkg_common::dealer::{ContractDealing, PagedDealingsResponse};
use nym_coconut_dkg_common::types::TOTAL_DEALINGS;
use nym_coconut_dkg_common::dealer::{DealingResponse, PagedDealingsResponse};
use nym_coconut_dkg_common::types::{DealingIndex, EpochId};
pub fn query_dealing(
deps: Deps<'_>,
epoch_id: EpochId,
dealer: String,
dealing_index: DealingIndex,
) -> StdResult<DealingResponse> {
let dealer = deps.api.addr_validate(&dealer)?;
let dealing = StoredDealing::read(deps.storage, epoch_id, &dealer, dealing_index);
Ok(DealingResponse {
epoch_id,
dealer,
dealing_index,
dealing,
})
}
pub fn query_dealings_paged(
deps: Deps<'_>,
idx: u64,
start_after: Option<String>,
epoch_id: EpochId,
dealer: String,
start_after: Option<DealingIndex>,
limit: Option<u32>,
) -> StdResult<PagedDealingsResponse> {
let limit = limit
.unwrap_or(storage::DEALINGS_PAGE_DEFAULT_LIMIT)
.min(storage::DEALINGS_PAGE_MAX_LIMIT) as usize;
.min(storage::DEALINGS_PAGE_MAX_LIMIT);
let idx = idx as usize;
if idx >= TOTAL_DEALINGS {
return Ok(PagedDealingsResponse::new(vec![], limit, None));
}
let dealer = deps.api.addr_validate(&dealer)?;
let start = start_after.map(Bound::exclusive);
let addr = start_after
.map(|addr| deps.api.addr_validate(&addr))
.transpose()?;
let start = addr.as_ref().map(Bound::exclusive);
let dealings = DEALINGS_BYTES[idx]
.range(deps.storage, start, None, Order::Ascending)
.take(limit)
.map(|res| res.map(|(dealer, dealing)| ContractDealing::new(dealing, dealer)))
let dealings = StoredDealing::prefix_range(deps.storage, (epoch_id, &dealer), start)
.take(limit as usize)
.collect::<StdResult<Vec<_>>>()?;
let start_next_after = dealings.last().map(|dealing| dealing.dealer.clone());
let start_next_after = dealings.last().map(|dealing| dealing.index);
Ok(PagedDealingsResponse::new(
epoch_id,
dealer,
dealings,
limit,
start_next_after,
))
}
+97 -50
View File
@@ -1,11 +1,12 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::error::ContractError;
use cosmwasm_std::{Addr, Storage};
use cw_storage_plus::Map;
use cosmwasm_std::{Addr, Order, Record, StdResult, Storage};
use cw_storage_plus::{
range_with_prefix, Bound, Key, KeyDeserialize, Path, Prefix, Prefixer, PrimaryKey,
};
use nym_coconut_dkg_common::types::{
ContractSafeBytes, DealingIndex, EpochId, PartialContractDealing, TOTAL_DEALINGS,
ContractDealing, ContractSafeBytes, DealingIndex, EpochId, PartialContractDealing,
};
pub(crate) const DEALINGS_PAGE_MAX_LIMIT: u32 = 2;
@@ -13,56 +14,102 @@ pub(crate) const DEALINGS_PAGE_DEFAULT_LIMIT: u32 = 1;
type Dealer<'a> = &'a Addr;
#[deprecated]
type DealingKey<'a> = &'a Addr;
// dealings are stored in a multilevel map with the following hierarchy:
// - epoch-id:
// - issuer-address:
// - dealing id:
// - dealing content
// NOTE: we're storing raw bytes bypassing serialization, so make sure you always use the below methods for using the storage!
pub(crate) const DEALINGS: Map<(EpochId, Dealer, DealingIndex), ContractSafeBytes> =
Map::new("dealing");
// NOTE: we're storing raw bytes bypassing serialization, so we can't use the `Map` type,
// thus make sure you always use the below methods for using the storage!
pub fn has_committed_dealing(
storage: &dyn Storage,
epoch_id: EpochId,
dealer: &Addr,
dealing_index: DealingIndex,
) -> bool {
DEALINGS.has(storage, (epoch_id, dealer, dealing_index))
pub(crate) struct StoredDealing;
impl StoredDealing {
const NAMESPACE: &'static [u8] = b"dealing";
fn deserialize_raw_dealing(kv: Record) -> StdResult<PartialContractDealing> {
let (k, v) = kv;
let index = <DealingIndex as KeyDeserialize>::from_vec(k)?;
let data = ContractSafeBytes(v);
Ok(PartialContractDealing { index, data })
}
fn storage_key(
epoch_id: EpochId,
dealer: Dealer,
dealing_index: DealingIndex,
) -> Path<Vec<u8>> {
// just replicate the behaviour from `Map::key`
let key = (epoch_id, dealer, dealing_index);
Path::new(
Self::NAMESPACE,
&key.key().iter().map(Key::as_ref).collect::<Vec<_>>(),
)
}
fn prefix(prefix: (EpochId, Dealer)) -> Prefix<DealingIndex, ContractSafeBytes> {
Prefix::with_deserialization_functions(
Self::NAMESPACE,
&prefix.prefix(),
&[],
// explicitly panic to make sure we're never attempting to call an unexpected deserializer on our data
|_, _, _| panic!("attempted to call custom de_fn_kv"),
|_, _, _| panic!("attempted to call custom de_fn_v"),
)
}
pub(crate) fn exists(
storage: &dyn Storage,
epoch_id: EpochId,
dealer: &Addr,
dealing_index: DealingIndex,
) -> bool {
StoredDealing::storage_key(epoch_id, dealer, dealing_index).has(storage)
}
pub(crate) fn save(
storage: &mut dyn Storage,
epoch_id: EpochId,
dealer: Dealer,
dealing: PartialContractDealing,
) {
// NOTE: we're storing bytes directly here!
let storage_key = StoredDealing::storage_key(epoch_id, dealer, dealing.index);
storage.set(&storage_key, dealing.data.as_slice());
}
pub(crate) fn read(
storage: &dyn Storage,
epoch_id: EpochId,
dealer: Dealer,
dealing_index: DealingIndex,
) -> Option<ContractDealing> {
let storage_key = StoredDealing::storage_key(epoch_id, dealer, dealing_index);
let raw_dealing = storage.get(&storage_key);
raw_dealing.map(ContractSafeBytes)
}
pub(crate) fn prefix_range<'a>(
storage: &'a dyn Storage,
prefix: (EpochId, Dealer),
start: Option<Bound<DealingIndex>>,
) -> Box<dyn Iterator<Item = StdResult<PartialContractDealing>> + 'a> {
// replicate the behaviour of `Prefix::range_raw` but without the fallible deserialization on the data
// (since we're reading from the storage directly)
// and whilst combining the data on the spot
let prefix = Self::prefix(prefix);
let mapped = range_with_prefix(
storage,
// note: Prefix's Deref implementation gives back its storage_prefix
&prefix,
start.map(|b| b.to_raw_bound()),
None,
Order::Ascending,
)
.map(Self::deserialize_raw_dealing);
Box::new(mapped)
}
}
pub fn save_dealing(
storage: &mut dyn Storage,
epoch_id: EpochId,
dealer: &Addr,
dealing: PartialContractDealing,
) {
// NOTE: we're storing bytes directly here!
let storage_key = DEALINGS.key((epoch_id, dealer, dealing.index));
storage.set(&storage_key, dealing.data.as_slice());
}
// 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.
// if TOTAL_DEALINGS is modified to anything other then current value (5), this part will also need
// to be modified
pub(crate) const DEALINGS_BYTES: [Map<'_, DealingKey<'_>, ContractSafeBytes>; TOTAL_DEALINGS] = [
Map::new("dbyt1"),
Map::new("dbyt2"),
Map::new("dbyt3"),
Map::new("dbyt4"),
Map::new("dbyt5"),
];
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
use crate::dealers::storage as dealers_storage;
use crate::dealings::storage::{has_committed_dealing, save_dealing};
use crate::dealings::storage::StoredDealing;
use crate::epoch_state::storage::{CURRENT_EPOCH, INITIAL_REPLACEMENT_DATA};
use crate::epoch_state::utils::check_epoch_state;
use crate::error::ContractError;
@@ -48,7 +48,7 @@ pub fn try_commit_dealings(
}
// check if this dealer has already committed this particular dealing
if has_committed_dealing(deps.storage, epoch.epoch_id, &info.sender, dealing.index) {
if StoredDealing::exists(deps.storage, epoch.epoch_id, &info.sender, dealing.index) {
return Err(ContractError::DealingAlreadyCommitted {
epoch_id: epoch.epoch_id,
dealer: info.sender,
@@ -56,7 +56,7 @@ pub fn try_commit_dealings(
});
}
save_dealing(deps.storage, epoch.epoch_id, &info.sender, dealing);
StoredDealing::save(deps.storage, epoch.epoch_id, &info.sender, dealing);
Ok(Response::new())
}
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0
use crate::dealers::storage::{current_dealers, past_dealers};
use crate::dealings::storage::DEALINGS_BYTES;
use crate::epoch_state::storage::{CURRENT_EPOCH, INITIAL_REPLACEMENT_DATA, THRESHOLD};
use crate::epoch_state::utils::check_epoch_state;
use crate::error::ContractError;
@@ -17,21 +16,22 @@ fn reset_epoch_state(storage: &mut dyn Storage) -> Result<(), ContractError> {
.keys(storage, None, None, Order::Ascending)
.collect::<Result<_, _>>()?;
for dealer_addr in dealers {
let details = current_dealers().load(storage, &dealer_addr)?;
for dealings in DEALINGS_BYTES {
let dealing_keys: Vec<_> = dealings
.keys(storage, None, None, Order::Ascending)
.flatten()
.collect();
for key in dealing_keys {
dealings.remove(storage, &key);
}
}
current_dealers().remove(storage, &dealer_addr)?;
past_dealers().save(storage, &dealer_addr, &details)?;
}
Ok(())
todo!()
// for dealer_addr in dealers {
// let details = current_dealers().load(storage, &dealer_addr)?;
// for dealings in DEALINGS_BYTES {
// let dealing_keys: Vec<_> = dealings
// .keys(storage, None, None, Order::Ascending)
// .flatten()
// .collect();
// for key in dealing_keys {
// dealings.remove(storage, &key);
// }
// }
// current_dealers().remove(storage, &dealer_addr)?;
// past_dealers().save(storage, &dealer_addr, &details)?;
// }
// Ok(())
}
fn dealers_still_active(