Initial event emission by the contract watcher
This commit is contained in:
Generated
+1
@@ -3239,6 +3239,7 @@ dependencies = [
|
||||
"async-trait",
|
||||
"attohttpc",
|
||||
"bincode",
|
||||
"bs58",
|
||||
"bytes",
|
||||
"cfg-if 1.0.0",
|
||||
"clap 2.34.0",
|
||||
|
||||
@@ -21,8 +21,10 @@ use crate::nymd::{
|
||||
error::NymdError, CosmWasmClient, NymdClient, QueryNymdClient, SigningNymdClient,
|
||||
};
|
||||
|
||||
#[cfg(feature = "dkg")]
|
||||
use crate::nymd::traits::DkgClient;
|
||||
use crate::nymd::SigningCosmWasmClient;
|
||||
#[cfg(feature = "dkg")]
|
||||
use coconut_dkg_common::types::DealerDetails;
|
||||
#[cfg(feature = "nymd-client")]
|
||||
use mixnet_contract_common::{
|
||||
@@ -165,6 +167,7 @@ impl Client<SigningNymdClient> {
|
||||
gateway_page_limit: config.gateway_page_limit,
|
||||
mixnode_delegations_page_limit: config.mixnode_delegations_page_limit,
|
||||
rewarded_set_page_limit: config.rewarded_set_page_limit,
|
||||
#[cfg(feature = "dkg")]
|
||||
dealers_page_limit: config.dealers_page_limit,
|
||||
validator_api: validator_api_client,
|
||||
nymd: nymd_client,
|
||||
@@ -226,6 +229,7 @@ impl Client<QueryNymdClient> {
|
||||
gateway_page_limit: config.gateway_page_limit,
|
||||
mixnode_delegations_page_limit: config.mixnode_delegations_page_limit,
|
||||
rewarded_set_page_limit: config.rewarded_set_page_limit,
|
||||
#[cfg(feature = "dkg")]
|
||||
dealers_page_limit: config.dealers_page_limit,
|
||||
validator_api: validator_api_client,
|
||||
nymd: nymd_client,
|
||||
|
||||
@@ -16,6 +16,9 @@ pub struct DealerDetails {
|
||||
pub ed25519_public_key: EncodedEd25519PublicKey,
|
||||
pub bte_public_key_with_proof: EncodedBTEPublicKeyWithProof,
|
||||
pub assigned_index: NodeIndex,
|
||||
// TODO: in the future, perhaps, this could get replaced by some gossip system and address books
|
||||
// like in 'normal' Tendermint?
|
||||
pub host: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq)]
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
use crate::types::{BlockHeight, EncodedBTEPublicKeyWithProof, EncodedEd25519PublicKey};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::net::SocketAddr;
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
@@ -18,6 +19,7 @@ pub enum ExecuteMsg {
|
||||
ed25519_key: EncodedEd25519PublicKey,
|
||||
bte_key_with_proof: EncodedBTEPublicKeyWithProof,
|
||||
owner_signature: String,
|
||||
host: String,
|
||||
},
|
||||
CommitDealing {
|
||||
epoch_id: u32,
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub use crate::dealer::{Blacklisting, BlacklistingReason, DealerDetails};
|
||||
pub use cosmwasm_std::Addr;
|
||||
pub type BlockHeight = u64;
|
||||
pub type EncodedEd25519PublicKey = String;
|
||||
pub type EncodedEd25519PublicKeyRef<'a> = &'a str;
|
||||
|
||||
@@ -347,7 +347,7 @@ impl PublicKey {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
pub struct PublicKeyWithProof {
|
||||
pub(crate) key: PublicKey,
|
||||
|
||||
@@ -13,7 +13,7 @@ use zeroize::Zeroize;
|
||||
const DISCRETE_LOG_DOMAIN: &[u8] =
|
||||
b"NYM_COCONUT_NIDKG_V01_CS01_WITH_BLS12381_XMD:SHA-256_SSWU_RO_PROOF_DISCRETE_LOG";
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
pub struct ProofOfDiscreteLog {
|
||||
pub(crate) rand_commitment: G1Projective,
|
||||
|
||||
@@ -110,6 +110,7 @@ pub fn try_add_dealer(
|
||||
ed25519_key: EncodedEd25519PublicKey,
|
||||
bte_key_with_proof: EncodedBTEPublicKeyWithProof,
|
||||
owner_signature: String,
|
||||
host: String,
|
||||
) -> Result<Response, ContractError> {
|
||||
// check whether this sender is eligible to become a dealer
|
||||
verify_dealer(deps.branch(), env.block.height, &info.sender)?;
|
||||
@@ -161,6 +162,7 @@ pub fn try_add_dealer(
|
||||
ed25519_public_key: ed25519_key,
|
||||
bte_public_key_with_proof: bte_key_with_proof,
|
||||
assigned_index: node_index,
|
||||
host,
|
||||
};
|
||||
dealers_storage::current_dealers().save(deps.storage, &info.sender, &dealer_details)?;
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ pub fn execute(
|
||||
ed25519_key,
|
||||
bte_key_with_proof,
|
||||
owner_signature,
|
||||
host,
|
||||
} => dealers::transactions::try_add_dealer(
|
||||
deps,
|
||||
env,
|
||||
@@ -62,6 +63,7 @@ pub fn execute(
|
||||
ed25519_key,
|
||||
bte_key_with_proof,
|
||||
owner_signature,
|
||||
host,
|
||||
),
|
||||
ExecuteMsg::CommitDealing {
|
||||
epoch_id,
|
||||
|
||||
@@ -50,6 +50,7 @@ schemars = { version = "0.8", features = ["preserve_order"] }
|
||||
|
||||
# required for DKG, perhaps will get locked behind feature flag
|
||||
bincode = "1.3.3"
|
||||
bs58 = "0.4.0"
|
||||
bytes = "1.1.0"
|
||||
coconut-dkg-common = { path = "../common/cosmwasm-smart-contracts/coconut-dkg-contract" }
|
||||
dkg = { path = "../common/crypto/dkg" }
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
use std::io;
|
||||
use thiserror::Error;
|
||||
use validator_client::nymd::error::NymdError;
|
||||
use validator_client::ValidatorClientError;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
@@ -13,12 +14,18 @@ pub enum DkgError {
|
||||
#[error("{0}")]
|
||||
ContractClient(#[from] ValidatorClientError),
|
||||
|
||||
#[error("{0}")]
|
||||
NymdClient(#[from] NymdError),
|
||||
|
||||
#[error("Networking error - {0}")]
|
||||
Networking(#[from] io::Error),
|
||||
|
||||
#[error("Failed to serialize message - {0}")]
|
||||
SerializationError(#[from] bincode::Error),
|
||||
|
||||
#[error("todo")]
|
||||
MalformedDealerDetails,
|
||||
|
||||
#[error("todo")]
|
||||
DeserializationError,
|
||||
}
|
||||
|
||||
@@ -11,6 +11,12 @@ pub(crate) enum Event {
|
||||
DkgContractChange(watcher::Event),
|
||||
}
|
||||
|
||||
impl Event {
|
||||
pub(crate) fn new_contract_change_event(event: watcher::Event) -> Self {
|
||||
Event::DkgContractChange(event)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Event {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::dkg::smart_contract::publisher::Publisher;
|
||||
use crate::dkg::smart_contract::watcher;
|
||||
use crate::dkg::state::{DkgState, StateAccessor};
|
||||
use crate::dkg::state::StateAccessor;
|
||||
use coconut_dkg_common::types::DealerDetails;
|
||||
use futures::channel::mpsc;
|
||||
use futures::StreamExt;
|
||||
|
||||
@@ -12,12 +14,19 @@ pub(crate) type ContractEventsReceiver = mpsc::UnboundedReceiver<watcher::Event>
|
||||
pub(crate) type ContractEventsSender = mpsc::UnboundedSender<watcher::Event>;
|
||||
|
||||
// it is driven by events received from the contract watcher
|
||||
pub(crate) struct ProcessingLoop {
|
||||
pub(crate) struct ProcessingLoop<C> {
|
||||
state_accessor: StateAccessor,
|
||||
contract_events_receiver: ContractEventsReceiver,
|
||||
|
||||
contract_publisher: Publisher<C>,
|
||||
// network_sender: Sender
|
||||
}
|
||||
|
||||
impl ProcessingLoop {
|
||||
impl<C> ProcessingLoop<C> {
|
||||
fn verify_dealer(&self, contract_dealer_details: &DealerDetails) {
|
||||
//
|
||||
}
|
||||
|
||||
async fn process_event(&self, event: watcher::Event) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
@@ -9,6 +9,14 @@ pub(crate) mod networking;
|
||||
mod smart_contract;
|
||||
pub(crate) mod state;
|
||||
|
||||
pub(crate) struct Config {
|
||||
// not entirely sure what should go here just yet
|
||||
}
|
||||
|
||||
pub(crate) fn initiate_dkg(config: Config) {
|
||||
//
|
||||
}
|
||||
|
||||
// upon startup, the following tasks will need to be spawned:
|
||||
// - smart contract watcher
|
||||
// - main loop processing
|
||||
|
||||
@@ -2,7 +2,18 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::Client;
|
||||
use validator_client::nymd::SigningCosmWasmClient;
|
||||
|
||||
pub(crate) struct Publisher<C> {
|
||||
client: Client<C>,
|
||||
}
|
||||
|
||||
impl<C> Publisher<C>
|
||||
where
|
||||
C: SigningCosmWasmClient + Send + Sync,
|
||||
{
|
||||
pub(crate) async fn submit_dealing_commitment(&self) {
|
||||
// self.client.submit_dealing_commitment().await;
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,45 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use coconut_dkg_common::types::{BlockHeight, DealerDetails};
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum Event {
|
||||
NewDealingCommitment,
|
||||
pub(crate) struct Event {
|
||||
height: BlockHeight,
|
||||
event_type: EventType,
|
||||
}
|
||||
|
||||
impl Event {
|
||||
pub(crate) fn new(height: BlockHeight, event_type: EventType) -> Self {
|
||||
Event { height, event_type }
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Event {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "SmartContractWatcherEvent - ")?;
|
||||
write!(
|
||||
f,
|
||||
"SmartContractWatcherEvent at height {}. {}",
|
||||
self.height, self.event_type
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum EventType {
|
||||
NewDealerIdentity { details: DealerDetails },
|
||||
NewDealingCommitment,
|
||||
}
|
||||
|
||||
impl Display for EventType {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "EventType - ")?;
|
||||
match self {
|
||||
Event::NewDealingCommitment => write!(f, "NewDealingCommitment"),
|
||||
EventType::NewDealerIdentity { details } => {
|
||||
write!(f, "NewDealerIdentity for {}", details.address)
|
||||
}
|
||||
EventType::NewDealingCommitment => write!(f, "NewDealingCommitment"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,22 +2,93 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::dkg::error::DkgError;
|
||||
use crate::dkg::state::StateAccessor;
|
||||
use crate::Client;
|
||||
use coconut_dkg_common::types::EpochState;
|
||||
use log::warn;
|
||||
use std::time::Duration;
|
||||
use tokio::time::interval;
|
||||
|
||||
mod event;
|
||||
pub(crate) use event::{Event, EventType};
|
||||
use validator_client::nymd::SigningCosmWasmClient;
|
||||
|
||||
pub(crate) use event::Event;
|
||||
mod event;
|
||||
|
||||
pub(crate) struct Watcher<C> {
|
||||
client: Client<C>,
|
||||
polling_rate: Duration,
|
||||
state_accessor: StateAccessor,
|
||||
}
|
||||
|
||||
impl<C> Watcher<C> {
|
||||
impl<C> Watcher<C>
|
||||
where
|
||||
C: SigningCosmWasmClient + Send + Sync,
|
||||
{
|
||||
async fn try_get_new_dealers(&self) -> Result<(), DkgError> {
|
||||
let known_dealers = self.state_accessor.get_known_dealers().await;
|
||||
let bad_dealers = self.state_accessor.get_malformed_dealers().await;
|
||||
|
||||
let current_height = self.client.current_block_height().await?.value();
|
||||
let current_dealers = self.client.get_current_dealers().await?;
|
||||
for dealer in current_dealers {
|
||||
let is_bad = bad_dealers.contains(&dealer.address);
|
||||
// ideally we would have been accessing the hashmap by address, but it would make
|
||||
// other parts inconvenient. However, we're extremely unlikely to have more than 100 dealers
|
||||
// anyway, so the overhead of iterating over the entire map is minimal
|
||||
let is_known = known_dealers
|
||||
.values()
|
||||
.any(|known_dealer| known_dealer.chain_address == dealer.address);
|
||||
|
||||
// we had absolutely no idea about this dealer existing
|
||||
if !is_bad || !is_known {
|
||||
let watcher_event = self::Event::new(
|
||||
current_height,
|
||||
EventType::NewDealerIdentity { details: dealer },
|
||||
);
|
||||
self.state_accessor
|
||||
.push_contract_change_event(watcher_event)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn perform_epoch_state_based_actions(&self, state: EpochState) -> Result<(), DkgError> {
|
||||
match state {
|
||||
EpochState::PublicKeySubmission { .. } => self.try_get_new_dealers().await,
|
||||
EpochState::DealingExchange { .. } => todo!(),
|
||||
EpochState::ComplaintSubmission { .. } => todo!(),
|
||||
EpochState::ComplaintVoting { .. } => todo!(),
|
||||
EpochState::VerificationKeySubmission { .. } => todo!(),
|
||||
EpochState::VerificationKeyMismatchSubmission { .. } => todo!(),
|
||||
EpochState::VerificationKeyMismatchVoting { .. } => todo!(),
|
||||
EpochState::InProgress { .. } => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
async fn poll_contract(&self) -> Result<(), DkgError> {
|
||||
// based on the current epoch state (assuming it HASN'T CHANGED since last check), the following further actions have to be performed:
|
||||
// (if the epoch state changed, we have to ALSO perform actions as if it was in the previous variants):
|
||||
|
||||
// 1. PublicKeySubmission -> get keys of all submitted dealers and if there are any new ones, update dkg state
|
||||
// 2. DealingExchange -> get commitments to dealings and if there are any new ones, update dkg state
|
||||
// 3. ComplaintSubmission -> look for any complaints and if there is any, grab it and emit an event
|
||||
// 4. ComplaintVoting -> grab information about any votes and if exist, emit an event
|
||||
// 5. VerificationKeySubmission -> get list of who submitted their verification keys and if there are any new ones either update state or emit an event
|
||||
// 6. VerificationKeyMismatchSubmission -> look for any complaints and if there is any, grab it and emit an event,
|
||||
// 7. VerificationKeyMismatchVoting -> grab information about any votes and if exist, emit an event
|
||||
// 8. InProgress -> No need to do anything (... I think? unless maybe there was any information about epoch transition, to be determined)
|
||||
|
||||
// figure out what we need to pay attention to (for example if we're in "waiting for complaints" state,
|
||||
// we don't care about identities of potential new dealers just yet)
|
||||
let prior_epoch = self.state_accessor.current_epoch().await;
|
||||
let current_epoch = self.client.get_dkg_epoch().await?;
|
||||
|
||||
if prior_epoch.state != current_epoch.state {
|
||||
todo!()
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::dkg::events::{DispatcherSender, Event};
|
||||
use crate::dkg::state::{DkgState, ReceivedDealing};
|
||||
use coconut_dkg_common::types::Epoch;
|
||||
use crate::dkg::smart_contract::watcher;
|
||||
use crate::dkg::state::{Dealer, DkgState, IdentityBytes, ReceivedDealing};
|
||||
use coconut_dkg_common::types::{Addr, Epoch};
|
||||
use crypto::asymmetric::identity;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::net::SocketAddr;
|
||||
|
||||
// essentially some intermediary that allows either pushing events to the dispatcher or operating
|
||||
@@ -25,6 +27,11 @@ impl StateAccessor {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn push_contract_change_event(&self, event: watcher::Event) {
|
||||
self.push_event(Event::new_contract_change_event(event))
|
||||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn current_epoch(&self) -> Epoch {
|
||||
self.dkg_state.current_epoch().await
|
||||
}
|
||||
@@ -39,4 +46,12 @@ impl StateAccessor {
|
||||
pub(crate) async fn is_dealers_remote_address(&self, remote: SocketAddr) -> (bool, Epoch) {
|
||||
self.dkg_state.is_dealers_remote_address(remote).await
|
||||
}
|
||||
|
||||
pub(crate) async fn get_known_dealers(&self) -> HashMap<IdentityBytes, Dealer> {
|
||||
self.dkg_state.get_known_dealers().await
|
||||
}
|
||||
|
||||
pub(crate) async fn get_malformed_dealers(&self) -> HashSet<Addr> {
|
||||
self.dkg_state.get_malformed_dealers().await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,12 +6,13 @@ use crypto::asymmetric::identity;
|
||||
use dkg::{bte, Dealing};
|
||||
use futures::lock::Mutex;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
|
||||
mod accessor;
|
||||
|
||||
use crate::dkg::error::DkgError;
|
||||
pub(crate) use accessor::StateAccessor;
|
||||
|
||||
type IdentityBytes = [u8; identity::PUBLIC_KEY_LENGTH];
|
||||
@@ -81,12 +82,17 @@ pub struct ReceivedDealing {
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct DkgStateInner {
|
||||
last_seen_height: BlockHeight,
|
||||
bte_decryption_key: bte::DecryptionKey,
|
||||
signing_key: identity::PublicKey,
|
||||
|
||||
current_epoch: Epoch,
|
||||
|
||||
expected_epoch_dealing_digests: HashMap<IdentityBytes, [u8; 32]>,
|
||||
|
||||
// we need to keep track of all bad dealers as well so that we wouldn't attempt to compalaint about them
|
||||
// repeatedly
|
||||
bad_dealers: HashSet<Addr>,
|
||||
current_epoch_dealers: HashMap<IdentityBytes, Dealer>,
|
||||
verified_epoch_dealings: HashMap<IdentityBytes, ReceivedDealing>,
|
||||
unconfirmed_dealings: HashMap<IdentityBytes, ReceivedDealing>,
|
||||
@@ -126,4 +132,12 @@ impl DkgState {
|
||||
.get(&dealer.to_bytes())
|
||||
.cloned()
|
||||
}
|
||||
|
||||
pub(crate) async fn get_known_dealers(&self) -> HashMap<IdentityBytes, Dealer> {
|
||||
self.inner.lock().await.current_epoch_dealers.clone()
|
||||
}
|
||||
|
||||
pub(crate) async fn get_malformed_dealers(&self) -> HashSet<Addr> {
|
||||
self.inner.lock().await.bad_dealers.clone()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,8 +22,8 @@ use validator_client::nymd::error::NymdError;
|
||||
use validator_client::nymd::traits::DkgClient;
|
||||
use validator_client::nymd::{
|
||||
hash::{Hash, SHA256_HASH_SIZE},
|
||||
CosmWasmClient, CosmosCoin, Fee, QueryNymdClient, SigningCosmWasmClient, SigningNymdClient,
|
||||
TendermintTime,
|
||||
CosmWasmClient, CosmosCoin, Fee, Height, QueryNymdClient, SigningCosmWasmClient,
|
||||
SigningNymdClient, TendermintTime,
|
||||
};
|
||||
use validator_client::ValidatorClientError;
|
||||
|
||||
@@ -119,6 +119,15 @@ impl<C> Client<C> {
|
||||
Ok(time)
|
||||
}
|
||||
|
||||
pub(crate) async fn current_block_height(&self) -> Result<Height, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
{
|
||||
let height = self.0.read().await.nymd.get_current_block_height().await?;
|
||||
|
||||
Ok(height)
|
||||
}
|
||||
|
||||
pub(crate) async fn get_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync,
|
||||
|
||||
Reference in New Issue
Block a user