Feature/auto dkg advance (#2714)

* Add dkg epoch

* Make epoch state advancement dependent only on time

* Nym api tries advancing the dkg epoch state

* Update the time table a bit

It still needs to be changed before production, as the sign-up timeframe
needs to be something like a few days.

* Update changelog

* Fix tests

* Fix clippy after rustc update
This commit is contained in:
Bogdan-Ștefan Neacşu
2022-12-16 12:21:39 +02:00
committed by GitHub
parent b7be48a1b3
commit 254302ec38
26 changed files with 335 additions and 149 deletions
+2
View File
@@ -12,8 +12,10 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
- all-binaries: improved error logging ([#2686])
- native client: bring shutdown logic up to the same level as socks5-client
- nym-api, coconut-dkg contract: automatic, time-based dkg epoch state advancement ([#2670])
[#2686]: https://github.com/nymtech/nym/pull/2686
[#2670]: https://github.com/nymtech/nym/pull/2670
## [v1.1.3] (2022-12-13)
@@ -8,13 +8,13 @@ use coconut_dkg_common::dealer::{
DealerDetailsResponse, PagedDealerResponse, PagedDealingsResponse,
};
use coconut_dkg_common::msg::QueryMsg as DkgQueryMsg;
use coconut_dkg_common::types::EpochState;
use coconut_dkg_common::types::Epoch;
use coconut_dkg_common::verification_key::PagedVKSharesResponse;
use cosmrs::AccountId;
#[async_trait]
pub trait DkgQueryClient {
async fn get_current_epoch_state(&self) -> Result<EpochState, NymdError>;
async fn get_current_epoch(&self) -> Result<Epoch, NymdError>;
async fn get_current_epoch_threshold(&self) -> Result<Option<u64>, NymdError>;
async fn get_dealer_details(
&self,
@@ -49,7 +49,7 @@ impl<C> DkgQueryClient for NymdClient<C>
where
C: CosmWasmClient + Send + Sync,
{
async fn get_current_epoch_state(&self) -> Result<EpochState, NymdError> {
async fn get_current_epoch(&self) -> Result<Epoch, NymdError> {
let request = DkgQueryMsg::GetCurrentEpochState {};
self.client
.query_contract_smart(self.coconut_dkg_contract_address(), &request)
@@ -12,6 +12,7 @@ use contracts_common::dealings::ContractSafeBytes;
#[async_trait]
pub trait DkgSigningClient {
async fn advance_dkg_epoch_state(&self, fee: Option<Fee>) -> Result<ExecuteResult, NymdError>;
async fn register_dealer(
&self,
bte_key: EncodedBTEPublicKeyWithProof,
@@ -37,6 +38,21 @@ impl<C> DkgSigningClient for NymdClient<C>
where
C: SigningCosmWasmClient + Send + Sync,
{
async fn advance_dkg_epoch_state(&self, fee: Option<Fee>) -> Result<ExecuteResult, NymdError> {
let req = DkgExecuteMsg::AdvanceEpochState {};
self.client
.execute(
self.address(),
self.coconut_dkg_contract_address(),
&req,
fee.unwrap_or_default(),
"advancing DKG state",
vec![],
)
.await
}
async fn register_dealer(
&self,
bte_key: EncodedBTEPublicKeyWithProof,
@@ -11,7 +11,6 @@ use serde::{Deserialize, Serialize};
pub struct InstantiateMsg {
pub group_addr: String,
pub multisig_addr: String,
pub admin: String,
pub mix_denom: String,
}
@@ -6,15 +6,48 @@ use std::fmt::{Display, Formatter};
pub use crate::dealer::{DealerDetails, PagedDealerResponse};
pub use contracts_common::dealings::ContractSafeBytes;
pub use cosmwasm_std::{Addr, Coin};
pub use cosmwasm_std::{Addr, Coin, Timestamp};
pub type EncodedBTEPublicKeyWithProof = String;
pub type EncodedBTEPublicKeyWithProofRef<'a> = &'a str;
pub type NodeIndex = u64;
// The time sign-up is open for dealers to join (2 minutes)
pub const PUBLIC_KEY_SUBMISSION_TIME_SECS: u64 = 60 * 2;
pub const DEALING_EXCHANGE_TIME_SECS: u64 = 60 * 5;
pub const VERIFICATION_KEY_SUBMISSION_TIME_SECS: u64 = 60 * 5;
pub const VERIFICATION_KEY_VALIDATION_TIME_SECS: u64 = 60;
pub const VERIFICATION_KEY_FINALIZATION_TIME_SECS: u64 = 60;
// The time an epoch lasts (2 weeks)
pub const IN_PROGRESS_TIME_SECS: u64 = 60 * 60 * 24 * 14;
// 2 public attributes, 2 private attributes, 1 fixed for coconut credential
pub const TOTAL_DEALINGS: usize = 2 + 2 + 1;
#[derive(Serialize, Deserialize, Default, Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)]
#[serde(rename_all = "snake_case")]
pub struct Epoch {
pub state: EpochState,
pub finish_timestamp: Timestamp,
}
impl Epoch {
pub fn new(state: EpochState, current_timestamp: Timestamp) -> Self {
let duration = match state {
EpochState::PublicKeySubmission => PUBLIC_KEY_SUBMISSION_TIME_SECS,
EpochState::DealingExchange => DEALING_EXCHANGE_TIME_SECS,
EpochState::VerificationKeySubmission => VERIFICATION_KEY_SUBMISSION_TIME_SECS,
EpochState::VerificationKeyValidation => VERIFICATION_KEY_VALIDATION_TIME_SECS,
EpochState::VerificationKeyFinalization => VERIFICATION_KEY_FINALIZATION_TIME_SECS,
EpochState::InProgress => IN_PROGRESS_TIME_SECS,
};
Epoch {
state,
finish_timestamp: current_timestamp.plus_seconds(duration),
}
}
}
// currently (it is still extremely likely to change, we might be able to get rid of verification key-related complaints),
// the epoch can be in the following states (in order):
// 1. PublicKeySubmission -> potential dealers are submitting their BTE and ed25519 public keys to participate in dealing exchange
+12 -14
View File
@@ -7,16 +7,16 @@ use crate::dealers::queries::{
use crate::dealers::transactions::try_add_dealer;
use crate::dealings::queries::query_dealings_paged;
use crate::dealings::transactions::try_commit_dealings;
use crate::epoch_state::queries::{query_current_epoch_state, query_current_epoch_threshold};
use crate::epoch_state::storage::CURRENT_EPOCH_STATE;
use crate::epoch_state::queries::{query_current_epoch, query_current_epoch_threshold};
use crate::epoch_state::storage::CURRENT_EPOCH;
use crate::epoch_state::transactions::advance_epoch_state;
use crate::error::ContractError;
use crate::state::{State, ADMIN, MULTISIG, STATE};
use crate::state::{State, MULTISIG, STATE};
use crate::verification_key_shares::queries::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 coconut_dkg_common::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg};
use coconut_dkg_common::types::EpochState;
use coconut_dkg_common::types::{Epoch, EpochState};
use cosmwasm_std::{
entry_point, to_binary, Deps, DepsMut, Env, MessageInfo, QueryResponse, Response,
};
@@ -30,13 +30,11 @@ use cw4::Cw4Contract;
#[entry_point]
pub fn instantiate(
mut deps: DepsMut<'_>,
_env: Env,
env: Env,
_info: MessageInfo,
msg: InstantiateMsg,
) -> Result<Response, ContractError> {
let admin_addr = deps.api.addr_validate(&msg.admin)?;
let multisig_addr = deps.api.addr_validate(&msg.multisig_addr)?;
ADMIN.set(deps.branch(), Some(admin_addr))?;
MULTISIG.set(deps.branch(), Some(multisig_addr.clone()))?;
let group_addr = Cw4Contract(deps.api.addr_validate(&msg.group_addr).map_err(|_| {
@@ -52,7 +50,10 @@ pub fn instantiate(
};
STATE.save(deps.storage, &state)?;
CURRENT_EPOCH_STATE.save(deps.storage, &EpochState::default())?;
CURRENT_EPOCH.save(
deps.storage,
&Epoch::new(EpochState::default(), env.block.time),
)?;
Ok(Response::default())
}
@@ -79,14 +80,14 @@ pub fn execute(
ExecuteMsg::VerifyVerificationKeyShare { owner } => {
try_verify_verification_key_share(deps, info, owner)
}
ExecuteMsg::AdvanceEpochState {} => advance_epoch_state(deps, info),
ExecuteMsg::AdvanceEpochState {} => advance_epoch_state(deps, env),
}
}
#[entry_point]
pub fn query(deps: Deps<'_>, _env: Env, msg: QueryMsg) -> Result<QueryResponse, ContractError> {
let response = match msg {
QueryMsg::GetCurrentEpochState {} => to_binary(&query_current_epoch_state(deps.storage)?)?,
QueryMsg::GetCurrentEpochState {} => to_binary(&query_current_epoch(deps.storage)?)?,
QueryMsg::GetCurrentEpochThreshold {} => {
to_binary(&query_current_epoch_threshold(deps.storage)?)?
}
@@ -120,9 +121,8 @@ pub fn migrate(_deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Respon
#[cfg(test)]
mod tests {
use super::*;
use crate::support::tests::fixtures::{dealer_details_fixture, TEST_MIX_DENOM};
use crate::support::tests::fixtures::TEST_MIX_DENOM;
use crate::support::tests::helpers::{ADMIN_ADDRESS, MULTISIG_CONTRACT};
use coconut_dkg_common::dealer::DealerDetails;
use coconut_dkg_common::msg::ExecuteMsg::RegisterDealer;
use coconut_dkg_common::types::NodeIndex;
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
@@ -163,7 +163,6 @@ mod tests {
let msg = InstantiateMsg {
group_addr: group_contract_addr.to_string(),
multisig_addr: MULTISIG_CONTRACT.to_string(),
admin: Addr::unchecked(ADMIN_ADDRESS).to_string(),
mix_denom: TEST_MIX_DENOM.to_string(),
};
app.instantiate_contract(
@@ -198,7 +197,6 @@ mod tests {
let msg = InstantiateMsg {
group_addr: "group_addr".to_string(),
multisig_addr: "multisig_addr".to_string(),
admin: "admin".to_string(),
mix_denom: "nym".to_string(),
};
let info = mock_info("creator", &[]);
+2 -9
View File
@@ -72,8 +72,7 @@ pub(crate) mod tests {
use crate::dealers::storage::{DEALERS_PAGE_DEFAULT_LIMIT, DEALERS_PAGE_MAX_LIMIT};
use crate::support::tests::fixtures::dealer_details_fixture;
use crate::support::tests::helpers::init_contract;
use cosmwasm_std::testing::mock_env;
use cosmwasm_std::{Addr, DepsMut};
use cosmwasm_std::DepsMut;
fn fill_dealers(deps: DepsMut<'_>, mapping: &IndexedDealersMap<'_>, size: usize) {
for n in 0..size {
@@ -95,8 +94,7 @@ pub(crate) mod tests {
#[test]
fn dealers_empty_on_init() {
let mut deps = init_contract();
let env = mock_env();
let deps = init_contract();
for mapping in [storage::current_dealers(), storage::past_dealers()] {
let page1 = query_dealers(deps.as_ref(), None, None, &mapping).unwrap();
@@ -107,8 +105,6 @@ pub(crate) mod tests {
#[test]
fn dealers_paged_retrieval_obeys_limits() {
let mut deps = init_contract();
let env = mock_env();
let owner = Addr::unchecked("owner");
let limit = 2;
for mapping in [storage::current_dealers(), storage::past_dealers()] {
@@ -124,7 +120,6 @@ pub(crate) mod tests {
#[test]
fn dealers_paged_retrieval_has_default_limit() {
let mut deps = init_contract();
let env = mock_env();
for mapping in [storage::current_dealers(), storage::past_dealers()] {
fill_dealers(deps.as_mut(), &mapping, 1000);
@@ -141,7 +136,6 @@ pub(crate) mod tests {
#[test]
fn dealers_paged_retrieval_has_max_limit() {
let mut deps = init_contract();
let env = mock_env();
// query with a crazily high limit in an attempt to use too many resources
let crazy_limit = 1000 * DEALERS_PAGE_MAX_LIMIT;
@@ -163,7 +157,6 @@ pub(crate) mod tests {
#[test]
fn dealers_pagination_works() {
let mut deps = init_contract();
let env = mock_env();
let per_page = 2;
@@ -70,21 +70,21 @@ pub fn try_add_dealer(
pub(crate) mod tests {
use super::*;
use crate::epoch_state::transactions::advance_epoch_state;
use crate::support::tests::fixtures::dealer_details_fixture;
use crate::support::tests::helpers;
use crate::support::tests::helpers::ADMIN_ADDRESS;
use cosmwasm_std::testing::mock_info;
use coconut_dkg_common::types::PUBLIC_KEY_SUBMISSION_TIME_SECS;
use cosmwasm_std::testing::{mock_env, mock_info};
#[test]
fn invalid_state() {
let mut deps = helpers::init_contract();
let owner = Addr::unchecked("owner");
let mut env = mock_env();
let info = mock_info(owner.as_str(), &[]);
let dealer_details = dealer_details_fixture(1);
let bte_key_with_proof = String::from("bte_key_with_proof");
let announce_address = String::from("localhost:8000");
advance_epoch_state(deps.as_mut(), mock_info(ADMIN_ADDRESS, &[])).unwrap();
env.block.time = env.block.time.plus_seconds(PUBLIC_KEY_SUBMISSION_TIME_SECS);
advance_epoch_state(deps.as_mut(), env).unwrap();
let ret = try_add_dealer(
deps.as_mut(),
@@ -50,7 +50,6 @@ pub(crate) mod tests {
use crate::dealings::storage::{DEALINGS_PAGE_DEFAULT_LIMIT, DEALINGS_PAGE_MAX_LIMIT};
use crate::support::tests::fixtures::dealing_bytes_fixture;
use crate::support::tests::helpers::init_contract;
use cosmwasm_std::testing::mock_env;
use cosmwasm_std::{Addr, DepsMut};
fn fill_dealings(deps: DepsMut<'_>, size: usize) {
@@ -68,7 +67,6 @@ pub(crate) mod tests {
#[test]
fn empty_on_bad_idx() {
let mut deps = init_contract();
let env = mock_env();
fill_dealings(deps.as_mut(), 1000);
for idx in TOTAL_DEALINGS as u64..100 * TOTAL_DEALINGS as u64 {
@@ -89,7 +87,6 @@ pub(crate) mod tests {
#[test]
fn dealings_paged_retrieval_obeys_limits() {
let mut deps = init_contract();
let env = mock_env();
let limit = 2;
fill_dealings(deps.as_mut(), 1000);
@@ -103,7 +100,6 @@ pub(crate) mod tests {
#[test]
fn dealings_paged_retrieval_has_default_limit() {
let mut deps = init_contract();
let env = mock_env();
fill_dealings(deps.as_mut(), 1000);
for idx in 0..TOTAL_DEALINGS as u64 {
@@ -117,7 +113,6 @@ pub(crate) mod tests {
#[test]
fn dealings_paged_retrieval_has_max_limit() {
let mut deps = init_contract();
let env = mock_env();
fill_dealings(deps.as_mut(), 1000);
// query with a crazily high limit in an attempt to use too many resources
@@ -135,7 +130,6 @@ pub(crate) mod tests {
#[test]
fn dealings_pagination_works() {
let mut deps = init_contract();
let env = mock_env();
fill_dealings(deps.as_mut(), 1);
@@ -42,16 +42,16 @@ pub(crate) mod tests {
use crate::epoch_state::transactions::advance_epoch_state;
use crate::support::tests::fixtures::dealing_bytes_fixture;
use crate::support::tests::helpers;
use crate::support::tests::helpers::ADMIN_ADDRESS;
use coconut_dkg_common::dealer::DealerDetails;
use coconut_dkg_common::types::TOTAL_DEALINGS;
use cosmwasm_std::testing::mock_info;
use coconut_dkg_common::types::PUBLIC_KEY_SUBMISSION_TIME_SECS;
use cosmwasm_std::testing::{mock_env, mock_info};
use cosmwasm_std::Addr;
#[test]
fn invalid_commit_dealing() {
let mut deps = helpers::init_contract();
let owner = Addr::unchecked("owner");
let mut env = mock_env();
let info = mock_info(owner.as_str(), &[]);
let dealing_bytes = dealing_bytes_fixture();
@@ -65,7 +65,8 @@ pub(crate) mod tests {
}
);
advance_epoch_state(deps.as_mut(), mock_info(ADMIN_ADDRESS, &[])).unwrap();
env.block.time = env.block.time.plus_seconds(PUBLIC_KEY_SUBMISSION_TIME_SECS);
advance_epoch_state(deps.as_mut(), env).unwrap();
let ret =
try_commit_dealings(deps.as_mut(), info.clone(), dealing_bytes.clone()).unwrap_err();
@@ -1,15 +1,13 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::epoch_state::storage::{CURRENT_EPOCH_STATE, THRESHOLD};
use crate::epoch_state::storage::{CURRENT_EPOCH, THRESHOLD};
use crate::error::ContractError;
use coconut_dkg_common::types::EpochState;
use coconut_dkg_common::types::Epoch;
use cosmwasm_std::Storage;
pub(crate) fn query_current_epoch_state(
storage: &dyn Storage,
) -> Result<EpochState, ContractError> {
CURRENT_EPOCH_STATE
pub(crate) fn query_current_epoch(storage: &dyn Storage) -> Result<Epoch, ContractError> {
CURRENT_EPOCH
.load(storage)
.map_err(|_| ContractError::EpochNotInitialised)
}
@@ -24,12 +22,21 @@ pub(crate) fn query_current_epoch_threshold(
pub(crate) mod test {
use super::*;
use crate::support::tests::helpers::init_contract;
use coconut_dkg_common::types::{EpochState, PUBLIC_KEY_SUBMISSION_TIME_SECS};
use cosmwasm_std::testing::mock_env;
#[test]
fn query_state() {
let mut deps = init_contract();
let state = query_current_epoch_state(deps.as_mut().storage).unwrap();
assert_eq!(state, EpochState::PublicKeySubmission);
let epoch = query_current_epoch(deps.as_mut().storage).unwrap();
assert_eq!(epoch.state, EpochState::PublicKeySubmission);
assert_eq!(
epoch.finish_timestamp,
mock_env()
.block
.time
.plus_seconds(PUBLIC_KEY_SUBMISSION_TIME_SECS)
);
}
#[test]
@@ -1,8 +1,8 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use coconut_dkg_common::types::EpochState;
use coconut_dkg_common::types::Epoch;
use cw_storage_plus::Item;
pub(crate) const CURRENT_EPOCH_STATE: Item<'_, EpochState> = Item::new("current_epoch_state");
pub(crate) const CURRENT_EPOCH: Item<'_, Epoch> = Item::new("current_epoch");
pub const THRESHOLD: Item<u64> = Item::new("threshold");
@@ -2,25 +2,29 @@
// SPDX-License-Identifier: Apache-2.0
use crate::dealers::storage::current_dealers;
use crate::epoch_state::storage::{CURRENT_EPOCH_STATE, THRESHOLD};
use crate::epoch_state::storage::{CURRENT_EPOCH, THRESHOLD};
use crate::error::ContractError;
use crate::state::ADMIN;
use coconut_dkg_common::types::EpochState;
use cosmwasm_std::{DepsMut, MessageInfo, Order, Response};
use coconut_dkg_common::types::{Epoch, EpochState};
use cosmwasm_std::{DepsMut, Env, Order, Response};
pub(crate) fn advance_epoch_state(
deps: DepsMut<'_>,
info: MessageInfo,
) -> Result<Response, ContractError> {
ADMIN.assert_admin(deps.as_ref(), &info.sender)?;
let current_epoch_state =
CURRENT_EPOCH_STATE.update::<_, ContractError>(deps.storage, |mut epoch_state| {
// TODO: When defaulting to the first state, some action will probably need to be taken on the
// rest of the contract, as we're starting with a new set of signers
epoch_state = epoch_state.next().unwrap_or_default();
Ok(epoch_state)
})?;
if current_epoch_state == EpochState::DealingExchange {
pub(crate) fn advance_epoch_state(deps: DepsMut<'_>, env: Env) -> Result<Response, ContractError> {
let epoch = CURRENT_EPOCH.load(deps.storage)?;
if epoch.finish_timestamp > env.block.time {
return Err(ContractError::EarlyEpochStateAdvancement(
epoch
.finish_timestamp
.minus_seconds(env.block.time.seconds())
.seconds(),
));
}
let current_epoch = CURRENT_EPOCH.update::<_, ContractError>(deps.storage, |mut epoch| {
// TODO: When defaulting to the first state, some action will probably need to be taken on the
// rest of the contract, as we're starting with a new set of signers
epoch = Epoch::new(epoch.state.next().unwrap_or_default(), env.block.time);
Ok(epoch)
})?;
if current_epoch.state == EpochState::DealingExchange {
let current_dealer_count = current_dealers()
.keys(deps.storage, None, None, Order::Ascending)
.count();
@@ -34,64 +38,147 @@ pub(crate) fn advance_epoch_state(
#[cfg(test)]
pub(crate) mod tests {
use super::*;
use crate::support::tests::helpers::{init_contract, ADMIN_ADDRESS};
use coconut_dkg_common::types::{DealerDetails, EpochState};
use cosmwasm_std::testing::mock_info;
use crate::error::ContractError::EarlyEpochStateAdvancement;
use crate::support::tests::helpers::init_contract;
use coconut_dkg_common::types::{
DealerDetails, EpochState, DEALING_EXCHANGE_TIME_SECS, IN_PROGRESS_TIME_SECS,
PUBLIC_KEY_SUBMISSION_TIME_SECS, VERIFICATION_KEY_FINALIZATION_TIME_SECS,
VERIFICATION_KEY_SUBMISSION_TIME_SECS, VERIFICATION_KEY_VALIDATION_TIME_SECS,
};
use cosmwasm_std::testing::mock_env;
use cosmwasm_std::Addr;
use cw_controllers::AdminError;
#[test]
fn advance_state() {
let mut deps = init_contract();
let info = mock_info("requester", &[]);
let admin_info = mock_info(ADMIN_ADDRESS, &[]);
let mut env = mock_env();
let epoch = CURRENT_EPOCH.load(deps.as_mut().storage).unwrap();
assert_eq!(epoch.state, EpochState::PublicKeySubmission);
assert_eq!(
advance_epoch_state(deps.as_mut(), info).unwrap_err(),
ContractError::Admin(AdminError::NotAdmin {})
epoch.finish_timestamp,
env.block.time.plus_seconds(PUBLIC_KEY_SUBMISSION_TIME_SECS)
);
advance_epoch_state(deps.as_mut(), admin_info.clone()).unwrap();
env.block.time = env
.block
.time
.plus_seconds(PUBLIC_KEY_SUBMISSION_TIME_SECS - 1);
assert_eq!(
CURRENT_EPOCH_STATE.load(deps.as_mut().storage).unwrap(),
EpochState::DealingExchange
advance_epoch_state(deps.as_mut(), env.clone()).unwrap_err(),
EarlyEpochStateAdvancement(1)
);
advance_epoch_state(deps.as_mut(), admin_info.clone()).unwrap();
env.block.time = env.block.time.plus_seconds(1);
advance_epoch_state(deps.as_mut(), env.clone()).unwrap();
let epoch = CURRENT_EPOCH.load(deps.as_mut().storage).unwrap();
assert_eq!(epoch.state, EpochState::DealingExchange);
assert_eq!(
CURRENT_EPOCH_STATE.load(deps.as_mut().storage).unwrap(),
EpochState::VerificationKeySubmission
epoch.finish_timestamp,
env.block.time.plus_seconds(DEALING_EXCHANGE_TIME_SECS)
);
advance_epoch_state(deps.as_mut(), admin_info.clone()).unwrap();
env.block.time = env.block.time.plus_seconds(DEALING_EXCHANGE_TIME_SECS - 2);
assert_eq!(
CURRENT_EPOCH_STATE.load(deps.as_mut().storage).unwrap(),
EpochState::VerificationKeyValidation
advance_epoch_state(deps.as_mut(), env.clone()).unwrap_err(),
EarlyEpochStateAdvancement(2)
);
advance_epoch_state(deps.as_mut(), admin_info.clone()).unwrap();
env.block.time = env.block.time.plus_seconds(3);
advance_epoch_state(deps.as_mut(), env.clone()).unwrap();
let epoch = CURRENT_EPOCH.load(deps.as_mut().storage).unwrap();
assert_eq!(epoch.state, EpochState::VerificationKeySubmission);
assert_eq!(
CURRENT_EPOCH_STATE.load(deps.as_mut().storage).unwrap(),
EpochState::VerificationKeyFinalization
epoch.finish_timestamp,
env.block
.time
.plus_seconds(VERIFICATION_KEY_SUBMISSION_TIME_SECS)
);
advance_epoch_state(deps.as_mut(), admin_info.clone()).unwrap();
env.block.time = env
.block
.time
.plus_seconds(VERIFICATION_KEY_SUBMISSION_TIME_SECS - 2);
assert_eq!(
CURRENT_EPOCH_STATE.load(deps.as_mut().storage).unwrap(),
EpochState::InProgress
advance_epoch_state(deps.as_mut(), env.clone()).unwrap_err(),
EarlyEpochStateAdvancement(2)
);
advance_epoch_state(deps.as_mut(), admin_info.clone()).unwrap();
env.block.time = env.block.time.plus_seconds(3);
advance_epoch_state(deps.as_mut(), env.clone()).unwrap();
let epoch = CURRENT_EPOCH.load(deps.as_mut().storage).unwrap();
assert_eq!(epoch.state, EpochState::VerificationKeyValidation);
assert_eq!(
CURRENT_EPOCH_STATE.load(deps.as_mut().storage).unwrap(),
EpochState::PublicKeySubmission
epoch.finish_timestamp,
env.block
.time
.plus_seconds(VERIFICATION_KEY_VALIDATION_TIME_SECS)
);
env.block.time = env
.block
.time
.plus_seconds(VERIFICATION_KEY_VALIDATION_TIME_SECS - 3);
assert_eq!(
advance_epoch_state(deps.as_mut(), env.clone()).unwrap_err(),
EarlyEpochStateAdvancement(3)
);
env.block.time = env.block.time.plus_seconds(3);
advance_epoch_state(deps.as_mut(), env.clone()).unwrap();
let epoch = CURRENT_EPOCH.load(deps.as_mut().storage).unwrap();
assert_eq!(epoch.state, EpochState::VerificationKeyFinalization);
assert_eq!(
epoch.finish_timestamp,
env.block
.time
.plus_seconds(VERIFICATION_KEY_FINALIZATION_TIME_SECS)
);
env.block.time = env
.block
.time
.plus_seconds(VERIFICATION_KEY_FINALIZATION_TIME_SECS - 1);
assert_eq!(
advance_epoch_state(deps.as_mut(), env.clone()).unwrap_err(),
EarlyEpochStateAdvancement(1)
);
env.block.time = env.block.time.plus_seconds(1);
advance_epoch_state(deps.as_mut(), env.clone()).unwrap();
let epoch = CURRENT_EPOCH.load(deps.as_mut().storage).unwrap();
assert_eq!(epoch.state, EpochState::InProgress);
assert_eq!(
epoch.finish_timestamp,
env.block.time.plus_seconds(IN_PROGRESS_TIME_SECS)
);
env.block.time = env.block.time.plus_seconds(IN_PROGRESS_TIME_SECS - 100);
assert_eq!(
advance_epoch_state(deps.as_mut(), env.clone()).unwrap_err(),
EarlyEpochStateAdvancement(100)
);
env.block.time = env.block.time.plus_seconds(50);
assert_eq!(
advance_epoch_state(deps.as_mut(), env.clone()).unwrap_err(),
EarlyEpochStateAdvancement(50)
);
env.block.time = env.block.time.plus_seconds(100);
advance_epoch_state(deps.as_mut(), env.clone()).unwrap();
let epoch = CURRENT_EPOCH.load(deps.as_mut().storage).unwrap();
assert_eq!(epoch.state, EpochState::PublicKeySubmission);
assert_eq!(
epoch.finish_timestamp,
env.block.time.plus_seconds(PUBLIC_KEY_SUBMISSION_TIME_SECS)
);
}
#[test]
fn verify_threshold() {
let mut deps = init_contract();
let admin_info = mock_info(ADMIN_ADDRESS, &[]);
let mut env = mock_env();
assert!(THRESHOLD.may_load(deps.as_mut().storage).unwrap().is_none());
@@ -111,7 +198,8 @@ pub(crate) mod tests {
.unwrap();
}
advance_epoch_state(deps.as_mut(), admin_info.clone()).unwrap();
env.block.time = env.block.time.plus_seconds(PUBLIC_KEY_SUBMISSION_TIME_SECS);
advance_epoch_state(deps.as_mut(), env).unwrap();
assert_eq!(
THRESHOLD.may_load(deps.as_mut().storage).unwrap().unwrap(),
67
+10 -4
View File
@@ -1,7 +1,7 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::epoch_state::storage::CURRENT_EPOCH_STATE;
use crate::epoch_state::storage::CURRENT_EPOCH;
use crate::error::ContractError;
use coconut_dkg_common::types::EpochState;
use cosmwasm_std::Storage;
@@ -10,7 +10,7 @@ pub(crate) fn check_epoch_state(
storage: &dyn Storage,
against: EpochState,
) -> Result<(), ContractError> {
let epoch_state = CURRENT_EPOCH_STATE.load(storage)?;
let epoch_state = CURRENT_EPOCH.load(storage)?.state;
if epoch_state != against {
Err(ContractError::IncorrectEpochState {
current_state: epoch_state.to_string(),
@@ -25,14 +25,20 @@ pub(crate) fn check_epoch_state(
pub(crate) mod test {
use super::*;
use crate::support::tests::helpers::init_contract;
use coconut_dkg_common::types::Epoch;
use cosmwasm_std::testing::mock_env;
#[test]
pub fn check_state() {
let mut deps = init_contract();
let env = mock_env();
for fixed_state in EpochState::default().all_until(EpochState::InProgress) {
CURRENT_EPOCH_STATE
.save(deps.as_mut().storage, &fixed_state)
CURRENT_EPOCH
.save(
deps.as_mut().storage,
&Epoch::new(fixed_state, env.block.time),
)
.unwrap();
for against_state in EpochState::default().all_until(EpochState::InProgress) {
let ret = check_epoch_state(deps.as_mut().storage, against_state);
+3
View File
@@ -23,6 +23,9 @@ pub enum ContractError {
#[error("This sender is already a dealer for the epoch")]
AlreadyADealer,
#[error("Too soon to advance epoch state. {0} more seconds until it can be advanced")]
EarlyEpochStateAdvancement(u64),
#[error("Epoch hasn't been correctly initialised!")]
EpochNotInitialised,
-1
View File
@@ -10,7 +10,6 @@ use serde::{Deserialize, Serialize};
// unique items
pub const STATE: Item<State> = Item::new("state");
pub const ADMIN: Admin = Admin::new("admin");
pub const MULTISIG: Admin = Admin::new("multisig");
#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)]
@@ -1,7 +1,7 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use coconut_dkg_common::dealer::{ContractDealing, DealerDetails};
use coconut_dkg_common::dealer::DealerDetails;
use coconut_dkg_common::types::ContractSafeBytes;
use coconut_dkg_common::verification_key::ContractVKShare;
use cosmwasm_std::Addr;
@@ -17,7 +17,6 @@ pub fn init_contract() -> OwnedDeps<MemoryStorage, MockApi, MockQuerier<Empty>>
let msg = InstantiateMsg {
group_addr: String::from(GROUP_CONTRACT),
multisig_addr: String::from(MULTISIG_CONTRACT),
admin: String::from(ADMIN_ADDRESS),
mix_denom: TEST_MIX_DENOM.to_string(),
};
let env = mock_env();
@@ -45,7 +45,6 @@ pub(crate) mod tests {
use crate::verification_key_shares::storage::{
VERIFICATION_KEY_SHARES_PAGE_DEFAULT_LIMIT, VERIFICATION_KEY_SHARES_PAGE_MAX_LIMIT,
};
use cosmwasm_std::testing::mock_env;
use cosmwasm_std::Addr;
#[test]
@@ -58,7 +57,6 @@ pub(crate) mod tests {
#[test]
fn vk_shares_paged_retrieval_obeys_limits() {
let mut deps = init_contract();
let env = mock_env();
let limit = 2;
for n in 0..1000 {
let vk_share = vk_share_fixture(n);
@@ -75,7 +73,6 @@ pub(crate) mod tests {
#[test]
fn vk_shares_paged_retrieval_has_default_limit() {
let mut deps = init_contract();
let env = mock_env();
for n in 0..1000 {
let vk_share = vk_share_fixture(n);
let sender = Addr::unchecked(format!("owner{}", n));
@@ -96,7 +93,6 @@ pub(crate) mod tests {
#[test]
fn vk_shares_paged_retrieval_has_max_limit() {
let mut deps = init_contract();
let env = mock_env();
for n in 0..1000 {
let vk_share = vk_share_fixture(n);
let sender = Addr::unchecked(format!("owner{}", n));
@@ -117,7 +113,6 @@ pub(crate) mod tests {
#[test]
fn vk_shares_pagination_works() {
let mut deps = init_contract();
let env = mock_env();
let vk_share = vk_share_fixture(1);
let sender = Addr::unchecked(format!("owner{}", 1));
@@ -73,20 +73,21 @@ pub fn try_verify_verification_key_share(
#[cfg(test)]
mod tests {
use super::*;
use crate::epoch_state::storage::CURRENT_EPOCH_STATE;
use crate::epoch_state::transactions::advance_epoch_state;
use crate::support::tests::helpers;
use crate::support::tests::helpers::{ADMIN_ADDRESS, MULTISIG_CONTRACT};
use crate::support::tests::helpers::MULTISIG_CONTRACT;
use coconut_dkg_common::dealer::DealerDetails;
use coconut_dkg_common::types::EpochState;
use coconut_dkg_common::types::{
EpochState, DEALING_EXCHANGE_TIME_SECS, PUBLIC_KEY_SUBMISSION_TIME_SECS,
VERIFICATION_KEY_SUBMISSION_TIME_SECS, VERIFICATION_KEY_VALIDATION_TIME_SECS,
};
use cosmwasm_std::testing::{mock_env, mock_info};
use cosmwasm_std::Storage;
use cw_controllers::AdminError;
#[test]
fn commit_vk_share() {
let mut deps = helpers::init_contract();
let env = mock_env();
let mut env = mock_env();
let info = mock_info("requester", &[]);
let share = "share".to_string();
@@ -104,8 +105,10 @@ mod tests {
expected_state: EpochState::VerificationKeySubmission.to_string()
}
);
advance_epoch_state(deps.as_mut(), mock_info(ADMIN_ADDRESS, &[])).unwrap();
advance_epoch_state(deps.as_mut(), mock_info(ADMIN_ADDRESS, &[])).unwrap();
env.block.time = env.block.time.plus_seconds(PUBLIC_KEY_SUBMISSION_TIME_SECS);
advance_epoch_state(deps.as_mut(), env.clone()).unwrap();
env.block.time = env.block.time.plus_seconds(DEALING_EXCHANGE_TIME_SECS);
advance_epoch_state(deps.as_mut(), env.clone()).unwrap();
let ret = try_commit_verification_key_share(
deps.as_mut(),
env.clone(),
@@ -147,6 +150,7 @@ mod tests {
#[test]
fn invalid_verify_vk_share() {
let mut deps = helpers::init_contract();
let mut env = mock_env();
let info = mock_info("requester", &[]);
let owner = Addr::unchecked("owner");
let multisig_info = mock_info(MULTISIG_CONTRACT, &[]);
@@ -161,10 +165,20 @@ mod tests {
}
);
advance_epoch_state(deps.as_mut(), mock_info(ADMIN_ADDRESS, &[])).unwrap();
advance_epoch_state(deps.as_mut(), mock_info(ADMIN_ADDRESS, &[])).unwrap();
advance_epoch_state(deps.as_mut(), mock_info(ADMIN_ADDRESS, &[])).unwrap();
advance_epoch_state(deps.as_mut(), mock_info(ADMIN_ADDRESS, &[])).unwrap();
env.block.time = env.block.time.plus_seconds(PUBLIC_KEY_SUBMISSION_TIME_SECS);
advance_epoch_state(deps.as_mut(), env.clone()).unwrap();
env.block.time = env.block.time.plus_seconds(DEALING_EXCHANGE_TIME_SECS);
advance_epoch_state(deps.as_mut(), env.clone()).unwrap();
env.block.time = env
.block
.time
.plus_seconds(VERIFICATION_KEY_SUBMISSION_TIME_SECS);
advance_epoch_state(deps.as_mut(), env.clone()).unwrap();
env.block.time = env
.block
.time
.plus_seconds(VERIFICATION_KEY_VALIDATION_TIME_SECS);
advance_epoch_state(deps.as_mut(), env).unwrap();
let ret =
try_verify_verification_key_share(deps.as_mut(), info, owner.clone()).unwrap_err();
@@ -183,14 +197,16 @@ mod tests {
#[test]
fn verify_vk_share() {
let mut deps = helpers::init_contract();
let env = mock_env();
let mut env = mock_env();
let owner = Addr::unchecked("owner");
let info = mock_info(owner.as_ref(), &[]);
let share = "share".to_string();
let multisig_info = mock_info(MULTISIG_CONTRACT, &[]);
advance_epoch_state(deps.as_mut(), mock_info(ADMIN_ADDRESS, &[])).unwrap();
advance_epoch_state(deps.as_mut(), mock_info(ADMIN_ADDRESS, &[])).unwrap();
env.block.time = env.block.time.plus_seconds(PUBLIC_KEY_SUBMISSION_TIME_SECS);
advance_epoch_state(deps.as_mut(), env.clone()).unwrap();
env.block.time = env.block.time.plus_seconds(DEALING_EXCHANGE_TIME_SECS);
advance_epoch_state(deps.as_mut(), env.clone()).unwrap();
let dealer_details = DealerDetails {
address: owner.clone(),
@@ -204,8 +220,16 @@ mod tests {
try_commit_verification_key_share(deps.as_mut(), env.clone(), info.clone(), share.clone())
.unwrap();
advance_epoch_state(deps.as_mut(), mock_info(ADMIN_ADDRESS, &[])).unwrap();
advance_epoch_state(deps.as_mut(), mock_info(ADMIN_ADDRESS, &[])).unwrap();
env.block.time = env
.block
.time
.plus_seconds(VERIFICATION_KEY_SUBMISSION_TIME_SECS);
advance_epoch_state(deps.as_mut(), env.clone()).unwrap();
env.block.time = env
.block
.time
.plus_seconds(VERIFICATION_KEY_VALIDATION_TIME_SECS);
advance_epoch_state(deps.as_mut(), env).unwrap();
try_verify_verification_key_share(deps.as_mut(), multisig_info, owner.clone()).unwrap();
}
@@ -71,7 +71,6 @@ fn dkg_proposal() {
let msg = DkgInstantiateMsg {
group_addr: group_contract_addr.to_string(),
multisig_addr: multisig_contract_addr.to_string(),
admin: Addr::unchecked(OWNER).to_string(),
mix_denom: TEST_COIN_DENOM.to_string(),
};
let coconut_dkg_contract_addr = app
@@ -109,6 +108,7 @@ fn dkg_proposal() {
.unwrap();
for _ in 0..2 {
app.update_block(|block| block.time = block.time.plus_seconds(1000));
app.execute_contract(
Addr::unchecked(OWNER),
coconut_dkg_contract_addr.clone(),
@@ -175,6 +175,7 @@ fn dkg_proposal() {
.unwrap();
for _ in 0..2 {
app.update_block(|block| block.time = block.time.plus_seconds(1000));
app.execute_contract(
Addr::unchecked(OWNER),
coconut_dkg_contract_addr.clone(),
+3 -2
View File
@@ -4,7 +4,7 @@
use crate::coconut::error::Result;
use coconut_bandwidth_contract_common::spend_credential::SpendCredentialResponse;
use coconut_dkg_common::dealer::{ContractDealing, DealerDetails, DealerDetailsResponse};
use coconut_dkg_common::types::{EncodedBTEPublicKeyWithProof, EpochState};
use coconut_dkg_common::types::{EncodedBTEPublicKeyWithProof, Epoch};
use coconut_dkg_common::verification_key::{ContractVKShare, VerificationKeyShare};
use contracts_common::dealings::ContractSafeBytes;
use cw3::ProposalResponse;
@@ -22,7 +22,7 @@ pub trait Client {
&self,
blinded_serial_number: String,
) -> Result<SpendCredentialResponse>;
async fn get_current_epoch_state(&self) -> Result<EpochState>;
async fn get_current_epoch(&self) -> Result<Epoch>;
async fn get_current_epoch_threshold(&self) -> Result<Option<Threshold>>;
async fn get_self_registered_dealer_details(&self) -> Result<DealerDetailsResponse>;
async fn get_current_dealers(&self) -> Result<Vec<DealerDetails>>;
@@ -31,6 +31,7 @@ pub trait Client {
async fn vote_proposal(&self, proposal_id: u64, vote_yes: bool, fee: Option<Fee>)
-> Result<()>;
async fn execute_proposal(&self, proposal_id: u64) -> Result<()>;
async fn advance_epoch_state(&self) -> Result<()>;
async fn register_dealer(
&self,
bte_key: EncodedBTEPublicKeyWithProof,
+8 -4
View File
@@ -4,7 +4,7 @@
use crate::coconut::client::Client;
use crate::coconut::error::CoconutError;
use coconut_dkg_common::dealer::{ContractDealing, DealerDetails, DealerDetailsResponse};
use coconut_dkg_common::types::{EncodedBTEPublicKeyWithProof, EpochState, NodeIndex};
use coconut_dkg_common::types::{EncodedBTEPublicKeyWithProof, Epoch, NodeIndex};
use coconut_dkg_common::verification_key::{ContractVKShare, VerificationKeyShare};
use contracts_common::dealings::ContractSafeBytes;
use cw3::ProposalResponse;
@@ -35,13 +35,13 @@ impl DkgClient {
self.inner.address().await
}
pub(crate) async fn get_current_epoch_state(&self) -> Result<EpochState, CoconutError> {
let mut ret = self.inner.get_current_epoch_state().await;
pub(crate) async fn get_current_epoch(&self) -> Result<Epoch, CoconutError> {
let mut ret = self.inner.get_current_epoch().await;
for _ in 0..Self::RETRIES {
if ret.is_ok() {
return ret;
}
ret = self.inner.get_current_epoch_state().await;
ret = self.inner.get_current_epoch().await;
}
ret
}
@@ -86,6 +86,10 @@ impl DkgClient {
self.inner.list_proposals().await
}
pub(crate) async fn advance_epoch_state(&self) -> Result<(), CoconutError> {
self.inner.advance_epoch_state().await
}
pub(crate) async fn register_dealer(
&self,
bte_key: EncodedBTEPublicKeyWithProof,
+15 -6
View File
@@ -18,7 +18,7 @@ use dkg::bte::keys::KeyPair as DkgKeyPair;
use rand::rngs::OsRng;
use rand::RngCore;
use std::path::PathBuf;
use std::time::Duration;
use std::time::{Duration, SystemTime};
use task::TaskClient;
use tokio::time::interval;
use validator_client::nymd::SigningNymdClient;
@@ -83,16 +83,16 @@ impl<R: RngCore + Clone> DkgController<R> {
}
pub(crate) async fn handle_epoch_state(&mut self) {
match self.dkg_client.get_current_epoch_state().await {
match self.dkg_client.get_current_epoch().await {
Err(e) => warn!("Could not get current epoch state {}", e),
Ok(epoch_state) => {
if let Err(e) = self.state.is_consistent(epoch_state).await {
Ok(epoch) => {
if let Err(e) = self.state.is_consistent(epoch.state).await {
error!(
"Epoch state is corrupted - {}, the process should be terminated",
e
);
}
let ret = match epoch_state {
let ret = match epoch.state {
EpochState::PublicKeySubmission => {
public_key_submission(&self.dkg_client, &mut self.state).await
}
@@ -122,7 +122,7 @@ impl<R: RngCore + Clone> DkgController<R> {
};
if let Err(e) = ret {
warn!("Could not handle this iteration for the epoch state: {}", e);
} else if epoch_state != EpochState::InProgress {
} else if epoch.state != EpochState::InProgress {
let persistent_state = PersistentState::from(&self.state);
if let Err(e) =
persistent_state.save_to_file(self.state.persistent_state_path())
@@ -130,6 +130,15 @@ impl<R: RngCore + Clone> DkgController<R> {
warn!("Could not backup the state for this iteration: {}", e);
}
}
if let Ok(current_timestamp) =
SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)
{
if current_timestamp.as_secs() >= epoch.finish_timestamp.seconds() {
// We try advancing the epoch state, on a best-effort basis
info!("Trying to advance the epoch");
self.dkg_client.advance_epoch_state().await.ok();
}
}
}
}
}
+11 -7
View File
@@ -40,7 +40,7 @@ use coconut_dkg_common::dealer::{
ContractDealing, DealerDetails, DealerDetailsResponse, DealerType,
};
use coconut_dkg_common::event_attributes::{DKG_PROPOSAL_ID, NODE_INDEX};
use coconut_dkg_common::types::{EncodedBTEPublicKeyWithProof, EpochState, TOTAL_DEALINGS};
use coconut_dkg_common::types::{EncodedBTEPublicKeyWithProof, Epoch, TOTAL_DEALINGS};
use coconut_dkg_common::verification_key::{ContractVKShare, VerificationKeyShare};
use contracts_common::dealings::ContractSafeBytes;
use crypto::asymmetric::{encryption, identity};
@@ -66,7 +66,7 @@ pub(crate) struct DummyClient {
proposal_db: Arc<RwLock<HashMap<u64, ProposalResponse>>>,
spent_credential_db: Arc<RwLock<HashMap<String, SpendCredentialResponse>>>,
epoch_state: Arc<RwLock<EpochState>>,
epoch: Arc<RwLock<Epoch>>,
dealer_details: Arc<RwLock<HashMap<String, DealerDetails>>>,
threshold: Arc<RwLock<Option<Threshold>>>,
dealings: Arc<RwLock<HashMap<String, Vec<ContractSafeBytes>>>>,
@@ -80,7 +80,7 @@ impl DummyClient {
tx_db: Arc::new(RwLock::new(HashMap::new())),
proposal_db: Arc::new(RwLock::new(HashMap::new())),
spent_credential_db: Arc::new(RwLock::new(HashMap::new())),
epoch_state: Arc::new(RwLock::new(EpochState::default())),
epoch: Arc::new(RwLock::new(Epoch::default())),
dealer_details: Arc::new(RwLock::new(HashMap::new())),
threshold: Arc::new(RwLock::new(None)),
dealings: Arc::new(RwLock::new(HashMap::new())),
@@ -109,8 +109,8 @@ impl DummyClient {
self
}
pub fn _with_epoch_state(mut self, epoch_state: &Arc<RwLock<EpochState>>) -> Self {
self.epoch_state = Arc::clone(epoch_state);
pub fn _with_epoch(mut self, epoch: &Arc<RwLock<Epoch>>) -> Self {
self.epoch = Arc::clone(epoch);
self
}
@@ -188,8 +188,8 @@ impl super::client::Client for DummyClient {
})
}
async fn get_current_epoch_state(&self) -> Result<EpochState> {
Ok(*self.epoch_state.read().unwrap())
async fn get_current_epoch(&self) -> Result<Epoch> {
Ok(*self.epoch.read().unwrap())
}
async fn get_current_epoch_threshold(&self) -> Result<Option<Threshold>> {
@@ -273,6 +273,10 @@ impl super::client::Client for DummyClient {
Ok(())
}
async fn advance_epoch_state(&self) -> Result<()> {
todo!()
}
async fn register_dealer(
&self,
bte_public_key_with_proof: EncodedBTEPublicKeyWithProof,
+13 -3
View File
@@ -30,7 +30,7 @@ use coconut_bandwidth_contract_common::spend_credential::SpendCredentialResponse
#[cfg(feature = "coconut")]
use coconut_dkg_common::dealer::{ContractDealing, DealerDetails, DealerDetailsResponse};
#[cfg(feature = "coconut")]
use coconut_dkg_common::types::{EncodedBTEPublicKeyWithProof, EpochState};
use coconut_dkg_common::types::{EncodedBTEPublicKeyWithProof, Epoch};
#[cfg(feature = "coconut")]
use coconut_dkg_common::verification_key::{ContractVKShare, VerificationKeyShare};
#[cfg(feature = "coconut")]
@@ -329,8 +329,8 @@ where
.await?)
}
async fn get_current_epoch_state(&self) -> crate::coconut::error::Result<EpochState> {
Ok(self.0.read().await.nymd.get_current_epoch_state().await?)
async fn get_current_epoch(&self) -> crate::coconut::error::Result<Epoch> {
Ok(self.0.read().await.nymd.get_current_epoch().await?)
}
async fn get_current_epoch_threshold(
@@ -405,6 +405,16 @@ where
Ok(())
}
async fn advance_epoch_state(&self) -> crate::coconut::error::Result<()> {
self.0
.write()
.await
.nymd
.advance_dkg_epoch_state(None)
.await?;
Ok(())
}
async fn register_dealer(
&self,
bte_key: EncodedBTEPublicKeyWithProof,