Feature/dkg rerun (#2839)
* Reset contract state when dkg needs rerun * Reset nym-api for rerun * Gateway updates signer APIs at runtime * Fix clippy * Add epoch id * Use IndexedMap for shares * Query with epoch id * Add Clone to client traits * Pass nyxd client instead of api data * Get the specific epoch vk * Make wasm work * Remove wasm test runs As there are no wasm tests and the target_arch macros are not compatible with the cargo test environment, we can safely remove (for now) the wasm test target runs. * Put epoch_id in storage pk * Gateway uses old keys but current verifiers * Add group contract to env * Move group msg in common * Only run DKG if part of group * Clippy test * Rename wasm_storage to wasm_mockups * Update changelog
This commit is contained in:
committed by
GitHub
parent
d6f87c40ed
commit
64c963e36e
@@ -29,11 +29,6 @@ jobs:
|
||||
command: build
|
||||
args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown --features=coconut
|
||||
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --manifest-path clients/webassembly/Cargo.toml
|
||||
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fmt
|
||||
|
||||
@@ -2,6 +2,14 @@
|
||||
|
||||
Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- dkg rerun from scratch and dkg-specific epochs ([#2839])
|
||||
|
||||
[#2839]: https://github.com/nymtech/nym/pull/2839
|
||||
|
||||
## [v1.1.6] (2023-01-17)
|
||||
|
||||
### Added
|
||||
|
||||
Generated
+13
@@ -2368,6 +2368,15 @@ dependencies = [
|
||||
"subtle 2.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "group-contract-common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cw4",
|
||||
"schemars",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.3.15"
|
||||
@@ -3447,6 +3456,7 @@ dependencies = [
|
||||
"crypto",
|
||||
"cw-utils",
|
||||
"cw3",
|
||||
"cw4",
|
||||
"dirs",
|
||||
"dkg",
|
||||
"dotenv",
|
||||
@@ -3802,6 +3812,7 @@ dependencies = [
|
||||
"tokio",
|
||||
"toml",
|
||||
"url",
|
||||
"validator-client",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6860,9 +6871,11 @@ dependencies = [
|
||||
"cosmrs",
|
||||
"cosmwasm-std",
|
||||
"cw3",
|
||||
"cw4",
|
||||
"execute",
|
||||
"flate2",
|
||||
"futures",
|
||||
"group-contract-common",
|
||||
"itertools",
|
||||
"log",
|
||||
"mixnet-contract-common",
|
||||
|
||||
@@ -34,6 +34,7 @@ members = [
|
||||
"common/cosmwasm-smart-contracts/coconut-bandwidth-contract",
|
||||
"common/cosmwasm-smart-contracts/coconut-dkg",
|
||||
"common/cosmwasm-smart-contracts/contracts-common",
|
||||
"common/cosmwasm-smart-contracts/group-contract",
|
||||
"common/cosmwasm-smart-contracts/mixnet-contract",
|
||||
"common/cosmwasm-smart-contracts/multisig-contract",
|
||||
"common/cosmwasm-smart-contracts/vesting-contract",
|
||||
|
||||
@@ -4,7 +4,7 @@ no-clippy: build cargo-test wasm fmt
|
||||
happy: fmt clippy-happy test
|
||||
clippy-all: clippy-main clippy-coconut clippy-all-contracts clippy-all-wallet clippy-all-connect clippy-all-wasm-client
|
||||
clippy-happy: clippy-happy-main clippy-happy-contracts clippy-happy-wallet clippy-happy-connect
|
||||
cargo-test: test-main test-contracts test-wallet test-connect test-coconut test-wasm-client
|
||||
cargo-test: test-main test-contracts test-wallet test-connect test-coconut
|
||||
cargo-test-expensive: test-main-expensive test-contracts-expensive test-wallet-expensive test-connect-expensive test-coconut-expensive
|
||||
build: build-contracts build-wallet build-main build-connect build-wasm-client
|
||||
fmt: fmt-main fmt-contracts fmt-wallet fmt-connect fmt-wasm-client
|
||||
@@ -68,9 +68,6 @@ test-wallet:
|
||||
test-wallet-expensive:
|
||||
cargo test --manifest-path nym-wallet/Cargo.toml --all-features -- --ignored
|
||||
|
||||
test-wasm-client:
|
||||
cargo test --workspace --manifest-path clients/webassembly/Cargo.toml --all-features
|
||||
|
||||
test-connect:
|
||||
cargo test --manifest-path nym-connect/Cargo.toml --all-features
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@ use client_connections::{ConnectionCommandReceiver, ConnectionCommandSender, Lan
|
||||
use crypto::asymmetric::{encryption, identity};
|
||||
use futures::channel::mpsc;
|
||||
use gateway_client::bandwidth::BandwidthController;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use gateway_client::wasm_mockups::CosmWasmClient;
|
||||
use gateway_client::{
|
||||
AcknowledgementReceiver, AcknowledgementSender, GatewayClient, MixnetMessageReceiver,
|
||||
MixnetMessageSender,
|
||||
@@ -39,6 +41,8 @@ use std::time::Duration;
|
||||
use tap::TapFallible;
|
||||
use task::{TaskClient, TaskManager};
|
||||
use url::Url;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use validator_client::nyxd::CosmWasmClient;
|
||||
|
||||
use super::received_buffer::ReceivedBufferMessage;
|
||||
|
||||
@@ -129,7 +133,7 @@ impl From<bool> for CredentialsToggle {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BaseClientBuilder<'a, B> {
|
||||
pub struct BaseClientBuilder<'a, B, C: Clone> {
|
||||
// due to wasm limitations I had to split it like this : (
|
||||
gateway_config: &'a GatewayEndpointConfig,
|
||||
debug_config: &'a DebugConfig,
|
||||
@@ -137,20 +141,21 @@ pub struct BaseClientBuilder<'a, B> {
|
||||
nym_api_endpoints: Vec<Url>,
|
||||
reply_storage_backend: B,
|
||||
|
||||
bandwidth_controller: Option<BandwidthController>,
|
||||
bandwidth_controller: Option<BandwidthController<C>>,
|
||||
key_manager: KeyManager,
|
||||
}
|
||||
|
||||
impl<'a, B> BaseClientBuilder<'a, B>
|
||||
impl<'a, B, C> BaseClientBuilder<'a, B, C>
|
||||
where
|
||||
B: ReplyStorageBackend + Send + Sync + 'static,
|
||||
C: CosmWasmClient + Sync + Send + Clone + 'static,
|
||||
{
|
||||
pub fn new_from_base_config<T>(
|
||||
base_config: &'a Config<T>,
|
||||
key_manager: KeyManager,
|
||||
bandwidth_controller: Option<BandwidthController>,
|
||||
bandwidth_controller: Option<BandwidthController<C>>,
|
||||
reply_storage_backend: B,
|
||||
) -> BaseClientBuilder<'a, B> {
|
||||
) -> BaseClientBuilder<'a, B, C> {
|
||||
BaseClientBuilder {
|
||||
gateway_config: base_config.get_gateway_endpoint_config(),
|
||||
debug_config: base_config.get_debug_config(),
|
||||
@@ -166,11 +171,11 @@ where
|
||||
gateway_config: &'a GatewayEndpointConfig,
|
||||
debug_config: &'a DebugConfig,
|
||||
key_manager: KeyManager,
|
||||
bandwidth_controller: Option<BandwidthController>,
|
||||
bandwidth_controller: Option<BandwidthController<C>>,
|
||||
reply_storage_backend: B,
|
||||
credentials_toggle: CredentialsToggle,
|
||||
nym_api_endpoints: Vec<Url>,
|
||||
) -> BaseClientBuilder<'a, B> {
|
||||
) -> BaseClientBuilder<'a, B, C> {
|
||||
BaseClientBuilder {
|
||||
gateway_config,
|
||||
debug_config,
|
||||
@@ -279,7 +284,7 @@ where
|
||||
mixnet_message_sender: MixnetMessageSender,
|
||||
ack_sender: AcknowledgementSender,
|
||||
shutdown: TaskClient,
|
||||
) -> Result<GatewayClient, ClientCoreError> {
|
||||
) -> Result<GatewayClient<C>, ClientCoreError> {
|
||||
let gateway_id = self.gateway_config.gateway_id.clone();
|
||||
if gateway_id.is_empty() {
|
||||
return Err(ClientCoreError::GatewayIdUnknown);
|
||||
@@ -365,7 +370,7 @@ where
|
||||
// over it. Perhaps GatewayClient needs to be thread-shareable or have some channel for
|
||||
// requests?
|
||||
fn start_mix_traffic_controller(
|
||||
gateway_client: GatewayClient,
|
||||
gateway_client: GatewayClient<C>,
|
||||
shutdown: TaskClient,
|
||||
) -> BatchMixMessageSender {
|
||||
info!("Starting mix traffic controller...");
|
||||
|
||||
@@ -2,9 +2,13 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::spawn_future;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use gateway_client::wasm_mockups::CosmWasmClient;
|
||||
use gateway_client::GatewayClient;
|
||||
use log::*;
|
||||
use nymsphinx::forwarding::packet::MixPacket;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use validator_client::nyxd::CosmWasmClient;
|
||||
|
||||
pub type BatchMixMessageSender = tokio::sync::mpsc::Sender<Vec<MixPacket>>;
|
||||
pub type BatchMixMessageReceiver = tokio::sync::mpsc::Receiver<Vec<MixPacket>>;
|
||||
@@ -13,10 +17,10 @@ pub type BatchMixMessageReceiver = tokio::sync::mpsc::Receiver<Vec<MixPacket>>;
|
||||
pub const MIX_MESSAGE_RECEIVER_BUFFER_SIZE: usize = 32;
|
||||
const MAX_FAILURE_COUNT: usize = 100;
|
||||
|
||||
pub struct MixTrafficController {
|
||||
pub struct MixTrafficController<C: Clone> {
|
||||
// TODO: most likely to be replaced by some higher level construct as
|
||||
// later on gateway_client will need to be accessible by other entities
|
||||
gateway_client: GatewayClient,
|
||||
gateway_client: GatewayClient<C>,
|
||||
mix_rx: BatchMixMessageReceiver,
|
||||
|
||||
// TODO: this is temporary work-around.
|
||||
@@ -24,8 +28,13 @@ pub struct MixTrafficController {
|
||||
consecutive_gateway_failure_count: usize,
|
||||
}
|
||||
|
||||
impl MixTrafficController {
|
||||
pub fn new(gateway_client: GatewayClient) -> (MixTrafficController, BatchMixMessageSender) {
|
||||
impl<C> MixTrafficController<C>
|
||||
where
|
||||
C: CosmWasmClient + Sync + Send + Clone + 'static,
|
||||
{
|
||||
pub fn new(
|
||||
gateway_client: GatewayClient<C>,
|
||||
) -> (MixTrafficController<C>, BatchMixMessageSender) {
|
||||
let (sphinx_message_sender, sphinx_message_receiver) =
|
||||
tokio::sync::mpsc::channel(MIX_MESSAGE_RECEIVER_BUFFER_SIZE);
|
||||
(
|
||||
|
||||
@@ -8,6 +8,8 @@ use crate::{
|
||||
};
|
||||
use config::NymConfig;
|
||||
use crypto::asymmetric::identity;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use gateway_client::wasm_mockups::SigningNyxdClient;
|
||||
use gateway_client::GatewayClient;
|
||||
use gateway_requests::registration::handshake::SharedKeys;
|
||||
use rand::{seq::SliceRandom, thread_rng};
|
||||
@@ -15,6 +17,8 @@ use std::{sync::Arc, time::Duration};
|
||||
use tap::TapFallible;
|
||||
use topology::{filter::VersionFilterable, gateway};
|
||||
use url::Url;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use validator_client::nyxd::SigningNyxdClient;
|
||||
|
||||
pub(super) async fn query_gateway_details(
|
||||
validator_servers: Vec<Url>,
|
||||
@@ -56,7 +60,7 @@ pub(super) async fn register_with_gateway(
|
||||
our_identity: Arc<identity::KeyPair>,
|
||||
) -> Result<Arc<SharedKeys>, ClientCoreError> {
|
||||
let timeout = Duration::from_millis(1500);
|
||||
let mut gateway_client = GatewayClient::new_init(
|
||||
let mut gateway_client: GatewayClient<SigningNyxdClient> = GatewayClient::new_init(
|
||||
gateway.clients_address(),
|
||||
gateway.identity_key,
|
||||
gateway.owner.clone(),
|
||||
|
||||
@@ -13,6 +13,7 @@ use credentials::coconut::bandwidth::{BandwidthVoucher, TOTAL_ATTRIBUTES};
|
||||
use credentials::coconut::utils::obtain_aggregate_signature;
|
||||
use crypto::asymmetric::{encryption, identity};
|
||||
use network_defaults::{NymNetworkDetails, VOUCHER_INFO};
|
||||
use validator_client::nyxd::traits::DkgQueryClient;
|
||||
use validator_client::nyxd::tx::Hash;
|
||||
use validator_client::{CoconutApiClient, Config};
|
||||
|
||||
@@ -80,7 +81,8 @@ pub(crate) async fn get_credential(state: &State, shared_storage: PersistentStor
|
||||
let network_details = NymNetworkDetails::new_from_env();
|
||||
let config = Config::try_from_nym_network_details(&network_details)?;
|
||||
let client = validator_client::Client::new_query(config)?;
|
||||
let coconut_api_clients = CoconutApiClient::all_coconut_api_clients(&client).await?;
|
||||
let epoch_id = client.nyxd.get_current_epoch().await?.epoch_id;
|
||||
let coconut_api_clients = CoconutApiClient::all_coconut_api_clients(&client, epoch_id).await?;
|
||||
|
||||
let params = Parameters::new(TOTAL_ATTRIBUTES).unwrap();
|
||||
let bandwidth_credential_attributes = BandwidthVoucher::new(
|
||||
@@ -106,6 +108,7 @@ pub(crate) async fn get_credential(state: &State, shared_storage: PersistentStor
|
||||
bandwidth_credential_attributes.get_private_attributes()[0].to_bs58(),
|
||||
bandwidth_credential_attributes.get_private_attributes()[1].to_bs58(),
|
||||
signature.to_bs58(),
|
||||
epoch_id.to_string(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ use nymsphinx::addressing::clients::Recipient;
|
||||
use nymsphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nymsphinx::receiver::ReconstructedMessage;
|
||||
use task::TaskManager;
|
||||
use validator_client::nyxd::QueryNyxdClient;
|
||||
|
||||
pub(crate) mod config;
|
||||
|
||||
@@ -44,42 +45,28 @@ impl SocketClient {
|
||||
}
|
||||
}
|
||||
|
||||
async fn create_bandwidth_controller(config: &Config) -> BandwidthController {
|
||||
#[cfg(feature = "coconut")]
|
||||
let bandwidth_controller = {
|
||||
let details = network_defaults::NymNetworkDetails::new_from_env();
|
||||
let mut client_config =
|
||||
validator_client::Config::try_from_nym_network_details(&details)
|
||||
.expect("failed to construct validator client config");
|
||||
let nyxd_url = config
|
||||
.get_base()
|
||||
.get_validator_endpoints()
|
||||
.pop()
|
||||
.expect("No nyxd validator endpoint provided");
|
||||
let api_url = config
|
||||
.get_base()
|
||||
.get_nym_api_endpoints()
|
||||
.pop()
|
||||
.expect("No validator api endpoint provided");
|
||||
// overwrite env configuration with config URLs
|
||||
client_config = client_config.with_urls(nyxd_url, api_url);
|
||||
let client = validator_client::Client::new_query(client_config)
|
||||
.expect("Could not construct query client");
|
||||
let coconut_api_clients =
|
||||
validator_client::CoconutApiClient::all_coconut_api_clients(&client)
|
||||
.await
|
||||
.expect("Could not query api clients");
|
||||
BandwidthController::new(
|
||||
credential_storage::initialise_storage(config.get_base().get_database_path()).await,
|
||||
coconut_api_clients,
|
||||
)
|
||||
};
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
let bandwidth_controller = BandwidthController::new(
|
||||
async fn create_bandwidth_controller(config: &Config) -> BandwidthController<QueryNyxdClient> {
|
||||
let details = network_defaults::NymNetworkDetails::new_from_env();
|
||||
let mut client_config = validator_client::Config::try_from_nym_network_details(&details)
|
||||
.expect("failed to construct validator client config");
|
||||
let nyxd_url = config
|
||||
.get_base()
|
||||
.get_validator_endpoints()
|
||||
.pop()
|
||||
.expect("No nyxd validator endpoint provided");
|
||||
let api_url = config
|
||||
.get_base()
|
||||
.get_nym_api_endpoints()
|
||||
.pop()
|
||||
.expect("No validator api endpoint provided");
|
||||
// overwrite env configuration with config URLs
|
||||
client_config = client_config.with_urls(nyxd_url, api_url);
|
||||
let client = validator_client::Client::new_query(client_config)
|
||||
.expect("Could not construct query client");
|
||||
BandwidthController::new(
|
||||
credential_storage::initialise_storage(config.get_base().get_database_path()).await,
|
||||
client,
|
||||
)
|
||||
.expect("Could not create bandwidth controller");
|
||||
bandwidth_controller
|
||||
}
|
||||
|
||||
fn start_websocket_listener(
|
||||
|
||||
@@ -20,6 +20,7 @@ use log::*;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use std::error::Error;
|
||||
use task::{TaskClient, TaskManager};
|
||||
use validator_client::nyxd::QueryNyxdClient;
|
||||
|
||||
pub mod config;
|
||||
|
||||
@@ -53,42 +54,28 @@ impl NymClient {
|
||||
}
|
||||
}
|
||||
|
||||
async fn create_bandwidth_controller(config: &Config) -> BandwidthController {
|
||||
#[cfg(feature = "coconut")]
|
||||
let bandwidth_controller = {
|
||||
let details = network_defaults::NymNetworkDetails::new_from_env();
|
||||
let mut client_config =
|
||||
validator_client::Config::try_from_nym_network_details(&details)
|
||||
.expect("failed to construct validator client config");
|
||||
let nyxd_url = config
|
||||
.get_base()
|
||||
.get_validator_endpoints()
|
||||
.pop()
|
||||
.expect("No nyxd validator endpoint provided");
|
||||
let api_url = config
|
||||
.get_base()
|
||||
.get_nym_api_endpoints()
|
||||
.pop()
|
||||
.expect("No validator api endpoint provided");
|
||||
// overwrite env configuration with config URLs
|
||||
client_config = client_config.with_urls(nyxd_url, api_url);
|
||||
let client = validator_client::Client::new_query(client_config)
|
||||
.expect("Could not construct query client");
|
||||
let coconut_api_clients =
|
||||
validator_client::CoconutApiClient::all_coconut_api_clients(&client)
|
||||
.await
|
||||
.expect("Could not query api clients");
|
||||
BandwidthController::new(
|
||||
credential_storage::initialise_storage(config.get_base().get_database_path()).await,
|
||||
coconut_api_clients,
|
||||
)
|
||||
};
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
let bandwidth_controller = BandwidthController::new(
|
||||
async fn create_bandwidth_controller(config: &Config) -> BandwidthController<QueryNyxdClient> {
|
||||
let details = network_defaults::NymNetworkDetails::new_from_env();
|
||||
let mut client_config = validator_client::Config::try_from_nym_network_details(&details)
|
||||
.expect("failed to construct validator client config");
|
||||
let nyxd_url = config
|
||||
.get_base()
|
||||
.get_validator_endpoints()
|
||||
.pop()
|
||||
.expect("No nyxd validator endpoint provided");
|
||||
let api_url = config
|
||||
.get_base()
|
||||
.get_nym_api_endpoints()
|
||||
.pop()
|
||||
.expect("No validator api endpoint provided");
|
||||
// overwrite env configuration with config URLs
|
||||
client_config = client_config.with_urls(nyxd_url, api_url);
|
||||
let client = validator_client::Client::new_query(client_config)
|
||||
.expect("Could not construct query client");
|
||||
BandwidthController::new(
|
||||
credential_storage::initialise_storage(config.get_base().get_database_path()).await,
|
||||
client,
|
||||
)
|
||||
.expect("Could not create bandwidth controller");
|
||||
bandwidth_controller
|
||||
}
|
||||
|
||||
fn start_socks5_listener(
|
||||
|
||||
@@ -11,6 +11,7 @@ use client_core::client::base_client::{
|
||||
use client_core::client::replies::reply_storage::browser_backend;
|
||||
use client_core::client::{inbound_messages::InputMessage, key_manager::KeyManager};
|
||||
use gateway_client::bandwidth::BandwidthController;
|
||||
use gateway_client::wasm_mockups::SigningNyxdClient;
|
||||
use js_sys::Promise;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use nymsphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
@@ -47,7 +48,7 @@ pub struct NymClientBuilder {
|
||||
on_message: js_sys::Function,
|
||||
|
||||
// unimplemented:
|
||||
bandwidth_controller: Option<BandwidthController>,
|
||||
bandwidth_controller: Option<BandwidthController<SigningNyxdClient>>,
|
||||
disabled_credentials: bool,
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ gateway-requests = { path = "../../../gateway/gateway-requests" }
|
||||
network-defaults = { path = "../../network-defaults" }
|
||||
nymsphinx = { path = "../../nymsphinx" }
|
||||
pemstore = { path = "../../pemstore" }
|
||||
validator-client = { path = "../validator-client", optional = true }
|
||||
validator-client = { path = "../validator-client" }
|
||||
task = { path = "../../task" }
|
||||
serde = { version = "1.0", features = ["derive"]}
|
||||
|
||||
@@ -79,5 +79,5 @@ features = ["js"]
|
||||
#url = "2.1"
|
||||
|
||||
[features]
|
||||
coconut = ["gateway-requests/coconut", "coconut-interface", "validator-client", "credentials/coconut"]
|
||||
coconut = ["gateway-requests/coconut", "coconut-interface", "credentials/coconut"]
|
||||
wasm = []
|
||||
|
||||
@@ -1,23 +1,26 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#[cfg(feature = "coconut")]
|
||||
use crate::error::GatewayClientError;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use crate::wasm_storage::Storage;
|
||||
use crate::wasm_mockups::Storage;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use credential_storage::storage::Storage;
|
||||
|
||||
#[cfg(all(target_arch = "wasm32", feature = "coconut"))]
|
||||
use crate::wasm_storage::StorageError;
|
||||
use crate::wasm_mockups::StorageError;
|
||||
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "coconut"))]
|
||||
use credential_storage::error::StorageError;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use crate::wasm_mockups::{Client, CosmWasmClient};
|
||||
#[cfg(feature = "coconut")]
|
||||
use std::str::FromStr;
|
||||
#[cfg(feature = "coconut")]
|
||||
use validator_client::client::CoconutApiClient;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use validator_client::{nyxd::CosmWasmClient, Client};
|
||||
#[cfg(feature = "coconut")]
|
||||
use {
|
||||
coconut_interface::Base58,
|
||||
@@ -28,41 +31,34 @@ use {
|
||||
|
||||
// TODO: make it nicer for wasm (I don't want to touch it for this experiment)
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use crate::wasm_storage::PersistentStorage;
|
||||
use crate::wasm_mockups::PersistentStorage;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use credential_storage::PersistentStorage;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct BandwidthController<St: Storage = PersistentStorage> {
|
||||
#[allow(dead_code)]
|
||||
#[allow(dead_code)]
|
||||
pub struct BandwidthController<C: Clone, St: Storage = PersistentStorage> {
|
||||
storage: St,
|
||||
#[cfg(feature = "coconut")]
|
||||
coconut_api_clients: Vec<CoconutApiClient>,
|
||||
nyxd_client: Client<C>,
|
||||
}
|
||||
|
||||
impl<St> BandwidthController<St>
|
||||
impl<C, St> BandwidthController<C, St>
|
||||
where
|
||||
C: CosmWasmClient + Sync + Send + Clone,
|
||||
St: Storage + Clone + 'static,
|
||||
{
|
||||
#[cfg(feature = "coconut")]
|
||||
pub fn new(storage: St, coconut_api_clients: Vec<CoconutApiClient>) -> Self {
|
||||
pub fn new(storage: St, nyxd_client: Client<C>) -> Self {
|
||||
BandwidthController {
|
||||
storage,
|
||||
coconut_api_clients,
|
||||
nyxd_client,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
pub fn new(storage: St) -> Result<Self, GatewayClientError> {
|
||||
Ok(BandwidthController { storage })
|
||||
}
|
||||
|
||||
#[cfg(feature = "coconut")]
|
||||
pub async fn prepare_coconut_credential(
|
||||
&self,
|
||||
) -> Result<(coconut_interface::Credential, i64), GatewayClientError> {
|
||||
let verification_key = obtain_aggregate_verification_key(&self.coconut_api_clients).await?;
|
||||
let bandwidth_credential = self.storage.get_next_coconut_credential().await?;
|
||||
let voucher_value = u64::from_str(&bandwidth_credential.voucher_value)
|
||||
.map_err(|_| StorageError::InconsistentData)?;
|
||||
@@ -73,6 +69,19 @@ where
|
||||
coconut_interface::Attribute::try_from_bs58(bandwidth_credential.binding_number)?;
|
||||
let signature =
|
||||
coconut_interface::Signature::try_from_bs58(bandwidth_credential.signature)?;
|
||||
let epoch_id = u64::from_str(&bandwidth_credential.epoch_id)
|
||||
.map_err(|_| StorageError::InconsistentData)?;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let coconut_api_clients = validator_client::CoconutApiClient::all_coconut_api_clients(
|
||||
&self.nyxd_client,
|
||||
epoch_id,
|
||||
)
|
||||
.await
|
||||
.expect("Could not query api clients");
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let coconut_api_clients = vec![];
|
||||
let verification_key = obtain_aggregate_verification_key(&coconut_api_clients).await?;
|
||||
|
||||
// the below would only be executed once we know where we want to spend it (i.e. which gateway and stuff)
|
||||
Ok((
|
||||
@@ -81,6 +90,7 @@ where
|
||||
voucher_info,
|
||||
serial_number,
|
||||
binding_number,
|
||||
epoch_id,
|
||||
&signature,
|
||||
&verification_key,
|
||||
)?,
|
||||
|
||||
@@ -32,9 +32,13 @@ use coconut_interface::Credential;
|
||||
use credential_storage::PersistentStorage;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use tokio_tungstenite::connect_async;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use validator_client::nyxd::CosmWasmClient;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use crate::wasm_storage::PersistentStorage;
|
||||
use crate::wasm_mockups::CosmWasmClient;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use crate::wasm_mockups::PersistentStorage;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use wasm_timer;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
@@ -43,7 +47,7 @@ use wasm_utils::websocket::JSWebsocket;
|
||||
const DEFAULT_RECONNECTION_ATTEMPTS: usize = 10;
|
||||
const DEFAULT_RECONNECTION_BACKOFF: Duration = Duration::from_secs(5);
|
||||
|
||||
pub struct GatewayClient {
|
||||
pub struct GatewayClient<C: Clone> {
|
||||
authenticated: bool,
|
||||
disabled_credentials_mode: bool,
|
||||
bandwidth_remaining: i64,
|
||||
@@ -55,7 +59,7 @@ pub struct GatewayClient {
|
||||
connection: SocketState,
|
||||
packet_router: PacketRouter,
|
||||
response_timeout_duration: Duration,
|
||||
bandwidth_controller: Option<BandwidthController<PersistentStorage>>,
|
||||
bandwidth_controller: Option<BandwidthController<C, PersistentStorage>>,
|
||||
|
||||
// reconnection related variables
|
||||
/// Specifies whether client should try to reconnect to gateway on connection failure.
|
||||
@@ -70,7 +74,10 @@ pub struct GatewayClient {
|
||||
shutdown: TaskClient,
|
||||
}
|
||||
|
||||
impl GatewayClient {
|
||||
impl<C> GatewayClient<C>
|
||||
where
|
||||
C: CosmWasmClient + Sync + Send + Clone,
|
||||
{
|
||||
// TODO: put it all in a Config struct
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
@@ -82,7 +89,7 @@ impl GatewayClient {
|
||||
mixnet_message_sender: MixnetMessageSender,
|
||||
ack_sender: AcknowledgementSender,
|
||||
response_timeout_duration: Duration,
|
||||
bandwidth_controller: Option<BandwidthController<PersistentStorage>>,
|
||||
bandwidth_controller: Option<BandwidthController<C, PersistentStorage>>,
|
||||
shutdown: TaskClient,
|
||||
) -> Self {
|
||||
GatewayClient {
|
||||
@@ -138,7 +145,7 @@ impl GatewayClient {
|
||||
let shutdown = TaskClient::dummy();
|
||||
let packet_router = PacketRouter::new(ack_tx, mix_tx, shutdown.clone());
|
||||
|
||||
GatewayClient {
|
||||
GatewayClient::<C> {
|
||||
authenticated: false,
|
||||
disabled_credentials_mode: true,
|
||||
bandwidth_remaining: 0,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use crate::wasm_storage::StorageError;
|
||||
use crate::wasm_mockups::StorageError;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use credential_storage::error::StorageError;
|
||||
use gateway_requests::registration::handshake::error::HandshakeError;
|
||||
|
||||
@@ -17,7 +17,7 @@ pub mod error;
|
||||
pub mod packet_router;
|
||||
pub mod socket_state;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
mod wasm_storage;
|
||||
pub mod wasm_mockups;
|
||||
|
||||
/// Helper method for reading from websocket stream. Helps to flatten the structure.
|
||||
pub(crate) fn cleanup_socket_message(
|
||||
|
||||
+14
@@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use async_trait::async_trait;
|
||||
use std::marker::PhantomData;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
@@ -14,6 +15,18 @@ pub enum StorageError {
|
||||
InconsistentData,
|
||||
}
|
||||
|
||||
pub trait CosmWasmClient {}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SigningNyxdClient {}
|
||||
|
||||
impl CosmWasmClient for SigningNyxdClient {}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Client<C> {
|
||||
_phantom: PhantomData<C>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PersistentStorage {}
|
||||
|
||||
@@ -24,6 +37,7 @@ pub struct CoconutCredential {
|
||||
pub serial_number: String,
|
||||
pub binding_number: String,
|
||||
pub signature: String,
|
||||
pub epoch_id: String,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@@ -17,6 +17,7 @@ mixnet-contract-common = { path= "../../cosmwasm-smart-contracts/mixnet-contract
|
||||
vesting-contract-common = { path= "../../cosmwasm-smart-contracts/vesting-contract" }
|
||||
coconut-bandwidth-contract-common = { path= "../../cosmwasm-smart-contracts/coconut-bandwidth-contract" }
|
||||
multisig-contract-common = { path = "../../cosmwasm-smart-contracts/multisig-contract" }
|
||||
group-contract-common = { path = "../../cosmwasm-smart-contracts/group-contract" }
|
||||
vesting-contract = { path = "../../../contracts/vesting" }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
@@ -39,6 +40,7 @@ bip39 = { version = "1", features = ["rand"], optional = true }
|
||||
config = { path = "../../config", optional = true }
|
||||
cosmrs = { git = "https://github.com/neacsu/cosmos-rust", branch = "neacsu/feegrant_support", features = ["rpc", "bip32", "cosmwasm"], optional = true}
|
||||
cw3 = { version = "0.13.4", optional = true }
|
||||
cw4 = { version = "0.13.4", optional = true }
|
||||
prost = { version = "0.10", default-features = false, optional = true }
|
||||
flate2 = { version = "1.0.20", optional = true }
|
||||
sha2 = { version = "0.9.5", optional = true }
|
||||
@@ -56,6 +58,7 @@ nyxd-client = [
|
||||
"config",
|
||||
"cosmrs",
|
||||
"cw3",
|
||||
"cw4",
|
||||
"prost",
|
||||
"flate2",
|
||||
"sha2",
|
||||
|
||||
@@ -21,7 +21,9 @@ use crate::nyxd::traits::{DkgQueryClient, MixnetQueryClient, MultisigQueryClient
|
||||
use crate::nyxd::{self, CosmWasmClient, NyxdClient, QueryNyxdClient, SigningNyxdClient};
|
||||
#[cfg(feature = "nyxd-client")]
|
||||
use coconut_dkg_common::{
|
||||
dealer::ContractDealing, types::DealerDetails, verification_key::ContractVKShare,
|
||||
dealer::ContractDealing,
|
||||
types::{DealerDetails, EpochId},
|
||||
verification_key::ContractVKShare,
|
||||
};
|
||||
#[cfg(feature = "nyxd-client")]
|
||||
use coconut_interface::Base58;
|
||||
@@ -128,7 +130,8 @@ impl Config {
|
||||
}
|
||||
|
||||
#[cfg(feature = "nyxd-client")]
|
||||
pub struct Client<C> {
|
||||
#[derive(Clone)]
|
||||
pub struct Client<C: Clone> {
|
||||
// TODO: we really shouldn't be storing a mnemonic here, but removing it would be
|
||||
// non-trivial amount of work and it's out of scope of the current branch
|
||||
mnemonic: Option<bip39::Mnemonic>,
|
||||
@@ -218,7 +221,10 @@ impl Client<QueryNyxdClient> {
|
||||
|
||||
// nyxd wrappers
|
||||
#[cfg(feature = "nyxd-client")]
|
||||
impl<C> Client<C> {
|
||||
impl<C> Client<C>
|
||||
where
|
||||
C: Clone,
|
||||
{
|
||||
// use case: somebody initialised client without a contract in order to upload and initialise one
|
||||
// and now they want to actually use it without making new client
|
||||
|
||||
@@ -676,6 +682,7 @@ impl<C> Client<C> {
|
||||
|
||||
pub async fn get_all_nyxd_verification_key_shares(
|
||||
&self,
|
||||
epoch_id: EpochId,
|
||||
) -> Result<Vec<ContractVKShare>, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync + Send,
|
||||
@@ -685,7 +692,11 @@ impl<C> Client<C> {
|
||||
loop {
|
||||
let mut paged_response = self
|
||||
.nyxd
|
||||
.get_vk_shares_paged(start_after.take(), self.verification_key_page_limit)
|
||||
.get_vk_shares_paged(
|
||||
epoch_id,
|
||||
start_after.take(),
|
||||
self.verification_key_page_limit,
|
||||
)
|
||||
.await?;
|
||||
shares.append(&mut paged_response.shares);
|
||||
|
||||
@@ -730,7 +741,10 @@ impl<C> Client<C> {
|
||||
|
||||
// validator-api wrappers
|
||||
#[cfg(feature = "nyxd-client")]
|
||||
impl<C> Client<C> {
|
||||
impl<C> Client<C>
|
||||
where
|
||||
C: Clone,
|
||||
{
|
||||
pub fn change_nym_api(&mut self, new_endpoint: Url) {
|
||||
self.nym_api.change_url(new_endpoint)
|
||||
}
|
||||
@@ -792,14 +806,15 @@ pub struct CoconutApiClient {
|
||||
|
||||
#[cfg(feature = "nyxd-client")]
|
||||
impl CoconutApiClient {
|
||||
pub async fn all_coconut_api_clients<C>(
|
||||
pub async fn all_coconut_api_clients<C: Clone>(
|
||||
nyxd_client: &Client<C>,
|
||||
epoch_id: EpochId,
|
||||
) -> Result<Vec<Self>, ValidatorClientError>
|
||||
where
|
||||
C: CosmWasmClient + Sync + Send,
|
||||
{
|
||||
Ok(nyxd_client
|
||||
.get_all_nyxd_verification_key_shares()
|
||||
.get_all_nyxd_verification_key_shares(epoch_id)
|
||||
.await?
|
||||
.into_iter()
|
||||
.filter_map(Self::try_from)
|
||||
|
||||
@@ -65,6 +65,7 @@ pub struct Config {
|
||||
pub(crate) vesting_contract_address: Option<AccountId>,
|
||||
pub(crate) bandwidth_claim_contract_address: Option<AccountId>,
|
||||
pub(crate) coconut_bandwidth_contract_address: Option<AccountId>,
|
||||
pub(crate) group_contract_address: Option<AccountId>,
|
||||
pub(crate) multisig_contract_address: Option<AccountId>,
|
||||
pub(crate) coconut_dkg_contract_address: Option<AccountId>,
|
||||
// TODO: add this in later commits
|
||||
@@ -119,6 +120,10 @@ impl Config {
|
||||
.as_ref(),
|
||||
prefix,
|
||||
)?,
|
||||
group_contract_address: Self::parse_optional_account(
|
||||
details.contracts.group_contract_address.as_ref(),
|
||||
prefix,
|
||||
)?,
|
||||
multisig_contract_address: Self::parse_optional_account(
|
||||
details.contracts.multisig_contract_address.as_ref(),
|
||||
prefix,
|
||||
@@ -131,8 +136,8 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NyxdClient<C> {
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct NyxdClient<C: Clone> {
|
||||
client: C,
|
||||
config: Config,
|
||||
client_address: Option<Vec<AccountId>>,
|
||||
@@ -209,7 +214,10 @@ impl NyxdClient<SigningNyxdClient> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> NyxdClient<C> {
|
||||
impl<C> NyxdClient<C>
|
||||
where
|
||||
C: Clone,
|
||||
{
|
||||
pub fn current_config(&self) -> &Config {
|
||||
&self.config
|
||||
}
|
||||
@@ -276,6 +284,10 @@ impl<C> NyxdClient<C> {
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn group_contract_address(&self) -> &AccountId {
|
||||
self.config.group_contract_address.as_ref().unwrap()
|
||||
}
|
||||
|
||||
// TODO: this should get changed into Result<&AccountId, NyxdError> (or Option<&AccountId> in future commits
|
||||
// note: what unwrap is doing here is just moving a failure that would have normally
|
||||
// occurred in `connect` when attempting to parse an empty address,
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ pub trait CoconutBandwidthQueryClient {
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<C: CosmWasmClient + Sync + Send> CoconutBandwidthQueryClient for NyxdClient<C> {
|
||||
impl<C: CosmWasmClient + Sync + Send + Clone> CoconutBandwidthQueryClient for NyxdClient<C> {
|
||||
async fn get_spent_credential(
|
||||
&self,
|
||||
blinded_serial_number: String,
|
||||
|
||||
+3
-1
@@ -30,7 +30,9 @@ pub trait CoconutBandwidthSigningClient {
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<C: SigningCosmWasmClient + Sync + Send> CoconutBandwidthSigningClient for NyxdClient<C> {
|
||||
impl<C: SigningCosmWasmClient + Sync + Send + Clone> CoconutBandwidthSigningClient
|
||||
for NyxdClient<C>
|
||||
{
|
||||
async fn deposit(
|
||||
&self,
|
||||
amount: Coin,
|
||||
|
||||
@@ -8,7 +8,7 @@ use coconut_dkg_common::dealer::{
|
||||
DealerDetailsResponse, PagedDealerResponse, PagedDealingsResponse,
|
||||
};
|
||||
use coconut_dkg_common::msg::QueryMsg as DkgQueryMsg;
|
||||
use coconut_dkg_common::types::Epoch;
|
||||
use coconut_dkg_common::types::{Epoch, EpochId};
|
||||
use coconut_dkg_common::verification_key::PagedVKSharesResponse;
|
||||
use cosmrs::AccountId;
|
||||
|
||||
@@ -39,6 +39,7 @@ pub trait DkgQueryClient {
|
||||
) -> Result<PagedDealingsResponse, NyxdError>;
|
||||
async fn get_vk_shares_paged(
|
||||
&self,
|
||||
epoch_id: EpochId,
|
||||
start_after: Option<String>,
|
||||
page_limit: Option<u32>,
|
||||
) -> Result<PagedVKSharesResponse, NyxdError>;
|
||||
@@ -47,7 +48,7 @@ pub trait DkgQueryClient {
|
||||
#[async_trait]
|
||||
impl<C> DkgQueryClient for NyxdClient<C>
|
||||
where
|
||||
C: CosmWasmClient + Send + Sync,
|
||||
C: CosmWasmClient + Send + Sync + Clone,
|
||||
{
|
||||
async fn get_current_epoch(&self) -> Result<Epoch, NyxdError> {
|
||||
let request = DkgQueryMsg::GetCurrentEpochState {};
|
||||
@@ -119,10 +120,12 @@ where
|
||||
|
||||
async fn get_vk_shares_paged(
|
||||
&self,
|
||||
epoch_id: EpochId,
|
||||
start_after: Option<String>,
|
||||
page_limit: Option<u32>,
|
||||
) -> Result<PagedVKSharesResponse, NyxdError> {
|
||||
let request = DkgQueryMsg::GetVerificationKeys {
|
||||
epoch_id,
|
||||
limit: page_limit,
|
||||
start_after,
|
||||
};
|
||||
|
||||
@@ -36,7 +36,7 @@ pub trait DkgSigningClient {
|
||||
#[async_trait]
|
||||
impl<C> DkgSigningClient for NyxdClient<C>
|
||||
where
|
||||
C: SigningCosmWasmClient + Send + Sync,
|
||||
C: SigningCosmWasmClient + Send + Sync + Clone,
|
||||
{
|
||||
async fn advance_dkg_epoch_state(&self, fee: Option<Fee>) -> Result<ExecuteResult, NyxdError> {
|
||||
let req = DkgExecuteMsg::AdvanceEpochState {};
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::nyxd::error::NyxdError;
|
||||
use crate::nyxd::{CosmWasmClient, NyxdClient};
|
||||
|
||||
use group_contract_common::msg::QueryMsg;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use cw4::MemberResponse;
|
||||
|
||||
#[async_trait]
|
||||
pub trait GroupQueryClient {
|
||||
async fn member(&self, addr: String) -> Result<MemberResponse, NyxdError>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<C: CosmWasmClient + Sync + Send + Clone> GroupQueryClient for NyxdClient<C> {
|
||||
async fn member(&self, addr: String) -> Result<MemberResponse, NyxdError> {
|
||||
let request = QueryMsg::Member {
|
||||
addr,
|
||||
at_height: None,
|
||||
};
|
||||
self.client
|
||||
.query_contract_smart(self.group_contract_address(), &request)
|
||||
.await
|
||||
}
|
||||
}
|
||||
@@ -395,7 +395,7 @@ pub trait MixnetQueryClient {
|
||||
#[async_trait]
|
||||
impl<C> MixnetQueryClient for NyxdClient<C>
|
||||
where
|
||||
C: CosmWasmClient + Sync + Send,
|
||||
C: CosmWasmClient + Sync + Send + Clone,
|
||||
{
|
||||
async fn query_mixnet_contract<T>(&self, query: MixnetQueryMsg) -> Result<T, NyxdError>
|
||||
where
|
||||
@@ -410,7 +410,7 @@ where
|
||||
#[async_trait]
|
||||
impl<C> MixnetQueryClient for crate::Client<C>
|
||||
where
|
||||
C: CosmWasmClient + Sync + Send,
|
||||
C: CosmWasmClient + Sync + Send + Clone,
|
||||
{
|
||||
async fn query_mixnet_contract<T>(&self, query: MixnetQueryMsg) -> Result<T, NyxdError>
|
||||
where
|
||||
|
||||
@@ -627,7 +627,7 @@ pub trait MixnetSigningClient {
|
||||
#[async_trait]
|
||||
impl<C> MixnetSigningClient for NyxdClient<C>
|
||||
where
|
||||
C: SigningCosmWasmClient + Sync + Send,
|
||||
C: SigningCosmWasmClient + Sync + Send + Clone,
|
||||
{
|
||||
async fn execute_mixnet_contract(
|
||||
&self,
|
||||
@@ -653,7 +653,7 @@ where
|
||||
#[async_trait]
|
||||
impl<C> MixnetSigningClient for crate::Client<C>
|
||||
where
|
||||
C: SigningCosmWasmClient + Sync + Send,
|
||||
C: SigningCosmWasmClient + Sync + Send + Clone,
|
||||
{
|
||||
async fn execute_mixnet_contract(
|
||||
&self,
|
||||
|
||||
@@ -5,6 +5,7 @@ mod coconut_bandwidth_query_client;
|
||||
mod coconut_bandwidth_signing_client;
|
||||
mod dkg_query_client;
|
||||
mod dkg_signing_client;
|
||||
mod group_query_client;
|
||||
mod mixnet_query_client;
|
||||
mod mixnet_signing_client;
|
||||
mod multisig_query_client;
|
||||
@@ -16,6 +17,7 @@ pub use coconut_bandwidth_query_client::CoconutBandwidthQueryClient;
|
||||
pub use coconut_bandwidth_signing_client::CoconutBandwidthSigningClient;
|
||||
pub use dkg_query_client::DkgQueryClient;
|
||||
pub use dkg_signing_client::DkgSigningClient;
|
||||
pub use group_query_client::GroupQueryClient;
|
||||
pub use mixnet_query_client::MixnetQueryClient;
|
||||
pub use mixnet_signing_client::MixnetSigningClient;
|
||||
pub use multisig_query_client::MultisigQueryClient;
|
||||
|
||||
@@ -20,7 +20,7 @@ pub trait MultisigQueryClient {
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<C: CosmWasmClient + Sync + Send> MultisigQueryClient for NyxdClient<C> {
|
||||
impl<C: CosmWasmClient + Sync + Send + Clone> MultisigQueryClient for NyxdClient<C> {
|
||||
async fn get_proposal(&self, proposal_id: u64) -> Result<ProposalResponse, NyxdError> {
|
||||
let request = QueryMsg::Proposal { proposal_id };
|
||||
self.client
|
||||
|
||||
@@ -38,7 +38,7 @@ pub trait MultisigSigningClient {
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<C: SigningCosmWasmClient + Sync + Send> MultisigSigningClient for NyxdClient<C> {
|
||||
impl<C: SigningCosmWasmClient + Sync + Send + Clone> MultisigSigningClient for NyxdClient<C> {
|
||||
async fn propose_release_funds(
|
||||
&self,
|
||||
title: String,
|
||||
|
||||
@@ -269,7 +269,7 @@ pub trait VestingQueryClient {
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<C: CosmWasmClient + Sync + Send> VestingQueryClient for NyxdClient<C> {
|
||||
impl<C: CosmWasmClient + Sync + Send + Clone> VestingQueryClient for NyxdClient<C> {
|
||||
async fn query_vesting_contract<T>(&self, query: VestingQueryMsg) -> Result<T, NyxdError>
|
||||
where
|
||||
for<'a> T: Deserialize<'a>,
|
||||
|
||||
@@ -129,7 +129,7 @@ pub trait VestingSigningClient {
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<C: SigningCosmWasmClient + Sync + Send> VestingSigningClient for NyxdClient<C> {
|
||||
impl<C: SigningCosmWasmClient + Sync + Send + Clone> VestingSigningClient for NyxdClient<C> {
|
||||
async fn execute_vesting_contract(
|
||||
&self,
|
||||
fee: Option<Fee>,
|
||||
|
||||
@@ -18,6 +18,8 @@ pub struct Credential {
|
||||
theta: Theta,
|
||||
voucher_value: u64,
|
||||
voucher_info: String,
|
||||
#[getset(get = "pub")]
|
||||
epoch_id: u64,
|
||||
}
|
||||
impl Credential {
|
||||
pub fn new(
|
||||
@@ -25,12 +27,14 @@ impl Credential {
|
||||
theta: Theta,
|
||||
voucher_value: u64,
|
||||
voucher_info: String,
|
||||
epoch_id: u64,
|
||||
) -> Credential {
|
||||
Credential {
|
||||
n_params,
|
||||
theta,
|
||||
voucher_value,
|
||||
voucher_info,
|
||||
epoch_id,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +72,7 @@ impl Credential {
|
||||
let theta_bytes = self.theta.to_bytes();
|
||||
let theta_bytes_len = theta_bytes.len();
|
||||
let voucher_value_bytes = self.voucher_value.to_be_bytes();
|
||||
let epoch_id_bytes = self.epoch_id.to_be_bytes();
|
||||
let voucher_info_bytes = self.voucher_info.as_bytes();
|
||||
let voucher_info_len = voucher_info_bytes.len();
|
||||
|
||||
@@ -76,6 +81,7 @@ impl Credential {
|
||||
bytes.extend_from_slice(&(theta_bytes_len as u64).to_be_bytes());
|
||||
bytes.extend_from_slice(&theta_bytes);
|
||||
bytes.extend_from_slice(&voucher_value_bytes);
|
||||
bytes.extend_from_slice(&epoch_id_bytes);
|
||||
bytes.extend_from_slice(voucher_info_bytes);
|
||||
|
||||
bytes
|
||||
@@ -103,7 +109,9 @@ impl Credential {
|
||||
.map_err(|e| CoconutError::Deserialization(e.to_string()))?;
|
||||
eight_byte.copy_from_slice(&bytes[12 + theta_len as usize..20 + theta_len as usize]);
|
||||
let voucher_value = u64::from_be_bytes(eight_byte);
|
||||
let voucher_info = String::from_utf8(bytes[20 + theta_len as usize..].to_vec())
|
||||
eight_byte.copy_from_slice(&bytes[20 + theta_len as usize..28 + theta_len as usize]);
|
||||
let epoch_id = u64::from_be_bytes(eight_byte);
|
||||
let voucher_info = String::from_utf8(bytes[28 + theta_len as usize..].to_vec())
|
||||
.map_err(|e| CoconutError::Deserialization(e.to_string()))?;
|
||||
|
||||
Ok(Credential {
|
||||
@@ -111,6 +119,7 @@ impl Credential {
|
||||
theta,
|
||||
voucher_value,
|
||||
voucher_info,
|
||||
epoch_id,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -166,7 +175,7 @@ mod tests {
|
||||
binding_number,
|
||||
)
|
||||
.unwrap();
|
||||
let credential = Credential::new(4, theta, voucher_value, voucher_info);
|
||||
let credential = Credential::new(4, theta, voucher_value, voucher_info, 42);
|
||||
|
||||
let serialized_credential = credential.as_bytes();
|
||||
let deserialized_credential = Credential::from_bytes(&serialized_credential).unwrap();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::types::{ContractSafeBytes, EncodedBTEPublicKeyWithProof, TimeConfiguration};
|
||||
use crate::types::{ContractSafeBytes, EncodedBTEPublicKeyWithProof, EpochId, TimeConfiguration};
|
||||
use crate::verification_key::VerificationKeyShare;
|
||||
use cosmwasm_std::Addr;
|
||||
use schemars::JsonSchema;
|
||||
@@ -35,6 +35,8 @@ pub enum ExecuteMsg {
|
||||
owner: Addr,
|
||||
},
|
||||
|
||||
SurpassedThreshold {},
|
||||
|
||||
AdvanceEpochState {},
|
||||
}
|
||||
|
||||
@@ -60,6 +62,7 @@ pub enum QueryMsg {
|
||||
start_after: Option<String>,
|
||||
},
|
||||
GetVerificationKeys {
|
||||
epoch_id: EpochId,
|
||||
limit: Option<u32>,
|
||||
start_after: Option<String>,
|
||||
},
|
||||
|
||||
@@ -13,6 +13,7 @@ pub use cosmwasm_std::{Addr, Coin, Timestamp};
|
||||
pub type EncodedBTEPublicKeyWithProof = String;
|
||||
pub type EncodedBTEPublicKeyWithProofRef<'a> = &'a str;
|
||||
pub type NodeIndex = u64;
|
||||
pub type EpochId = u64;
|
||||
|
||||
// 2 public attributes, 2 private attributes, 1 fixed for coconut credential
|
||||
pub const TOTAL_DEALINGS: usize = 2 + 2 + 1;
|
||||
@@ -72,6 +73,7 @@ impl Default for TimeConfiguration {
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct Epoch {
|
||||
pub state: EpochState,
|
||||
pub epoch_id: EpochId,
|
||||
pub time_configuration: TimeConfiguration,
|
||||
pub finish_timestamp: Timestamp,
|
||||
}
|
||||
@@ -79,6 +81,7 @@ pub struct Epoch {
|
||||
impl Epoch {
|
||||
pub fn new(
|
||||
state: EpochState,
|
||||
epoch_id: u64,
|
||||
time_configuration: TimeConfiguration,
|
||||
current_timestamp: Timestamp,
|
||||
) -> Self {
|
||||
@@ -98,6 +101,7 @@ impl Epoch {
|
||||
};
|
||||
Epoch {
|
||||
state,
|
||||
epoch_id,
|
||||
time_configuration,
|
||||
finish_timestamp: current_timestamp.plus_seconds(duration),
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::msg::ExecuteMsg;
|
||||
use crate::types::NodeIndex;
|
||||
use crate::types::{EpochId, NodeIndex};
|
||||
use cosmwasm_std::{from_binary, to_binary, Addr, CosmosMsg, StdResult, Timestamp, WasmMsg};
|
||||
use cw_utils::Expiration;
|
||||
use multisig_contract_common::msg::ExecuteMsg as MultisigExecuteMsg;
|
||||
@@ -16,6 +16,7 @@ pub struct ContractVKShare {
|
||||
pub announce_address: String,
|
||||
pub node_index: NodeIndex,
|
||||
pub owner: Addr,
|
||||
pub epoch_id: EpochId,
|
||||
pub verified: bool,
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "group-contract-common"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
cw4 = { version = "0.13.4" }
|
||||
schemars = "0.8"
|
||||
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
|
||||
@@ -0,0 +1 @@
|
||||
pub mod msg;
|
||||
+3
@@ -1,3 +1,6 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
DROP TABLE coconut_credentials;
|
||||
CREATE TABLE coconut_credentials
|
||||
(
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
voucher_value TEXT NOT NULL,
|
||||
voucher_info TEXT NOT NULL,
|
||||
serial_number TEXT NOT NULL,
|
||||
binding_number TEXT NOT NULL,
|
||||
signature TEXT NOT NULL UNIQUE,
|
||||
epoch_id TEXT NOT NULL,
|
||||
consumed BOOLEAN NOT NULL
|
||||
);
|
||||
@@ -34,10 +34,11 @@ impl CoconutCredentialManager {
|
||||
serial_number: String,
|
||||
binding_number: String,
|
||||
signature: String,
|
||||
epoch_id: String,
|
||||
) -> Result<(), sqlx::Error> {
|
||||
sqlx::query!(
|
||||
"INSERT INTO coconut_credentials(voucher_value, voucher_info, serial_number, binding_number, signature, consumed) VALUES (?, ?, ?, ?, ?, ?)",
|
||||
voucher_value, voucher_info, serial_number, binding_number, signature, false
|
||||
"INSERT INTO coconut_credentials(voucher_value, voucher_info, serial_number, binding_number, signature, epoch_id, consumed) VALUES (?, ?, ?, ?, ?, ?, ?)",
|
||||
voucher_value, voucher_info, serial_number, binding_number, signature, epoch_id, false
|
||||
)
|
||||
.execute(&self.connection_pool)
|
||||
.await?;
|
||||
|
||||
@@ -70,6 +70,7 @@ impl Storage for PersistentStorage {
|
||||
serial_number: String,
|
||||
binding_number: String,
|
||||
signature: String,
|
||||
epoch_id: String,
|
||||
) -> Result<(), StorageError> {
|
||||
self.coconut_credential_manager
|
||||
.insert_coconut_credential(
|
||||
@@ -78,6 +79,7 @@ impl Storage for PersistentStorage {
|
||||
serial_number,
|
||||
binding_number,
|
||||
signature,
|
||||
epoch_id,
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -9,5 +9,6 @@ pub struct CoconutCredential {
|
||||
pub serial_number: String,
|
||||
pub binding_number: String,
|
||||
pub signature: String,
|
||||
pub epoch_id: String,
|
||||
pub consumed: bool,
|
||||
}
|
||||
|
||||
@@ -12,7 +12,12 @@ pub trait Storage: Send + Sync {
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `voucher_value`: How much bandwidth is in the credential.
|
||||
/// * `voucher_info`: What type of credential it is.
|
||||
/// * `serial_number`: Serial number of the credential.
|
||||
/// * `binding_number`: Binding number of the credential.
|
||||
/// * `signature`: Coconut credential in the form of a signature.
|
||||
/// * `epoch_id`: The epoch when it was signed.
|
||||
async fn insert_coconut_credential(
|
||||
&self,
|
||||
voucher_value: String,
|
||||
@@ -20,6 +25,7 @@ pub trait Storage: Send + Sync {
|
||||
serial_number: String,
|
||||
binding_number: String,
|
||||
signature: String,
|
||||
epoch_id: String,
|
||||
) -> Result<(), StorageError>;
|
||||
|
||||
/// Tries to retrieve one of the stored, unused credentials.
|
||||
|
||||
@@ -168,6 +168,7 @@ pub fn prepare_for_spending(
|
||||
voucher_info: String,
|
||||
serial_number: PrivateAttribute,
|
||||
binding_number: PrivateAttribute,
|
||||
epoch_id: u64,
|
||||
signature: &Signature,
|
||||
verification_key: &VerificationKey,
|
||||
) -> Result<Credential, Error> {
|
||||
@@ -179,6 +180,7 @@ pub fn prepare_for_spending(
|
||||
voucher_info,
|
||||
serial_number,
|
||||
binding_number,
|
||||
epoch_id,
|
||||
signature,
|
||||
verification_key,
|
||||
)
|
||||
|
||||
@@ -137,12 +137,14 @@ pub async fn obtain_aggregate_signature(
|
||||
}
|
||||
|
||||
// TODO: better type flow
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn prepare_credential_for_spending(
|
||||
params: &Parameters,
|
||||
voucher_value: u64,
|
||||
voucher_info: String,
|
||||
serial_number: Attribute,
|
||||
binding_number: Attribute,
|
||||
epoch_id: u64,
|
||||
signature: &Signature,
|
||||
verification_key: &VerificationKey,
|
||||
) -> Result<Credential, Error> {
|
||||
@@ -159,5 +161,6 @@ pub fn prepare_credential_for_spending(
|
||||
theta,
|
||||
voucher_value,
|
||||
voucher_info,
|
||||
epoch_id,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ pub struct NymContracts {
|
||||
pub vesting_contract_address: Option<String>,
|
||||
pub bandwidth_claim_contract_address: Option<String>,
|
||||
pub coconut_bandwidth_contract_address: Option<String>,
|
||||
pub group_contract_address: Option<String>,
|
||||
pub multisig_contract_address: Option<String>,
|
||||
pub coconut_dkg_contract_address: Option<String>,
|
||||
}
|
||||
@@ -95,6 +96,9 @@ impl NymNetworkDetails {
|
||||
var(var_names::COCONUT_BANDWIDTH_CONTRACT_ADDRESS)
|
||||
.expect("coconut bandwidth contract not set"),
|
||||
))
|
||||
.with_group_contract(Some(
|
||||
var(var_names::GROUP_CONTRACT_ADDRESS).expect("group contract not set"),
|
||||
))
|
||||
.with_multisig_contract(Some(
|
||||
var(var_names::MULTISIG_CONTRACT_ADDRESS).expect("multisig contract not set"),
|
||||
))
|
||||
@@ -125,6 +129,7 @@ impl NymNetworkDetails {
|
||||
coconut_bandwidth_contract_address: parse_optional_str(
|
||||
mainnet::COCONUT_BANDWIDTH_CONTRACT_ADDRESS,
|
||||
),
|
||||
group_contract_address: parse_optional_str(mainnet::GROUP_CONTRACT_ADDRESS),
|
||||
multisig_contract_address: parse_optional_str(mainnet::MULTISIG_CONTRACT_ADDRESS),
|
||||
coconut_dkg_contract_address: parse_optional_str(
|
||||
mainnet::COCONUT_DKG_CONTRACT_ADDRESS,
|
||||
@@ -193,6 +198,12 @@ impl NymNetworkDetails {
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_group_contract<S: Into<String>>(mut self, contract: Option<S>) -> Self {
|
||||
self.contracts.multisig_contract_address = contract.map(Into::into);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_multisig_contract<S: Into<String>>(mut self, contract: Option<S>) -> Self {
|
||||
self.contracts.multisig_contract_address = contract.map(Into::into);
|
||||
|
||||
@@ -17,6 +17,7 @@ pub(crate) const BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str =
|
||||
"n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0";
|
||||
pub(crate) const COCONUT_BANDWIDTH_CONTRACT_ADDRESS: &str =
|
||||
"n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0";
|
||||
pub(crate) const GROUP_CONTRACT_ADDRESS: &str = "n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0";
|
||||
pub(crate) const MULTISIG_CONTRACT_ADDRESS: &str = "n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0";
|
||||
pub(crate) const COCONUT_DKG_CONTRACT_ADDRESS: &str = "n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0";
|
||||
pub(crate) const _ETH_CONTRACT_ADDRESS: [u8; 20] =
|
||||
@@ -81,6 +82,7 @@ pub fn export_to_env() {
|
||||
var_names::COCONUT_BANDWIDTH_CONTRACT_ADDRESS,
|
||||
COCONUT_BANDWIDTH_CONTRACT_ADDRESS,
|
||||
);
|
||||
set_var_to_default(var_names::GROUP_CONTRACT_ADDRESS, GROUP_CONTRACT_ADDRESS);
|
||||
set_var_to_default(
|
||||
var_names::MULTISIG_CONTRACT_ADDRESS,
|
||||
MULTISIG_CONTRACT_ADDRESS,
|
||||
@@ -125,6 +127,7 @@ pub fn export_to_env_if_not_set() {
|
||||
var_names::COCONUT_BANDWIDTH_CONTRACT_ADDRESS,
|
||||
COCONUT_BANDWIDTH_CONTRACT_ADDRESS,
|
||||
);
|
||||
set_var_conditionally_to_default(var_names::GROUP_CONTRACT_ADDRESS, GROUP_CONTRACT_ADDRESS);
|
||||
set_var_conditionally_to_default(
|
||||
var_names::MULTISIG_CONTRACT_ADDRESS,
|
||||
MULTISIG_CONTRACT_ADDRESS,
|
||||
|
||||
@@ -14,6 +14,7 @@ pub const MIXNET_CONTRACT_ADDRESS: &str = "MIXNET_CONTRACT_ADDRESS";
|
||||
pub const VESTING_CONTRACT_ADDRESS: &str = "VESTING_CONTRACT_ADDRESS";
|
||||
pub const BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str = "BANDWIDTH_CLAIM_CONTRACT_ADDRESS";
|
||||
pub const COCONUT_BANDWIDTH_CONTRACT_ADDRESS: &str = "COCONUT_BANDWIDTH_CONTRACT_ADDRESS";
|
||||
pub const GROUP_CONTRACT_ADDRESS: &str = "GROUP_CONTRACT_ADDRESS";
|
||||
pub const MULTISIG_CONTRACT_ADDRESS: &str = "MULTISIG_CONTRACT_ADDRESS";
|
||||
pub const COCONUT_DKG_CONTRACT_ADDRESS: &str = "COCONUT_DKG_CONTRACT_ADDRESS";
|
||||
pub const REWARDING_VALIDATOR_ADDRESS: &str = "REWARDING_VALIDATOR_ADDRESS";
|
||||
|
||||
@@ -89,6 +89,9 @@ pub fn theta_from_keys_and_attributes(
|
||||
}
|
||||
|
||||
pub fn transpose_matrix<T: Debug>(matrix: Vec<Vec<T>>) -> Vec<Vec<T>> {
|
||||
if matrix.is_empty() {
|
||||
return vec![];
|
||||
}
|
||||
let len = matrix[0].len();
|
||||
let mut iters: Vec<_> = matrix.into_iter().map(|d| d.into_iter()).collect();
|
||||
(0..len)
|
||||
|
||||
@@ -23,4 +23,5 @@ thiserror = "1.0.23"
|
||||
|
||||
[dev-dependencies]
|
||||
cw-multi-test = { version = "0.13.4" }
|
||||
cw4-group = { path = "../multisig/cw4-group" }
|
||||
cw4-group = { path = "../multisig/cw4-group" }
|
||||
group-contract-common = { path = "../../common/cosmwasm-smart-contracts/group-contract" }
|
||||
@@ -3,3 +3,6 @@
|
||||
|
||||
// Wait time for the verification to take place (currently 24h)
|
||||
pub(crate) const BLOCK_TIME_FOR_VERIFICATION_SECS: u64 = 86400;
|
||||
|
||||
pub(crate) const VK_SHARES_PK_NAMESPACE: &str = "vksp";
|
||||
pub(crate) const VK_SHARES_EPOCH_ID_IDX_NAMESPACE: &str = "vkse";
|
||||
|
||||
@@ -9,7 +9,7 @@ use crate::dealings::queries::query_dealings_paged;
|
||||
use crate::dealings::transactions::try_commit_dealings;
|
||||
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::epoch_state::transactions::{advance_epoch_state, try_surpassed_threshold};
|
||||
use crate::error::ContractError;
|
||||
use crate::state::{State, MULTISIG, STATE};
|
||||
use crate::verification_key_shares::queries::query_vk_shares_paged;
|
||||
@@ -54,6 +54,7 @@ pub fn instantiate(
|
||||
deps.storage,
|
||||
&Epoch::new(
|
||||
EpochState::default(),
|
||||
0,
|
||||
msg.time_configuration.unwrap_or_default(),
|
||||
env.block.time,
|
||||
),
|
||||
@@ -84,6 +85,7 @@ pub fn execute(
|
||||
ExecuteMsg::VerifyVerificationKeyShare { owner } => {
|
||||
try_verify_verification_key_share(deps, info, owner)
|
||||
}
|
||||
ExecuteMsg::SurpassedThreshold {} => try_surpassed_threshold(deps, env),
|
||||
ExecuteMsg::AdvanceEpochState {} => advance_epoch_state(deps, env),
|
||||
}
|
||||
}
|
||||
@@ -109,9 +111,11 @@ pub fn query(deps: Deps<'_>, _env: Env, msg: QueryMsg) -> Result<QueryResponse,
|
||||
limit,
|
||||
start_after,
|
||||
} => to_binary(&query_dealings_paged(deps, idx, start_after, limit)?)?,
|
||||
QueryMsg::GetVerificationKeys { limit, start_after } => {
|
||||
to_binary(&query_vk_shares_paged(deps, start_after, limit)?)?
|
||||
}
|
||||
QueryMsg::GetVerificationKeys {
|
||||
epoch_id,
|
||||
limit,
|
||||
start_after,
|
||||
} => to_binary(&query_vk_shares_paged(deps, epoch_id, start_after, limit)?)?,
|
||||
};
|
||||
|
||||
Ok(response)
|
||||
@@ -132,8 +136,8 @@ mod tests {
|
||||
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
|
||||
use cosmwasm_std::{coins, Addr};
|
||||
use cw4::Member;
|
||||
use cw4_group::msg::InstantiateMsg as GroupInstantiateMsg;
|
||||
use cw_multi_test::{App, AppBuilder, AppResponse, ContractWrapper, Executor};
|
||||
use group_contract_common::msg::InstantiateMsg as GroupInstantiateMsg;
|
||||
|
||||
fn instantiate_with_group(app: &mut App, members: &[Addr]) -> Addr {
|
||||
let group_code_id = app.store_code(Box::new(ContractWrapper::new(
|
||||
|
||||
@@ -1,11 +1,49 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::dealers::storage::current_dealers;
|
||||
use crate::dealers::storage::{current_dealers, past_dealers};
|
||||
use crate::dealings::storage::DEALINGS_BYTES;
|
||||
use crate::epoch_state::storage::{CURRENT_EPOCH, THRESHOLD};
|
||||
use crate::epoch_state::utils::check_epoch_state;
|
||||
use crate::error::ContractError;
|
||||
use crate::state::STATE;
|
||||
use coconut_dkg_common::types::{Epoch, EpochState};
|
||||
use cosmwasm_std::{DepsMut, Env, Order, Response};
|
||||
use cosmwasm_std::{DepsMut, Env, Order, Response, Storage};
|
||||
|
||||
fn reset_epoch_state(storage: &mut dyn Storage) -> Result<(), ContractError> {
|
||||
THRESHOLD.remove(storage);
|
||||
let dealers: Vec<_> = current_dealers()
|
||||
.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 {
|
||||
dealings.remove(storage, &details.address);
|
||||
}
|
||||
current_dealers().remove(storage, &dealer_addr)?;
|
||||
past_dealers().save(storage, &dealer_addr, &details)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn dealers_still_active(deps: &DepsMut<'_>) -> Result<usize, ContractError> {
|
||||
let state = STATE.load(deps.storage)?;
|
||||
let mut still_active = 0;
|
||||
for dealer_addr in current_dealers()
|
||||
.keys(deps.storage, None, None, Order::Ascending)
|
||||
.flatten()
|
||||
{
|
||||
if state
|
||||
.group_addr
|
||||
.is_voting_member(&deps.querier, &dealer_addr, None)?
|
||||
.is_some()
|
||||
{
|
||||
still_active += 1;
|
||||
}
|
||||
}
|
||||
Ok(still_active)
|
||||
}
|
||||
|
||||
pub(crate) fn advance_epoch_state(deps: DepsMut<'_>, env: Env) -> Result<Response, ContractError> {
|
||||
let epoch = CURRENT_EPOCH.load(deps.storage)?;
|
||||
@@ -18,24 +56,71 @@ pub(crate) fn advance_epoch_state(deps: DepsMut<'_>, env: Env) -> Result<Respons
|
||||
));
|
||||
}
|
||||
|
||||
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(),
|
||||
epoch.time_configuration,
|
||||
let current_epoch = CURRENT_EPOCH.load(deps.storage)?;
|
||||
let next_epoch = if let Some(state) = current_epoch.state.next() {
|
||||
// We are during DKG process
|
||||
if state == EpochState::DealingExchange {
|
||||
let current_dealer_count = current_dealers()
|
||||
.keys(deps.storage, None, None, Order::Ascending)
|
||||
.count();
|
||||
// note: ceiling in integer division can be achieved via q = (x + y - 1) / y;
|
||||
let threshold = (2 * current_dealer_count as u64 + 3 - 1) / 3;
|
||||
THRESHOLD.save(deps.storage, &threshold)?;
|
||||
}
|
||||
Epoch::new(
|
||||
state,
|
||||
current_epoch.epoch_id,
|
||||
current_epoch.time_configuration,
|
||||
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();
|
||||
// note: ceiling in integer division can be achieved via q = (x + y - 1) / y;
|
||||
let threshold = (2 * current_dealer_count as u64 + 3 - 1) / 3;
|
||||
THRESHOLD.save(deps.storage, &threshold)?;
|
||||
)
|
||||
} else if dealers_still_active(&deps)?
|
||||
== STATE
|
||||
.load(deps.storage)?
|
||||
.group_addr
|
||||
.list_members(&deps.querier, None, None)?
|
||||
.len()
|
||||
{
|
||||
// The dealer set hasn't changed, so we only extend the finish timestamp
|
||||
Epoch::new(
|
||||
current_epoch.state,
|
||||
current_epoch.epoch_id,
|
||||
current_epoch.time_configuration,
|
||||
env.block.time,
|
||||
)
|
||||
} else {
|
||||
// Dealer set changed, we need to redo DKG from scratch
|
||||
reset_epoch_state(deps.storage)?;
|
||||
Epoch::new(
|
||||
EpochState::default(),
|
||||
current_epoch.epoch_id + 1,
|
||||
current_epoch.time_configuration,
|
||||
env.block.time,
|
||||
)
|
||||
};
|
||||
CURRENT_EPOCH.save(deps.storage, &next_epoch)?;
|
||||
|
||||
Ok(Response::default())
|
||||
}
|
||||
|
||||
pub(crate) fn try_surpassed_threshold(
|
||||
deps: DepsMut<'_>,
|
||||
env: Env,
|
||||
) -> Result<Response, ContractError> {
|
||||
check_epoch_state(deps.storage, EpochState::InProgress)?;
|
||||
|
||||
let threshold = THRESHOLD.load(deps.storage)?;
|
||||
if dealers_still_active(&deps)? < threshold as usize {
|
||||
reset_epoch_state(deps.storage)?;
|
||||
CURRENT_EPOCH.update::<_, ContractError>(deps.storage, |epoch| {
|
||||
Ok(Epoch::new(
|
||||
EpochState::default(),
|
||||
epoch.epoch_id + 1,
|
||||
epoch.time_configuration,
|
||||
env.block.time,
|
||||
))
|
||||
})?;
|
||||
}
|
||||
|
||||
Ok(Response::default())
|
||||
}
|
||||
|
||||
@@ -186,17 +271,6 @@ pub(crate) mod tests {
|
||||
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(epoch.time_configuration.public_key_submission_time_secs)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -37,7 +37,7 @@ pub(crate) mod test {
|
||||
CURRENT_EPOCH
|
||||
.save(
|
||||
deps.as_mut().storage,
|
||||
&Epoch::new(fixed_state, TimeConfiguration::default(), env.block.time),
|
||||
&Epoch::new(fixed_state, 0, TimeConfiguration::default(), env.block.time),
|
||||
)
|
||||
.unwrap();
|
||||
for against_state in EpochState::default().all_until(EpochState::InProgress) {
|
||||
|
||||
@@ -14,6 +14,7 @@ pub fn vk_share_fixture(index: u64) -> ContractVKShare {
|
||||
announce_address: format!("localhost:{}", index),
|
||||
node_index: index,
|
||||
owner: Addr::unchecked(format!("owner{}", index)),
|
||||
epoch_id: 0,
|
||||
verified: index % 2 == 0,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,15 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::verification_key_shares::storage;
|
||||
use crate::verification_key_shares::storage::VK_SHARES;
|
||||
use crate::verification_key_shares::storage::vk_shares;
|
||||
use coconut_dkg_common::types::EpochId;
|
||||
use coconut_dkg_common::verification_key::PagedVKSharesResponse;
|
||||
use cosmwasm_std::{Deps, Order, StdResult};
|
||||
use cw_storage_plus::Bound;
|
||||
|
||||
pub fn query_vk_shares_paged(
|
||||
deps: Deps<'_>,
|
||||
epoch_id: EpochId,
|
||||
start_after: Option<String>,
|
||||
limit: Option<u32>,
|
||||
) -> StdResult<PagedVKSharesResponse> {
|
||||
@@ -20,9 +22,12 @@ pub fn query_vk_shares_paged(
|
||||
.map(|addr| deps.api.addr_validate(&addr))
|
||||
.transpose()?;
|
||||
|
||||
let start = addr.as_ref().map(Bound::exclusive);
|
||||
let start = addr.as_ref().map(|addr| Bound::exclusive((addr, epoch_id)));
|
||||
|
||||
let shares = VK_SHARES
|
||||
let shares = vk_shares()
|
||||
.idx
|
||||
.epoch_id
|
||||
.prefix(epoch_id)
|
||||
.range(deps.storage, start, None, Order::Ascending)
|
||||
.take(limit)
|
||||
.map(|res| res.map(|(_, share)| share))
|
||||
@@ -50,7 +55,7 @@ pub(crate) mod tests {
|
||||
#[test]
|
||||
fn vk_shares_empty_on_init() {
|
||||
let deps = init_contract();
|
||||
let response = query_vk_shares_paged(deps.as_ref(), None, Option::from(2)).unwrap();
|
||||
let response = query_vk_shares_paged(deps.as_ref(), 0, None, Option::from(2)).unwrap();
|
||||
assert_eq!(0, response.shares.len());
|
||||
}
|
||||
|
||||
@@ -61,12 +66,12 @@ pub(crate) mod tests {
|
||||
for n in 0..1000 {
|
||||
let vk_share = vk_share_fixture(n);
|
||||
let sender = Addr::unchecked(format!("owner{}", n));
|
||||
VK_SHARES
|
||||
.save(&mut deps.storage, &sender, &vk_share)
|
||||
vk_shares()
|
||||
.save(&mut deps.storage, (&sender, 0), &vk_share)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
let page1 = query_vk_shares_paged(deps.as_ref(), None, Option::from(limit)).unwrap();
|
||||
let page1 = query_vk_shares_paged(deps.as_ref(), 0, None, Option::from(limit)).unwrap();
|
||||
assert_eq!(limit, page1.shares.len() as u32);
|
||||
}
|
||||
|
||||
@@ -76,13 +81,13 @@ pub(crate) mod tests {
|
||||
for n in 0..1000 {
|
||||
let vk_share = vk_share_fixture(n);
|
||||
let sender = Addr::unchecked(format!("owner{}", n));
|
||||
VK_SHARES
|
||||
.save(&mut deps.storage, &sender, &vk_share)
|
||||
vk_shares()
|
||||
.save(&mut deps.storage, (&sender, 0), &vk_share)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// query without explicitly setting a limit
|
||||
let page1 = query_vk_shares_paged(deps.as_ref(), None, None).unwrap();
|
||||
let page1 = query_vk_shares_paged(deps.as_ref(), 0, None, None).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
VERIFICATION_KEY_SHARES_PAGE_DEFAULT_LIMIT,
|
||||
@@ -96,14 +101,15 @@ pub(crate) mod tests {
|
||||
for n in 0..1000 {
|
||||
let vk_share = vk_share_fixture(n);
|
||||
let sender = Addr::unchecked(format!("owner{}", n));
|
||||
VK_SHARES
|
||||
.save(&mut deps.storage, &sender, &vk_share)
|
||||
vk_shares()
|
||||
.save(&mut deps.storage, (&sender, 0), &vk_share)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// query with a crazily high limit in an attempt to use too many resources
|
||||
let crazy_limit = 1000 * VERIFICATION_KEY_SHARES_PAGE_MAX_LIMIT;
|
||||
let page1 = query_vk_shares_paged(deps.as_ref(), None, Option::from(crazy_limit)).unwrap();
|
||||
let page1 =
|
||||
query_vk_shares_paged(deps.as_ref(), 0, None, Option::from(crazy_limit)).unwrap();
|
||||
|
||||
// we default to a decent sized upper bound instead
|
||||
let expected_limit = VERIFICATION_KEY_SHARES_PAGE_MAX_LIMIT;
|
||||
@@ -116,12 +122,12 @@ pub(crate) mod tests {
|
||||
|
||||
let vk_share = vk_share_fixture(1);
|
||||
let sender = Addr::unchecked(format!("owner{}", 1));
|
||||
VK_SHARES
|
||||
.save(&mut deps.storage, &sender, &vk_share)
|
||||
vk_shares()
|
||||
.save(&mut deps.storage, (&sender, 0), &vk_share)
|
||||
.unwrap();
|
||||
|
||||
let per_page = 2;
|
||||
let page1 = query_vk_shares_paged(deps.as_ref(), None, Option::from(per_page)).unwrap();
|
||||
let page1 = query_vk_shares_paged(deps.as_ref(), 0, None, Option::from(per_page)).unwrap();
|
||||
|
||||
// page should have 1 result on it
|
||||
assert_eq!(1, page1.shares.len());
|
||||
@@ -129,28 +135,29 @@ pub(crate) mod tests {
|
||||
// save another
|
||||
let vk_share = vk_share_fixture(2);
|
||||
let sender = Addr::unchecked(format!("owner{}", 2));
|
||||
VK_SHARES
|
||||
.save(&mut deps.storage, &sender, &vk_share)
|
||||
vk_shares()
|
||||
.save(&mut deps.storage, (&sender, 0), &vk_share)
|
||||
.unwrap();
|
||||
|
||||
// page1 should have 2 results on it
|
||||
let page1 = query_vk_shares_paged(deps.as_ref(), None, Option::from(per_page)).unwrap();
|
||||
let page1 = query_vk_shares_paged(deps.as_ref(), 0, None, Option::from(per_page)).unwrap();
|
||||
assert_eq!(2, page1.shares.len());
|
||||
|
||||
let vk_share = vk_share_fixture(3);
|
||||
let sender = Addr::unchecked(format!("owner{}", 3));
|
||||
VK_SHARES
|
||||
.save(&mut deps.storage, &sender, &vk_share)
|
||||
vk_shares()
|
||||
.save(&mut deps.storage, (&sender, 0), &vk_share)
|
||||
.unwrap();
|
||||
|
||||
// page1 still has 2 results
|
||||
let page1 = query_vk_shares_paged(deps.as_ref(), None, Option::from(per_page)).unwrap();
|
||||
let page1 = query_vk_shares_paged(deps.as_ref(), 0, None, Option::from(per_page)).unwrap();
|
||||
assert_eq!(2, page1.shares.len());
|
||||
|
||||
// retrieving the next page should start after the last key on this page
|
||||
let start_after = page1.start_next_after.unwrap();
|
||||
let page2 = query_vk_shares_paged(
|
||||
deps.as_ref(),
|
||||
0,
|
||||
Option::from(start_after.to_string()),
|
||||
Option::from(per_page),
|
||||
)
|
||||
@@ -160,12 +167,13 @@ pub(crate) mod tests {
|
||||
|
||||
let vk_share = vk_share_fixture(4);
|
||||
let sender = Addr::unchecked(format!("owner{}", 4));
|
||||
VK_SHARES
|
||||
.save(&mut deps.storage, &sender, &vk_share)
|
||||
vk_shares()
|
||||
.save(&mut deps.storage, (&sender, 0), &vk_share)
|
||||
.unwrap();
|
||||
|
||||
let page2 = query_vk_shares_paged(
|
||||
deps.as_ref(),
|
||||
0,
|
||||
Option::from(start_after.to_string()),
|
||||
Option::from(per_page),
|
||||
)
|
||||
|
||||
@@ -3,13 +3,35 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::constants::{VK_SHARES_EPOCH_ID_IDX_NAMESPACE, VK_SHARES_PK_NAMESPACE};
|
||||
use coconut_dkg_common::types::EpochId;
|
||||
use coconut_dkg_common::verification_key::ContractVKShare;
|
||||
use cosmwasm_std::Addr;
|
||||
use cw_storage_plus::Map;
|
||||
use cw_storage_plus::{Index, IndexList, IndexedMap, MultiIndex};
|
||||
|
||||
pub(crate) const VERIFICATION_KEY_SHARES_PAGE_MAX_LIMIT: u32 = 75;
|
||||
pub(crate) const VERIFICATION_KEY_SHARES_PAGE_DEFAULT_LIMIT: u32 = 50;
|
||||
|
||||
type VKShareKey<'a> = &'a Addr;
|
||||
type VKShareKey<'a> = (&'a Addr, EpochId);
|
||||
|
||||
pub(crate) const VK_SHARES: Map<'_, VKShareKey<'_>, ContractVKShare> = Map::new("vks");
|
||||
pub(crate) struct VkShareIndex<'a> {
|
||||
pub(crate) epoch_id: MultiIndex<'a, EpochId, ContractVKShare, VKShareKey<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> IndexList<ContractVKShare> for VkShareIndex<'a> {
|
||||
fn get_indexes(&'_ self) -> Box<dyn Iterator<Item = &'_ dyn Index<ContractVKShare>> + '_> {
|
||||
let v: Vec<&dyn Index<ContractVKShare>> = vec![&self.epoch_id];
|
||||
Box::new(v.into_iter())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn vk_shares<'a>() -> IndexedMap<'a, VKShareKey<'a>, ContractVKShare, VkShareIndex<'a>> {
|
||||
let indexes = VkShareIndex {
|
||||
epoch_id: MultiIndex::new(
|
||||
|d| d.epoch_id,
|
||||
VK_SHARES_PK_NAMESPACE,
|
||||
VK_SHARES_EPOCH_ID_IDX_NAMESPACE,
|
||||
),
|
||||
};
|
||||
IndexedMap::new(VK_SHARES_PK_NAMESPACE, indexes)
|
||||
}
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
|
||||
use crate::constants::BLOCK_TIME_FOR_VERIFICATION_SECS;
|
||||
use crate::dealers::storage as dealers_storage;
|
||||
use crate::epoch_state::storage::CURRENT_EPOCH;
|
||||
use crate::epoch_state::utils::check_epoch_state;
|
||||
use crate::error::ContractError;
|
||||
use crate::state::{MULTISIG, STATE};
|
||||
use crate::verification_key_shares::storage::VK_SHARES;
|
||||
use crate::verification_key_shares::storage::vk_shares;
|
||||
use coconut_dkg_common::types::EpochState;
|
||||
use coconut_dkg_common::verification_key::{to_cosmos_msg, ContractVKShare, VerificationKeyShare};
|
||||
use cosmwasm_std::{Addr, DepsMut, Env, MessageInfo, Response};
|
||||
@@ -22,7 +23,11 @@ pub fn try_commit_verification_key_share(
|
||||
let details = dealers_storage::current_dealers()
|
||||
.load(deps.storage, &info.sender)
|
||||
.map_err(|_| ContractError::NotADealer)?;
|
||||
if VK_SHARES.may_load(deps.storage, &info.sender)?.is_some() {
|
||||
let epoch_id = CURRENT_EPOCH.load(deps.storage)?.epoch_id;
|
||||
if vk_shares()
|
||||
.may_load(deps.storage, (&info.sender, epoch_id))?
|
||||
.is_some()
|
||||
{
|
||||
return Err(ContractError::AlreadyCommitted {
|
||||
commitment: String::from("verification key share"),
|
||||
});
|
||||
@@ -33,9 +38,10 @@ pub fn try_commit_verification_key_share(
|
||||
node_index: details.assigned_index,
|
||||
announce_address: details.announce_address,
|
||||
owner: info.sender.clone(),
|
||||
epoch_id: CURRENT_EPOCH.load(deps.storage)?.epoch_id,
|
||||
verified: false,
|
||||
};
|
||||
VK_SHARES.save(deps.storage, &info.sender, &data)?;
|
||||
vk_shares().save(deps.storage, (&info.sender, epoch_id), &data)?;
|
||||
|
||||
let msg = to_cosmos_msg(
|
||||
info.sender,
|
||||
@@ -55,8 +61,9 @@ pub fn try_verify_verification_key_share(
|
||||
owner: Addr,
|
||||
) -> Result<Response, ContractError> {
|
||||
check_epoch_state(deps.storage, EpochState::VerificationKeyFinalization)?;
|
||||
let epoch_id = CURRENT_EPOCH.load(deps.storage)?.epoch_id;
|
||||
MULTISIG.assert_admin(deps.as_ref(), &info.sender)?;
|
||||
VK_SHARES.update(deps.storage, &owner, |vk_share| {
|
||||
vk_shares().update(deps.storage, (&owner, epoch_id), |vk_share| {
|
||||
vk_share
|
||||
.map(|mut share| {
|
||||
share.verified = true;
|
||||
|
||||
@@ -10,6 +10,7 @@ bandwidth-claim-contract = { path = "../../common/bandwidth-claim-contract" }
|
||||
coconut-bandwidth-contract-common = { path = "../../common/cosmwasm-smart-contracts/coconut-bandwidth-contract" }
|
||||
coconut-dkg-common = { path = "../../common/cosmwasm-smart-contracts/coconut-dkg" }
|
||||
multisig-contract-common = { path = "../../common/cosmwasm-smart-contracts/multisig-contract" }
|
||||
group-contract-common = { path = "../../common/cosmwasm-smart-contracts/group-contract" }
|
||||
|
||||
cosmwasm-std = "1.0.0"
|
||||
cosmwasm-storage = "1.0.0"
|
||||
|
||||
@@ -7,9 +7,9 @@ use coconut_bandwidth_contract_common::{
|
||||
spend_credential::SpendCredentialData,
|
||||
};
|
||||
use cosmwasm_std::{coins, Addr, Coin, Decimal};
|
||||
use cw4_group::msg::InstantiateMsg as GroupInstantiateMsg;
|
||||
use cw_multi_test::Executor;
|
||||
use cw_utils::{Duration, Threshold};
|
||||
use group_contract_common::msg::InstantiateMsg as GroupInstantiateMsg;
|
||||
use multisig_contract_common::msg::InstantiateMsg as MultisigInstantiateMsg;
|
||||
|
||||
pub const TEST_COIN_DENOM: &str = "unym";
|
||||
|
||||
@@ -15,9 +15,9 @@ use coconut_dkg_common::msg::QueryMsg::GetVerificationKeys;
|
||||
use coconut_dkg_common::verification_key::PagedVKSharesResponse;
|
||||
use cosmwasm_std::{coins, Addr, Decimal};
|
||||
use cw4::Member;
|
||||
use cw4_group::msg::InstantiateMsg as GroupInstantiateMsg;
|
||||
use cw_multi_test::Executor;
|
||||
use cw_utils::{Duration, Threshold};
|
||||
use group_contract_common::msg::InstantiateMsg as GroupInstantiateMsg;
|
||||
use multisig_contract_common::msg::ExecuteMsg::{Execute, Vote};
|
||||
use multisig_contract_common::msg::InstantiateMsg as MultisigInstantiateMsg;
|
||||
|
||||
@@ -152,6 +152,7 @@ fn dkg_proposal() {
|
||||
.query_wasm_smart(
|
||||
coconut_dkg_contract_addr.clone(),
|
||||
&GetVerificationKeys {
|
||||
epoch_id: 0,
|
||||
limit: None,
|
||||
start_after: None,
|
||||
},
|
||||
@@ -199,6 +200,7 @@ fn dkg_proposal() {
|
||||
.query_wasm_smart(
|
||||
coconut_dkg_contract_addr,
|
||||
&GetVerificationKeys {
|
||||
epoch_id: 0,
|
||||
limit: None,
|
||||
start_after: None,
|
||||
},
|
||||
|
||||
@@ -28,6 +28,7 @@ schemars = "0.8.1"
|
||||
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
|
||||
thiserror = { version = "1.0.23" }
|
||||
|
||||
group-contract-common = { path = "../../../common/cosmwasm-smart-contracts/group-contract" }
|
||||
multisig-contract-common = { path= "../../../common/cosmwasm-smart-contracts/multisig-contract" }
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -502,7 +502,7 @@ mod tests {
|
||||
// uploads code and returns address of group contract
|
||||
fn instantiate_group(app: &mut App, members: Vec<Member>) -> Addr {
|
||||
let group_id = app.store_code(contract_group());
|
||||
let msg = cw4_group::msg::InstantiateMsg {
|
||||
let msg = group_contract_common::msg::InstantiateMsg {
|
||||
admin: Some(OWNER.into()),
|
||||
members,
|
||||
};
|
||||
@@ -1410,7 +1410,7 @@ mod tests {
|
||||
// adds NEWBIE with 2 power -> with snapshot, invalid vote
|
||||
// removes VOTER3 -> with snapshot, can vote on proposal
|
||||
let newbie: &str = "newbie";
|
||||
let update_msg = cw4_group::msg::ExecuteMsg::UpdateMembers {
|
||||
let update_msg = group_contract_common::msg::ExecuteMsg::UpdateMembers {
|
||||
remove: vec![VOTER3.into()],
|
||||
add: vec![member(VOTER2, 21), member(newbie, 2)],
|
||||
};
|
||||
@@ -1623,7 +1623,7 @@ mod tests {
|
||||
|
||||
// admin changes the group (3 -> 0, 2 -> 9, 0 -> 29) - total = 56, require 29 to pass
|
||||
let newbie: &str = "newbie";
|
||||
let update_msg = cw4_group::msg::ExecuteMsg::UpdateMembers {
|
||||
let update_msg = group_contract_common::msg::ExecuteMsg::UpdateMembers {
|
||||
remove: vec![VOTER3.into()],
|
||||
add: vec![member(VOTER2, 9), member(newbie, 29)],
|
||||
};
|
||||
@@ -1702,7 +1702,7 @@ mod tests {
|
||||
|
||||
// admin changes the group (3 -> 0, 2 -> 9, 0 -> 28) - total = 55, require 28 to pass
|
||||
let newbie: &str = "newbie";
|
||||
let update_msg = cw4_group::msg::ExecuteMsg::UpdateMembers {
|
||||
let update_msg = group_contract_common::msg::ExecuteMsg::UpdateMembers {
|
||||
remove: vec![VOTER3.into()],
|
||||
add: vec![member(VOTER2, 9), member(newbie, 29)],
|
||||
};
|
||||
|
||||
@@ -24,6 +24,8 @@ crate-type = ["cdylib", "rlib"]
|
||||
library = []
|
||||
|
||||
[dependencies]
|
||||
group-contract-common = { path = "../../../common/cosmwasm-smart-contracts/group-contract" }
|
||||
|
||||
cw-utils = { version = "0.13.4" }
|
||||
cw2 = { version = "0.13.4" }
|
||||
cw4 = { version = "0.13.4" }
|
||||
|
||||
@@ -13,8 +13,8 @@ use cw_storage_plus::Bound;
|
||||
use cw_utils::maybe_addr;
|
||||
|
||||
use crate::error::ContractError;
|
||||
use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg};
|
||||
use crate::state::{ADMIN, HOOKS, MEMBERS, TOTAL};
|
||||
use group_contract_common::msg::{ExecuteMsg, InstantiateMsg, QueryMsg};
|
||||
|
||||
// version info for migration info
|
||||
const CONTRACT_NAME: &str = "crates.io:cw4-group";
|
||||
|
||||
@@ -5,7 +5,7 @@ use std::ops::Deref;
|
||||
use cosmwasm_std::{to_binary, Addr, CosmosMsg, StdResult, WasmMsg};
|
||||
use cw4::{Cw4Contract, Member};
|
||||
|
||||
use crate::msg::ExecuteMsg;
|
||||
use group_contract_common::msg::ExecuteMsg;
|
||||
|
||||
/// Cw4GroupContract is a wrapper around Cw4Contract that provides a lot of helpers
|
||||
/// for working with cw4-group contracts.
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
pub mod contract;
|
||||
pub mod error;
|
||||
pub mod helpers;
|
||||
pub mod msg;
|
||||
pub mod state;
|
||||
|
||||
pub use crate::error::ContractError;
|
||||
|
||||
+4
-1
@@ -13,9 +13,12 @@ MIXNET_CONTRACT_ADDRESS=n1xsml6tm6pnx8nsuz3a54cznh55g6nuwu9ug9t92ucjkq5ewp5w9syx
|
||||
VESTING_CONTRACT_ADDRESS=n1xr3rq8yvd7qplsw5yx90ftsr2zdhg4e9z60h5duusgxpv72hud3sjkxkav
|
||||
BANDWIDTH_CLAIM_CONTRACT_ADDRESS=n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0
|
||||
COCONUT_BANDWIDTH_CONTRACT_ADDRESS=n1lp5zex6685kd22agzskhqsylpnssxnweyuvsz4edr4p4ta92qf3q3dhmsx
|
||||
GROUP_CONTRACT_ADDRESS=n1rw8fw2mpcpzzq3jpa4e52ufawnmj5a4u68p35umvgskewuw0nlzsaa5w4m
|
||||
MULTISIG_CONTRACT_ADDRESS=n1rw8fw2mpcpzzq3jpa4e52ufawnmj5a4u68p35umvgskewuw0nlzsaa5w4m
|
||||
COCONUT_DKG_CONTRACT_ADDRESS=n15f5e6ffz33khfzaadaug9axjt5r38xfe84v9jvlhfs0y7mv9sxvs2xt0u6
|
||||
COCONUT_DKG_CONTRACT_ADDRESS=n1vwtgazgpancsfel04y7syc95ausmat47cjtldqzkdmx6phyrwx2qvkv32p
|
||||
REWARDING_VALIDATOR_ADDRESS=n1tfzd4qz3a45u8p4mr5zmzv66457uwjgcl05jdq
|
||||
STATISTICS_SERVICE_DOMAIN_ADDRESS="http://0.0.0.0"
|
||||
NYXD="http://127.0.0.1:26657"
|
||||
NYM_API="http://127.0.0.1:8000"
|
||||
|
||||
DKG_TIME_CONFIGURATION="600,300,300,60,60,1209600"
|
||||
|
||||
@@ -13,6 +13,7 @@ MIXNET_CONTRACT_ADDRESS=n17srjznxl9dvzdkpwpw24gg668wc73val88a6m5ajg6ankwvz9wtst0
|
||||
VESTING_CONTRACT_ADDRESS=n1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrq73f2nw
|
||||
BANDWIDTH_CLAIM_CONTRACT_ADDRESS=n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0
|
||||
COCONUT_BANDWIDTH_CONTRACT_ADDRESS=n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0
|
||||
GROUP_CONTRACT_ADDRESS=n1rw8fw2mpcpzzq3jpa4e52ufawnmj5a4u68p35umvgskewuw0nlzsaa5w4m
|
||||
MULTISIG_CONTRACT_ADDRESS=n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0
|
||||
COCONUT_DKG_CONTRACT_ADDRESS=n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0
|
||||
REWARDING_VALIDATOR_ADDRESS=n10yyd98e2tuwu0f7ypz9dy3hhjw7v772q6287gy
|
||||
|
||||
@@ -13,6 +13,7 @@ MIXNET_CONTRACT_ADDRESS=n14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sjy
|
||||
VESTING_CONTRACT_ADDRESS=n1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrq73f2nw
|
||||
BANDWIDTH_CLAIM_CONTRACT_ADDRESS=n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0
|
||||
COCONUT_BANDWIDTH_CONTRACT_ADDRESS=n12ckdkm3q7eytefs7rwu4ue3t9hxgvl9v08jddmtwgct2ve0pv50q0t8dlt
|
||||
GROUP_CONTRACT_ADDRESS=n1rw8fw2mpcpzzq3jpa4e52ufawnmj5a4u68p35umvgskewuw0nlzsaa5w4m
|
||||
MULTISIG_CONTRACT_ADDRESS=n14krxe8ukzagwhvec0rmteexu62w8k9kp9sra9ww6em2hnmzcukqsa0utc8
|
||||
COCONUT_DKG_CONTRACT_ADDRESS=n1rl5n6cxuz2hdy3f7d9hsnw8zn0zwwwr0r4dxfz7tktgpgkcnz9zshmvksc
|
||||
REWARDING_VALIDATOR_ADDRESS=n10yyd98e2tuwu0f7ypz9dy3hhjw7v772q6287gy
|
||||
|
||||
@@ -13,6 +13,7 @@ MIXNET_CONTRACT_ADDRESS=n1rjzps6qrmdqmf0xz4cn4x4rcmqeqzq6hnzqg4wcvd0r2lyasdq5sep
|
||||
VESTING_CONTRACT_ADDRESS=n1xr3rq8yvd7qplsw5yx90ftsr2zdhg4e9z60h5duusgxpv72hud3sjkxkav
|
||||
BANDWIDTH_CLAIM_CONTRACT_ADDRESS=n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0
|
||||
COCONUT_BANDWIDTH_CONTRACT_ADDRESS=n1ghd753shjuwexxywmgs4xz7x2q732vcn7ty4yw
|
||||
GROUP_CONTRACT_ADDRESS=n1rw8fw2mpcpzzq3jpa4e52ufawnmj5a4u68p35umvgskewuw0nlzsaa5w4m
|
||||
MULTISIG_CONTRACT_ADDRESS=n17p9rzwnnfxcjp32un9ug7yhhzgtkhvl988qccs
|
||||
COCONUT_DKG_CONTRACT_ADDRESS=n17p9rzwnnfxcjp32un9ug7yhhzgtkhvl988qccs
|
||||
REWARDING_VALIDATOR_ADDRESS=n1tfzd4qz3a45u8p4mr5zmzv66457uwjgcl05jdq
|
||||
|
||||
@@ -44,25 +44,4 @@ pub(crate) enum GatewayError {
|
||||
expected_prefix: String,
|
||||
actual_prefix: String,
|
||||
},
|
||||
|
||||
#[cfg(feature = "coconut")]
|
||||
#[error("could not obtain all coconut coconut verifiers details: {source}")]
|
||||
CoconutVerifiersQueryFailure {
|
||||
#[source]
|
||||
source: ValidatorClientError,
|
||||
},
|
||||
|
||||
#[cfg(feature = "coconut")]
|
||||
#[error("failed to aggregate coconut verification keys: {source}")]
|
||||
CoconutVerificationKeyAggregationFailure {
|
||||
#[source]
|
||||
source: credentials::error::Error,
|
||||
},
|
||||
|
||||
#[cfg(feature = "coconut")]
|
||||
#[error("failed to create coconut verifier: {source}")]
|
||||
CoconutVerifierCreationFailure {
|
||||
#[source]
|
||||
source: crate::node::client_handling::websocket::connection_handler::RequestHandlingError,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -67,6 +67,10 @@ pub(crate) enum RequestHandlingError {
|
||||
#[cfg(feature = "coconut")]
|
||||
#[error("Coconut interface error - {0}")]
|
||||
CoconutInterfaceError(#[from] coconut_interface::error::CoconutInterfaceError),
|
||||
|
||||
#[cfg(feature = "coconut")]
|
||||
#[error("Credential error - {0}")]
|
||||
CredentialError(#[from] credentials::error::Error),
|
||||
}
|
||||
|
||||
impl RequestHandlingError {
|
||||
@@ -208,12 +212,28 @@ where
|
||||
iv,
|
||||
)?;
|
||||
|
||||
if !credential.verify(
|
||||
self.inner
|
||||
.coconut_verifier
|
||||
.as_ref()
|
||||
.aggregated_verification_key(),
|
||||
) {
|
||||
// Get the latest coconut signers and their VK
|
||||
let credential_api_clients = self
|
||||
.inner
|
||||
.coconut_verifier
|
||||
.all_coconut_api_clients(*credential.epoch_id())
|
||||
.await?;
|
||||
let current_api_clients = self
|
||||
.inner
|
||||
.coconut_verifier
|
||||
.all_current_coconut_api_clients()
|
||||
.await?;
|
||||
if credential_api_clients.is_empty() || current_api_clients.is_empty() {
|
||||
return Err(RequestHandlingError::NotEnoughNymAPIs {
|
||||
received: 0,
|
||||
needed: 1,
|
||||
});
|
||||
}
|
||||
|
||||
let aggregated_verification_key =
|
||||
credentials::obtain_aggregate_verification_key(&credential_api_clients).await?;
|
||||
|
||||
if !credential.verify(&aggregated_verification_key) {
|
||||
return Err(RequestHandlingError::InvalidBandwidthCredential(
|
||||
String::from("credential failed to verify on gateway"),
|
||||
));
|
||||
@@ -221,7 +241,7 @@ where
|
||||
|
||||
self.inner
|
||||
.coconut_verifier
|
||||
.release_funds(&credential)
|
||||
.release_funds(current_api_clients, &credential)
|
||||
.await?;
|
||||
|
||||
let bandwidth = Bandwidth::from(credential);
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use coconut_interface::{Credential, VerificationKey};
|
||||
use coconut_interface::Credential;
|
||||
use log::*;
|
||||
use std::time::{Duration, SystemTime};
|
||||
use validator_client::nyxd::traits::DkgQueryClient;
|
||||
use validator_client::{
|
||||
nyxd::{
|
||||
cosmwasm_client::logs::{find_attribute, BANDWIDTH_PROPOSAL_ID},
|
||||
@@ -19,24 +20,12 @@ const ONE_HOUR_SEC: u64 = 3600;
|
||||
const MAX_FEEGRANT_UNYM: u128 = 10000;
|
||||
|
||||
pub(crate) struct CoconutVerifier {
|
||||
nym_api_clients: Vec<CoconutApiClient>,
|
||||
nyxd_client: Client<SigningNyxdClient>,
|
||||
mix_denom_base: String,
|
||||
aggregated_verification_key: VerificationKey,
|
||||
}
|
||||
|
||||
impl CoconutVerifier {
|
||||
pub fn new(
|
||||
api_clients: Vec<CoconutApiClient>,
|
||||
nyxd_client: Client<SigningNyxdClient>,
|
||||
aggregated_verification_key: VerificationKey,
|
||||
) -> Result<Self, RequestHandlingError> {
|
||||
if api_clients.is_empty() {
|
||||
return Err(RequestHandlingError::NotEnoughNymAPIs {
|
||||
received: 0,
|
||||
needed: 1,
|
||||
});
|
||||
}
|
||||
pub fn new(nyxd_client: Client<SigningNyxdClient>) -> Self {
|
||||
let mix_denom_base = nyxd_client
|
||||
.nyxd
|
||||
.current_chain_details()
|
||||
@@ -44,19 +33,31 @@ impl CoconutVerifier {
|
||||
.base
|
||||
.clone();
|
||||
|
||||
Ok(CoconutVerifier {
|
||||
nym_api_clients: api_clients,
|
||||
CoconutVerifier {
|
||||
nyxd_client,
|
||||
mix_denom_base,
|
||||
aggregated_verification_key,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn aggregated_verification_key(&self) -> &VerificationKey {
|
||||
&self.aggregated_verification_key
|
||||
pub async fn all_current_coconut_api_clients(
|
||||
&self,
|
||||
) -> Result<Vec<CoconutApiClient>, RequestHandlingError> {
|
||||
let epoch_id = self.nyxd_client.nyxd.get_current_epoch().await?.epoch_id;
|
||||
self.all_coconut_api_clients(epoch_id).await
|
||||
}
|
||||
|
||||
pub async fn release_funds(&self, credential: &Credential) -> Result<(), RequestHandlingError> {
|
||||
pub async fn all_coconut_api_clients(
|
||||
&self,
|
||||
epoch_id: u64,
|
||||
) -> Result<Vec<CoconutApiClient>, RequestHandlingError> {
|
||||
Ok(CoconutApiClient::all_coconut_api_clients(&self.nyxd_client, epoch_id).await?)
|
||||
}
|
||||
|
||||
pub async fn release_funds(
|
||||
&self,
|
||||
api_clients: Vec<CoconutApiClient>,
|
||||
credential: &Credential,
|
||||
) -> Result<(), RequestHandlingError> {
|
||||
// Use a custom multiplier for revoke, as the default one (1.3)
|
||||
// isn't enough
|
||||
let revoke_fee = Some(Fee::Auto(Some(1.5)));
|
||||
@@ -96,7 +97,7 @@ impl CoconutVerifier {
|
||||
proposal_id,
|
||||
self.nyxd_client.nyxd.address().clone(),
|
||||
);
|
||||
for client in self.nym_api_clients.iter() {
|
||||
for client in api_clients {
|
||||
self.nyxd_client
|
||||
.nyxd
|
||||
.grant_allowance(
|
||||
|
||||
@@ -14,9 +14,6 @@ use tokio_tungstenite::WebSocketStream;
|
||||
pub(crate) use self::authenticated::AuthenticatedHandler;
|
||||
pub(crate) use self::fresh::FreshHandler;
|
||||
|
||||
#[cfg(feature = "coconut")]
|
||||
pub(crate) use self::authenticated::RequestHandlingError;
|
||||
|
||||
mod authenticated;
|
||||
#[cfg(feature = "coconut")]
|
||||
pub(crate) mod coconut;
|
||||
|
||||
+2
-13
@@ -28,11 +28,9 @@ use task::{TaskClient, TaskManager};
|
||||
#[cfg(feature = "coconut")]
|
||||
use crate::node::client_handling::websocket::connection_handler::coconut::CoconutVerifier;
|
||||
#[cfg(feature = "coconut")]
|
||||
use credentials::coconut::utils::obtain_aggregate_verification_key;
|
||||
#[cfg(feature = "coconut")]
|
||||
use network_defaults::NymNetworkDetails;
|
||||
#[cfg(feature = "coconut")]
|
||||
use validator_client::{Client, CoconutApiClient};
|
||||
use validator_client::Client;
|
||||
|
||||
pub(crate) mod client_handling;
|
||||
pub(crate) mod mixnet_handling;
|
||||
@@ -321,16 +319,7 @@ where
|
||||
#[cfg(feature = "coconut")]
|
||||
let coconut_verifier = {
|
||||
let nyxd_client = self.random_nyxd_client();
|
||||
let api_clients = CoconutApiClient::all_coconut_api_clients(&nyxd_client)
|
||||
.await
|
||||
.map_err(|source| GatewayError::CoconutVerifiersQueryFailure { source })?;
|
||||
let validators_verification_key = obtain_aggregate_verification_key(&api_clients)
|
||||
.await
|
||||
.map_err(
|
||||
|source| GatewayError::CoconutVerificationKeyAggregationFailure { source },
|
||||
)?;
|
||||
CoconutVerifier::new(api_clients, nyxd_client, validators_verification_key)
|
||||
.map_err(|source| GatewayError::CoconutVerifierCreationFailure { source })?
|
||||
CoconutVerifier::new(nyxd_client)
|
||||
};
|
||||
|
||||
let mix_forwarding_channel = self.start_packet_forwarder(shutdown.subscribe());
|
||||
|
||||
@@ -76,6 +76,7 @@ credentials = { path = "../common/credentials", optional = true }
|
||||
crypto = { path = "../common/crypto" }
|
||||
logging = { path = "../common/logging"}
|
||||
cw3 = { version = "0.13.4", optional = true }
|
||||
cw4 = { version = "0.13.4", optional = true }
|
||||
dkg = { path = "../common/crypto/dkg", optional = true }
|
||||
gateway-client = { path = "../common/client-libs/gateway-client" }
|
||||
inclusion-probability = { path = "../common/inclusion-probability" }
|
||||
@@ -99,6 +100,7 @@ coconut = [
|
||||
"coconut-interface",
|
||||
"credentials",
|
||||
"cw3",
|
||||
"cw4",
|
||||
"gateway-client/coconut",
|
||||
"credentials/coconut",
|
||||
"nym-api-requests/coconut",
|
||||
|
||||
@@ -4,10 +4,11 @@
|
||||
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, Epoch};
|
||||
use coconut_dkg_common::types::{EncodedBTEPublicKeyWithProof, Epoch, EpochId};
|
||||
use coconut_dkg_common::verification_key::{ContractVKShare, VerificationKeyShare};
|
||||
use contracts_common::dealings::ContractSafeBytes;
|
||||
use cw3::ProposalResponse;
|
||||
use cw4::MemberResponse;
|
||||
use dkg::Threshold;
|
||||
use validator_client::nyxd::cosmwasm_client::types::ExecuteResult;
|
||||
use validator_client::nyxd::{AccountId, Fee, TxResponse};
|
||||
@@ -23,11 +24,12 @@ pub trait Client {
|
||||
blinded_serial_number: String,
|
||||
) -> Result<SpendCredentialResponse>;
|
||||
async fn get_current_epoch(&self) -> Result<Epoch>;
|
||||
async fn group_member(&self, addr: String) -> Result<MemberResponse>;
|
||||
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>>;
|
||||
async fn get_dealings(&self, idx: usize) -> Result<Vec<ContractDealing>>;
|
||||
async fn get_verification_key_shares(&self) -> Result<Vec<ContractVKShare>>;
|
||||
async fn get_verification_key_shares(&self, epoch_id: EpochId) -> Result<Vec<ContractVKShare>>;
|
||||
async fn vote_proposal(&self, proposal_id: u64, vote_yes: bool, fee: Option<Fee>)
|
||||
-> Result<()>;
|
||||
async fn execute_proposal(&self, proposal_id: u64) -> Result<()>;
|
||||
|
||||
@@ -3,13 +3,14 @@
|
||||
|
||||
use crate::coconut::error::Result;
|
||||
use crate::nyxd;
|
||||
use coconut_dkg_common::types::EpochId;
|
||||
use coconut_interface::VerificationKey;
|
||||
use credentials::coconut::utils::obtain_aggregate_verification_key;
|
||||
use validator_client::CoconutApiClient;
|
||||
|
||||
#[async_trait]
|
||||
pub trait APICommunicationChannel {
|
||||
async fn aggregated_verification_key(&self) -> Result<VerificationKey>;
|
||||
async fn aggregated_verification_key(&self, epoch_id: EpochId) -> Result<VerificationKey>;
|
||||
}
|
||||
|
||||
pub(crate) struct QueryCommunicationChannel {
|
||||
@@ -24,9 +25,10 @@ impl QueryCommunicationChannel {
|
||||
|
||||
#[async_trait]
|
||||
impl APICommunicationChannel for QueryCommunicationChannel {
|
||||
async fn aggregated_verification_key(&self) -> Result<VerificationKey> {
|
||||
async fn aggregated_verification_key(&self, epoch_id: EpochId) -> Result<VerificationKey> {
|
||||
let client = self.nyxd_client.0.read().await;
|
||||
let coconut_api_clients = CoconutApiClient::all_coconut_api_clients(&client).await?;
|
||||
let coconut_api_clients =
|
||||
CoconutApiClient::all_coconut_api_clients(&client, epoch_id).await?;
|
||||
let vk = obtain_aggregate_verification_key(&coconut_api_clients).await?;
|
||||
Ok(vk)
|
||||
}
|
||||
|
||||
@@ -4,10 +4,11 @@
|
||||
use crate::coconut::client::Client;
|
||||
use crate::coconut::error::CoconutError;
|
||||
use coconut_dkg_common::dealer::{ContractDealing, DealerDetails, DealerDetailsResponse};
|
||||
use coconut_dkg_common::types::{EncodedBTEPublicKeyWithProof, Epoch, NodeIndex};
|
||||
use coconut_dkg_common::types::{EncodedBTEPublicKeyWithProof, Epoch, EpochId, NodeIndex};
|
||||
use coconut_dkg_common::verification_key::{ContractVKShare, VerificationKeyShare};
|
||||
use contracts_common::dealings::ContractSafeBytes;
|
||||
use cw3::ProposalResponse;
|
||||
use cw4::MemberResponse;
|
||||
use dkg::Threshold;
|
||||
use validator_client::nyxd::cosmwasm_client::logs::{find_attribute, NODE_INDEX};
|
||||
use validator_client::nyxd::cosmwasm_client::types::ExecuteResult;
|
||||
@@ -31,7 +32,7 @@ impl DkgClient {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn _get_address(&self) -> AccountId {
|
||||
pub(crate) async fn get_address(&self) -> AccountId {
|
||||
self.inner.address().await
|
||||
}
|
||||
|
||||
@@ -46,6 +47,12 @@ impl DkgClient {
|
||||
ret
|
||||
}
|
||||
|
||||
pub(crate) async fn group_member(&self) -> Result<MemberResponse, CoconutError> {
|
||||
self.inner
|
||||
.group_member(self.get_address().await.to_string())
|
||||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn get_current_epoch_threshold(
|
||||
&self,
|
||||
) -> Result<Option<Threshold>, CoconutError> {
|
||||
@@ -78,8 +85,9 @@ impl DkgClient {
|
||||
|
||||
pub(crate) async fn get_verification_key_shares(
|
||||
&self,
|
||||
epoch_id: EpochId,
|
||||
) -> Result<Vec<ContractVKShare>, CoconutError> {
|
||||
self.inner.get_verification_key_shares().await
|
||||
self.inner.get_verification_key_shares(epoch_id).await
|
||||
}
|
||||
|
||||
pub(crate) async fn list_proposals(&self) -> Result<Vec<ProposalResponse>, CoconutError> {
|
||||
|
||||
@@ -61,7 +61,7 @@ impl<R: RngCore + Clone> DkgController<R> {
|
||||
config.secret_key_path(),
|
||||
config.verification_key_path(),
|
||||
)) {
|
||||
coconut_keypair.set(coconut_keypair_value).await;
|
||||
coconut_keypair.set(Some(coconut_keypair_value)).await;
|
||||
}
|
||||
let persistent_state =
|
||||
PersistentState::load_from_file(config.persistent_state_path()).unwrap_or_default();
|
||||
@@ -86,8 +86,19 @@ impl<R: RngCore + Clone> DkgController<R> {
|
||||
match self.dkg_client.get_current_epoch().await {
|
||||
Err(err) => warn!("Could not get current epoch state {err}"),
|
||||
Ok(epoch) => {
|
||||
if self
|
||||
.dkg_client
|
||||
.group_member()
|
||||
.await
|
||||
.map(|resp| resp.weight.is_none())
|
||||
.unwrap_or(true)
|
||||
{
|
||||
debug!("Not a member of the group, DKG won't be run");
|
||||
return;
|
||||
}
|
||||
if let Err(err) = self.state.is_consistent(epoch.state).await {
|
||||
error!("Epoch state is corrupted - {err}, the process should be terminated");
|
||||
return;
|
||||
}
|
||||
let ret = match epoch.state {
|
||||
EpochState::PublicKeySubmission => {
|
||||
@@ -115,7 +126,10 @@ impl<R: RngCore + Clone> DkgController<R> {
|
||||
verification_key_finalization(&self.dkg_client, &mut self.state).await
|
||||
}
|
||||
// Just wait, in case we need to redo dkg at some point
|
||||
EpochState::InProgress => Ok(()),
|
||||
EpochState::InProgress => {
|
||||
self.state.set_was_in_progress();
|
||||
Ok(())
|
||||
}
|
||||
};
|
||||
if let Err(err) = ret {
|
||||
warn!("Could not handle this iteration for the epoch state: {err}");
|
||||
@@ -132,7 +146,7 @@ impl<R: RngCore + Clone> DkgController<R> {
|
||||
{
|
||||
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");
|
||||
info!("DKG: Trying to advance the epoch");
|
||||
self.dkg_client.advance_epoch_state().await.ok();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,23 +4,31 @@
|
||||
use crate::coconut::dkg::client::DkgClient;
|
||||
use crate::coconut::dkg::state::State;
|
||||
use crate::coconut::error::CoconutError;
|
||||
use coconut_dkg_common::dealer::DealerType;
|
||||
|
||||
pub(crate) async fn public_key_submission(
|
||||
dkg_client: &DkgClient,
|
||||
state: &mut State,
|
||||
) -> Result<(), CoconutError> {
|
||||
if state.was_in_progress() {
|
||||
state.reset_persistent().await;
|
||||
}
|
||||
if state.node_index().is_some() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let bte_key = bs58::encode(&state.dkg_keypair().public_key().to_bytes()).into_string();
|
||||
let index = if let Some(details) = dkg_client
|
||||
.get_self_registered_dealer_details()
|
||||
.await?
|
||||
.details
|
||||
{
|
||||
let dealer_details = dkg_client.get_self_registered_dealer_details().await?;
|
||||
let index = if let Some(details) = dealer_details.details {
|
||||
if dealer_details.dealer_type == DealerType::Past {
|
||||
// If it was a dealer in a previous epoch, re-register it for this epoch
|
||||
dkg_client
|
||||
.register_dealer(bte_key, state.announce_address().to_string())
|
||||
.await?;
|
||||
}
|
||||
details.assigned_index
|
||||
} else {
|
||||
// First time registration
|
||||
dkg_client
|
||||
.register_dealer(bte_key, state.announce_address().to_string())
|
||||
.await?
|
||||
|
||||
@@ -170,6 +170,7 @@ pub(crate) struct PersistentState {
|
||||
proposal_id: Option<u64>,
|
||||
voted_vks: bool,
|
||||
executed_proposal: bool,
|
||||
was_in_progress: bool,
|
||||
}
|
||||
|
||||
impl From<&State> for PersistentState {
|
||||
@@ -183,6 +184,7 @@ impl From<&State> for PersistentState {
|
||||
proposal_id: s.proposal_id,
|
||||
voted_vks: s.voted_vks,
|
||||
executed_proposal: s.executed_proposal,
|
||||
was_in_progress: s.was_in_progress,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -211,6 +213,7 @@ pub(crate) struct State {
|
||||
proposal_id: Option<u64>,
|
||||
voted_vks: bool,
|
||||
executed_proposal: bool,
|
||||
was_in_progress: bool,
|
||||
}
|
||||
|
||||
impl State {
|
||||
@@ -234,9 +237,23 @@ impl State {
|
||||
proposal_id: persistent_state.proposal_id,
|
||||
voted_vks: persistent_state.voted_vks,
|
||||
executed_proposal: persistent_state.executed_proposal,
|
||||
was_in_progress: persistent_state.was_in_progress,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn reset_persistent(&mut self) {
|
||||
self.coconut_keypair.set(None).await;
|
||||
self.node_index = Default::default();
|
||||
self.dealers = Default::default();
|
||||
self.receiver_index = Default::default();
|
||||
self.threshold = Default::default();
|
||||
self.recovered_vks = Default::default();
|
||||
self.proposal_id = Default::default();
|
||||
self.voted_vks = Default::default();
|
||||
self.executed_proposal = Default::default();
|
||||
self.was_in_progress = Default::default();
|
||||
}
|
||||
|
||||
pub fn persistent_state_path(&self) -> PathBuf {
|
||||
self.persistent_state_path.clone()
|
||||
}
|
||||
@@ -299,12 +316,16 @@ impl State {
|
||||
self.executed_proposal
|
||||
}
|
||||
|
||||
pub fn was_in_progress(&self) -> bool {
|
||||
self.was_in_progress
|
||||
}
|
||||
|
||||
pub fn set_recovered_vks(&mut self, recovered_vks: Vec<RecoveredVerificationKeys>) {
|
||||
self.recovered_vks = recovered_vks;
|
||||
}
|
||||
|
||||
pub async fn set_coconut_keypair(&mut self, coconut_keypair: coconut_interface::KeyPair) {
|
||||
self.coconut_keypair.set(coconut_keypair).await
|
||||
self.coconut_keypair.set(Some(coconut_keypair)).await
|
||||
}
|
||||
|
||||
pub fn set_node_index(&mut self, node_index: Option<NodeIndex>) {
|
||||
@@ -349,6 +370,10 @@ impl State {
|
||||
self.executed_proposal = true;
|
||||
}
|
||||
|
||||
pub fn set_was_in_progress(&mut self) {
|
||||
self.was_in_progress = true;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn all_dealers(&self) -> &BTreeMap<Addr, Result<DkgParticipant, ComplaintReason>> {
|
||||
&self.dealers
|
||||
|
||||
@@ -177,7 +177,8 @@ pub(crate) async fn verification_key_validation(
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let vk_shares = dkg_client.get_verification_key_shares().await?;
|
||||
let epoch_id = dkg_client.get_current_epoch().await?.epoch_id;
|
||||
let vk_shares = dkg_client.get_verification_key_shares(epoch_id).await?;
|
||||
let proposal_ids = BTreeMap::from_iter(
|
||||
dkg_client
|
||||
.list_proposals()
|
||||
|
||||
@@ -20,8 +20,8 @@ impl KeyPair {
|
||||
self.inner.read().await
|
||||
}
|
||||
|
||||
pub async fn set(&self, keypair: coconut_interface::KeyPair) {
|
||||
pub async fn set(&self, keypair: Option<coconut_interface::KeyPair>) {
|
||||
let mut w_lock = self.inner.write().await;
|
||||
*w_lock = Some(keypair);
|
||||
*w_lock = keypair;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ use crate::support::storage::NymApiStorage;
|
||||
use coconut_bandwidth_contract_common::spend_credential::{
|
||||
funds_from_cosmos_msgs, SpendCredentialStatus,
|
||||
};
|
||||
use coconut_dkg_common::types::EpochId;
|
||||
use coconut_interface::KeyPair as CoconutKeyPair;
|
||||
use coconut_interface::{
|
||||
Attribute, BlindSignRequest, BlindedSignature, Parameters, VerificationKey,
|
||||
@@ -132,8 +133,10 @@ impl State {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn verification_key(&self) -> Result<VerificationKey> {
|
||||
self.comm_channel.aggregated_verification_key().await
|
||||
pub async fn verification_key(&self, epoch_id: EpochId) -> Result<VerificationKey> {
|
||||
self.comm_channel
|
||||
.aggregated_verification_key(epoch_id)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -284,7 +287,9 @@ pub async fn verify_bandwidth_credential(
|
||||
status: format!("{:?}", credential_status),
|
||||
});
|
||||
}
|
||||
let verification_key = state.verification_key().await?;
|
||||
let verification_key = state
|
||||
.verification_key(*verify_credential_body.credential().epoch_id())
|
||||
.await?;
|
||||
let mut vote_yes = verify_credential_body
|
||||
.credential()
|
||||
.verify(&verification_key);
|
||||
|
||||
@@ -40,11 +40,12 @@ 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, Epoch, TOTAL_DEALINGS};
|
||||
use coconut_dkg_common::types::{EncodedBTEPublicKeyWithProof, Epoch, EpochId, TOTAL_DEALINGS};
|
||||
use coconut_dkg_common::verification_key::{ContractVKShare, VerificationKeyShare};
|
||||
use contracts_common::dealings::ContractSafeBytes;
|
||||
use crypto::asymmetric::{encryption, identity};
|
||||
use cw3::ProposalResponse;
|
||||
use cw4::MemberResponse;
|
||||
use dkg::Threshold;
|
||||
use rand_07::rngs::OsRng;
|
||||
use rand_07::Rng;
|
||||
@@ -192,6 +193,10 @@ impl super::client::Client for DummyClient {
|
||||
Ok(*self.epoch.read().unwrap())
|
||||
}
|
||||
|
||||
async fn group_member(&self, _addr: String) -> Result<MemberResponse> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_current_epoch_threshold(&self) -> Result<Option<Threshold>> {
|
||||
Ok(*self.threshold.read().unwrap())
|
||||
}
|
||||
@@ -231,7 +236,10 @@ impl super::client::Client for DummyClient {
|
||||
.collect())
|
||||
}
|
||||
|
||||
async fn get_verification_key_shares(&self) -> Result<Vec<ContractVKShare>> {
|
||||
async fn get_verification_key_shares(
|
||||
&self,
|
||||
_epoch_id: EpochId,
|
||||
) -> Result<Vec<ContractVKShare>> {
|
||||
Ok(self
|
||||
.verification_share
|
||||
.read()
|
||||
@@ -342,6 +350,7 @@ impl super::client::Client for DummyClient {
|
||||
announce_address: dealer_details.announce_address.clone(),
|
||||
node_index: dealer_details.assigned_index,
|
||||
owner: Addr::unchecked(self.validator_address.to_string()),
|
||||
epoch_id: 0,
|
||||
verified: false,
|
||||
},
|
||||
);
|
||||
@@ -398,7 +407,7 @@ impl DummyCommunicationChannel {
|
||||
|
||||
#[async_trait]
|
||||
impl super::comm::APICommunicationChannel for DummyCommunicationChannel {
|
||||
async fn aggregated_verification_key(&self) -> Result<VerificationKey> {
|
||||
async fn aggregated_verification_key(&self, _epoch_id: EpochId) -> Result<VerificationKey> {
|
||||
Ok(self.aggregated_verification_key.clone())
|
||||
}
|
||||
}
|
||||
@@ -471,7 +480,7 @@ async fn signed_before() {
|
||||
.with_tx_db(&tx_db);
|
||||
let comm_channel = DummyCommunicationChannel::new(key_pair.verification_key());
|
||||
let staged_key_pair = crate::coconut::KeyPair::new();
|
||||
staged_key_pair.set(key_pair).await;
|
||||
staged_key_pair.set(Some(key_pair)).await;
|
||||
|
||||
let rocket = rocket::build().attach(InternalSignRequest::stage(
|
||||
nyxd_client,
|
||||
@@ -539,7 +548,7 @@ async fn state_functions() {
|
||||
let storage = NymApiStorage::init(db_dir).await.unwrap();
|
||||
let comm_channel = DummyCommunicationChannel::new(key_pair.verification_key());
|
||||
let staged_key_pair = crate::coconut::KeyPair::new();
|
||||
staged_key_pair.set(key_pair).await;
|
||||
staged_key_pair.set(Some(key_pair)).await;
|
||||
let state = State::new(
|
||||
nyxd_client,
|
||||
TEST_COIN_DENOM.to_string(),
|
||||
@@ -708,7 +717,7 @@ async fn blind_sign_correct() {
|
||||
.with_tx_db(&tx_db);
|
||||
let comm_channel = DummyCommunicationChannel::new(key_pair.verification_key());
|
||||
let staged_key_pair = crate::coconut::KeyPair::new();
|
||||
staged_key_pair.set(key_pair).await;
|
||||
staged_key_pair.set(Some(key_pair)).await;
|
||||
|
||||
let rocket = rocket::build().attach(InternalSignRequest::stage(
|
||||
nyxd_client,
|
||||
@@ -785,7 +794,7 @@ async fn signature_test() {
|
||||
DummyClient::new(AccountId::from_str(TEST_REWARDING_VALIDATOR_ADDRESS).unwrap());
|
||||
let comm_channel = DummyCommunicationChannel::new(key_pair.verification_key());
|
||||
let staged_key_pair = crate::coconut::KeyPair::new();
|
||||
staged_key_pair.set(key_pair).await;
|
||||
staged_key_pair.set(Some(key_pair)).await;
|
||||
|
||||
let rocket = rocket::build().attach(InternalSignRequest::stage(
|
||||
nyxd_client,
|
||||
@@ -872,7 +881,7 @@ async fn verification_of_bandwidth_credential() {
|
||||
let storage1 = NymApiStorage::init(db_dir).await.unwrap();
|
||||
let comm_channel = DummyCommunicationChannel::new(key_pair.verification_key());
|
||||
let staged_key_pair = crate::coconut::KeyPair::new();
|
||||
staged_key_pair.set(key_pair).await;
|
||||
staged_key_pair.set(Some(key_pair)).await;
|
||||
let rocket = rocket::build().attach(InternalSignRequest::stage(
|
||||
nyxd_client.clone(),
|
||||
TEST_COIN_DENOM.to_string(),
|
||||
@@ -885,7 +894,7 @@ async fn verification_of_bandwidth_credential() {
|
||||
.await
|
||||
.expect("valid rocket instance");
|
||||
|
||||
let credential = Credential::new(4, theta.clone(), voucher_value, voucher_info.to_string());
|
||||
let credential = Credential::new(4, theta.clone(), voucher_value, voucher_info.to_string(), 0);
|
||||
let proposal_id = 42;
|
||||
// The address is not used, so we can use a duplicate
|
||||
let gateway_cosmos_addr = validator_address.clone();
|
||||
@@ -1036,6 +1045,7 @@ async fn verification_of_bandwidth_credential() {
|
||||
theta.clone(),
|
||||
voucher_value,
|
||||
String::from("bad voucher info"),
|
||||
0,
|
||||
);
|
||||
let bad_req =
|
||||
VerifyCredentialBody::new(bad_credential, proposal_id, gateway_cosmos_addr.clone());
|
||||
|
||||
@@ -22,6 +22,7 @@ use futures::channel::mpsc;
|
||||
use gateway_client::bandwidth::BandwidthController;
|
||||
use std::sync::Arc;
|
||||
use task::TaskManager;
|
||||
use validator_client::nyxd::SigningNyxdClient;
|
||||
|
||||
pub(crate) mod chunker;
|
||||
pub(crate) mod gateways_reader;
|
||||
@@ -93,25 +94,14 @@ impl<'a> NetworkMonitorBuilder<'a> {
|
||||
*encryption_keypair.public_key(),
|
||||
);
|
||||
|
||||
#[cfg(feature = "coconut")]
|
||||
let bandwidth_controller = {
|
||||
let client = self._nyxd_client.0.read().await;
|
||||
let coconut_api_clients =
|
||||
validator_client::CoconutApiClient::all_coconut_api_clients(&client)
|
||||
.await
|
||||
.expect("Could not query api clients");
|
||||
BandwidthController::new(
|
||||
credential_storage::initialise_storage(self.config.get_credentials_database_path())
|
||||
.await,
|
||||
coconut_api_clients,
|
||||
client.clone(),
|
||||
)
|
||||
};
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
let bandwidth_controller = BandwidthController::new(
|
||||
credential_storage::initialise_storage(self.config.get_credentials_database_path())
|
||||
.await,
|
||||
)
|
||||
.expect("Could not create bandwidth controller");
|
||||
|
||||
let packet_sender = new_packet_sender(
|
||||
self.config,
|
||||
@@ -188,7 +178,7 @@ fn new_packet_sender(
|
||||
gateways_status_updater: GatewayClientUpdateSender,
|
||||
local_identity: Arc<identity::KeyPair>,
|
||||
max_sending_rate: usize,
|
||||
bandwidth_controller: BandwidthController<PersistentStorage>,
|
||||
bandwidth_controller: BandwidthController<SigningNyxdClient, PersistentStorage>,
|
||||
disabled_credentials_mode: bool,
|
||||
) -> PacketSender {
|
||||
PacketSender::new(
|
||||
|
||||
@@ -6,18 +6,21 @@ use gateway_client::GatewayClient;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::{Mutex, MutexGuard, TryLockError};
|
||||
use validator_client::nyxd::SigningNyxdClient;
|
||||
|
||||
pub(crate) struct GatewayClientHandle(Arc<GatewayClientHandleInner>);
|
||||
|
||||
struct GatewayClientHandleInner {
|
||||
client: Mutex<Option<GatewayClient>>,
|
||||
client: Mutex<Option<GatewayClient<SigningNyxdClient>>>,
|
||||
raw_identity: [u8; PUBLIC_KEY_LENGTH],
|
||||
}
|
||||
|
||||
pub(crate) struct UnlockedGatewayClientHandle<'a>(MutexGuard<'a, Option<GatewayClient>>);
|
||||
pub(crate) struct UnlockedGatewayClientHandle<'a>(
|
||||
MutexGuard<'a, Option<GatewayClient<SigningNyxdClient>>>,
|
||||
);
|
||||
|
||||
impl GatewayClientHandle {
|
||||
pub(crate) fn new(gateway_client: GatewayClient) -> Self {
|
||||
pub(crate) fn new(gateway_client: GatewayClient<SigningNyxdClient>) -> Self {
|
||||
GatewayClientHandle(Arc::new(GatewayClientHandleInner {
|
||||
raw_identity: gateway_client.gateway_identity().to_bytes(),
|
||||
client: Mutex::new(Some(gateway_client)),
|
||||
@@ -56,11 +59,11 @@ impl GatewayClientHandle {
|
||||
}
|
||||
|
||||
impl<'a> UnlockedGatewayClientHandle<'a> {
|
||||
pub(crate) fn get_mut_unchecked(&mut self) -> &mut GatewayClient {
|
||||
pub(crate) fn get_mut_unchecked(&mut self) -> &mut GatewayClient<SigningNyxdClient> {
|
||||
self.0.as_mut().unwrap()
|
||||
}
|
||||
|
||||
pub(crate) fn inner_mut(&mut self) -> Option<&mut GatewayClient> {
|
||||
pub(crate) fn inner_mut(&mut self) -> Option<&mut GatewayClient<SigningNyxdClient>> {
|
||||
self.0.as_mut()
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ use std::time::Duration;
|
||||
use task::TaskClient;
|
||||
|
||||
use gateway_client::bandwidth::BandwidthController;
|
||||
use validator_client::nyxd::SigningNyxdClient;
|
||||
|
||||
const TIME_CHUNK_SIZE: Duration = Duration::from_millis(50);
|
||||
|
||||
@@ -90,7 +91,7 @@ struct FreshGatewayClientData {
|
||||
gateways_status_updater: GatewayClientUpdateSender,
|
||||
local_identity: Arc<identity::KeyPair>,
|
||||
gateway_response_timeout: Duration,
|
||||
bandwidth_controller: BandwidthController<PersistentStorage>,
|
||||
bandwidth_controller: BandwidthController<SigningNyxdClient, PersistentStorage>,
|
||||
disabled_credentials_mode: bool,
|
||||
}
|
||||
|
||||
@@ -148,7 +149,7 @@ impl PacketSender {
|
||||
gateway_connection_timeout: Duration,
|
||||
max_concurrent_clients: usize,
|
||||
max_sending_rate: usize,
|
||||
bandwidth_controller: BandwidthController<PersistentStorage>,
|
||||
bandwidth_controller: BandwidthController<SigningNyxdClient, PersistentStorage>,
|
||||
disabled_credentials_mode: bool,
|
||||
) -> Self {
|
||||
PacketSender {
|
||||
@@ -218,7 +219,7 @@ impl PacketSender {
|
||||
}
|
||||
|
||||
async fn attempt_to_send_packets(
|
||||
client: &mut GatewayClient,
|
||||
client: &mut GatewayClient<SigningNyxdClient>,
|
||||
mut mix_packets: Vec<MixPacket>,
|
||||
max_sending_rate: usize,
|
||||
) -> Result<(), GatewayClientError> {
|
||||
@@ -327,7 +328,7 @@ impl PacketSender {
|
||||
}
|
||||
|
||||
async fn check_remaining_bandwidth(
|
||||
client: &mut GatewayClient,
|
||||
client: &mut GatewayClient<SigningNyxdClient>,
|
||||
) -> Result<(), GatewayClientError> {
|
||||
if client.remaining_bandwidth() < REMAINING_BANDWIDTH_THRESHOLD {
|
||||
Err(GatewayClientError::NotEnoughBandwidth(
|
||||
|
||||
@@ -99,7 +99,7 @@ pub(crate) struct CliArgs {
|
||||
|
||||
/// Flag to indicate whether coconut signer authority is enabled on this API
|
||||
#[cfg(feature = "coconut")]
|
||||
#[clap(long, requires = "mnemonic", requires = "announce-address")]
|
||||
#[clap(long, requires = "mnemonic", requires = "announce_address")]
|
||||
pub(crate) enable_coconut: Option<bool>,
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ use coconut_bandwidth_contract_common::spend_credential::SpendCredentialResponse
|
||||
#[cfg(feature = "coconut")]
|
||||
use coconut_dkg_common::{
|
||||
dealer::{ContractDealing, DealerDetails, DealerDetailsResponse},
|
||||
types::{EncodedBTEPublicKeyWithProof, Epoch},
|
||||
types::{EncodedBTEPublicKeyWithProof, Epoch, EpochId},
|
||||
verification_key::{ContractVKShare, VerificationKeyShare},
|
||||
};
|
||||
#[cfg(feature = "coconut")]
|
||||
@@ -40,11 +40,13 @@ use contracts_common::dealings::ContractSafeBytes;
|
||||
#[cfg(feature = "coconut")]
|
||||
use cw3::ProposalResponse;
|
||||
#[cfg(feature = "coconut")]
|
||||
use cw4::MemberResponse;
|
||||
#[cfg(feature = "coconut")]
|
||||
use validator_client::nyxd::{
|
||||
cosmwasm_client::types::ExecuteResult,
|
||||
traits::{
|
||||
CoconutBandwidthQueryClient, DkgQueryClient, DkgSigningClient, MultisigQueryClient,
|
||||
MultisigSigningClient,
|
||||
CoconutBandwidthQueryClient, DkgQueryClient, DkgSigningClient, GroupQueryClient,
|
||||
MultisigQueryClient, MultisigSigningClient,
|
||||
},
|
||||
Fee,
|
||||
};
|
||||
@@ -327,6 +329,10 @@ impl crate::coconut::client::Client for Client {
|
||||
Ok(self.0.read().await.nyxd.get_current_epoch().await?)
|
||||
}
|
||||
|
||||
async fn group_member(&self, addr: String) -> crate::coconut::error::Result<MemberResponse> {
|
||||
Ok(self.0.read().await.nyxd.member(addr).await?)
|
||||
}
|
||||
|
||||
async fn get_current_epoch_threshold(
|
||||
&self,
|
||||
) -> crate::coconut::error::Result<Option<dkg::Threshold>> {
|
||||
@@ -365,12 +371,13 @@ impl crate::coconut::client::Client for Client {
|
||||
|
||||
async fn get_verification_key_shares(
|
||||
&self,
|
||||
epoch_id: EpochId,
|
||||
) -> crate::coconut::error::Result<Vec<ContractVKShare>> {
|
||||
Ok(self
|
||||
.0
|
||||
.read()
|
||||
.await
|
||||
.get_all_nyxd_verification_key_shares()
|
||||
.get_all_nyxd_verification_key_shares(epoch_id)
|
||||
.await?)
|
||||
}
|
||||
|
||||
|
||||
Generated
+11
@@ -1892,6 +1892,15 @@ dependencies = [
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "group-contract-common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cw4",
|
||||
"schemars",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gtk"
|
||||
version = "0.15.4"
|
||||
@@ -5403,9 +5412,11 @@ dependencies = [
|
||||
"cosmrs",
|
||||
"cosmwasm-std",
|
||||
"cw3",
|
||||
"cw4",
|
||||
"execute",
|
||||
"flate2",
|
||||
"futures",
|
||||
"group-contract-common",
|
||||
"itertools",
|
||||
"log",
|
||||
"mixnet-contract-common",
|
||||
|
||||
@@ -109,6 +109,7 @@ mod sandbox {
|
||||
"nymt17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9f8xzkv";
|
||||
pub(crate) const COCONUT_BANDWIDTH_CONTRACT_ADDRESS: &str =
|
||||
"nymt1nz0r0au8aj6dc00wmm3ufy4g4k86rjzlgq608r";
|
||||
pub(crate) const GROUP_CONTRACT_ADDRESS: &str = "nymt1k8re7jwz6rnnwrktnejdwkwnncte7ek7kk6fvg";
|
||||
pub(crate) const MULTISIG_CONTRACT_ADDRESS: &str =
|
||||
"nymt1k8re7jwz6rnnwrktnejdwkwnncte7ek7kk6fvg";
|
||||
pub(crate) const COCONUT_DKG_CONTRACT_ADDRESS: &str =
|
||||
@@ -145,6 +146,7 @@ mod sandbox {
|
||||
coconut_bandwidth_contract_address: parse_optional_str(
|
||||
COCONUT_BANDWIDTH_CONTRACT_ADDRESS,
|
||||
),
|
||||
group_contract_address: parse_optional_str(GROUP_CONTRACT_ADDRESS),
|
||||
multisig_contract_address: parse_optional_str(MULTISIG_CONTRACT_ADDRESS),
|
||||
coconut_dkg_contract_address: parse_optional_str(COCONUT_DKG_CONTRACT_ADDRESS),
|
||||
},
|
||||
@@ -170,6 +172,7 @@ mod qa {
|
||||
"n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0";
|
||||
pub(crate) const COCONUT_BANDWIDTH_CONTRACT_ADDRESS: &str =
|
||||
"n1ghd753shjuwexxywmgs4xz7x2q732vcn7ty4yw";
|
||||
pub(crate) const GROUP_CONTRACT_ADDRESS: &str = "n17p9rzwnnfxcjp32un9ug7yhhzgtkhvl988qccs";
|
||||
pub(crate) const MULTISIG_CONTRACT_ADDRESS: &str = "n17p9rzwnnfxcjp32un9ug7yhhzgtkhvl988qccs";
|
||||
pub(crate) const COCONUT_DKG_CONTRACT_ADDRESS: &str =
|
||||
"n17p9rzwnnfxcjp32un9ug7yhhzgtkhvl988qccs";
|
||||
@@ -204,6 +207,7 @@ mod qa {
|
||||
coconut_bandwidth_contract_address: parse_optional_str(
|
||||
COCONUT_BANDWIDTH_CONTRACT_ADDRESS,
|
||||
),
|
||||
group_contract_address: parse_optional_str(GROUP_CONTRACT_ADDRESS),
|
||||
multisig_contract_address: parse_optional_str(MULTISIG_CONTRACT_ADDRESS),
|
||||
coconut_dkg_contract_address: parse_optional_str(COCONUT_DKG_CONTRACT_ADDRESS),
|
||||
},
|
||||
|
||||
@@ -14,6 +14,7 @@ gateway-requests = { path = "../../../gateway/gateway-requests" }
|
||||
network-defaults = { path = "../../../common/network-defaults" }
|
||||
nymsphinx = { path = "../../../common/nymsphinx" }
|
||||
task = { path = "../../../common/task" }
|
||||
validator-client = { path = "../../../common/client-libs/validator-client" }
|
||||
|
||||
futures = "0.3"
|
||||
log = { workspace = true }
|
||||
|
||||
@@ -21,6 +21,7 @@ use nymsphinx::{
|
||||
use task::TaskManager;
|
||||
|
||||
use futures::StreamExt;
|
||||
use validator_client::nyxd::SigningNyxdClient;
|
||||
|
||||
use super::{connection_state::BuilderState, Config, GatewayKeyMode, Keys, KeysArc, StoragePaths};
|
||||
use crate::error::{Error, Result};
|
||||
@@ -224,7 +225,7 @@ impl ClientBuilder {
|
||||
let reply_storage_backend =
|
||||
non_wasm_helpers::setup_empty_reply_surb_backend(&self.config.debug_config);
|
||||
|
||||
let base_builder = BaseClientBuilder::new(
|
||||
let base_builder: BaseClientBuilder<_, SigningNyxdClient> = BaseClientBuilder::new(
|
||||
&gateway_endpoint_config,
|
||||
&self.config.debug_config,
|
||||
self.key_manager.clone(),
|
||||
|
||||
Reference in New Issue
Block a user