From 3a06e8f8d85a6ba42bf8d149b9137594747fee1c Mon Sep 17 00:00:00 2001 From: danielsanchezq Date: Mon, 25 Mar 2024 16:13:21 +0100 Subject: [PATCH] Base cleaning of da to new traits/structure Added new da protocols and types --- Cargo.toml | 3 +- nodes/nomos-node/src/api.rs | 78 +------ nodes/nomos-node/src/config.rs | 20 -- nodes/nomos-node/src/lib.rs | 37 +-- nodes/nomos-node/src/main.rs | 17 +- nomos-cli/src/api/da.rs | 18 +- nomos-cli/src/cmds/chat/mod.rs | 14 +- nomos-cli/src/cmds/mod.rs | 21 +- nomos-cli/src/da/disseminate.rs | 2 +- nomos-cli/src/lib.rs | 2 +- nomos-core/src/da/attestation/mod.rs | 8 +- nomos-core/src/da/blob/mod.rs | 13 -- nomos-core/src/da/certificate/mod.rs | 13 +- nomos-core/src/da/certificate/select.rs | 2 +- nomos-core/src/da/certificate_metadata.rs | 6 + nomos-core/src/da/mod.rs | 52 ++--- nomos-core/src/da/vid.rs | 7 + nomos-da/full-replication/src/lib.rs | 124 +++------- .../api/src/http/consensus/cryptarchia.rs | 16 +- nomos-services/api/src/http/da.rs | 75 ------ nomos-services/api/src/http/mod.rs | 1 - .../cryptarchia-consensus/src/lib.rs | 10 +- .../src/backend/memory_cache.rs | 68 ------ .../data-availability/src/backend/mod.rs | 24 -- nomos-services/data-availability/src/lib.rs | 213 ------------------ .../src/network/adapters/libp2p.rs | 113 ---------- .../src/network/adapters/mod.rs | 2 - .../data-availability/src/network/mod.rs | 33 --- tests/src/lib.rs | 2 +- tests/src/nodes/mod.rs | 4 +- 30 files changed, 124 insertions(+), 874 deletions(-) delete mode 100644 nomos-core/src/da/blob/mod.rs create mode 100644 nomos-core/src/da/certificate_metadata.rs create mode 100644 nomos-core/src/da/vid.rs delete mode 100644 nomos-services/api/src/http/da.rs delete mode 100644 nomos-services/data-availability/src/backend/memory_cache.rs delete mode 100644 nomos-services/data-availability/src/backend/mod.rs delete mode 100644 nomos-services/data-availability/src/network/adapters/libp2p.rs delete mode 100644 nomos-services/data-availability/src/network/adapters/mod.rs delete mode 100644 nomos-services/data-availability/src/network/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 3aa60f50..ee8cb169 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,8 @@ members = [ "nomos-da/reed-solomon", "nomos-da/kzg", "nomos-da/full-replication", - "nomos-cli", + # TODO: add it again and reimplement full replication + # "nomos-cli", "nomos-utils", "nodes/nomos-node", "mixnet", diff --git a/nodes/nomos-node/src/api.rs b/nodes/nomos-node/src/api.rs index f3a5235b..5b55563a 100644 --- a/nodes/nomos-node/src/api.rs +++ b/nodes/nomos-node/src/api.rs @@ -20,7 +20,7 @@ use utoipa::OpenApi; use utoipa_swagger_ui::SwaggerUi; use full_replication::{Blob, Certificate}; -use nomos_core::{da::blob, header::HeaderId, tx::Transaction}; +use nomos_core::{header::HeaderId, tx::Transaction}; use nomos_mempool::{ network::adapters::libp2p::Libp2pAdapter as MempoolNetworkAdapter, openapi::Status, MempoolMetrics, @@ -29,9 +29,10 @@ use nomos_network::backends::libp2p::Libp2p as NetworkBackend; use nomos_storage::backends::StorageSerde; use nomos_api::{ - http::{cl, consensus, da, libp2p, mempool, metrics, storage}, + http::{cl, consensus, libp2p, mempool, metrics, storage}, Backend, }; +use nomos_core::da::certificate; /// Configuration for the Http Server #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] @@ -51,8 +52,6 @@ pub struct AxumBackend { #[derive(OpenApi)] #[openapi( paths( - da_metrics, - da_status, ), components( schemas(Status, MempoolMetrics) @@ -117,9 +116,6 @@ where ) .layer(TraceLayer::new_for_http()) .merge(SwaggerUi::new("/swagger-ui").url("/api-docs/openapi.json", ApiDoc::openapi())) - .route("/da/metrics", routing::get(da_metrics)) - .route("/da/status", routing::post(da_status)) - .route("/da/blobs", routing::post(da_blobs)) .route("/cl/metrics", routing::get(cl_metrics::)) .route("/cl/status", routing::post(cl_status::)) .route( @@ -133,7 +129,6 @@ where .route("/network/info", routing::get(libp2p_info)) .route("/storage/block", routing::post(block::)) .route("/mempool/add/tx", routing::post(add_tx::)) - .route("/mempool/add/cert", routing::post(add_cert)) .route("/metrics", routing::get(get_metrics)) .with_state(handle); @@ -158,48 +153,6 @@ macro_rules! make_request_and_return_response { }}; } -#[utoipa::path( - get, - path = "/da/metrics", - responses( - (status = 200, description = "Get the mempool metrics of the da service", body = MempoolMetrics), - (status = 500, description = "Internal server error", body = String), - ) -)] -async fn da_metrics(State(handle): State) -> Response { - make_request_and_return_response!(da::da_mempool_metrics(&handle)) -} - -#[utoipa::path( - post, - path = "/da/status", - responses( - (status = 200, description = "Query the mempool status of the da service", body = Vec<::Hash>), - (status = 500, description = "Internal server error", body = String), - ) -)] -async fn da_status( - State(handle): State, - Json(items): Json::Hash>>, -) -> Response { - make_request_and_return_response!(da::da_mempool_status(&handle, items)) -} - -#[utoipa::path( - post, - path = "/da/blobs", - responses( - (status = 200, description = "Get pending blobs", body = Vec), - (status = 500, description = "Internal server error", body = String), - ) -)] -async fn da_blobs( - State(handle): State, - Json(items): Json::Hash>>, -) -> Response { - make_request_and_return_response!(da::da_blobs(&handle, items)) -} - #[utoipa::path( get, path = "/cl/metrics", @@ -360,31 +313,6 @@ where >(&handle, tx, Transaction::hash)) } -#[utoipa::path( - post, - path = "/mempool/add/cert", - responses( - (status = 200, description = "Add certificate to the mempool"), - (status = 500, description = "Internal server error", body = String), - ) -)] -async fn add_cert( - State(handle): State, - Json(cert): Json, -) -> Response { - make_request_and_return_response!(mempool::add::< - NetworkBackend, - MempoolNetworkAdapter::Hash>, - nomos_mempool::Certificate, - Certificate, - ::Hash, - >( - &handle, - cert, - nomos_core::da::certificate::Certificate::hash - )) -} - #[utoipa::path( get, path = "/metrics", diff --git a/nodes/nomos-node/src/config.rs b/nodes/nomos-node/src/config.rs index f1ce6d1b..76ccceda 100644 --- a/nodes/nomos-node/src/config.rs +++ b/nodes/nomos-node/src/config.rs @@ -4,11 +4,9 @@ use std::{ }; use crate::api::AxumBackend; -use crate::DataAvailability; use crate::{Tx, Wire, MB16}; use clap::{Parser, ValueEnum}; use color_eyre::eyre::{eyre, Result}; -use hex::FromHex; use nomos_api::ApiService; use nomos_libp2p::{secp256k1::SecretKey, Multiaddr}; use nomos_log::{Logger, LoggerBackend, LoggerFormat}; @@ -85,12 +83,6 @@ pub struct CryptarchiaArgs { slot_duration: Option, } -#[derive(Parser, Debug, Clone)] -pub struct DaArgs { - #[clap(long = "da-voter", env = "DA_VOTER")] - da_voter: Option, -} - #[derive(Parser, Debug, Clone)] pub struct MetricsArgs { #[clap(long = "with-metrics", env = "WITH_METRICS")] @@ -103,7 +95,6 @@ pub struct Config { pub network: as ServiceData>::Settings, pub http: > as ServiceData>::Settings, pub cryptarchia: ::Settings, - pub da: ::Settings, } impl Config { @@ -217,15 +208,4 @@ impl Config { Ok(self) } - - pub fn update_da(mut self, da_args: DaArgs) -> Result { - let DaArgs { da_voter } = da_args; - - if let Some(voter) = da_voter { - let bytes = <[u8; 32]>::from_hex(voter)?; - self.da.da_protocol.voter = bytes; - } - - Ok(self) - } } diff --git a/nodes/nomos-node/src/lib.rs b/nodes/nomos-node/src/lib.rs index e1517236..9982b95f 100644 --- a/nodes/nomos-node/src/lib.rs +++ b/nodes/nomos-node/src/lib.rs @@ -10,18 +10,9 @@ use metrics::{backend::map::MapMetricsBackend, types::MetricsData, MetricsServic use api::AxumBackend; use bytes::Bytes; -pub use config::{Config, CryptarchiaArgs, DaArgs, HttpArgs, LogArgs, MetricsArgs, NetworkArgs}; +pub use config::{Config, CryptarchiaArgs, HttpArgs, LogArgs, MetricsArgs, NetworkArgs}; use nomos_api::ApiService; -use nomos_core::{ - da::{blob, certificate}, - header::HeaderId, - tx::Transaction, - wire, -}; -use nomos_da::{ - backend::memory_cache::BlobCache, network::adapters::libp2p::Libp2pAdapter as DaNetworkAdapter, - DataAvailabilityService, -}; +use nomos_core::{da::certificate, header::HeaderId, tx::Transaction, wire}; use nomos_log::Logger; use nomos_mempool::network::adapters::libp2p::Libp2pAdapter as MempoolNetworkAdapter; use nomos_mempool::{ @@ -58,26 +49,13 @@ pub type Cryptarchia = cryptarchia_consensus::CryptarchiaConsensus< cryptarchia_consensus::network::adapters::libp2p::LibP2pAdapter, MockPool::Hash>, MempoolNetworkAdapter::Hash>, - MockPool< - HeaderId, - Certificate, - <::Blob as blob::Blob>::Hash, - >, - MempoolNetworkAdapter< - Certificate, - <::Blob as blob::Blob>::Hash, - >, + MockPool::Id>, + MempoolNetworkAdapter::Id>, FillSizeWithTx, FillSizeWithBlobsCertificate, RocksBackend, >; -pub type DataAvailability = DataAvailabilityService< - FullReplication>, - BlobCache<::Hash, Blob>, - DaNetworkAdapter, ->; - type Mempool = MempoolService, MockPool, D>; #[derive(Services)] @@ -86,15 +64,10 @@ pub struct Nomos { network: ServiceHandle>, cl_mempool: ServiceHandle::Hash, TxDiscriminant>>, da_mempool: ServiceHandle< - Mempool< - Certificate, - <::Blob as blob::Blob>::Hash, - CertDiscriminant, - >, + Mempool::Id, CertDiscriminant>, >, cryptarchia: ServiceHandle, http: ServiceHandle>>, - da: ServiceHandle, storage: ServiceHandle>>, #[cfg(feature = "metrics")] metrics: ServiceHandle, diff --git a/nodes/nomos-node/src/main.rs b/nodes/nomos-node/src/main.rs index 414b56ca..8381da67 100644 --- a/nodes/nomos-node/src/main.rs +++ b/nodes/nomos-node/src/main.rs @@ -2,16 +2,13 @@ use full_replication::{Blob, Certificate}; #[cfg(feature = "metrics")] use nomos_metrics::MetricsSettings; use nomos_node::{ - Config, CryptarchiaArgs, DaArgs, HttpArgs, LogArgs, MetricsArgs, NetworkArgs, Nomos, + Config, CryptarchiaArgs, HttpArgs, LogArgs, MetricsArgs, NetworkArgs, Nomos, NomosServiceSettings, Tx, }; use clap::Parser; use color_eyre::eyre::{eyre, Result}; -use nomos_core::{ - da::{blob, certificate}, - tx::Transaction, -}; +use nomos_core::{da::certificate, tx::Transaction}; use nomos_mempool::network::adapters::libp2p::Settings as AdapterSettings; @@ -35,9 +32,6 @@ struct Args { http_args: HttpArgs, #[clap(flatten)] cryptarchia_args: CryptarchiaArgs, - /// Overrides da config. - #[clap(flatten)] - da_args: DaArgs, /// Overrides metrics config. #[clap(flatten)] metrics_args: MetricsArgs, @@ -46,7 +40,6 @@ struct Args { fn main() -> Result<()> { let Args { config, - da_args, log_args, http_args, network_args, @@ -54,7 +47,6 @@ fn main() -> Result<()> { metrics_args, } = Args::parse(); let config = serde_yaml::from_reader::<_, Config>(std::fs::File::open(config)?)? - .update_da(da_args)? .update_log(log_args)? .update_http(http_args)? .update_network(network_args)? @@ -92,7 +84,6 @@ fn main() -> Result<()> { cryptarchia: config.cryptarchia, #[cfg(feature = "metrics")] metrics: MetricsSettings { registry }, - da: config.da, storage: nomos_storage::backends::rocksdb::RocksBackendSettings { db_path: std::path::PathBuf::from(DEFAULT_DB_PATH), read_only: false, @@ -107,7 +98,7 @@ fn main() -> Result<()> { Ok(()) } -fn cert_id(cert: &Certificate) -> ::Hash { +fn cert_id(cert: &Certificate) -> ::Id { use certificate::Certificate; - cert.hash() + cert.id() } diff --git a/nomos-cli/src/api/da.rs b/nomos-cli/src/api/da.rs index 7a3d3c07..42d956c6 100644 --- a/nomos-cli/src/api/da.rs +++ b/nomos-cli/src/api/da.rs @@ -1,18 +1,4 @@ use super::CLIENT; -use full_replication::Blob; -use nomos_core::da::blob; +use full_replication::Certificate; +use nomos_core::da::certificate; use reqwest::Url; - -pub async fn get_blobs( - node: &Url, - ids: Vec<::Hash>, -) -> Result, reqwest::Error> { - const BLOBS_PATH: &str = "da/blobs"; - CLIENT - .post(node.join(BLOBS_PATH).unwrap()) - .json(&ids) - .send() - .await? - .json() - .await -} diff --git a/nomos-cli/src/cmds/chat/mod.rs b/nomos-cli/src/cmds/chat/mod.rs index 69a604d7..62d3c9df 100644 --- a/nomos-cli/src/cmds/chat/mod.rs +++ b/nomos-cli/src/cmds/chat/mod.rs @@ -6,19 +6,19 @@ mod ui; use crate::{ api::consensus::get_headers_info, - da::{ - disseminate::{ - DaProtocolChoice, DisseminateApp, DisseminateAppServiceSettings, Settings, Status, - }, - retrieve::get_block_blobs, - }, + //da::{ + // disseminate::{ + // DaProtocolChoice, DisseminateApp, DisseminateAppServiceSettings, Settings, Status, + // }, + // retrieve::get_block_blobs, + //}, }; use clap::Args; use full_replication::{ AbsoluteNumber, Attestation, Certificate, FullReplication, Settings as DaSettings, }; use futures::{stream, StreamExt}; -use nomos_core::{da::DaProtocol, header::HeaderId, wire}; +use nomos_core::{header::HeaderId, wire}; use nomos_log::{LoggerBackend, LoggerSettings, SharedWriter}; use nomos_network::backends::libp2p::Libp2p as NetworkBackend; use nomos_network::NetworkService; diff --git a/nomos-cli/src/cmds/mod.rs b/nomos-cli/src/cmds/mod.rs index bf2648ac..4d4752d7 100644 --- a/nomos-cli/src/cmds/mod.rs +++ b/nomos-cli/src/cmds/mod.rs @@ -1,21 +1,22 @@ use clap::Subcommand; -pub mod chat; -pub mod disseminate; +// pub mod chat; +// pub mod disseminate; #[derive(Debug, Subcommand)] pub enum Command { - /// Send a blob to the network and collect attestations to create a DA proof - Disseminate(disseminate::Disseminate), - /// (Almost) Instant messaging protocol on top of the Nomos network - Chat(chat::NomosChat), + // /// Send a blob to the network and collect attestations to create a DA proof + // Disseminate(disseminate::Disseminate), + // /// (Almost) Instant messaging protocol on top of the Nomos network + // Chat(chat::NomosChat), } impl Command { pub fn run(&self) -> Result<(), Box> { - match self { - Command::Disseminate(cmd) => cmd.run(), - Command::Chat(cmd) => cmd.run(), - } + // match self { + // Command::Disseminate(cmd) => cmd.run(), + // Command::Chat(cmd) => cmd.run(), + // } + Ok(()) } } diff --git a/nomos-cli/src/da/disseminate.rs b/nomos-cli/src/da/disseminate.rs index ec4fc5bd..729547ea 100644 --- a/nomos-cli/src/da/disseminate.rs +++ b/nomos-cli/src/da/disseminate.rs @@ -3,7 +3,7 @@ use clap::{Args, ValueEnum}; use full_replication::{AbsoluteNumber, Attestation, Certificate, FullReplication, Voter}; use futures::StreamExt; use hex::FromHex; -use nomos_core::{da::DaProtocol, wire}; +use nomos_core::wire; use nomos_da::network::{adapters::libp2p::Libp2pAdapter as DaNetworkAdapter, NetworkAdapter}; use nomos_log::Logger; use nomos_network::backends::libp2p::Libp2p as NetworkBackend; diff --git a/nomos-cli/src/lib.rs b/nomos-cli/src/lib.rs index 27e0099a..ffc18115 100644 --- a/nomos-cli/src/lib.rs +++ b/nomos-cli/src/lib.rs @@ -1,6 +1,6 @@ pub mod api; pub mod cmds; -pub mod da; +// pub mod da; use clap::Parser; use cmds::Command; diff --git a/nomos-core/src/da/attestation/mod.rs b/nomos-core/src/da/attestation/mod.rs index a3dfd8dd..eadd31db 100644 --- a/nomos-core/src/da/attestation/mod.rs +++ b/nomos-core/src/da/attestation/mod.rs @@ -1,11 +1,7 @@ -use crate::da::blob::Blob; use bytes::Bytes; use std::hash::Hash; pub trait Attestation { - type Blob: Blob; - type Hash: Hash + Eq + Clone; - fn blob(&self) -> ::Hash; - fn hash(&self) -> Self::Hash; - fn as_bytes(&self) -> Bytes; + type Signature; + fn attestation_signature(&self) -> Self::Signature; } diff --git a/nomos-core/src/da/blob/mod.rs b/nomos-core/src/da/blob/mod.rs deleted file mode 100644 index f7780db4..00000000 --- a/nomos-core/src/da/blob/mod.rs +++ /dev/null @@ -1,13 +0,0 @@ -use bytes::Bytes; -use std::hash::Hash; - -pub type BlobHasher = fn(&T) -> ::Hash; - -pub trait Blob { - const HASHER: BlobHasher; - type Hash: Hash + Eq + Clone; - fn hash(&self) -> Self::Hash { - Self::HASHER(self) - } - fn as_bytes(&self) -> Bytes; -} diff --git a/nomos-core/src/da/certificate/mod.rs b/nomos-core/src/da/certificate/mod.rs index cd1238af..86e1e5b2 100644 --- a/nomos-core/src/da/certificate/mod.rs +++ b/nomos-core/src/da/certificate/mod.rs @@ -1,15 +1,16 @@ pub mod select; -use crate::da::blob::Blob; use bytes::Bytes; use std::hash::Hash; pub trait Certificate { - type Blob: Blob; - type Hash: Hash + Eq + Clone; - fn blob(&self) -> ::Hash; - fn hash(&self) -> Self::Hash; - fn as_bytes(&self) -> Bytes; + type VerificationParameters; + type Signature; + type Id; + fn signers(&self) -> Vec; + fn signature(&self) -> Self::Signature; + fn id(&self) -> Self::Id; + fn verify(&self, authorization_parameters: Self::VerificationParameters) -> bool; } pub trait BlobCertificateSelect { diff --git a/nomos-core/src/da/certificate/select.rs b/nomos-core/src/da/certificate/select.rs index fe2f08f0..163d8e77 100644 --- a/nomos-core/src/da/certificate/select.rs +++ b/nomos-core/src/da/certificate/select.rs @@ -32,7 +32,7 @@ impl BlobCertificateSelect for FillSize impl Iterator + 'i { utils::select::select_from_till_fill_size::( - |blob| blob.as_bytes().len(), + |blob| SIZE, certificates, ) } diff --git a/nomos-core/src/da/certificate_metadata.rs b/nomos-core/src/da/certificate_metadata.rs new file mode 100644 index 00000000..512a75b8 --- /dev/null +++ b/nomos-core/src/da/certificate_metadata.rs @@ -0,0 +1,6 @@ +use super::certificate::Certificate; + +pub trait CertificateExtension { + type Extension; + fn extension(&self) -> Self::Extension; +} diff --git a/nomos-core/src/da/mod.rs b/nomos-core/src/da/mod.rs index db301fba..12921613 100644 --- a/nomos-core/src/da/mod.rs +++ b/nomos-core/src/da/mod.rs @@ -1,40 +1,26 @@ +use std::error::Error; // crates -use bytes::Bytes; // internal -use crate::da::attestation::Attestation; -use crate::da::blob::Blob; -use crate::da::certificate::Certificate; pub mod attestation; -pub mod blob; pub mod certificate; +pub mod certificate_metadata; +pub mod vid; -pub trait DaProtocol { - type Blob: Blob; - type Attestation: Attestation; - type Certificate: Certificate; - type Settings: Clone; - - // Construct a new instance - fn new(settings: Self::Settings) -> Self; - /// Encode bytes into blobs - fn encode>(&self, data: T) -> Vec; - /// Feed a blob for decoding. - /// Depending on the protocol, it may be necessary to feed multiple blobs to - /// recover the initial data. - fn recv_blob(&mut self, blob: Self::Blob); - /// Attempt to recover the initial data from fed blobs. - /// If the protocol is not yet ready to return the data, return None. - fn extract(&mut self) -> Option; - /// Attest that we have received and stored a blob. - fn attest(&self, blob: &Self::Blob) -> Self::Attestation; - /// Validate that an attestation is valid for a blob. - fn validate_attestation(&self, blob: &Self::Blob, attestation: &Self::Attestation) -> bool; - /// Buffer attestations to produce a certificate of correct dispersal. - fn recv_attestation(&mut self, attestation: Self::Attestation); - /// Attempt to produce a certificate of correct disperal for a blob. - /// If the protocol is not yet ready to return the certificate, return None. - fn certify_dispersal(&mut self) -> Option; - /// Validate a certificate. - fn validate_certificate(&self, certificate: &Self::Certificate) -> bool; +pub trait DaEncoder { + type EncodedData; + fn encode(b: &[u8]) -> Result; +} + +pub trait DaVerifier { + type DaBlob; + type Attestation; + fn verify(&self, blob: Self::DaBlob) -> Result; +} + +pub trait DaDispersal { + type EncodedData; + type Certificate; + + fn disperse(&self, encoded_data: Self::EncodedData) -> Result; } diff --git a/nomos-core/src/da/vid.rs b/nomos-core/src/da/vid.rs new file mode 100644 index 00000000..c72b4e82 --- /dev/null +++ b/nomos-core/src/da/vid.rs @@ -0,0 +1,7 @@ +use crate::da::certificate_metadata::CertificateExtension; + +pub trait VID: CertificateExtension { + type CertificateId; + + fn certificate_id(&self) -> Self::CertificateId; +} diff --git a/nomos-da/full-replication/src/lib.rs b/nomos-da/full-replication/src/lib.rs index e39c6d7b..0ace160f 100644 --- a/nomos-da/full-replication/src/lib.rs +++ b/nomos-da/full-replication/src/lib.rs @@ -1,8 +1,7 @@ // internal use nomos_core::da::{ attestation::{self, Attestation as _}, - blob::{self, BlobHasher}, - certificate, DaProtocol, + certificate, }; // std use std::collections::HashSet; @@ -13,6 +12,7 @@ use blake2::{ Blake2bVar, }; use bytes::Bytes; +use nomos_core::da::certificate_metadata::CertificateExtension; use nomos_core::wire; use serde::{Deserialize, Serialize}; @@ -111,15 +111,6 @@ fn hasher(blob: &Blob) -> [u8; 32] { output } -impl blob::Blob for Blob { - const HASHER: BlobHasher = hasher as BlobHasher; - type Hash = [u8; 32]; - - fn as_bytes(&self) -> bytes::Bytes { - self.data.clone() - } -} - #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] #[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))] pub struct Attestation { @@ -128,22 +119,11 @@ pub struct Attestation { } impl attestation::Attestation for Attestation { - type Blob = Blob; - type Hash = [u8; 32]; + type Signature = [u8; 32]; - fn blob(&self) -> [u8; 32] { - self.blob - } - - fn hash(&self) -> ::Hash { + fn attestation_signature(&self) -> Self::Signature { hash([self.blob, self.voter].concat()) } - - fn as_bytes(&self) -> Bytes { - wire::serialize(self) - .expect("Attestation shouldn't fail to be serialized") - .into() - } } #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] @@ -154,92 +134,54 @@ pub struct Certificate { impl Hash for Certificate { fn hash(&self, state: &mut H) { - state.write(certificate::Certificate::as_bytes(self).as_ref()); + state.write(::id(self).as_ref()); } } -impl certificate::Certificate for Certificate { - type Blob = Blob; - type Hash = [u8; 32]; +pub struct CertificateVerificationParameters { + threshold: usize, +} - fn blob(&self) -> ::Hash { - self.attestations[0].blob +impl certificate::Certificate for Certificate { + type VerificationParameters = CertificateVerificationParameters; + type Signature = [u8; 32]; + type Id = [u8; 32]; + + fn signers(&self) -> Vec { + self.attestations.iter().map(|_| true).collect() } - fn hash(&self) -> ::Hash { + fn signature(&self) -> Self::Signature { + let signatures: Vec = self + .attestations + .iter() + .map(|attestation| attestation.attestation_signature()) + .flatten() + .collect(); + hash(signatures) + } + + fn id(&self) -> Self::Id { let mut input = self .attestations .iter() - .map(|a| a.hash()) + .map(|a| a.attestation_signature()) .collect::>(); // sort to make the hash deterministic input.sort(); hash(input.concat()) } - fn as_bytes(&self) -> Bytes { - wire::serialize(self) - .expect("Certificate shouldn't fail to be serialized") - .into() + fn verify(&self, authorization_parameters: Self::VerificationParameters) -> bool { + authorization_parameters.threshold <= self.attestations.len() } } -// TODO: add generic impl when the trait for Certificate is expanded -impl DaProtocol for FullReplication> { - type Blob = Blob; - type Attestation = Attestation; - type Certificate = Certificate; - type Settings = Settings; +impl CertificateExtension for Certificate { + type Extension = (); - fn new(settings: Self::Settings) -> Self { - Self::new( - settings.voter, - AbsoluteNumber::new(settings.num_attestations), - ) - } - - fn encode>(&self, data: T) -> Vec { - vec![Blob { - data: Bytes::copy_from_slice(data.as_ref()), - }] - } - - fn recv_blob(&mut self, blob: Self::Blob) { - self.output_buffer.push(blob.data); - } - - fn extract(&mut self) -> Option { - self.output_buffer.pop() - } - - fn attest(&self, blob: &Self::Blob) -> Self::Attestation { - Attestation { - blob: hasher(blob), - voter: self.voter, - } - } - - fn validate_attestation(&self, blob: &Self::Blob, attestation: &Self::Attestation) -> bool { - hasher(blob) == attestation.blob - } - - fn recv_attestation(&mut self, attestation: Self::Attestation) { - self.attestations.push(attestation); - if self.certificate_strategy.can_build(&self.attestations) { - self.output_certificate_buf.push( - self.certificate_strategy - .build(std::mem::take(&mut self.attestations)), - ); - } - } - - fn certify_dispersal(&mut self) -> Option { - self.output_certificate_buf.pop() - } - - fn validate_certificate(&self, certificate: &Self::Certificate) -> bool { - self.certificate_strategy - .can_build(&certificate.attestations) + fn extension(&self) -> Self::Extension { + () } } diff --git a/nomos-services/api/src/http/consensus/cryptarchia.rs b/nomos-services/api/src/http/consensus/cryptarchia.rs index 7fff5f87..6d54560a 100644 --- a/nomos-services/api/src/http/consensus/cryptarchia.rs +++ b/nomos-services/api/src/http/consensus/cryptarchia.rs @@ -11,10 +11,7 @@ use cryptarchia_consensus::{ }; use full_replication::Certificate; use nomos_core::{ - da::{ - blob, - certificate::{self, select::FillSize as FillSizeWithBlobsCertificate}, - }, + da::certificate::{self, select::FillSize as FillSizeWithBlobsCertificate}, header::HeaderId, tx::{select::FillSize as FillSizeWithTx, Transaction}, }; @@ -27,15 +24,8 @@ pub type Cryptarchia = CryptarchiaConsensus< ConsensusNetworkAdapter, MockPool::Hash>, MempoolNetworkAdapter::Hash>, - MockPool< - HeaderId, - Certificate, - <::Blob as blob::Blob>::Hash, - >, - MempoolNetworkAdapter< - Certificate, - <::Blob as blob::Blob>::Hash, - >, + MockPool::Id>, + MempoolNetworkAdapter::Id>, FillSizeWithTx, FillSizeWithBlobsCertificate, RocksBackend, diff --git a/nomos-services/api/src/http/da.rs b/nomos-services/api/src/http/da.rs deleted file mode 100644 index d2f44f3a..00000000 --- a/nomos-services/api/src/http/da.rs +++ /dev/null @@ -1,75 +0,0 @@ -use full_replication::{AbsoluteNumber, Attestation, Blob, Certificate, FullReplication}; -use nomos_core::da::blob; -use nomos_core::header::HeaderId; -use nomos_da::{ - backend::memory_cache::BlobCache, network::adapters::libp2p::Libp2pAdapter as DaNetworkAdapter, - DaMsg, DataAvailabilityService, -}; -use nomos_mempool::{ - backend::mockpool::MockPool, - network::adapters::libp2p::Libp2pAdapter as MempoolNetworkAdapter, - openapi::{MempoolMetrics, Status}, - Certificate as CertDiscriminant, MempoolMsg, MempoolService, -}; -use tokio::sync::oneshot; - -pub type DaMempoolService = MempoolService< - MempoolNetworkAdapter::Hash>, - MockPool::Hash>, - CertDiscriminant, ->; - -pub type DataAvailability = DataAvailabilityService< - FullReplication>, - BlobCache<::Hash, Blob>, - DaNetworkAdapter, ->; - -pub async fn da_mempool_metrics( - handle: &overwatch_rs::overwatch::handle::OverwatchHandle, -) -> Result { - let relay = handle.relay::().connect().await?; - let (sender, receiver) = oneshot::channel(); - relay - .send(MempoolMsg::Metrics { - reply_channel: sender, - }) - .await - .map_err(|(e, _)| e)?; - - Ok(receiver.await.unwrap()) -} - -pub async fn da_mempool_status( - handle: &overwatch_rs::overwatch::handle::OverwatchHandle, - items: Vec<::Hash>, -) -> Result>, super::DynError> { - let relay = handle.relay::().connect().await?; - let (sender, receiver) = oneshot::channel(); - relay - .send(MempoolMsg::Status { - items, - reply_channel: sender, - }) - .await - .map_err(|(e, _)| e)?; - - Ok(receiver.await.unwrap()) -} - -pub async fn da_blobs( - handle: &overwatch_rs::overwatch::handle::OverwatchHandle, - ids: Vec<::Hash>, -) -> Result, super::DynError> { - let relay = handle.relay::().connect().await?; - let (reply_channel, receiver) = oneshot::channel(); - relay - .send(DaMsg::Get { - ids: Box::new(ids.into_iter()), - reply_channel, - }) - .await - .map_err(|(e, _)| e)?; - - Ok(receiver.await?) -} diff --git a/nomos-services/api/src/http/mod.rs b/nomos-services/api/src/http/mod.rs index 6ab13b2a..d63a1021 100644 --- a/nomos-services/api/src/http/mod.rs +++ b/nomos-services/api/src/http/mod.rs @@ -1,7 +1,6 @@ pub type DynError = Box; pub mod cl; pub mod consensus; -pub mod da; pub mod libp2p; pub mod mempool; pub mod metrics; diff --git a/nomos-services/cryptarchia-consensus/src/lib.rs b/nomos-services/cryptarchia-consensus/src/lib.rs index 4fbea2ca..a0f5de71 100644 --- a/nomos-services/cryptarchia-consensus/src/lib.rs +++ b/nomos-services/cryptarchia-consensus/src/lib.rs @@ -8,6 +8,7 @@ use cryptarchia_ledger::{Coin, LeaderProof, LedgerState}; use futures::StreamExt; use network::{messages::NetworkMessage, NetworkAdapter}; use nomos_core::da::certificate::{BlobCertificateSelect, Certificate}; +use nomos_core::da::certificate_metadata::CertificateExtension; use nomos_core::header::{cryptarchia::Header, HeaderId}; use nomos_core::tx::{Transaction, TxSelect}; use nomos_core::{ @@ -201,7 +202,9 @@ where + Send + Sync + 'static, - DaPool::Item: Certificate + // TODO: Change to specific certificate bounds here + DaPool::Item: Certificate + + CertificateExtension + Debug + Clone + Eq @@ -368,7 +371,8 @@ where + Send + Sync + 'static, - DaPool::Item: Certificate + DaPool::Item: Certificate + + CertificateExtension + Debug + Clone + Eq @@ -489,7 +493,7 @@ where ) .await; - mark_in_block(da_mempool_relay, block.blobs().map(Certificate::hash), id).await; + mark_in_block(da_mempool_relay, block.blobs().map(Certificate::id), id).await; // store block let msg = >::new_store_message(header.id(), block.clone()); diff --git a/nomos-services/data-availability/src/backend/memory_cache.rs b/nomos-services/data-availability/src/backend/memory_cache.rs deleted file mode 100644 index 8b64e37c..00000000 --- a/nomos-services/data-availability/src/backend/memory_cache.rs +++ /dev/null @@ -1,68 +0,0 @@ -use crate::backend::{DaBackend, DaError}; -use moka::future::{Cache, CacheBuilder}; -use nomos_core::da::blob::Blob; -use serde::{Deserialize, Serialize}; -use std::time::Duration; - -#[derive(Clone, Copy, Debug, Serialize, Deserialize)] -pub struct BlobCacheSettings { - pub max_capacity: usize, - pub evicting_period: Duration, -} - -pub struct BlobCache(Cache); - -impl BlobCache -where - B: Clone + Blob + Send + Sync + 'static, - B::Hash: Send + Sync + 'static, -{ - pub fn new(settings: BlobCacheSettings) -> Self { - let BlobCacheSettings { - max_capacity, - evicting_period, - } = settings; - let cache = CacheBuilder::new(max_capacity as u64) - .time_to_live(evicting_period) - // can we leverage this to evict really old blobs? - .time_to_idle(evicting_period) - .build(); - Self(cache) - } - - pub async fn add(&self, blob: B) { - self.0.insert(blob.hash(), blob).await - } - - pub async fn remove(&self, hash: &B::Hash) { - self.0.remove(hash).await; - } -} - -#[async_trait::async_trait] -impl DaBackend for BlobCache -where - B: Clone + Blob + Send + Sync + 'static, - B::Hash: Send + Sync + 'static, -{ - type Settings = BlobCacheSettings; - type Blob = B; - - fn new(settings: Self::Settings) -> Self { - BlobCache::new(settings) - } - - async fn add_blob(&self, blob: Self::Blob) -> Result<(), DaError> { - self.add(blob).await; - Ok(()) - } - - async fn remove_blob(&self, blob: &::Hash) -> Result<(), DaError> { - self.remove(blob).await; - Ok(()) - } - - fn get_blob(&self, id: &::Hash) -> Option { - self.0.get(id) - } -} diff --git a/nomos-services/data-availability/src/backend/mod.rs b/nomos-services/data-availability/src/backend/mod.rs deleted file mode 100644 index 6ed72c33..00000000 --- a/nomos-services/data-availability/src/backend/mod.rs +++ /dev/null @@ -1,24 +0,0 @@ -pub mod memory_cache; - -use nomos_core::da::blob::Blob; -use overwatch_rs::DynError; - -#[derive(Debug)] -pub enum DaError { - Dyn(DynError), -} - -#[async_trait::async_trait] -pub trait DaBackend { - type Settings: Clone; - - type Blob: Blob; - - fn new(settings: Self::Settings) -> Self; - - async fn add_blob(&self, blob: Self::Blob) -> Result<(), DaError>; - - async fn remove_blob(&self, blob: &::Hash) -> Result<(), DaError>; - - fn get_blob(&self, id: &::Hash) -> Option; -} diff --git a/nomos-services/data-availability/src/lib.rs b/nomos-services/data-availability/src/lib.rs index edffb8fb..8b137891 100644 --- a/nomos-services/data-availability/src/lib.rs +++ b/nomos-services/data-availability/src/lib.rs @@ -1,214 +1 @@ -pub mod backend; -pub mod network; -// std -use overwatch_rs::DynError; -use std::fmt::{Debug, Formatter}; -// crates -use futures::StreamExt; -use serde::{Deserialize, Serialize}; -use tokio::sync::oneshot::Sender; -// internal -use crate::backend::{DaBackend, DaError}; -use crate::network::NetworkAdapter; -use nomos_core::da::{blob::Blob, DaProtocol}; -use nomos_network::NetworkService; -use overwatch_rs::services::handle::ServiceStateHandle; -use overwatch_rs::services::life_cycle::LifecycleMessage; -use overwatch_rs::services::relay::{Relay, RelayMessage}; -use overwatch_rs::services::state::{NoOperator, NoState}; -use overwatch_rs::services::{ServiceCore, ServiceData, ServiceId}; -use tracing::error; - -pub struct DataAvailabilityService -where - Protocol: DaProtocol, - Backend: DaBackend, - Backend::Blob: 'static, - Network: NetworkAdapter, -{ - service_state: ServiceStateHandle, - backend: Backend, - da: Protocol, - network_relay: Relay>, -} - -pub enum DaMsg { - RemoveBlobs { - blobs: Box::Hash> + Send>, - }, - Get { - ids: Box::Hash> + Send>, - reply_channel: Sender>, - }, -} - -impl Debug for DaMsg { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - DaMsg::RemoveBlobs { .. } => { - write!(f, "DaMsg::RemoveBlobs") - } - DaMsg::Get { .. } => { - write!(f, "DaMsg::Get") - } - } - } -} - -impl RelayMessage for DaMsg {} - -impl ServiceData for DataAvailabilityService -where - Protocol: DaProtocol, - Backend: DaBackend, - Backend::Blob: 'static, - Network: NetworkAdapter, -{ - const SERVICE_ID: ServiceId = "DA"; - type Settings = Settings; - type State = NoState; - type StateOperator = NoOperator; - type Message = DaMsg; -} - -impl DataAvailabilityService -where - Protocol: DaProtocol + Send + Sync, - Backend: DaBackend + Send + Sync, - Protocol::Settings: Clone + Send + Sync + 'static, - Protocol::Blob: 'static, - Backend::Settings: Clone + Send + Sync + 'static, - Protocol::Blob: Send, - Protocol::Attestation: Send, - ::Hash: Debug + Send + Sync, - Network: - NetworkAdapter + Send + Sync, -{ - async fn handle_new_blob( - da: &Protocol, - backend: &Backend, - adapter: &Network, - blob: Protocol::Blob, - ) -> Result<(), DaError> { - // we need to handle the reply (verification + signature) - let attestation = da.attest(&blob); - backend.add_blob(blob).await?; - // we do not call `da.recv_blob` here because that is meant to - // be called to retrieve the original data, while here we're only interested - // in storing the blob. - // We might want to refactor the backend to be part of implementations of the - // Da protocol instead of this service and clear this confusion. - adapter - .send_attestation(attestation) - .await - .map_err(DaError::Dyn) - } - - async fn handle_da_msg(backend: &Backend, msg: DaMsg) -> Result<(), DaError> { - match msg { - DaMsg::RemoveBlobs { blobs } => { - futures::stream::iter(blobs) - .for_each_concurrent(None, |blob| async move { - if let Err(e) = backend.remove_blob(&blob).await { - tracing::debug!("Could not remove blob {blob:?} due to: {e:?}"); - } - }) - .await; - } - DaMsg::Get { ids, reply_channel } => { - let res = ids.filter_map(|id| backend.get_blob(&id)).collect(); - if reply_channel.send(res).is_err() { - tracing::error!("Could not returns blobs"); - } - } - } - Ok(()) - } - - async fn should_stop_service(message: LifecycleMessage) -> bool { - match message { - LifecycleMessage::Shutdown(sender) => { - if sender.send(()).is_err() { - error!( - "Error sending successful shutdown signal from service {}", - Self::SERVICE_ID - ); - } - true - } - LifecycleMessage::Kill => true, - } - } -} - -#[async_trait::async_trait] -impl ServiceCore for DataAvailabilityService -where - Protocol: DaProtocol + Send + Sync, - Backend: DaBackend + Send + Sync, - Protocol::Settings: Clone + Send + Sync + 'static, - Backend::Settings: Clone + Send + Sync + 'static, - Protocol::Blob: Send, - Protocol::Attestation: Send, - ::Hash: Debug + Send + Sync, - Network: - NetworkAdapter + Send + Sync, -{ - fn init(service_state: ServiceStateHandle) -> Result { - let network_relay = service_state.overwatch_handle.relay(); - let settings = service_state.settings_reader.get_updated_settings(); - let backend = Backend::new(settings.backend); - let da = Protocol::new(settings.da_protocol); - Ok(Self { - service_state, - backend, - da, - network_relay, - }) - } - - async fn run(self) -> Result<(), DynError> { - let Self { - mut service_state, - backend, - da, - network_relay, - } = self; - - let network_relay = network_relay - .connect() - .await - .expect("Relay connection with NetworkService should succeed"); - - let adapter = Network::new(network_relay).await; - let mut network_blobs = adapter.blob_stream().await; - let mut lifecycle_stream = service_state.lifecycle_handle.message_stream(); - loop { - tokio::select! { - Some(blob) = network_blobs.next() => { - if let Err(e) = Self::handle_new_blob(&da, &backend, &adapter, blob).await { - tracing::debug!("Failed to add a new received blob: {e:?}"); - } - } - Some(msg) = service_state.inbound_relay.recv() => { - if let Err(e) = Self::handle_da_msg(&backend, msg).await { - tracing::debug!("Failed to handle da msg: {e:?}"); - } - } - Some(msg) = lifecycle_stream.next() => { - if Self::should_stop_service(msg).await { - break; - } - } - } - } - Ok(()) - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, Default)] -pub struct Settings { - pub da_protocol: P, - pub backend: B, -} diff --git a/nomos-services/data-availability/src/network/adapters/libp2p.rs b/nomos-services/data-availability/src/network/adapters/libp2p.rs deleted file mode 100644 index b219833f..00000000 --- a/nomos-services/data-availability/src/network/adapters/libp2p.rs +++ /dev/null @@ -1,113 +0,0 @@ -// std -use futures::Stream; -use overwatch_rs::DynError; -use std::marker::PhantomData; -// crates - -// internal -use crate::network::NetworkAdapter; -use nomos_core::wire; -use nomos_network::backends::libp2p::{Command, Event, EventKind, Libp2p, Message, TopicHash}; -use nomos_network::{NetworkMsg, NetworkService}; -use overwatch_rs::services::relay::OutboundRelay; -use overwatch_rs::services::ServiceData; -use serde::de::DeserializeOwned; -use serde::Serialize; -use tokio_stream::wrappers::BroadcastStream; -use tokio_stream::StreamExt; -use tracing::debug; - -pub const NOMOS_DA_TOPIC: &str = "NomosDa"; - -pub struct Libp2pAdapter { - network_relay: OutboundRelay< as ServiceData>::Message>, - _blob: PhantomData, - _attestation: PhantomData, -} - -impl Libp2pAdapter -where - B: Serialize + DeserializeOwned + Send + Sync + 'static, - A: Serialize + DeserializeOwned + Send + Sync + 'static, -{ - async fn stream_for(&self) -> Box + Unpin + Send> { - let topic_hash = TopicHash::from_raw(NOMOS_DA_TOPIC); - let (sender, receiver) = tokio::sync::oneshot::channel(); - self.network_relay - .send(NetworkMsg::Subscribe { - kind: EventKind::Message, - sender, - }) - .await - .expect("Network backend should be ready"); - let receiver = receiver.await.unwrap(); - Box::new(Box::pin(BroadcastStream::new(receiver).filter_map( - move |msg| match msg { - Ok(Event::Message(Message { topic, data, .. })) if topic == topic_hash => { - match wire::deserialize::(&data) { - Ok(msg) => Some(msg), - Err(e) => { - debug!("Unrecognized message: {e}"); - None - } - } - } - _ => None, - }, - ))) - } - - async fn send(&self, data: E) -> Result<(), DynError> { - let message = wire::serialize(&data)?.into_boxed_slice(); - self.network_relay - .send(NetworkMsg::Process(Command::Broadcast { - topic: NOMOS_DA_TOPIC.to_string(), - message, - })) - .await - .map_err(|(e, _)| Box::new(e) as DynError) - } -} - -#[async_trait::async_trait] -impl NetworkAdapter for Libp2pAdapter -where - B: Serialize + DeserializeOwned + Send + Sync + 'static, - A: Serialize + DeserializeOwned + Send + Sync + 'static, -{ - type Backend = Libp2p; - type Blob = B; - type Attestation = A; - - async fn new( - network_relay: OutboundRelay< as ServiceData>::Message>, - ) -> Self { - network_relay - .send(NetworkMsg::Process(Command::Subscribe( - NOMOS_DA_TOPIC.to_string(), - ))) - .await - .expect("Network backend should be ready"); - Self { - network_relay, - _blob: Default::default(), - _attestation: Default::default(), - } - } - - async fn blob_stream(&self) -> Box + Unpin + Send> { - self.stream_for::().await - } - - async fn attestation_stream(&self) -> Box + Unpin + Send> { - self.stream_for::().await - } - - async fn send_attestation(&self, attestation: Self::Attestation) -> Result<(), DynError> { - self.send(attestation).await - } - - async fn send_blob(&self, blob: Self::Blob) -> Result<(), DynError> { - self.send(blob).await - } -} diff --git a/nomos-services/data-availability/src/network/adapters/mod.rs b/nomos-services/data-availability/src/network/adapters/mod.rs deleted file mode 100644 index a22ade97..00000000 --- a/nomos-services/data-availability/src/network/adapters/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[cfg(feature = "libp2p")] -pub mod libp2p; diff --git a/nomos-services/data-availability/src/network/mod.rs b/nomos-services/data-availability/src/network/mod.rs deleted file mode 100644 index 360a63da..00000000 --- a/nomos-services/data-availability/src/network/mod.rs +++ /dev/null @@ -1,33 +0,0 @@ -pub mod adapters; - -// std -// crates -use futures::Stream; -// internal -use nomos_network::backends::NetworkBackend; -use nomos_network::NetworkService; -use overwatch_rs::services::relay::OutboundRelay; -use overwatch_rs::services::ServiceData; -use overwatch_rs::DynError; -use serde::de::DeserializeOwned; -use serde::Serialize; - -#[async_trait::async_trait] -pub trait NetworkAdapter { - type Backend: NetworkBackend + 'static; - - type Blob: Serialize + DeserializeOwned + Send + Sync + 'static; - type Attestation: Serialize + DeserializeOwned + Send + Sync + 'static; - - async fn new( - network_relay: OutboundRelay< as ServiceData>::Message>, - ) -> Self; - - async fn blob_stream(&self) -> Box + Unpin + Send>; - - async fn attestation_stream(&self) -> Box + Unpin + Send>; - - async fn send_attestation(&self, attestation: Self::Attestation) -> Result<(), DynError>; - - async fn send_blob(&self, blob: Self::Blob) -> Result<(), DynError>; -} diff --git a/tests/src/lib.rs b/tests/src/lib.rs index 708da679..dffd18c5 100644 --- a/tests/src/lib.rs +++ b/tests/src/lib.rs @@ -1,5 +1,5 @@ pub mod nodes; -pub use nodes::NomosNode; +// pub use nodes::NomosNode; use once_cell::sync::Lazy; use std::env; diff --git a/tests/src/nodes/mod.rs b/tests/src/nodes/mod.rs index fa1985c1..fd5fbcde 100644 --- a/tests/src/nodes/mod.rs +++ b/tests/src/nodes/mod.rs @@ -1,5 +1,5 @@ -pub mod nomos; -pub use nomos::NomosNode; +// pub mod nomos; +// pub use nomos::NomosNode; use tempfile::TempDir;