feat: key rotation (#5777)
* wip * wip: wrap node's sphinx key with a manager * wip: choosing correct key for packet processing * further propagation of key rotation information * attaching key rotation information to reply surbs * added basic key rotation information to mixnet contract * wip: introducing cached queries for key rotation info from nym api * unified nym-api contract cache refreshing * finish packet decoding * multi api client + retrieving rotation id * rotating sphinx key files * logic for migrating config file * wip: putting new sphinx keys to self described endpoints * processing loop of KeyRotationController * fixed sphinx key loading * rotating bloomfilters * wired up KeyRotationController * flushing bloomfilters to disk and loading * most of nym-node changes * post rebase fixes * fixes due to backwards compatible hostkeys * split http state.rs file * dont use deprecated fields * fixed backwards compatible deserialisation of host information * split up node describe cache * added a dedicated CacheRefresher listener to perform full refresh outside the set interval * controlling announced sphinx keys within nym-api * retrieving rotation id when pulling topology * split nym-nodes http handlers * v2 nym-api endpoints to retrieve nodes with additional metadata information * bug fixes... * additional bugfixes and guards against stuck epoch * testnet manager: set first nym-api as the rewarder * fixed host information deserialisation * fixed panic during first key rotation * post rebase fixes * clippy * more guards against stuck epochs * added helper method to reset node's sphinx key * instantiate mixnet contract with custom key rotation validity * additional bugfixes and debugging nym-api deadlock * passing shutdown to nym apis client * remove dead test * post rebasing fixes * missing MixnetQueryClient variants * remove usage of deprecated methods in sdk example * fix: incorrect method signature * post rebasing fixes * attempt to retrieve key rotation id before doing any config migration work * ignore tests relying on networking behaviour * allow networking failures in certain tests
This commit is contained in:
committed by
GitHub
parent
adbe0392ca
commit
d8c84cc4d6
@@ -2,18 +2,26 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::error::NymNodeError;
|
||||
use crate::node::key_rotation::active_keys::ActiveSphinxKeys;
|
||||
use crate::node::routing_filter::network_filter::NetworkRoutingFilter;
|
||||
use async_trait::async_trait;
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
use nym_gateway::node::UserAgent;
|
||||
use nym_node_metrics::prometheus_wrapper::{PrometheusMetric, PROMETHEUS_METRICS};
|
||||
use nym_task::ShutdownToken;
|
||||
use nym_topology::node::RoutingNode;
|
||||
use nym_topology::{EpochRewardedSet, NymTopology, Role, TopologyProvider};
|
||||
use nym_topology::{
|
||||
EntryDetails, EpochRewardedSet, NodeId, NymTopology, NymTopologyMetadata, Role,
|
||||
TopologyProvider,
|
||||
};
|
||||
use nym_validator_client::nym_api::NymApiClientExt;
|
||||
use nym_validator_client::nym_nodes::{NodesByAddressesResponse, SkimmedNode};
|
||||
use nym_validator_client::nym_nodes::{
|
||||
NodesByAddressesResponse, SkimmedNode, SkimmedNodesWithMetadata,
|
||||
};
|
||||
use nym_validator_client::{NymApiClient, ValidatorClientError};
|
||||
use std::collections::HashSet;
|
||||
use std::net::IpAddr;
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tokio::sync::RwLock;
|
||||
@@ -22,6 +30,8 @@ use tracing::log::error;
|
||||
use tracing::{debug, trace, warn};
|
||||
use url::Url;
|
||||
|
||||
const LOCAL_NODE_ID: NodeId = 1234567890;
|
||||
|
||||
struct NodesQuerier {
|
||||
client: NymApiClient,
|
||||
nym_api_urls: Vec<Url>,
|
||||
@@ -53,10 +63,10 @@ impl NodesQuerier {
|
||||
res
|
||||
}
|
||||
|
||||
async fn current_nymnodes(&mut self) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
|
||||
async fn current_nymnodes(&mut self) -> Result<SkimmedNodesWithMetadata, ValidatorClientError> {
|
||||
let res = self
|
||||
.client
|
||||
.get_all_basic_nodes()
|
||||
.get_all_basic_nodes_with_metadata()
|
||||
.await
|
||||
.inspect_err(|err| error!("failed to get network nodes: {err}"));
|
||||
|
||||
@@ -84,16 +94,40 @@ impl NodesQuerier {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct LocalGatewayNode {
|
||||
pub(crate) active_sphinx_keys: ActiveSphinxKeys,
|
||||
pub(crate) mix_host: SocketAddr,
|
||||
pub(crate) identity_key: ed25519::PublicKey,
|
||||
pub(crate) entry: EntryDetails,
|
||||
}
|
||||
|
||||
impl LocalGatewayNode {
|
||||
pub(crate) fn to_routing_node(&self) -> RoutingNode {
|
||||
RoutingNode {
|
||||
node_id: LOCAL_NODE_ID,
|
||||
mix_host: self.mix_host,
|
||||
entry: Some(self.entry.clone()),
|
||||
identity_key: self.identity_key,
|
||||
sphinx_key: self.active_sphinx_keys.primary().deref().x25519_pubkey(),
|
||||
supported_roles: nym_topology::SupportedRoles {
|
||||
mixnode: false,
|
||||
mixnet_entry: true,
|
||||
mixnet_exit: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CachedTopologyProvider {
|
||||
gateway_node: Arc<RoutingNode>,
|
||||
gateway_node: Arc<LocalGatewayNode>,
|
||||
cached_network: CachedNetwork,
|
||||
min_mix_performance: u8,
|
||||
}
|
||||
|
||||
impl CachedTopologyProvider {
|
||||
pub(crate) fn new(
|
||||
gateway_node: RoutingNode,
|
||||
gateway_node: LocalGatewayNode,
|
||||
cached_network: CachedNetwork,
|
||||
min_mix_performance: u8,
|
||||
) -> Self {
|
||||
@@ -111,20 +145,24 @@ impl TopologyProvider for CachedTopologyProvider {
|
||||
let network_guard = self.cached_network.inner.read().await;
|
||||
let self_node = self.gateway_node.identity_key;
|
||||
|
||||
let mut topology = NymTopology::new_empty(network_guard.rewarded_set.clone())
|
||||
.with_additional_nodes(network_guard.network_nodes.iter().filter(|node| {
|
||||
if node.supported_roles.mixnode {
|
||||
node.performance.round_to_integer() >= self.min_mix_performance
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}));
|
||||
let mut topology = NymTopology::new(
|
||||
network_guard.topology_metadata,
|
||||
network_guard.rewarded_set.clone(),
|
||||
Vec::new(),
|
||||
)
|
||||
.with_additional_nodes(network_guard.network_nodes.iter().filter(|node| {
|
||||
if node.supported_roles.mixnode {
|
||||
node.performance.round_to_integer() >= self.min_mix_performance
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}));
|
||||
|
||||
if !topology.has_node_details(self.gateway_node.node_id) {
|
||||
if !topology.has_node(self.gateway_node.identity_key) {
|
||||
debug!("{self_node} didn't exist in topology. inserting it.",);
|
||||
topology.insert_node_details(self.gateway_node.as_ref().clone());
|
||||
topology.insert_node_details(self.gateway_node.to_routing_node());
|
||||
}
|
||||
topology.force_set_active(self.gateway_node.node_id, Role::EntryGateway);
|
||||
topology.force_set_active(LOCAL_NODE_ID, Role::EntryGateway);
|
||||
|
||||
Some(topology)
|
||||
}
|
||||
@@ -140,6 +178,7 @@ impl CachedNetwork {
|
||||
CachedNetwork {
|
||||
inner: Arc::new(RwLock::new(CachedNetworkInner {
|
||||
rewarded_set: Default::default(),
|
||||
topology_metadata: Default::default(),
|
||||
network_nodes: vec![],
|
||||
})),
|
||||
}
|
||||
@@ -148,6 +187,7 @@ impl CachedNetwork {
|
||||
|
||||
struct CachedNetworkInner {
|
||||
rewarded_set: EpochRewardedSet,
|
||||
topology_metadata: NymTopologyMetadata,
|
||||
network_nodes: Vec<SkimmedNode>,
|
||||
}
|
||||
|
||||
@@ -235,7 +275,9 @@ impl NetworkRefresher {
|
||||
|
||||
async fn refresh_network_nodes_inner(&mut self) -> Result<(), ValidatorClientError> {
|
||||
let rewarded_set = self.querier.rewarded_set().await?;
|
||||
let nodes = self.querier.current_nymnodes().await?;
|
||||
let res = self.querier.current_nymnodes().await?;
|
||||
let nodes = res.nodes;
|
||||
let metadata = res.metadata;
|
||||
|
||||
// collect all known/allowed nodes information
|
||||
let known_nodes = nodes
|
||||
@@ -264,6 +306,8 @@ impl NetworkRefresher {
|
||||
self.routing_filter.pending.clear().await;
|
||||
|
||||
let mut network_guard = self.network.inner.write().await;
|
||||
network_guard.topology_metadata =
|
||||
NymTopologyMetadata::new(metadata.rotation_id, metadata.absolute_epoch_id);
|
||||
network_guard.network_nodes = nodes;
|
||||
network_guard.rewarded_set = rewarded_set;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user