ee5b55fab6
* Feature/ephemera compile (#3437) * Include ephemera node code in repo * Upgrade deps * Bump minor version of cosmwasm-std * Include ephemera in nym-api dep and downgrade rusqlite * Fix clippy and ephemera docs code * More clippy on ephemera --------- Co-authored-by: Andrus Salumets <andrus@nymtech.net> * Start ephemera components in nym-api (#3475) * Start ephemera components in nym-api * Pass nyxd client and use common metric structures * Swap url endpoint with contract for sending rewarding messages * Fix build after rebase * Perform ephemera rewards computation before normal nym-api ones * Remove contract mock from ephemera * Take raw rewards from network monitor * Remove ephemera old reward version * Use nym shutdown procedure in ephemera * Temporary fix for some warnings * Umock contract membership of ephemera (#3574) * Pass nyxd client to members provider * Basic ephemera contract * Add register peer tx * Add query all peers * Nyxd ephemera client * Add registration of ephemera peer * Replace epoch http api with actual contract * Merge ephemera config into nym-api config * Load cluster from contract * Guard nym-outfox out of cosmwasm builds (#3650) * Feature/fixes while testing (#3668) * Commit local peer before querying contract * Default to anyonline * Remove string from template * Fix avg computing * Use updated qa env * Fix clippy * Add unit tests for ephemera contract * Upload ephemera contract in CI * Add group check for peer signup * Peer registration unit test * Start ephemera only on monitoring * Remove old MixnodeToReward struct * Move all ephemera config to its file * Skip with serde ephemera config * Fix default value in args * Feature/add ephemera flag (#3727) * Replace unwrap with error handling * Add ephemera enable flag * Fix template * Add json schema to ephemera contract (#3735) * Update lock files * Update changelog --------- Co-authored-by: Andrus Salumets <andrus@nymtech.net>
141 lines
4.0 KiB
Rust
141 lines
4.0 KiB
Rust
use anyhow::anyhow;
|
|
use std::str::FromStr;
|
|
use std::sync::Arc;
|
|
|
|
use clap::Parser;
|
|
use log::trace;
|
|
use nym_task::TaskManager;
|
|
use reqwest::Url;
|
|
|
|
use crate::ephemera_api::ApplicationResult;
|
|
use crate::utilities::codec::{Codec, EphemeraCodec};
|
|
use crate::{
|
|
api::application::CheckBlockResult,
|
|
cli::PEERS_CONFIG_FILE,
|
|
config::Configuration,
|
|
crypto::EphemeraKeypair,
|
|
crypto::Keypair,
|
|
ephemera_api::{ApiBlock, ApiEphemeraMessage, Application, Dummy, RawApiEphemeraMessage},
|
|
network::members::ConfigMembersProvider,
|
|
EphemeraStarterInit,
|
|
};
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct HttpMembersProviderArg {
|
|
pub url: Url,
|
|
}
|
|
|
|
impl FromStr for HttpMembersProviderArg {
|
|
type Err = anyhow::Error;
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
Ok(HttpMembersProviderArg { url: s.parse()? })
|
|
}
|
|
}
|
|
|
|
#[derive(Parser)]
|
|
pub struct RunExternalNodeCmd {
|
|
#[clap(short, long)]
|
|
pub config_file: String,
|
|
#[clap(short, long)]
|
|
pub peers_config: String,
|
|
}
|
|
|
|
impl RunExternalNodeCmd {
|
|
/// # Errors
|
|
/// If the members provider cannot be created.
|
|
///
|
|
/// # Panics
|
|
/// If the ephemera cannot be created.
|
|
pub async fn execute(&self) -> anyhow::Result<()> {
|
|
let ephemera_conf = match Configuration::try_load(self.config_file.clone()) {
|
|
Ok(conf) => conf,
|
|
Err(err) => anyhow::bail!("Error loading configuration file: {err:?}"),
|
|
};
|
|
|
|
let members_provider = Self::config_members_provider_with_path(self.peers_config.clone())?;
|
|
let ephemera = EphemeraStarterInit::new(ephemera_conf.clone())
|
|
.unwrap()
|
|
.with_application(Dummy)
|
|
.with_members_provider(members_provider)?
|
|
.build();
|
|
|
|
let shutdown = TaskManager::new(10);
|
|
|
|
let shutdown_listener = shutdown.subscribe();
|
|
tokio::spawn(ephemera.run(shutdown_listener));
|
|
|
|
if let Err(err) = shutdown.catch_interrupt().await {
|
|
Err(anyhow!("Shutdown error {:?}", err))
|
|
} else {
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
fn config_members_provider() -> anyhow::Result<ConfigMembersProvider> {
|
|
let peers_conf_path = Configuration::ephemera_root_dir(None)
|
|
.unwrap()
|
|
.join(PEERS_CONFIG_FILE);
|
|
|
|
let peers_conf = match ConfigMembersProvider::init(peers_conf_path) {
|
|
Ok(conf) => conf,
|
|
Err(err) => anyhow::bail!("Error loading peers file: {err:?}"),
|
|
};
|
|
Ok(peers_conf)
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
fn config_members_provider_with_path(
|
|
peers_conf_path: String,
|
|
) -> anyhow::Result<ConfigMembersProvider> {
|
|
let peers_conf = match ConfigMembersProvider::init(peers_conf_path) {
|
|
Ok(conf) => conf,
|
|
Err(err) => anyhow::bail!("Error loading peers file: {err:?}"),
|
|
};
|
|
Ok(peers_conf)
|
|
}
|
|
}
|
|
|
|
pub struct SignatureVerificationApplication {
|
|
keypair: Arc<Keypair>,
|
|
}
|
|
|
|
impl SignatureVerificationApplication {
|
|
#[must_use]
|
|
pub fn new(keypair: Arc<Keypair>) -> Self {
|
|
Self { keypair }
|
|
}
|
|
|
|
pub(crate) fn verify_message(&self, msg: ApiEphemeraMessage) -> anyhow::Result<()> {
|
|
let signature = msg.certificate.clone();
|
|
let raw_message: RawApiEphemeraMessage = msg.into();
|
|
let encoded_message = Codec::encode(&raw_message)?;
|
|
if self
|
|
.keypair
|
|
.verify(&encoded_message, &signature.signature.into())
|
|
{
|
|
Ok(())
|
|
} else {
|
|
anyhow::bail!("Invalid signature")
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Application for SignatureVerificationApplication {
|
|
fn check_tx(&self, tx: ApiEphemeraMessage) -> ApplicationResult<bool> {
|
|
trace!("SignatureVerificationApplicationHook::check_tx");
|
|
self.verify_message(tx)?;
|
|
Ok(true)
|
|
}
|
|
|
|
fn check_block(&self, _block: &ApiBlock) -> ApplicationResult<CheckBlockResult> {
|
|
Ok(CheckBlockResult::Accept)
|
|
}
|
|
|
|
fn deliver_block(&self, _block: ApiBlock) -> ApplicationResult<()> {
|
|
trace!("SignatureVerificationApplicationHook::deliver_block");
|
|
Ok(())
|
|
}
|
|
}
|