Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f7bbd0c93e |
@@ -497,6 +497,11 @@ impl NymApiClient {
|
|||||||
Ok(nodes)
|
Ok(nodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// retrieve basic information for all bonded nodes on the network
|
||||||
|
pub async fn retrieve_basic_nodes_batch(&self, node_ids: Vec<u32>) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
|
||||||
|
Ok(self.nym_api.retrieve_basic_nodes_batch(&node_ids).await?.nodes)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn health(&self) -> Result<ApiHealthResponse, ValidatorClientError> {
|
pub async fn health(&self) -> Result<ApiHealthResponse, ValidatorClientError> {
|
||||||
Ok(self.nym_api.health().await?)
|
Ok(self.nym_api.health().await?)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -253,10 +253,10 @@ pub trait NymApiClientExt: ApiClient {
|
|||||||
self.get_json(
|
self.get_json(
|
||||||
&[
|
&[
|
||||||
routes::API_VERSION,
|
routes::API_VERSION,
|
||||||
"unstable",
|
routes::UNSTABLE,
|
||||||
routes::NYM_NODES_ROUTES,
|
routes::NYM_NODES_ROUTES,
|
||||||
"mixnodes",
|
"mixnodes",
|
||||||
"skimmed",
|
routes::SKIMMED,
|
||||||
],
|
],
|
||||||
NO_PARAMS,
|
NO_PARAMS,
|
||||||
)
|
)
|
||||||
@@ -269,10 +269,10 @@ pub trait NymApiClientExt: ApiClient {
|
|||||||
self.get_json(
|
self.get_json(
|
||||||
&[
|
&[
|
||||||
routes::API_VERSION,
|
routes::API_VERSION,
|
||||||
"unstable",
|
routes::UNSTABLE,
|
||||||
routes::NYM_NODES_ROUTES,
|
routes::NYM_NODES_ROUTES,
|
||||||
"gateways",
|
"gateways",
|
||||||
"skimmed",
|
routes::SKIMMED,
|
||||||
],
|
],
|
||||||
NO_PARAMS,
|
NO_PARAMS,
|
||||||
)
|
)
|
||||||
@@ -318,9 +318,9 @@ pub trait NymApiClientExt: ApiClient {
|
|||||||
self.get_json(
|
self.get_json(
|
||||||
&[
|
&[
|
||||||
routes::API_VERSION,
|
routes::API_VERSION,
|
||||||
"unstable",
|
routes::UNSTABLE,
|
||||||
routes::NYM_NODES_ROUTES,
|
routes::NYM_NODES_ROUTES,
|
||||||
"skimmed",
|
routes::SKIMMED,
|
||||||
"entry-gateways",
|
"entry-gateways",
|
||||||
"all",
|
"all",
|
||||||
],
|
],
|
||||||
@@ -355,9 +355,9 @@ pub trait NymApiClientExt: ApiClient {
|
|||||||
self.get_json(
|
self.get_json(
|
||||||
&[
|
&[
|
||||||
routes::API_VERSION,
|
routes::API_VERSION,
|
||||||
"unstable",
|
routes::UNSTABLE,
|
||||||
routes::NYM_NODES_ROUTES,
|
routes::NYM_NODES_ROUTES,
|
||||||
"skimmed",
|
routes::SKIMMED,
|
||||||
"mixnodes",
|
"mixnodes",
|
||||||
"active",
|
"active",
|
||||||
],
|
],
|
||||||
@@ -392,9 +392,9 @@ pub trait NymApiClientExt: ApiClient {
|
|||||||
self.get_json(
|
self.get_json(
|
||||||
&[
|
&[
|
||||||
routes::API_VERSION,
|
routes::API_VERSION,
|
||||||
"unstable",
|
routes::UNSTABLE,
|
||||||
routes::NYM_NODES_ROUTES,
|
routes::NYM_NODES_ROUTES,
|
||||||
"skimmed",
|
routes::SKIMMED,
|
||||||
"mixnodes",
|
"mixnodes",
|
||||||
"all",
|
"all",
|
||||||
],
|
],
|
||||||
@@ -403,6 +403,31 @@ pub trait NymApiClientExt: ApiClient {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Send a Post request with a set of node ids. A successful response will contain descriptors
|
||||||
|
/// for all nodes associated with those node IDs available in the current full topology.
|
||||||
|
///
|
||||||
|
/// If a provided node ID is not present there will be no descriptor for that node in the response.
|
||||||
|
///
|
||||||
|
/// If no node IDs are provided the response will contain no descriptors.
|
||||||
|
#[instrument(level = "debug", skip(self))]
|
||||||
|
async fn retrieve_basic_nodes_batch(
|
||||||
|
&self,
|
||||||
|
node_ids: &[NodeId],
|
||||||
|
) -> Result<CachedNodesResponse<SkimmedNode>, NymAPIError> {
|
||||||
|
self.post_json(
|
||||||
|
&[
|
||||||
|
routes::API_VERSION,
|
||||||
|
routes::UNSTABLE,
|
||||||
|
routes::NYM_NODES_ROUTES,
|
||||||
|
routes::SKIMMED,
|
||||||
|
routes::BATCH,
|
||||||
|
],
|
||||||
|
NO_PARAMS,
|
||||||
|
node_ids,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(self))]
|
#[instrument(level = "debug", skip(self))]
|
||||||
async fn get_basic_nodes(
|
async fn get_basic_nodes(
|
||||||
&self,
|
&self,
|
||||||
@@ -427,9 +452,9 @@ pub trait NymApiClientExt: ApiClient {
|
|||||||
self.get_json(
|
self.get_json(
|
||||||
&[
|
&[
|
||||||
routes::API_VERSION,
|
routes::API_VERSION,
|
||||||
"unstable",
|
routes::UNSTABLE,
|
||||||
routes::NYM_NODES_ROUTES,
|
routes::NYM_NODES_ROUTES,
|
||||||
"skimmed",
|
routes::SKIMMED,
|
||||||
],
|
],
|
||||||
¶ms,
|
¶ms,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -70,3 +70,7 @@ pub const SERVICE_PROVIDERS: &str = "services";
|
|||||||
|
|
||||||
pub const DETAILS: &str = "details";
|
pub const DETAILS: &str = "details";
|
||||||
pub const NETWORK: &str = "network";
|
pub const NETWORK: &str = "network";
|
||||||
|
|
||||||
|
pub const UNSTABLE: &str = "unstable";
|
||||||
|
pub const SKIMMED: &str = "skimmed";
|
||||||
|
pub const BATCH: &str = "batch";
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ use utoipa::{IntoParams, ToSchema};
|
|||||||
|
|
||||||
pub(crate) mod legacy;
|
pub(crate) mod legacy;
|
||||||
pub(crate) mod unstable;
|
pub(crate) mod unstable;
|
||||||
|
pub(crate) mod topology;
|
||||||
|
|
||||||
pub(crate) fn nym_node_routes() -> Router<AppState> {
|
pub(crate) fn nym_node_routes() -> Router<AppState> {
|
||||||
Router::new()
|
Router::new()
|
||||||
|
|||||||
@@ -0,0 +1,153 @@
|
|||||||
|
#![warn(missing_docs)]
|
||||||
|
#![warn(rustdoc::missing_crate_level_docs)]
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
node_status_api::models::{AxumErrorResponse, AxumResult},
|
||||||
|
support::http::{helpers::NodeIdParam, topology_cache::{TopologyCache, PayloadFormat}},
|
||||||
|
};
|
||||||
|
|
||||||
|
use axum::{
|
||||||
|
extract::{Path, Query, State},
|
||||||
|
routing::{get, post},
|
||||||
|
Json, Router,
|
||||||
|
};
|
||||||
|
use nym_mixnet_contract_common::{Interval, NodeId};
|
||||||
|
use nym_api_requests::models::RewardedSetResponse;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
type SkimmedNodes = AxumResult<Json<TopologyResponse>>;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, utoipa::IntoParams)]
|
||||||
|
#[into_params(parameter_in = Query)]
|
||||||
|
struct TopologyParams {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
semver_compatibility: Option<String>,
|
||||||
|
|
||||||
|
// Identifier for the current epoch of the topology state. When sent by a client we can check if
|
||||||
|
// the client already knows about the latest topology state, allowing a `no-updates` response
|
||||||
|
// instead of wasting bandwidth serving an unchanged topology.
|
||||||
|
epoch_id: Option<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(deprecated)]
|
||||||
|
pub(crate) fn topology_routes() -> Router<Arc<TopologyCache>> {
|
||||||
|
Router::new()
|
||||||
|
.route("layer-assignments", get(layer_assignments))
|
||||||
|
.nest(
|
||||||
|
"/skimmed",
|
||||||
|
Router::new()
|
||||||
|
.route("/", get(nodes_basic_all))
|
||||||
|
.route("batch", post(nodes_basic_batch))
|
||||||
|
.route("/:node_id", get(node_basic)),
|
||||||
|
)
|
||||||
|
// // NOT IMPLEMENTED
|
||||||
|
// .nest(
|
||||||
|
// "/semi-skimmed",
|
||||||
|
// Router::new().route("/", get(nodes_expanded_all)),
|
||||||
|
// )
|
||||||
|
// .nest(
|
||||||
|
// "/full-fat",
|
||||||
|
// Router::new().route("/", get(nodes_detailed_all)),
|
||||||
|
// )
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn nodes_basic_all(
|
||||||
|
State(state): State<Arc<TopologyCache>>,
|
||||||
|
Query(query_params): Query<TopologyParams>,
|
||||||
|
) -> AxumResult<Json<TopologyResponse>> {
|
||||||
|
Err(AxumErrorResponse::not_implemented())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn nodes_basic_batch(
|
||||||
|
State(state): State<Arc<TopologyCache>>,
|
||||||
|
Query(query_params): Query<TopologyParams>,
|
||||||
|
Json(node_ids): Json<Vec<NodeId>>,
|
||||||
|
) -> AxumResult<Json<TopologyResponse>> {
|
||||||
|
Err(AxumErrorResponse::not_implemented())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn node_basic(
|
||||||
|
Path(NodeIdParam { node_id }): Path<NodeIdParam>,
|
||||||
|
State(state): State<Arc<TopologyCache>>,
|
||||||
|
Query(query_params): Query<TopologyParams>,
|
||||||
|
) -> AxumResult<Json<TopologyResponse>> {
|
||||||
|
Err(AxumErrorResponse::not_implemented())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn layer_assignments(
|
||||||
|
State(state): State<Arc<TopologyCache>>,
|
||||||
|
Query(query_params): Query<TopologyParams>,
|
||||||
|
) -> AxumResult<Json<LayerAssignmentsResponse>> {
|
||||||
|
Err(AxumErrorResponse::not_implemented())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, schemars::JsonSchema, utoipa::ToSchema)]
|
||||||
|
struct LayerAssignmentsResponse {
|
||||||
|
pub status: Option<TopologyRequestStatus>,
|
||||||
|
|
||||||
|
pub assignments: RewardedSetResponse,
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, schemars::JsonSchema, utoipa::ToSchema)]
|
||||||
|
struct TopologyResponse {
|
||||||
|
pub status: Option<TopologyRequestStatus>,
|
||||||
|
|
||||||
|
payload: Vec<u8>,
|
||||||
|
payload_format: Option<PayloadFormat>,
|
||||||
|
payload_signature: Option<Vec<u8>>,
|
||||||
|
|
||||||
|
current_topology_hash: Option<Vec<u8>>,
|
||||||
|
topology_signature: Option<Vec<u8>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize, schemars::JsonSchema, utoipa::ToSchema)]
|
||||||
|
#[serde(rename_all = "kebab-case")]
|
||||||
|
pub enum TopologyRequestStatus {
|
||||||
|
NoUpdates,
|
||||||
|
Fresh(Interval),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use axum_test::TestServer;
|
||||||
|
use nym_topology::NymTopology;
|
||||||
|
use time::OffsetDateTime;
|
||||||
|
|
||||||
|
use crate::support::http::topology_cache::Epoch;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn build_test_topology_cache() -> TopologyCache {
|
||||||
|
|
||||||
|
let current_epoch = Epoch {
|
||||||
|
id: 123,
|
||||||
|
current_epoch_start: OffsetDateTime::now_utc(),
|
||||||
|
epoch_length: Duration::from_secs(120),
|
||||||
|
};
|
||||||
|
|
||||||
|
let topology = NymTopology::default();
|
||||||
|
|
||||||
|
TopologyCache::new(current_epoch, topology);
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_topology_basic() -> Result<(), Box<dyn ::std::error::Error>> {
|
||||||
|
let state = Arc::new(build_test_topology_cache());
|
||||||
|
let app = topology_routes().with_state(state);
|
||||||
|
|
||||||
|
let server = TestServer::new(app)?;
|
||||||
|
|
||||||
|
let response = server
|
||||||
|
.get(&"/layer_assignments")
|
||||||
|
.await;
|
||||||
|
|
||||||
|
response.assert_text("hello!");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,11 +25,11 @@ use crate::nym_nodes::handlers::unstable::semi_skimmed::nodes_expanded;
|
|||||||
use crate::nym_nodes::handlers::unstable::skimmed::{
|
use crate::nym_nodes::handlers::unstable::skimmed::{
|
||||||
entry_gateways_basic_active, entry_gateways_basic_all, exit_gateways_basic_active,
|
entry_gateways_basic_active, entry_gateways_basic_all, exit_gateways_basic_active,
|
||||||
exit_gateways_basic_all, mixnodes_basic_active, mixnodes_basic_all, nodes_basic_active,
|
exit_gateways_basic_all, mixnodes_basic_active, mixnodes_basic_all, nodes_basic_active,
|
||||||
nodes_basic_all,
|
nodes_basic_all, nodes_basic_batch,
|
||||||
};
|
};
|
||||||
use crate::support::http::helpers::PaginationRequest;
|
use crate::support::http::helpers::PaginationRequest;
|
||||||
use crate::support::http::state::AppState;
|
use crate::support::http::state::AppState;
|
||||||
use axum::routing::get;
|
use axum::routing::{get, post};
|
||||||
use axum::Router;
|
use axum::Router;
|
||||||
use nym_api_requests::nym_nodes::NodeRoleQueryParam;
|
use nym_api_requests::nym_nodes::NodeRoleQueryParam;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
@@ -47,6 +47,7 @@ pub(crate) fn nym_node_routes_unstable() -> Router<AppState> {
|
|||||||
"/skimmed",
|
"/skimmed",
|
||||||
Router::new()
|
Router::new()
|
||||||
.route("/", get(nodes_basic_all))
|
.route("/", get(nodes_basic_all))
|
||||||
|
.route("batch", post(nodes_basic_batch))
|
||||||
.route("/active", get(nodes_basic_active))
|
.route("/active", get(nodes_basic_active))
|
||||||
.nest(
|
.nest(
|
||||||
"/mixnodes",
|
"/mixnodes",
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ use tracing::trace;
|
|||||||
use utoipa::ToSchema;
|
use utoipa::ToSchema;
|
||||||
|
|
||||||
pub type PaginatedSkimmedNodes = AxumResult<Json<PaginatedCachedNodesResponse<SkimmedNode>>>;
|
pub type PaginatedSkimmedNodes = AxumResult<Json<PaginatedCachedNodesResponse<SkimmedNode>>>;
|
||||||
|
type SkimmedNodes = AxumResult<Json<CachedNodesResponse<SkimmedNode>>>;
|
||||||
|
|
||||||
/// Given all relevant caches, build part of response for JUST Nym Nodes
|
/// Given all relevant caches, build part of response for JUST Nym Nodes
|
||||||
fn build_nym_nodes_response<'a, NI>(
|
fn build_nym_nodes_response<'a, NI>(
|
||||||
@@ -196,7 +197,7 @@ where
|
|||||||
pub(super) async fn deprecated_gateways_basic(
|
pub(super) async fn deprecated_gateways_basic(
|
||||||
state: State<AppState>,
|
state: State<AppState>,
|
||||||
query_params: Query<NodesParams>,
|
query_params: Query<NodesParams>,
|
||||||
) -> AxumResult<Json<CachedNodesResponse<SkimmedNode>>> {
|
) -> SkimmedNodes {
|
||||||
// 1. call '/v1/unstable/skimmed/entry-gateways/all'
|
// 1. call '/v1/unstable/skimmed/entry-gateways/all'
|
||||||
let all_gateways = entry_gateways_basic_all(state, query_params).await?;
|
let all_gateways = entry_gateways_basic_all(state, query_params).await?;
|
||||||
|
|
||||||
@@ -223,7 +224,7 @@ pub(super) async fn deprecated_gateways_basic(
|
|||||||
pub(super) async fn deprecated_mixnodes_basic(
|
pub(super) async fn deprecated_mixnodes_basic(
|
||||||
state: State<AppState>,
|
state: State<AppState>,
|
||||||
query_params: Query<NodesParams>,
|
query_params: Query<NodesParams>,
|
||||||
) -> AxumResult<Json<CachedNodesResponse<SkimmedNode>>> {
|
) -> SkimmedNodes {
|
||||||
// 1. call '/v1/unstable/nym-nodes/skimmed/mixnodes/active'
|
// 1. call '/v1/unstable/nym-nodes/skimmed/mixnodes/active'
|
||||||
let active_mixnodes = mixnodes_basic_active(state, query_params).await?;
|
let active_mixnodes = mixnodes_basic_active(state, query_params).await?;
|
||||||
|
|
||||||
@@ -239,7 +240,7 @@ async fn nodes_basic(
|
|||||||
state: State<AppState>,
|
state: State<AppState>,
|
||||||
Query(_query_params): Query<NodesParams>,
|
Query(_query_params): Query<NodesParams>,
|
||||||
active_only: bool,
|
active_only: bool,
|
||||||
) -> PaginatedSkimmedNodes {
|
) -> SkimmedNodes {
|
||||||
// unfortunately we have to build the response semi-manually here as we need to add two sources of legacy nodes
|
// unfortunately we have to build the response semi-manually here as we need to add two sources of legacy nodes
|
||||||
|
|
||||||
// 1. grab all relevant described nym-nodes
|
// 1. grab all relevant described nym-nodes
|
||||||
@@ -281,10 +282,10 @@ async fn nodes_basic(
|
|||||||
legacy_gateways.timestamp(),
|
legacy_gateways.timestamp(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Ok(Json(PaginatedCachedNodesResponse::new_full(
|
Ok(Json(CachedNodesResponse {
|
||||||
refreshed_at,
|
refreshed_at,
|
||||||
nodes,
|
nodes,
|
||||||
)))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)] // not dead, used in OpenAPI docs
|
#[allow(dead_code)] // not dead, used in OpenAPI docs
|
||||||
@@ -329,6 +330,31 @@ pub(super) async fn nodes_basic_all(
|
|||||||
nodes_basic(state, Query(query_params.into()), false).await
|
nodes_basic(state, Query(query_params.into()), false).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Post request handler taking a json array of NodeId (u32) values and returning descriptors for
|
||||||
|
/// the provided NodeId values. A successful response will contain descriptors for all nodes
|
||||||
|
/// associated with those node IDs available in the current full topology.
|
||||||
|
///
|
||||||
|
/// If a provided node ID is not present in the current topology there will be no descriptor for
|
||||||
|
/// that node in the response.
|
||||||
|
///
|
||||||
|
/// If no node IDs are provided the response will contain no descriptors.
|
||||||
|
#[utoipa::path(
|
||||||
|
tag = "Unstable Nym Nodes batch by Node ID",
|
||||||
|
get,
|
||||||
|
params(NodesParamsWithRole),
|
||||||
|
path = "batch",
|
||||||
|
context_path = "/v1/unstable/nym-nodes/skimmed",
|
||||||
|
responses(
|
||||||
|
(status = 200, body = PaginatedCachedNodesResponseSchema)
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub(super) async fn nodes_basic_batch(
|
||||||
|
state: State<AppState>,
|
||||||
|
Query(query_params): Query<NodesParamsWithRole>,
|
||||||
|
) -> SkimmedNodes {
|
||||||
|
nodes_basic(state, Query(query_params.into()), false).await
|
||||||
|
}
|
||||||
|
|
||||||
/// Return Nym Nodes and optionally legacy mixnodes/gateways (if `no-legacy` flag is not used)
|
/// Return Nym Nodes and optionally legacy mixnodes/gateways (if `no-legacy` flag is not used)
|
||||||
/// that are currently bonded and are in the **active set**
|
/// that are currently bonded and are in the **active set**
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ use crate::support::config::Config;
|
|||||||
use crate::support::http::state::{
|
use crate::support::http::state::{
|
||||||
AppState, ForcedRefresh, ShutdownHandles, TASK_MANAGER_TIMEOUT_S,
|
AppState, ForcedRefresh, ShutdownHandles, TASK_MANAGER_TIMEOUT_S,
|
||||||
};
|
};
|
||||||
|
use crate::support::http::topology_cache::{Epoch, TopologyCache};
|
||||||
use crate::support::http::RouterBuilder;
|
use crate::support::http::RouterBuilder;
|
||||||
use crate::support::nyxd;
|
use crate::support::nyxd;
|
||||||
use crate::support::storage::runtime_migrations::m001_directory_services_v2_1::migrate_to_directory_services_v2_1;
|
use crate::support::storage::runtime_migrations::m001_directory_services_v2_1::migrate_to_directory_services_v2_1;
|
||||||
@@ -35,6 +36,7 @@ use anyhow::{bail, Context};
|
|||||||
use nym_config::defaults::NymNetworkDetails;
|
use nym_config::defaults::NymNetworkDetails;
|
||||||
use nym_sphinx::receiver::SphinxMessageReceiver;
|
use nym_sphinx::receiver::SphinxMessageReceiver;
|
||||||
use nym_task::TaskManager;
|
use nym_task::TaskManager;
|
||||||
|
use nym_topology::NymTopology;
|
||||||
use nym_validator_client::nyxd::Coin;
|
use nym_validator_client::nyxd::Coin;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@@ -133,8 +135,6 @@ async fn start_nym_api_tasks_axum(config: &Config) -> anyhow::Result<ShutdownHan
|
|||||||
let identity_keypair = config.base.storage_paths.load_identity()?;
|
let identity_keypair = config.base.storage_paths.load_identity()?;
|
||||||
let identity_public_key = *identity_keypair.public_key();
|
let identity_public_key = *identity_keypair.public_key();
|
||||||
|
|
||||||
let router = RouterBuilder::with_default_routes(config.network_monitor.enabled);
|
|
||||||
|
|
||||||
let nym_contract_cache_state = NymContractCache::new();
|
let nym_contract_cache_state = NymContractCache::new();
|
||||||
let node_status_cache_state = NodeStatusCache::new();
|
let node_status_cache_state = NodeStatusCache::new();
|
||||||
let mix_denom = network_details.network.chain_details.mix_denom.base.clone();
|
let mix_denom = network_details.network.chain_details.mix_denom.base.clone();
|
||||||
@@ -190,7 +190,16 @@ async fn start_nym_api_tasks_axum(config: &Config) -> anyhow::Result<ShutdownHan
|
|||||||
};
|
};
|
||||||
|
|
||||||
ecash_state.spawn_background_cleaner();
|
ecash_state.spawn_background_cleaner();
|
||||||
let router = router.with_state(AppState {
|
|
||||||
|
|
||||||
|
let epoch = Epoch::from(nym_contract_cache_state.current_interval().await.take());
|
||||||
|
let topology = {
|
||||||
|
todo!("cannot proceed without implementing this.");
|
||||||
|
NymTopology::default()
|
||||||
|
};
|
||||||
|
let topology_cache = TopologyCache::new(epoch, topology);
|
||||||
|
|
||||||
|
let state = AppState {
|
||||||
forced_refresh: ForcedRefresh::new(
|
forced_refresh: ForcedRefresh::new(
|
||||||
config.topology_cacher.debug.node_describe_allow_illegal_ips,
|
config.topology_cacher.debug.node_describe_allow_illegal_ips,
|
||||||
),
|
),
|
||||||
@@ -203,7 +212,11 @@ async fn start_nym_api_tasks_axum(config: &Config) -> anyhow::Result<ShutdownHan
|
|||||||
node_info_cache,
|
node_info_cache,
|
||||||
api_status: ApiStatusState::new(signer_information),
|
api_status: ApiStatusState::new(signer_information),
|
||||||
ecash_state: Arc::new(ecash_state),
|
ecash_state: Arc::new(ecash_state),
|
||||||
});
|
topology_cache: Arc::new(topology_cache)
|
||||||
|
};
|
||||||
|
|
||||||
|
let router = RouterBuilder::with_default_routes(&state, config.network_monitor.enabled);
|
||||||
|
let router = router.with_state(state);
|
||||||
|
|
||||||
// start note describe cache refresher
|
// start note describe cache refresher
|
||||||
// we should be doing the below, but can't due to our current startup structure
|
// we should be doing the below, but can't due to our current startup structure
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ pub(crate) mod openapi;
|
|||||||
pub(crate) mod router;
|
pub(crate) mod router;
|
||||||
pub(crate) mod state;
|
pub(crate) mod state;
|
||||||
mod unstable_routes;
|
mod unstable_routes;
|
||||||
|
pub(crate) mod topology_cache;
|
||||||
|
|
||||||
pub(crate) use router::RouterBuilder;
|
pub(crate) use router::RouterBuilder;
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use crate::node_status_api::handlers::status_routes;
|
|||||||
use crate::nym_contract_cache::handlers::nym_contract_cache_routes;
|
use crate::nym_contract_cache::handlers::nym_contract_cache_routes;
|
||||||
use crate::nym_nodes::handlers::legacy::legacy_nym_node_routes;
|
use crate::nym_nodes::handlers::legacy::legacy_nym_node_routes;
|
||||||
use crate::nym_nodes::handlers::nym_node_routes;
|
use crate::nym_nodes::handlers::nym_node_routes;
|
||||||
|
use crate::nym_nodes::handlers::topology::topology_routes;
|
||||||
use crate::status;
|
use crate::status;
|
||||||
use crate::support::http::openapi::ApiDoc;
|
use crate::support::http::openapi::ApiDoc;
|
||||||
use crate::support::http::state::AppState;
|
use crate::support::http::state::AppState;
|
||||||
@@ -38,7 +39,7 @@ pub(crate) struct RouterBuilder {
|
|||||||
impl RouterBuilder {
|
impl RouterBuilder {
|
||||||
/// All routes should be, if possible, added here. Exceptions are e.g.
|
/// All routes should be, if possible, added here. Exceptions are e.g.
|
||||||
/// routes which are added conditionally in other places based on some `if`.
|
/// routes which are added conditionally in other places based on some `if`.
|
||||||
pub(crate) fn with_default_routes(network_monitor: bool) -> Self {
|
pub(crate) fn with_default_routes(state: &AppState, network_monitor: bool) -> Self {
|
||||||
// https://docs.rs/tower-http/0.1.1/tower_http/trace/index.html
|
// https://docs.rs/tower-http/0.1.1/tower_http/trace/index.html
|
||||||
// TODO rocket use tracing instead of env_logger
|
// TODO rocket use tracing instead of env_logger
|
||||||
// https://github.com/tokio-rs/axum/blob/main/examples/tracing-aka-logging/src/main.rs
|
// https://github.com/tokio-rs/axum/blob/main/examples/tracing-aka-logging/src/main.rs
|
||||||
@@ -64,7 +65,9 @@ impl RouterBuilder {
|
|||||||
.nest("/api-status", status::handlers::api_status_routes())
|
.nest("/api-status", status::handlers::api_status_routes())
|
||||||
.nest("/nym-nodes", nym_node_routes())
|
.nest("/nym-nodes", nym_node_routes())
|
||||||
.nest("/ecash", ecash_routes())
|
.nest("/ecash", ecash_routes())
|
||||||
.nest("/unstable", unstable_routes()), // CORS layer needs to be "outside" of routes
|
.nest("/unstable", unstable_routes())
|
||||||
|
.nest("/topology", topology_routes().with_state(state.topology_cache.clone())),
|
||||||
|
// CORS layer needs to be "outside" of routes
|
||||||
);
|
);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ use crate::nym_contract_cache::cache::NymContractCache;
|
|||||||
use crate::status::ApiStatusState;
|
use crate::status::ApiStatusState;
|
||||||
use crate::support::caching::cache::SharedCache;
|
use crate::support::caching::cache::SharedCache;
|
||||||
use crate::support::caching::Cache;
|
use crate::support::caching::Cache;
|
||||||
|
use crate::support::http::topology_cache::TopologyCache;
|
||||||
use crate::support::storage;
|
use crate::support::storage;
|
||||||
use axum::extract::FromRef;
|
use axum::extract::FromRef;
|
||||||
use nym_api_requests::models::{GatewayBondAnnotated, MixNodeBondAnnotated, NodeAnnotation};
|
use nym_api_requests::models::{GatewayBondAnnotated, MixNodeBondAnnotated, NodeAnnotation};
|
||||||
@@ -87,6 +88,7 @@ pub(crate) struct AppState {
|
|||||||
pub(crate) api_status: ApiStatusState,
|
pub(crate) api_status: ApiStatusState,
|
||||||
// todo: refactor it into inner: Arc<EcashStateInner>
|
// todo: refactor it into inner: Arc<EcashStateInner>
|
||||||
pub(crate) ecash_state: Arc<EcashState>,
|
pub(crate) ecash_state: Arc<EcashState>,
|
||||||
|
pub(crate) topology_cache: Arc<TopologyCache>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromRef<AppState> for ApiStatusState {
|
impl FromRef<AppState> for ApiStatusState {
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
#![warn(missing_docs)]
|
||||||
|
#![warn(rustdoc::missing_crate_level_docs)]
|
||||||
|
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use nym_topology::NymTopology;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use nym_mixnet_contract_common::{EpochId, Interval};
|
||||||
|
use std::time::Duration;
|
||||||
|
use time::OffsetDateTime;
|
||||||
|
|
||||||
|
pub struct Epoch {
|
||||||
|
pub id: EpochId,
|
||||||
|
pub current_epoch_start: OffsetDateTime,
|
||||||
|
pub epoch_length: Duration,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Interval> for Epoch {
|
||||||
|
fn from(value: Interval) -> Self {
|
||||||
|
Self {
|
||||||
|
id: value.current_epoch_id(),
|
||||||
|
current_epoch_start: value.current_epoch_start(),
|
||||||
|
epoch_length: value.epoch_length(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Format for
|
||||||
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize, schemars::JsonSchema, utoipa::ToSchema)]
|
||||||
|
#[serde(rename_all = "kebab-case")]
|
||||||
|
pub(crate) enum PayloadFormat {
|
||||||
|
Json,
|
||||||
|
BitCode,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct TopologyCache {
|
||||||
|
current_epoch: Epoch,
|
||||||
|
formats: HashMap<PayloadFormat, SerializedTopology>,
|
||||||
|
cached: NymTopology,
|
||||||
|
hash: Option<Vec<u8>>,
|
||||||
|
signature: Option<Vec<u8>>
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct SerializedTopology{
|
||||||
|
bytes: Vec<u8>,
|
||||||
|
signature: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl TopologyCache {
|
||||||
|
pub fn new(current_epoch: Epoch, initial: NymTopology) -> Self {
|
||||||
|
Self {
|
||||||
|
current_epoch,
|
||||||
|
formats: HashMap::new(),
|
||||||
|
cached: initial,
|
||||||
|
hash: None,
|
||||||
|
signature: None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user