Skip to content

Commit

Permalink
add epoch id tag in NymTopology
Browse files Browse the repository at this point in the history
  • Loading branch information
Simon Wicky authored and simonwicky committed Feb 14, 2024
1 parent 6a0818b commit 81df088
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,15 @@ impl NymApiTopologyProvider {
}

async fn get_current_compatible_topology(&mut self) -> Option<NymTopology> {

let epoch = match self.validator_client.get_cached_current_epoch().await {
Err(err) => {
error!("failed to get current epoch - {err}");
return None;
}
Ok(interval) => interval.current_epoch_id(),
};

let mixnodes = match self.validator_client.get_cached_active_mixnodes().await {
Err(err) => {
error!("failed to get network mixnodes - {err}");
Expand All @@ -77,7 +86,22 @@ impl NymApiTopologyProvider {
Ok(gateways) => gateways,
};

let topology = nym_topology_from_detailed(mixnodes, gateways)
//there is a slight chance that the epoch changed between the epoch fetching and the topology fetching
//we thus need to check it didn't, otherwise, encryption keys will not match the one the mixnodes will try to decrypt with
//if indeed the epoch changed, we can return a failure. The old topology will be used for a little while, no problem to that
match self.validator_client.get_cached_current_epoch().await {
Err(err) => {
error!("failed to get current epoch a second time - {err}");
return None;
}
Ok(interval) => {
if interval.current_epoch_id() != epoch { //epoch changed indeed
return None;
}
}
}

let topology = nym_topology_from_detailed(mixnodes, gateways, epoch)
.filter_system_version(&self.client_version);

if let Err(err) = self.check_layer_distribution(&topology) {
Expand Down
34 changes: 34 additions & 0 deletions common/client-libs/validator-client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,36 @@ use nym_api_requests::models::{
GatewayCoreStatusResponse, MixnodeCoreStatusResponse, MixnodeStatusResponse,
RewardEstimationResponse, StakeSaturationResponse,
};
use nym_coconut_dkg_common::types::NodeIndex;
use nym_coconut_interface::VerificationKey;
pub use nym_mixnet_contract_common::{
mixnode::MixNodeDetails, GatewayBond, IdentityKeyRef, Interval, MixId,
};

#[cfg(feature = "nyxd-client")]
use crate::nyxd::traits::{DkgQueryClient, MixnetQueryClient, MultisigQueryClient};
#[cfg(feature = "nyxd-client")]
use crate::nyxd::{self, CosmWasmClient, NyxdClient, QueryNyxdClient, SigningNyxdClient};
#[cfg(feature = "nyxd-client")]
use cw3::ProposalResponse;
#[cfg(feature = "nyxd-client")]
use nym_api_requests::models::MixNodeBondAnnotated;
#[cfg(feature = "nyxd-client")]
use nym_coconut_dkg_common::{
dealer::ContractDealing,
types::{DealerDetails, EpochId},
verification_key::ContractVKShare,
};
#[cfg(feature = "nyxd-client")]
use nym_coconut_interface::Base58;
#[cfg(feature = "nyxd-client")]
use nym_mixnet_contract_common::{
families::{Family, FamilyHead},
mixnode::MixNodeBond,
pending_events::{PendingEpochEvent, PendingIntervalEvent},
Delegation, IdentityKey, RewardedSetNodeStatus, UnbondedMixnode,
};
#[cfg(feature = "nyxd-client")]
use nym_network_defaults::NymNetworkDetails;
use url::Url;

Expand Down Expand Up @@ -332,6 +362,10 @@ impl NymApiClient {
Ok(self.nym_api.get_mixnode_stake_saturation(mix_id).await?)
}

pub async fn get_cached_current_epoch(&self) -> Result<Interval, ValidatorClientError> {
Ok(self.nym_api_client.get_current_epoch().await?)
}

pub async fn blind_sign(
&self,
request_body: &BlindSignRequestBody,
Expand Down
13 changes: 12 additions & 1 deletion common/client-libs/validator-client/src/nym_api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,12 @@ pub use nym_api_requests::{
};
pub use nym_coconut_dkg_common::types::EpochId;
use nym_mixnet_contract_common::mixnode::MixNodeDetails;
use nym_mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixId};
use nym_mixnet_contract_common::{GatewayBond, IdentityKeyRef, Interval, MixId};
use nym_name_service_common::response::NamesListResponse;
use nym_service_provider_directory_common::response::ServicesListResponse;
use reqwest::Response;
use serde::{Deserialize, Serialize};
use url::Url;

pub mod error;
pub mod routes;
Expand Down Expand Up @@ -373,6 +376,14 @@ pub trait NymApiClientExt: ApiClient {
.await
}

async fn get_current_epoch(&self) -> Result<Interval, NymAPIError> {
self.query_nym_api(
&[routes::API_VERSION, routes::EPOCH, routes::CURRENT],
NO_PARAMS,
)
.await
}

async fn blind_sign(
&self,
request_body: &BlindSignRequestBody,
Expand Down
3 changes: 3 additions & 0 deletions common/client-libs/validator-client/src/nym_api/routes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ pub const REWARDED: &str = "rewarded";
pub const COCONUT_ROUTES: &str = "coconut";
pub const BANDWIDTH: &str = "bandwidth";

pub const EPOCH: &str = "epoch";
pub const CURRENT: &str = "current";

pub const COCONUT_BLIND_SIGN: &str = "blind-sign";
pub const COCONUT_VERIFY_BANDWIDTH_CREDENTIAL: &str = "verify-bandwidth-credential";
pub const COCONUT_EPOCH_CREDENTIALS: &str = "epoch-credentials";
Expand Down
23 changes: 20 additions & 3 deletions common/topology/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::filter::VersionFilterable;
pub use error::NymTopologyError;
use log::warn;
use nym_mixnet_contract_common::mixnode::MixNodeDetails;
use nym_mixnet_contract_common::EpochId;
use nym_mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixId};
use nym_sphinx_addressing::nodes::NodeIdentity;
use nym_sphinx_types::Node as SphinxNode;
Expand Down Expand Up @@ -115,11 +116,24 @@ pub type MixLayer = u8;
pub struct NymTopology {
mixes: BTreeMap<MixLayer, Vec<mix::Node>>,
gateways: Vec<gateway::Node>,
epoch: EpochId,
}

impl NymTopology {
pub fn new(mixes: BTreeMap<MixLayer, Vec<mix::Node>>, gateways: Vec<gateway::Node>) -> Self {
NymTopology { mixes, gateways }
pub fn new(
mixes: HashMap<MixLayer, Vec<mix::Node>>,
gateways: Vec<gateway::Node>,
epoch: EpochId,
) -> Self {
NymTopology {
mixes,
gateways,
epoch,
}
}

pub fn epoch(&self) -> EpochId {
self.epoch
}

pub fn new_unordered(unordered_mixes: Vec<mix::Node>, gateways: Vec<gateway::Node>) -> Self {
Expand Down Expand Up @@ -379,6 +393,7 @@ impl NymTopology {
NymTopology {
mixes: self.mixes.filter_by_version(expected_mix_version),
gateways: self.gateways.clone(),
epoch: self.epoch,
}
}
}
Expand Down Expand Up @@ -426,12 +441,14 @@ impl IntoGatewayNode for DescribedGateway {
pub fn nym_topology_from_detailed<G>(
mix_details: Vec<MixNodeDetails>,
gateway_bonds: Vec<G>,
epoch: EpochId,
) -> NymTopology
where
G: IntoGatewayNode,
<G as TryInto<gateway::Node>>::Error: Display,
{
let mut mixes = BTreeMap::new();
let mut mixes = HashMap::new();
for bond in mix_details
.into_iter()
.map(|details| details.bond_information)
Expand Down Expand Up @@ -469,7 +486,7 @@ where
}
}

NymTopology::new(mixes, gateways)
NymTopology::new(mixes, gateways, epoch)
}

#[cfg(test)]
Expand Down
64 changes: 61 additions & 3 deletions nym-api/src/network_monitor/monitor/preparer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ use crate::network_monitor::test_route::TestRoute;
use crate::nym_contract_cache::cache::NymContractCache;
use log::info;
use nym_crypto::asymmetric::{encryption, identity};
use nym_mixnet_contract_common::{GatewayBond, Layer, MixNodeBond};
use nym_node_tester_utils::node::TestableNode;
use nym_node_tester_utils::NodeTester;
use nym_sphinx::acknowledgements::AckKey;
use nym_mixnet_contract_common::{Addr, GatewayBond, Layer, MixId, MixNodeBond, EpochId};
use nym_sphinx::addressing::clients::Recipient;
use nym_sphinx::forwarding::packet::MixPacket;
use nym_sphinx::params::{PacketSize, PacketType};
Expand Down Expand Up @@ -192,6 +192,9 @@ impl PacketPreparer {
let gateways = self.validator_cache.gateways_filtered().await;

(mixnodes, gateways)
async fn current_epoch(&self) -> Option<EpochId> {
let interval = self.validator_cache.current_interval().await;
Some(interval.into_inner()?.current_epoch_id())
}

pub(crate) fn try_parse_mix_bond(&self, mix: &MixNodeBond) -> Result<mix::Node, String> {
Expand All @@ -217,7 +220,14 @@ impl PacketPreparer {
n: usize,
blacklist: &mut HashSet<String>,
) -> Option<Vec<TestRoute>> {
let (mixnodes, gateways) = self.filtered_mixnodes_and_gateways().await;
let (mixnodes, gateways) = self.all_mixnodes_and_gateways().await;
let epoch = match self.current_epoch().await{
None => {
error!("Cannot construct test routes. Cannot retrieve epoch");
return None;
}
Some(epoch_id) => epoch_id
};
// separate mixes into layers for easier selection
let mut layered_mixes = HashMap::new();
for mix in mixnodes {
Expand Down Expand Up @@ -252,7 +262,55 @@ impl PacketPreparer {

if most_available == 0 {
error!("Cannot construct test routes. No nodes or gateways available");
return None;
None
} else {
trace!("Generating test routes...");
let mut routes = Vec::new();
for i in 0..most_available {
let node_1 = match self.try_parse_mix_bond(rand_l1[i]) {
Ok(node) => node,
Err(id) => {
blacklist.insert(id);
continue;
}
};

let node_2 = match self.try_parse_mix_bond(rand_l2[i]) {
Ok(node) => node,
Err(id) => {
blacklist.insert(id);
continue;
}
};

let node_3 = match self.try_parse_mix_bond(rand_l3[i]) {
Ok(node) => node,
Err(id) => {
blacklist.insert(id);
continue;
}
};

let gateway = match self.try_parse_gateway_bond(rand_gateways[i]) {
Ok(node) => node,
Err(id) => {
blacklist.insert(id);
continue;
}
};

routes.push(TestRoute::new(
rng.gen(),
&self.system_version,
node_1,
node_2,
node_3,
gateway,
epoch,
))
}
info!("{:?}", routes);
Some(routes)
}

trace!("Generating test routes...");
Expand Down
5 changes: 4 additions & 1 deletion nym-api/src/network_monitor/test_route/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use crate::network_monitor::test_packet::NymApiTestMessageExt;
use crate::network_monitor::ROUTE_TESTING_TEST_NONCE;
use nym_crypto::asymmetric::identity;
use nym_mixnet_contract_common::EpochId;
use nym_topology::{gateway, mix, NymTopology};
use std::fmt::{Debug, Formatter};

Expand All @@ -20,6 +21,7 @@ impl TestRoute {
l2_mix: mix::Node,
l3_mix: mix::Node,
gateway: gateway::Node,
epoch: EpochId,
) -> Self {
let layered_mixes = [
(1u8, vec![l1_mix]),
Expand All @@ -31,7 +33,8 @@ impl TestRoute {

TestRoute {
id,
nodes: NymTopology::new(layered_mixes, vec![gateway]),
system_version: system_version.to_string(),
nodes: NymTopology::new(layered_mixes, vec![gateway], epoch),
}
}

Expand Down

0 comments on commit 81df088

Please sign in to comment.