re-expose LP information on the http API
This commit is contained in:
Generated
+1
-2
@@ -7226,7 +7226,6 @@ dependencies = [
|
||||
"opentelemetry_sdk",
|
||||
"rand 0.8.5",
|
||||
"rand 0.9.2",
|
||||
"rand_chacha 0.3.1",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2 0.10.9",
|
||||
@@ -7274,9 +7273,9 @@ dependencies = [
|
||||
"nym-http-api-client",
|
||||
"nym-kkt-ciphersuite",
|
||||
"nym-noise-keys",
|
||||
"nym-test-utils",
|
||||
"nym-upgrade-mode-check",
|
||||
"nym-wireguard-types",
|
||||
"rand_chacha 0.3.1",
|
||||
"schemars 0.8.22",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
||||
@@ -20,7 +20,7 @@ use nym_api_requests::ecash::{
|
||||
};
|
||||
use nym_api_requests::models::{
|
||||
ApiHealthResponse, GatewayCoreStatusResponse, HistoricalPerformanceResponse,
|
||||
MixnodeCoreStatusResponse, NymNodeDescriptionV1,
|
||||
MixnodeCoreStatusResponse, NymNodeDescriptionV1, NymNodeDescriptionV2,
|
||||
};
|
||||
use nym_api_requests::nym_nodes::{
|
||||
NodesByAddressesResponse, SemiSkimmedNodesWithMetadata, SkimmedNode, SkimmedNodesWithMetadata,
|
||||
@@ -273,18 +273,18 @@ impl<C, S> Client<C, S> {
|
||||
Ok(history)
|
||||
}
|
||||
|
||||
// #[deprecated(note = "use get_all_cached_described_nodes_v2 instead")]
|
||||
#[deprecated(note = "use get_all_cached_described_nodes_v2 instead")]
|
||||
pub async fn get_all_cached_described_nodes(
|
||||
&self,
|
||||
) -> Result<Vec<NymNodeDescriptionV1>, ValidatorClientError> {
|
||||
Ok(self.nym_api.get_all_described_nodes().await?)
|
||||
}
|
||||
|
||||
// pub async fn get_all_cached_described_nodes_v2(
|
||||
// &self,
|
||||
// ) -> Result<Vec<NymNodeDescriptionV2>, ValidatorClientError> {
|
||||
// Ok(self.nym_api.get_all_described_nodes_v2().await?)
|
||||
// }
|
||||
pub async fn get_all_cached_described_nodes_v2(
|
||||
&self,
|
||||
) -> Result<Vec<NymNodeDescriptionV2>, ValidatorClientError> {
|
||||
Ok(self.nym_api.get_all_described_nodes_v2().await?)
|
||||
}
|
||||
|
||||
pub async fn get_all_cached_bonded_nym_nodes(
|
||||
&self,
|
||||
@@ -473,7 +473,7 @@ impl NymApiClient {
|
||||
Ok(self.nym_api.health().await?)
|
||||
}
|
||||
|
||||
// #[deprecated(note = "use .get_all_described_nodes_v2 instead")]
|
||||
#[deprecated(note = "use .get_all_described_nodes_v2 instead")]
|
||||
pub async fn get_all_described_nodes(
|
||||
&self,
|
||||
) -> Result<Vec<NymNodeDescriptionV1>, ValidatorClientError> {
|
||||
@@ -495,29 +495,29 @@ impl NymApiClient {
|
||||
Ok(descriptions)
|
||||
}
|
||||
|
||||
// pub async fn get_all_described_nodes_v2(
|
||||
// &self,
|
||||
// ) -> Result<Vec<NymNodeDescriptionV2>, ValidatorClientError> {
|
||||
// // TODO: deal with paging in macro or some helper function or something, because it's the same pattern everywhere
|
||||
// let mut page = 0;
|
||||
// let mut descriptions = Vec::new();
|
||||
//
|
||||
// loop {
|
||||
// let mut res = self
|
||||
// .nym_api
|
||||
// .get_nodes_described_v2(Some(page), None)
|
||||
// .await?;
|
||||
//
|
||||
// descriptions.append(&mut res.data);
|
||||
// if descriptions.len() < res.pagination.total {
|
||||
// page += 1
|
||||
// } else {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Ok(descriptions)
|
||||
// }
|
||||
pub async fn get_all_described_nodes_v2(
|
||||
&self,
|
||||
) -> Result<Vec<NymNodeDescriptionV2>, ValidatorClientError> {
|
||||
// TODO: deal with paging in macro or some helper function or something, because it's the same pattern everywhere
|
||||
let mut page = 0;
|
||||
let mut descriptions = Vec::new();
|
||||
|
||||
loop {
|
||||
let mut res = self
|
||||
.nym_api
|
||||
.get_nodes_described_v2(Some(page), None)
|
||||
.await?;
|
||||
|
||||
descriptions.append(&mut res.data);
|
||||
if descriptions.len() < res.pagination.total {
|
||||
page += 1
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(descriptions)
|
||||
}
|
||||
|
||||
pub async fn get_all_bonded_nym_nodes(
|
||||
&self,
|
||||
|
||||
@@ -17,7 +17,7 @@ use nym_api_requests::ecash::VerificationKeyResponse;
|
||||
use nym_api_requests::models::{
|
||||
AnnotationResponse, ApiHealthResponse, BinaryBuildInformationOwned, ChainBlocksStatusResponse,
|
||||
ChainStatusResponse, KeyRotationInfoResponse, NodePerformanceResponse, NodeRefreshBody,
|
||||
NymNodeDescriptionV1, PerformanceHistoryResponse, RewardedSetResponse,
|
||||
NymNodeDescriptionV1, NymNodeDescriptionV2, PerformanceHistoryResponse, RewardedSetResponse,
|
||||
SignerInformationResponse,
|
||||
};
|
||||
use nym_api_requests::nym_nodes::{
|
||||
@@ -117,7 +117,7 @@ pub trait NymApiClientExt: ApiClient {
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip_all)]
|
||||
// #[deprecated(note = "use .get_nodes_described_v2 instead")]
|
||||
#[deprecated(note = "use .get_nodes_described_v2 instead")]
|
||||
async fn get_nodes_described(
|
||||
&self,
|
||||
page: Option<u32>,
|
||||
@@ -144,32 +144,32 @@ pub trait NymApiClientExt: ApiClient {
|
||||
.await
|
||||
}
|
||||
|
||||
// #[tracing::instrument(level = "debug", skip_all)]
|
||||
// async fn get_nodes_described_v2(
|
||||
// &self,
|
||||
// page: Option<u32>,
|
||||
// per_page: Option<u32>,
|
||||
// ) -> Result<PaginatedResponse<NymNodeDescriptionV2>, NymAPIError> {
|
||||
// let mut params = Vec::new();
|
||||
//
|
||||
// if let Some(page) = page {
|
||||
// params.push(("page", page.to_string()))
|
||||
// }
|
||||
//
|
||||
// if let Some(per_page) = per_page {
|
||||
// params.push(("per_page", per_page.to_string()))
|
||||
// }
|
||||
//
|
||||
// self.get_json(
|
||||
// &[
|
||||
// routes::V2_API_VERSION,
|
||||
// routes::NYM_NODES_ROUTES,
|
||||
// routes::NYM_NODES_DESCRIBED,
|
||||
// ],
|
||||
// ¶ms,
|
||||
// )
|
||||
// .await
|
||||
// }
|
||||
#[tracing::instrument(level = "debug", skip_all)]
|
||||
async fn get_nodes_described_v2(
|
||||
&self,
|
||||
page: Option<u32>,
|
||||
per_page: Option<u32>,
|
||||
) -> Result<PaginatedResponse<NymNodeDescriptionV2>, NymAPIError> {
|
||||
let mut params = Vec::new();
|
||||
|
||||
if let Some(page) = page {
|
||||
params.push(("page", page.to_string()))
|
||||
}
|
||||
|
||||
if let Some(per_page) = per_page {
|
||||
params.push(("per_page", per_page.to_string()))
|
||||
}
|
||||
|
||||
self.get_json(
|
||||
&[
|
||||
routes::V2_API_VERSION,
|
||||
routes::NYM_NODES_ROUTES,
|
||||
routes::NYM_NODES_DESCRIBED,
|
||||
],
|
||||
¶ms,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_current_rewarded_set(&self) -> Result<RewardedSetResponse, NymAPIError> {
|
||||
self.get_rewarded_set().await
|
||||
@@ -302,8 +302,8 @@ pub trait NymApiClientExt: ApiClient {
|
||||
Ok(SkimmedNodesWithMetadata::new(nodes, metadata))
|
||||
}
|
||||
|
||||
// #[deprecated(note = "use .get_all_described_nodes_v2 instead")]
|
||||
// #[allow(deprecated)]
|
||||
#[deprecated(note = "use .get_all_described_nodes_v2 instead")]
|
||||
#[allow(deprecated)]
|
||||
async fn get_all_described_nodes(&self) -> Result<Vec<NymNodeDescriptionV1>, NymAPIError> {
|
||||
// TODO: deal with paging in macro or some helper function or something, because it's the same pattern everywhere
|
||||
let mut page = 0;
|
||||
@@ -323,24 +323,24 @@ pub trait NymApiClientExt: ApiClient {
|
||||
Ok(descriptions)
|
||||
}
|
||||
|
||||
// async fn (&self) -> Result<Vec<NymNodeDescriptionV2>, NymAPIError> {
|
||||
// // TODO: deal with paging in macro or some helper function or something, because it's the same pattern everywhere
|
||||
// let mut page = 0;
|
||||
// let mut descriptions = Vec::new();
|
||||
//
|
||||
// loop {
|
||||
// let mut res = self.get_nodes_described_v2(Some(page), None).await?;
|
||||
//
|
||||
// descriptions.append(&mut res.data);
|
||||
// if descriptions.len() < res.pagination.total {
|
||||
// page += 1
|
||||
// } else {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Ok(descriptions)
|
||||
// }
|
||||
async fn get_all_described_nodes_v2(&self) -> Result<Vec<NymNodeDescriptionV2>, NymAPIError> {
|
||||
// TODO: deal with paging in macro or some helper function or something, because it's the same pattern everywhere
|
||||
let mut page = 0;
|
||||
let mut descriptions = Vec::new();
|
||||
|
||||
loop {
|
||||
let mut res = self.get_nodes_described_v2(Some(page), None).await?;
|
||||
|
||||
descriptions.append(&mut res.data);
|
||||
if descriptions.len() < res.pagination.total {
|
||||
page += 1
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(descriptions)
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip_all)]
|
||||
async fn get_nym_nodes(
|
||||
|
||||
@@ -9,6 +9,7 @@ license.workspace = true
|
||||
rust-version.workspace = true
|
||||
readme.workspace = true
|
||||
version.workspace = true
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
thiserror = { workspace = true }
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
use crate::error::KKTCiphersuiteError;
|
||||
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
||||
use std::collections::HashMap;
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt::Display;
|
||||
use strum_macros::{Display, EnumIter, EnumString};
|
||||
|
||||
@@ -47,12 +47,7 @@ pub mod xwing {
|
||||
pub const PUBLIC_KEY_LENGTH: usize = x25519::PUBLIC_KEY_LENGTH + ml_kem768::PUBLIC_KEY_LENGTH;
|
||||
}
|
||||
|
||||
pub type KEMKeyDigests = KeyDigests;
|
||||
|
||||
#[deprecated]
|
||||
pub type SigningKeyDigests = KeyDigests;
|
||||
|
||||
pub type KeyDigests = HashMap<HashFunction, Vec<u8>>;
|
||||
pub type KEMKeyDigests = BTreeMap<HashFunction, Vec<u8>>;
|
||||
|
||||
#[derive(
|
||||
Clone,
|
||||
@@ -66,6 +61,8 @@ pub type KeyDigests = HashMap<HashFunction, Vec<u8>>;
|
||||
EnumIter,
|
||||
EnumString,
|
||||
Display,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
)]
|
||||
#[strum(ascii_case_insensitive)]
|
||||
#[strum(serialize_all = "lowercase")]
|
||||
@@ -209,6 +206,8 @@ impl SignatureScheme {
|
||||
EnumString,
|
||||
Display,
|
||||
Default,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
)]
|
||||
#[strum(ascii_case_insensitive)]
|
||||
#[strum(serialize_all = "lowercase")]
|
||||
|
||||
@@ -9,6 +9,7 @@ license.workspace = true
|
||||
rust-version.workspace = true
|
||||
readme.workspace = true
|
||||
version.workspace = true
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
num_enum = { workspace = true }
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
use libcrux_ml_kem::mlkem768::MlKem768KeyPair;
|
||||
use libcrux_psq::handshake::types::DHKeyPair;
|
||||
use nym_kkt_ciphersuite::{DEFAULT_HASH_LEN, HashFunction, KeyDigests};
|
||||
use nym_kkt_ciphersuite::{DEFAULT_HASH_LEN, HashFunction, KEMKeyDigests};
|
||||
use rand09::{CryptoRng, RngCore};
|
||||
use std::collections::HashMap;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
pub fn generate_lp_keypair_x25519<R>(rng: &mut R) -> DHKeyPair
|
||||
where
|
||||
@@ -38,9 +38,9 @@ pub fn hash_key_bytes(
|
||||
|
||||
/// attempt to produce digests of the provided key using all known [HashFunction] with a default
|
||||
/// hash length where variable output is available
|
||||
pub fn produce_key_digests(key_bytes: &[u8]) -> KeyDigests {
|
||||
pub fn produce_key_digests(key_bytes: &[u8]) -> KEMKeyDigests {
|
||||
use strum::IntoEnumIterator;
|
||||
let mut digests = HashMap::new();
|
||||
let mut digests = BTreeMap::new();
|
||||
for hash in HashFunction::iter() {
|
||||
digests.insert(hash, hash.digest(key_bytes, DEFAULT_HASH_LEN));
|
||||
}
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
|
||||
use crate::error::KKTError;
|
||||
use libcrux_psq::handshake::types::PQEncapsulationKey;
|
||||
use nym_kkt_ciphersuite::KEM;
|
||||
use nym_kkt_ciphersuite::{KEM, KEMKeyDigests};
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::key_utils::produce_key_digests;
|
||||
pub use libcrux_ml_kem::mlkem768::{MlKem768KeyPair, MlKem768PrivateKey, MlKem768PublicKey};
|
||||
pub use libcrux_psq::classic_mceliece as mceliece;
|
||||
pub use libcrux_psq::handshake::types::{DHKeyPair, DHPrivateKey, DHPublicKey};
|
||||
@@ -41,6 +43,18 @@ impl KEMKeys {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn encapsulation_keys_digests(&self) -> BTreeMap<KEM, KEMKeyDigests> {
|
||||
let mut digests = BTreeMap::new();
|
||||
|
||||
let mlkem_digests = produce_key_digests(self.ml_kem768_pk.as_slice());
|
||||
let mceliece_digests = produce_key_digests(self.mc_eliece_pk.as_ref().as_ref());
|
||||
|
||||
digests.insert(KEM::MlKem768, mlkem_digests);
|
||||
digests.insert(KEM::McEliece, mceliece_digests);
|
||||
|
||||
digests
|
||||
}
|
||||
|
||||
pub fn encoded_encapsulation_key(&self, kem: KEM) -> Option<&[u8]> {
|
||||
match kem {
|
||||
KEM::McEliece => Some(self.mc_eliece_pk.as_ref().as_ref()),
|
||||
|
||||
@@ -9,6 +9,7 @@ license.workspace = true
|
||||
rust-version.workspace = true
|
||||
readme.workspace = true
|
||||
version.workspace = true
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
bytes = { workspace = true }
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
use crate::LpError;
|
||||
use nym_crypto::asymmetric::x25519;
|
||||
use nym_kkt_ciphersuite::{Ciphersuite, KEM, KEMKeyDigests};
|
||||
use std::collections::HashMap;
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -46,17 +46,11 @@ impl LpLocalPeer {
|
||||
/// Convert this `LpLocalPeer` into a valid `LpRemotePeer` that can be used within tests
|
||||
#[doc(hidden)]
|
||||
pub fn as_remote(&self) -> LpRemotePeer {
|
||||
let mut expected_kem_key_digests = HashMap::new();
|
||||
if let Some(keys) = &self.kem_keypairs {
|
||||
for kem in [KEM::MlKem768, KEM::McEliece] {
|
||||
expected_kem_key_digests.insert(
|
||||
kem,
|
||||
nym_kkt::key_utils::produce_key_digests(
|
||||
keys.encoded_encapsulation_key(kem).unwrap(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
let expected_kem_key_digests = self
|
||||
.kem_keypairs
|
||||
.as_ref()
|
||||
.map(|k| k.encapsulation_keys_digests())
|
||||
.unwrap_or_default();
|
||||
|
||||
LpRemotePeer {
|
||||
x25519_public: self.x25519.pk,
|
||||
@@ -87,7 +81,7 @@ pub struct LpRemotePeer {
|
||||
pub(crate) x25519_public: DHPublicKey,
|
||||
|
||||
/// Expected digests of the remote's KEM key
|
||||
pub(crate) expected_kem_key_digests: HashMap<KEM, KEMKeyDigests>,
|
||||
pub(crate) expected_kem_key_digests: BTreeMap<KEM, KEMKeyDigests>,
|
||||
}
|
||||
|
||||
impl LpRemotePeer {
|
||||
@@ -107,7 +101,7 @@ impl LpRemotePeer {
|
||||
#[must_use]
|
||||
pub fn with_key_digests(
|
||||
mut self,
|
||||
expected_kem_key_digests: HashMap<KEM, KEMKeyDigests>,
|
||||
expected_kem_key_digests: BTreeMap<KEM, KEMKeyDigests>,
|
||||
) -> Self {
|
||||
self.expected_kem_key_digests = expected_kem_key_digests;
|
||||
self
|
||||
|
||||
@@ -5,15 +5,16 @@
|
||||
//! and defines required conversion methods
|
||||
|
||||
use celes::Country;
|
||||
use nym_crypto::asymmetric::ed25519::serde_helpers::bs58_ed25519_pubkey;
|
||||
use nym_crypto::asymmetric::ed25519::serde_helpers::{bs58_ed25519_pubkey, bs58_ed25519_signature};
|
||||
use nym_crypto::asymmetric::x25519::serde_helpers::{bs58_dh_public_key, bs58_x25519_pubkey};
|
||||
use nym_crypto::asymmetric::{ed25519, x25519};
|
||||
use nym_kkt_ciphersuite::{HashFunction, SignatureScheme, KEM};
|
||||
use nym_network_defaults::{WG_METADATA_PORT, WG_TUNNEL_PORT};
|
||||
use nym_node_requests::api::SignedData;
|
||||
use nym_noise_keys::VersionedNoiseKeyV1;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::collections::BTreeMap;
|
||||
use std::net::IpAddr;
|
||||
use strum_macros::{Display, EnumString};
|
||||
use thiserror::Error;
|
||||
@@ -200,6 +201,16 @@ pub struct WireguardDetailsV1 {
|
||||
// even if you put `#[serde(default)]` all over the place
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, schemars::JsonSchema, ToSchema, PartialEq)]
|
||||
pub struct LewesProtocolDetailsV1 {
|
||||
pub content: LewesProtocolDetailsDataV1,
|
||||
|
||||
#[serde(with = "bs58_ed25519_signature")]
|
||||
#[schemars(with = "String")]
|
||||
#[schema(value_type = String)]
|
||||
pub signature: ed25519::Signature,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, schemars::JsonSchema, ToSchema, PartialEq)]
|
||||
pub struct LewesProtocolDetailsDataV1 {
|
||||
/// Helper field that specifies whether the LP listener(s) is enabled on this node.
|
||||
/// It is directly controlled by the node's role (i.e. it is enabled if it supports 'entry' mode)
|
||||
pub enabled: bool,
|
||||
@@ -219,14 +230,14 @@ pub struct LewesProtocolDetailsV1 {
|
||||
/// Digests of the KEM keys available to this node alongside hashing algorithms used
|
||||
/// for their computation.
|
||||
/// note: digests are hex encoded
|
||||
pub kem_keys: HashMap<LPKEM, HashMap<LPHashFunction, String>>,
|
||||
pub kem_keys: BTreeMap<LPKEM, BTreeMap<LPHashFunction, String>>,
|
||||
}
|
||||
|
||||
impl LewesProtocolDetailsV1 {
|
||||
impl LewesProtocolDetailsDataV1 {
|
||||
fn decode_digests(
|
||||
digests: &HashMap<LPHashFunction, String>,
|
||||
) -> Result<HashMap<HashFunction, Vec<u8>>, MalformedLPData> {
|
||||
let mut kem_digests = HashMap::new();
|
||||
digests: &BTreeMap<LPHashFunction, String>,
|
||||
) -> Result<BTreeMap<HashFunction, Vec<u8>>, MalformedLPData> {
|
||||
let mut kem_digests = BTreeMap::new();
|
||||
for (hash_function, digest) in digests {
|
||||
let digest = hex::decode(digest).map_err(|source| MalformedLPData::MalformedHash {
|
||||
value: digest.to_string(),
|
||||
@@ -239,8 +250,8 @@ impl LewesProtocolDetailsV1 {
|
||||
|
||||
pub fn kem_keys(
|
||||
&self,
|
||||
) -> Result<HashMap<KEM, HashMap<HashFunction, Vec<u8>>>, MalformedLPData> {
|
||||
let mut kem_keys = HashMap::new();
|
||||
) -> Result<BTreeMap<KEM, BTreeMap<HashFunction, Vec<u8>>>, MalformedLPData> {
|
||||
let mut kem_keys = BTreeMap::new();
|
||||
for (kem, digests) in &self.kem_keys {
|
||||
let kem_digests = Self::decode_digests(digests)?;
|
||||
kem_keys.insert((*kem).try_into()?, kem_digests);
|
||||
@@ -251,8 +262,8 @@ impl LewesProtocolDetailsV1 {
|
||||
|
||||
/// Convert map of digests from `nym_node_requests` types into `nym-api-requests` types
|
||||
fn translate_digests(
|
||||
digests: HashMap<nym_node_requests::api::v1::lewes_protocol::models::LPHashFunction, String>,
|
||||
) -> HashMap<LPHashFunction, String> {
|
||||
digests: BTreeMap<nym_node_requests::api::v1::lewes_protocol::models::LPHashFunction, String>,
|
||||
) -> BTreeMap<LPHashFunction, String> {
|
||||
digests
|
||||
.into_iter()
|
||||
.map(|(hash_fn, digest)| (hash_fn.into(), digest))
|
||||
@@ -273,6 +284,7 @@ fn translate_digests(
|
||||
Display,
|
||||
EnumString,
|
||||
ToSchema,
|
||||
Ord,
|
||||
)]
|
||||
#[strum(serialize_all = "lowercase")]
|
||||
#[non_exhaustive]
|
||||
@@ -295,6 +307,7 @@ pub enum LPKEM {
|
||||
Display,
|
||||
EnumString,
|
||||
ToSchema,
|
||||
Ord,
|
||||
)]
|
||||
#[strum(serialize_all = "lowercase")]
|
||||
#[non_exhaustive]
|
||||
@@ -437,20 +450,26 @@ impl From<nym_node_requests::api::v1::gateway::models::Wireguard> for WireguardD
|
||||
}
|
||||
}
|
||||
|
||||
impl From<nym_node_requests::api::v1::lewes_protocol::models::LewesProtocol>
|
||||
impl From<SignedData<nym_node_requests::api::v1::lewes_protocol::models::LewesProtocol>>
|
||||
for LewesProtocolDetailsV1
|
||||
{
|
||||
fn from(value: nym_node_requests::api::v1::lewes_protocol::models::LewesProtocol) -> Self {
|
||||
fn from(
|
||||
value: SignedData<nym_node_requests::api::v1::lewes_protocol::models::LewesProtocol>,
|
||||
) -> Self {
|
||||
LewesProtocolDetailsV1 {
|
||||
enabled: value.enabled,
|
||||
control_port: value.control_port,
|
||||
data_port: value.data_port,
|
||||
x25519: value.x25519,
|
||||
kem_keys: value
|
||||
.kem_keys
|
||||
.into_iter()
|
||||
.map(|(kem, digests)| (kem.into(), translate_digests(digests)))
|
||||
.collect(),
|
||||
signature: value.signature,
|
||||
content: LewesProtocolDetailsDataV1 {
|
||||
enabled: value.enabled,
|
||||
control_port: value.control_port,
|
||||
data_port: value.data_port,
|
||||
x25519: value.x25519,
|
||||
kem_keys: value
|
||||
.data
|
||||
.kem_keys
|
||||
.into_iter()
|
||||
.map(|(kem, digests)| (kem.into(), translate_digests(digests)))
|
||||
.collect(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -549,3 +568,14 @@ impl TryFrom<LPSignatureScheme> for SignatureScheme {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn signature_validity_after_conversion() {
|
||||
// make sure the serialisation stays the same and signature is still valid
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,7 +231,7 @@ async fn get_bonded_nodes(
|
||||
),
|
||||
params(PaginationRequest)
|
||||
)]
|
||||
// #[deprecated(note = "use '/v2/nym-nodes/described' instead")]
|
||||
#[deprecated(note = "use '/v2/nym-nodes/described' instead")]
|
||||
async fn get_described_nodes(
|
||||
State(state): State<AppState>,
|
||||
Query(pagination): Query<PaginationRequest>,
|
||||
|
||||
@@ -8,7 +8,7 @@ use axum::extract::{Query, State};
|
||||
use axum::routing::get;
|
||||
use axum::Router;
|
||||
use nym_api_requests::models::NymNodeDescriptionV2;
|
||||
use nym_api_requests::pagination::PaginatedResponse;
|
||||
use nym_api_requests::pagination::{PaginatedResponse, Pagination};
|
||||
use nym_http_api_common::FormattedResponse;
|
||||
use tower_http::compression::CompressionLayer;
|
||||
|
||||
@@ -36,23 +36,19 @@ async fn get_described_nodes(
|
||||
State(state): State<AppState>,
|
||||
Query(pagination): Query<PaginationRequest>,
|
||||
) -> AxumResult<FormattedResponse<PaginatedResponse<NymNodeDescriptionV2>>> {
|
||||
let _ = state;
|
||||
// TODO: implement it
|
||||
let _ = pagination;
|
||||
Err(AxumErrorResponse::not_implemented())
|
||||
let output = pagination.output.unwrap_or_default();
|
||||
|
||||
// // TODO: implement it
|
||||
// let _ = pagination;
|
||||
// let output = pagination.output.unwrap_or_default();
|
||||
//
|
||||
// let cache = state.described_nodes_cache.get().await?;
|
||||
// let descriptions = cache.all_nodes().cloned().collect::<Vec<_>>();
|
||||
//
|
||||
// Ok(output.to_response(PaginatedResponse {
|
||||
// pagination: Pagination {
|
||||
// total: descriptions.len(),
|
||||
// page: 0,
|
||||
// size: descriptions.len(),
|
||||
// },
|
||||
// data: descriptions,
|
||||
// }))
|
||||
let cache = state.described_nodes_cache.get().await?;
|
||||
let descriptions = cache.all_nodes().cloned().collect::<Vec<_>>();
|
||||
|
||||
Ok(output.to_response(PaginatedResponse {
|
||||
pagination: Pagination {
|
||||
total: descriptions.len(),
|
||||
page: 0,
|
||||
size: descriptions.len(),
|
||||
},
|
||||
data: descriptions,
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -134,7 +134,6 @@ cargo_metadata = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = { workspace = true, features = ["async_tokio"] }
|
||||
rand_chacha = { workspace = true }
|
||||
|
||||
[features]
|
||||
tokio-console = ["console-subscriber", "nym-task/tokio-tracing"]
|
||||
|
||||
@@ -48,7 +48,7 @@ nym-bin-common = { workspace = true, features = [
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { workspace = true, features = ["full"] }
|
||||
rand_chacha = { workspace = true }
|
||||
nym-test-utils = { workspace = true }
|
||||
nym-crypto = { workspace = true, features = ["rand"] }
|
||||
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ use nym_http_api_client::{ApiClient, HttpClientError};
|
||||
|
||||
use super::v1::gateway::models::Wireguard;
|
||||
use super::v1::metrics::models::SessionStats;
|
||||
use crate::api::SignedLewesProtocol;
|
||||
use crate::api::v1::authenticator::models::Authenticator;
|
||||
use crate::api::v1::health::models::NodeHealth;
|
||||
use crate::api::v1::ip_packet_router::models::IpPacketRouter;
|
||||
@@ -98,7 +99,7 @@ pub trait NymNodeApiClientExt: ApiClient {
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_lewes_protocol(&self) -> Result<LewesProtocol, NymNodeApiClientError> {
|
||||
async fn get_lewes_protocol(&self) -> Result<SignedLewesProtocol, NymNodeApiClientError> {
|
||||
self.get_json_from(routes::api::v1::lp_absolute()).await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ pub use client::Client;
|
||||
|
||||
// create the type alias manually if openapi is not enabled
|
||||
pub type SignedHostInformation = SignedData<crate::api::v1::node::models::HostInformation>;
|
||||
pub type SignedLewesProtocol = SignedData<crate::api::v1::lewes_protocol::models::LewesProtocol>;
|
||||
|
||||
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
|
||||
pub struct SignedDataHostInfo {
|
||||
@@ -28,11 +29,20 @@ pub struct SignedDataHostInfo {
|
||||
pub signature: String,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
|
||||
pub struct SignedLewesProtocolInfo {
|
||||
// #[serde(flatten)]
|
||||
pub data: crate::api::v1::lewes_protocol::models::LewesProtocol,
|
||||
pub signature: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SignedData<T> {
|
||||
// #[serde(flatten)]
|
||||
pub data: T,
|
||||
pub signature: String,
|
||||
|
||||
#[serde(with = "ed25519::bs58_ed25519_signature")]
|
||||
pub signature: ed25519::Signature,
|
||||
}
|
||||
|
||||
impl<T> SignedData<T> {
|
||||
@@ -42,7 +52,7 @@ impl<T> SignedData<T> {
|
||||
{
|
||||
let plaintext = serde_json::to_string(&data)?;
|
||||
|
||||
let signature = key.sign(plaintext).to_base58_string();
|
||||
let signature = key.sign(plaintext);
|
||||
Ok(SignedData { data, signature })
|
||||
}
|
||||
|
||||
@@ -54,11 +64,7 @@ impl<T> SignedData<T> {
|
||||
return false;
|
||||
};
|
||||
|
||||
let Ok(signature) = ed25519::Signature::from_base58_string(&self.signature) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
key.verify(plaintext, &signature).is_ok()
|
||||
key.verify(plaintext, &self.signature).is_ok()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +78,7 @@ impl SignedHostInformation {
|
||||
|
||||
let legacy_v3 = SignedData {
|
||||
data: LegacyHostInformationV3::from(self.data.clone()),
|
||||
signature: self.signature.clone(),
|
||||
signature: self.signature,
|
||||
};
|
||||
|
||||
if legacy_v3.verify(&self.keys.ed25519_identity) {
|
||||
@@ -82,7 +88,7 @@ impl SignedHostInformation {
|
||||
// attempt to verify legacy signatures
|
||||
let legacy_v3 = SignedData {
|
||||
data: LegacyHostInformationV3::from(self.data.clone()),
|
||||
signature: self.signature.clone(),
|
||||
signature: self.signature,
|
||||
};
|
||||
|
||||
if legacy_v3.verify(&self.keys.ed25519_identity) {
|
||||
@@ -91,7 +97,7 @@ impl SignedHostInformation {
|
||||
|
||||
let legacy_v2 = SignedData {
|
||||
data: LegacyHostInformationV2::from(legacy_v3.data),
|
||||
signature: self.signature.clone(),
|
||||
signature: self.signature,
|
||||
};
|
||||
|
||||
if legacy_v2.verify(&self.keys.ed25519_identity) {
|
||||
@@ -100,7 +106,7 @@ impl SignedHostInformation {
|
||||
|
||||
SignedData {
|
||||
data: LegacyHostInformationV1::from(legacy_v2.data),
|
||||
signature: self.signature.clone(),
|
||||
signature: self.signature,
|
||||
}
|
||||
.verify(&self.keys.ed25519_identity)
|
||||
}
|
||||
@@ -133,11 +139,11 @@ mod tests {
|
||||
use crate::api::v1::node::models::{HostKeys, SphinxKey};
|
||||
use nym_crypto::asymmetric::{ed25519, x25519};
|
||||
use nym_noise_keys::{NoiseVersion, VersionedNoiseKeyV1};
|
||||
use rand_chacha::rand_core::SeedableRng;
|
||||
use nym_test_utils::helpers::deterministic_rng;
|
||||
|
||||
#[test]
|
||||
fn dummy_signed_host_verification() {
|
||||
let mut rng = rand_chacha::ChaCha20Rng::from_seed([0u8; 32]);
|
||||
let mut rng = deterministic_rng();
|
||||
let ed22519 = ed25519::KeyPair::new(&mut rng);
|
||||
let x25519_sphinx = x25519::KeyPair::new(&mut rng);
|
||||
let x25519_sphinx2 = x25519::KeyPair::new(&mut rng);
|
||||
|
||||
@@ -5,7 +5,7 @@ use nym_crypto::asymmetric::x25519;
|
||||
use nym_crypto::asymmetric::x25519::serde_helpers::bs58_dh_public_key;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::collections::BTreeMap;
|
||||
use strum_macros::{Display, EnumIter, EnumString};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema)]
|
||||
@@ -30,7 +30,7 @@ pub struct LewesProtocol {
|
||||
/// Digests of the KEM keys available to this node alongside hashing algorithms used
|
||||
/// for their computation.
|
||||
/// note: digests are hex encoded
|
||||
pub kem_keys: HashMap<LPKEM, HashMap<LPHashFunction, String>>,
|
||||
pub kem_keys: BTreeMap<LPKEM, BTreeMap<LPHashFunction, String>>,
|
||||
}
|
||||
|
||||
impl LewesProtocol {
|
||||
@@ -39,7 +39,7 @@ impl LewesProtocol {
|
||||
control_port: u16,
|
||||
data_port: u16,
|
||||
x25519: x25519::DHPublicKey,
|
||||
kem_keys: HashMap<LPKEM, HashMap<LPHashFunction, String>>,
|
||||
kem_keys: BTreeMap<LPKEM, BTreeMap<LPHashFunction, String>>,
|
||||
) -> Self {
|
||||
LewesProtocol {
|
||||
enabled,
|
||||
@@ -69,6 +69,7 @@ impl LewesProtocol {
|
||||
PartialOrd,
|
||||
Display,
|
||||
EnumString,
|
||||
Ord,
|
||||
)]
|
||||
#[strum(serialize_all = "lowercase")]
|
||||
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
|
||||
@@ -109,6 +110,7 @@ impl From<nym_kkt_ciphersuite::KEM> for LPKEM {
|
||||
Display,
|
||||
EnumString,
|
||||
EnumIter,
|
||||
Ord,
|
||||
)]
|
||||
#[strum(serialize_all = "lowercase")]
|
||||
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
|
||||
use axum::Router;
|
||||
use axum::routing::get;
|
||||
use nym_node_requests::api::v1::lewes_protocol::models;
|
||||
use nym_node_requests::api::SignedLewesProtocol;
|
||||
|
||||
pub mod root;
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Config {
|
||||
pub details: Option<models::LewesProtocol>,
|
||||
pub details: SignedLewesProtocol,
|
||||
}
|
||||
|
||||
pub(crate) fn routes<S: Send + Sync + 'static + Clone>(config: Config) -> Router<S> {
|
||||
|
||||
@@ -4,30 +4,29 @@
|
||||
use axum::extract::Query;
|
||||
use axum::http::StatusCode;
|
||||
use nym_http_api_common::{FormattedResponse, OutputParams};
|
||||
use nym_node_requests::api::v1::lewes_protocol::models::LewesProtocol;
|
||||
use nym_node_requests::api::{SignedLewesProtocol, SignedLewesProtocolInfo};
|
||||
|
||||
/// Returns root Lewes Protocol information
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "",
|
||||
context_path = "/api/v1/lewes-protocol",
|
||||
path = "/lewes-protocol",
|
||||
context_path = "/api/v1",
|
||||
tag = "Lewes Protocol",
|
||||
responses(
|
||||
(status = 501, description = "the endpoint hasn't been implemented yet"),
|
||||
(status = 200, content(
|
||||
(LewesProtocol = "application/json"),
|
||||
(LewesProtocol = "application/yaml"),
|
||||
(LewesProtocol = "application/bincode")
|
||||
(SignedLewesProtocolInfo = "application/json"),
|
||||
(SignedLewesProtocolInfo = "application/yaml"),
|
||||
(SignedLewesProtocolInfo = "application/bincode")
|
||||
))
|
||||
),
|
||||
params(OutputParams)
|
||||
)]
|
||||
pub(crate) async fn root_lewes_protocol(
|
||||
config: Option<LewesProtocol>,
|
||||
config: SignedLewesProtocol,
|
||||
Query(output): Query<OutputParams>,
|
||||
) -> Result<LewesProtocolResponse, StatusCode> {
|
||||
let config = config.ok_or(StatusCode::NOT_IMPLEMENTED)?;
|
||||
Ok(output.to_response(config))
|
||||
}
|
||||
|
||||
pub type LewesProtocolResponse = FormattedResponse<LewesProtocol>;
|
||||
pub type LewesProtocolResponse = FormattedResponse<SignedLewesProtocol>;
|
||||
|
||||
@@ -16,7 +16,8 @@ use nym_node_requests::api::{SignedDataHostInfo, v1::node::models::SignedHostInf
|
||||
responses(
|
||||
(status = 200, content(
|
||||
(SignedDataHostInfo = "application/json"),
|
||||
(SignedDataHostInfo = "application/yaml")
|
||||
(SignedDataHostInfo = "application/yaml"),
|
||||
(SignedDataHostInfo = "application/bincode")
|
||||
))
|
||||
),
|
||||
params(OutputParams)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::node::http::NymNodeHttpServer;
|
||||
use crate::node::http::api::v1::lewes_protocol;
|
||||
use crate::node::http::error::NymNodeHttpError;
|
||||
use crate::node::http::state::AppState;
|
||||
use axum::Router;
|
||||
@@ -9,6 +10,7 @@ use axum::response::Redirect;
|
||||
use axum::routing::get;
|
||||
use nym_bin_common::bin_info_owned;
|
||||
use nym_http_api_common::middleware::logging;
|
||||
use nym_node_requests::api::SignedLewesProtocol;
|
||||
use nym_node_requests::api::v1::authenticator::models::Authenticator;
|
||||
use nym_node_requests::api::v1::gateway::models::{Bridges, Gateway};
|
||||
use nym_node_requests::api::v1::ip_packet_router::models::IpPacketRouter;
|
||||
@@ -33,7 +35,7 @@ pub struct HttpServerConfig {
|
||||
}
|
||||
|
||||
impl HttpServerConfig {
|
||||
pub fn new() -> Self {
|
||||
pub fn new(signed_lewes_protocol: SignedLewesProtocol) -> Self {
|
||||
HttpServerConfig {
|
||||
landing: Default::default(),
|
||||
api: api::Config {
|
||||
@@ -52,7 +54,9 @@ impl HttpServerConfig {
|
||||
network_requester: Default::default(),
|
||||
ip_packet_router: Default::default(),
|
||||
authenticator: Default::default(),
|
||||
lewes_protocol: Default::default(),
|
||||
lewes_protocol: lewes_protocol::Config {
|
||||
details: signed_lewes_protocol,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
+39
-40
@@ -57,6 +57,8 @@ use nym_network_requester::{
|
||||
};
|
||||
use nym_node_metrics::NymNodeMetrics;
|
||||
use nym_node_metrics::events::MetricEventsSender;
|
||||
use nym_node_requests::api::SignedData;
|
||||
use nym_node_requests::api::v1::lewes_protocol::models::{LPHashFunction, LPKEM, LewesProtocol};
|
||||
use nym_node_requests::api::v1::node::models::{AnnouncePorts, NodeDescription};
|
||||
use nym_noise::config::{NoiseConfig, NoiseNetworkView};
|
||||
use nym_noise_keys::VersionedNoiseKeyV1;
|
||||
@@ -70,6 +72,7 @@ use nym_wireguard::{WireguardGatewayData, peer_controller::PeerControlRequest};
|
||||
use rand::rngs::OsRng;
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use rand09::SeedableRng;
|
||||
use std::collections::BTreeMap;
|
||||
use std::net::SocketAddr;
|
||||
use std::ops::Deref;
|
||||
use std::path::Path;
|
||||
@@ -736,13 +739,11 @@ impl NymNode {
|
||||
self.config.gateway_tasks.lp.control_bind_address,
|
||||
self.config.gateway_tasks.lp.data_bind_address,
|
||||
);
|
||||
let lp_listener = gateway_tasks_builder
|
||||
let mut lp_listener = gateway_tasks_builder
|
||||
.build_lp_listener(wg_peer_registrator.clone(), active_clients_store.clone())
|
||||
.await?;
|
||||
// make sure lp listener can be built, but do not start it
|
||||
let _ = lp_listener;
|
||||
// self.shutdown_tracker()
|
||||
// .try_spawn_named(async move { lp_listener.run().await }, "LpListener");
|
||||
self.shutdown_tracker()
|
||||
.try_spawn_named(async move { lp_listener.run().await }, "LpListener");
|
||||
} else {
|
||||
info!("node not running in entry mode: the websocket and LP will remain closed");
|
||||
}
|
||||
@@ -818,40 +819,24 @@ impl NymNode {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
//
|
||||
// fn compute_kem_key_hashes(&self) -> HashMap<LPKEM, HashMap<LPHashFunction, String>> {
|
||||
// let kem = LPKEM::X25519;
|
||||
//
|
||||
// let kem_key_bytes = self.entry_gateway.psq_kem_key.public_key().as_bytes();
|
||||
//
|
||||
// // convert from `nym_kkt_ciphersuite` types into `nym_nodes_requests`
|
||||
// let digests = produce_key_digests(kem_key_bytes.as_ref())
|
||||
// .into_iter()
|
||||
// .map(|(f, digest)| (f.into(), hex::encode(&digest)))
|
||||
// .collect();
|
||||
//
|
||||
// let mut hashes = HashMap::new();
|
||||
// hashes.insert(kem, digests);
|
||||
// hashes
|
||||
// }
|
||||
//
|
||||
// fn compute_signing_key_hashes(
|
||||
// &self,
|
||||
// ) -> HashMap<LPSignatureScheme, HashMap<LPHashFunction, String>> {
|
||||
// let scheme = LPSignatureScheme::Ed25519;
|
||||
//
|
||||
// let kem_key_bytes = self.ed25519_identity_keys.public_key().as_bytes();
|
||||
//
|
||||
// // convert from `nym_kkt_ciphersuite` types into `nym_nodes_requests`
|
||||
// let digests = produce_key_digests(kem_key_bytes.as_ref())
|
||||
// .into_iter()
|
||||
// .map(|(f, digest)| (f.into(), hex::encode(&digest)))
|
||||
// .collect();
|
||||
//
|
||||
// let mut hashes = HashMap::new();
|
||||
// hashes.insert(scheme, digests);
|
||||
// hashes
|
||||
// }
|
||||
|
||||
fn compute_kem_key_hashes(&self) -> BTreeMap<LPKEM, BTreeMap<LPHashFunction, String>> {
|
||||
let digests = self.psq_kem_keys.encapsulation_keys_digests();
|
||||
|
||||
// convert from `nym_kkt_ciphersuite` types into `nym_nodes_requests`
|
||||
digests
|
||||
.into_iter()
|
||||
.map(|(kem, kem_digests)| {
|
||||
(
|
||||
kem.into(),
|
||||
kem_digests
|
||||
.into_iter()
|
||||
.map(|(f, digest)| (f.into(), hex::encode(&digest)))
|
||||
.collect(),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) async fn build_http_server(&self) -> Result<NymNodeHttpServer, NymNodeError> {
|
||||
let auxiliary_details = api_requests::v1::node::models::AuxiliaryDetails {
|
||||
@@ -926,7 +911,21 @@ impl NymNode {
|
||||
policy: None,
|
||||
};
|
||||
|
||||
let mut config = HttpServerConfig::new()
|
||||
let lewes_protocol = LewesProtocol {
|
||||
enabled: self.modes().entry,
|
||||
control_port: self.config.gateway_tasks.lp.announced_control_port(),
|
||||
data_port: self.config.gateway_tasks.lp.announced_data_port(),
|
||||
x25519: self.x25519_lp_keys.pk,
|
||||
kem_keys: self.compute_kem_key_hashes(),
|
||||
};
|
||||
|
||||
// SAFETY: the only way for this call to fail is if serialisation of LewesProtocol fails.
|
||||
// however, that conversion is stable and infallible
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let signed_lewes_protocol =
|
||||
SignedData::new(lewes_protocol, self.ed25519_identity_keys.private_key()).unwrap();
|
||||
|
||||
let mut config = HttpServerConfig::new(signed_lewes_protocol)
|
||||
.with_landing_page_assets(self.config.http.landing_page_assets_path.as_ref())
|
||||
.with_mixnode_details(mixnode_details)
|
||||
.with_gateway_details(gateway_details)
|
||||
|
||||
Reference in New Issue
Block a user