From b6a2304dfced7ad3272536a712dccf7edbaaccdb Mon Sep 17 00:00:00 2001 From: Nick Pavlov Date: Fri, 19 Apr 2024 14:53:32 +0300 Subject: [PATCH 01/44] wip --- Cargo.lock | 2 +- crates/chain-listener/Cargo.toml | 2 +- crates/chain-listener/src/lib.rs | 4 + crates/chain-listener/src/listener.rs | 281 +++++++++++++--------- crates/chain-listener/src/subscription.rs | 198 +++++++++++++++ nox/src/node.rs | 22 +- 6 files changed, 383 insertions(+), 126 deletions(-) create mode 100644 crates/chain-listener/src/subscription.rs diff --git a/Cargo.lock b/Cargo.lock index aa7ee3e285..345f2c91e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1389,7 +1389,7 @@ dependencies = [ "peer-metrics", "serde", "serde_json", - "server-config", + "tempfile", "thiserror", "tokio", "tokio-stream", diff --git a/crates/chain-listener/Cargo.toml b/crates/chain-listener/Cargo.toml index 3ca52632f4..2ecf02af25 100644 --- a/crates/chain-listener/Cargo.toml +++ b/crates/chain-listener/Cargo.toml @@ -21,7 +21,6 @@ tracing = { workspace = true } eyre = { workspace = true } serde_json = { workspace = true } tokio = { workspace = true, features = ["rt"] } -server-config = { workspace = true } types = { workspace = true } libipld = { workspace = true } @@ -43,3 +42,4 @@ peer-metrics = { workspace = true } [dev-dependencies] jsonrpsee = { workspace = true, features = ["server"] } +tempfile = { workspace = true } diff --git a/crates/chain-listener/src/lib.rs b/crates/chain-listener/src/lib.rs index 29df6d6ccd..9db799c296 100644 --- a/crates/chain-listener/src/lib.rs +++ b/crates/chain-listener/src/lib.rs @@ -7,8 +7,12 @@ extern crate core; pub use listener::ChainListener; +pub use listener::ChainListenerConfig; +pub use subscription::WsEventSubscription; +pub use subscription::WsSubscriptionConfig; mod event; mod listener; mod persistence; +mod subscription; diff --git a/crates/chain-listener/src/listener.rs b/crates/chain-listener/src/listener.rs index 92cc5d9a79..6ba73ac088 100644 --- a/crates/chain-listener/src/listener.rs +++ b/crates/chain-listener/src/listener.rs @@ -1,5 +1,4 @@ use alloy_primitives::{Address, BlockNumber, FixedBytes, Uint, U256}; -use alloy_sol_types::SolEvent; use backoff::Error::Permanent; use std::collections::{BTreeMap, BTreeSet, HashMap}; use std::future::{pending, Future}; @@ -18,14 +17,10 @@ use ccp_shared::types::{Difficulty, GlobalNonce, LocalNonce, ResultHash}; use cpu_utils::PhysicalCoreId; use eyre::{eyre, Report}; -use jsonrpsee::core::client::{Client as WsClient, Subscription, SubscriptionClientT}; -use jsonrpsee::core::params::ArrayParams; +use jsonrpsee::core::client::Subscription; use jsonrpsee::core::{client, JsonValue}; -use jsonrpsee::rpc_params; -use jsonrpsee::ws_client::WsClientBuilder; -use libp2p_identity::PeerId; use serde::de::DeserializeOwned; -use serde_json::{json, Value}; +use serde_json::Value; use tokio::task::JoinHandle; use tokio::time::{interval, Instant}; use tokio_stream::wrappers::IntervalStream; @@ -36,34 +31,41 @@ use chain_connector::{ is_commitment_not_active, is_too_many_proofs, CCStatus, ChainConnector, CommitmentId, ConnectorError, Deal, PEER_NOT_EXISTS, }; -use chain_data::{parse_log, peer_id_to_hex, Log}; +use chain_data::{parse_log, Log}; use core_manager::errors::AcquireError; use core_manager::types::{AcquireRequest, Assignment, WorkType}; use core_manager::{CoreManager, CoreManagerFunctions, CUID}; use peer_metrics::ChainListenerMetrics; -use server_config::{ChainConfig, ChainListenerConfig}; use types::DealId; use crate::event::cc_activated::CommitmentActivated; use crate::event::{ComputeUnitMatched, UnitActivated, UnitDeactivated}; use crate::persistence; +use crate::subscription::EventSubscription; const PROOF_POLL_LIMIT: usize = 50; +pub struct ChainListenerConfig { + proof_poll_period: Duration, +} + +impl ChainListenerConfig { + pub fn new(proof_poll_period: Duration) -> Self { + Self { proof_poll_period } + } +} + pub struct ChainListener { - config: ChainConfig, listener_config: ChainListenerConfig, chain_connector: Arc, // To subscribe to chain events - ws_client: WsClient, + event_subscription: Box, ccp_client: Option, core_manager: Arc, - host_id: PeerId, - // These settings aren't changed // We refresh them on some errors, but it's enough to get them only on start without refreshing difficulty: Difficulty, @@ -113,10 +115,8 @@ where impl ChainListener { pub fn new( - chain_config: ChainConfig, - ws_client: WsClient, listener_config: ChainListenerConfig, - host_id: PeerId, + event_subscription: Box, chain_connector: Arc, core_manager: Arc, ccp_client: Option, @@ -128,11 +128,9 @@ impl ChainListener { } Self { - chain_connector, - ws_client, listener_config, - config: chain_config, - host_id, + chain_connector, + event_subscription, difficulty: Difficulty::default(), init_timestamp: U256::ZERO, global_nonce: GlobalNonce::new([0; 32]), @@ -453,44 +451,18 @@ impl ChainListener { } } - pub async fn create_ws_client(ws_endpoint: &str) -> Result { - let ws_client = retry(ExponentialBackoff::default(), || async { - let client = WsClientBuilder::default() - .build(ws_endpoint) - .await - .map_err(|err| { - tracing::warn!( - target: "chain-listener", - "Error connecting to websocket endpoint {}, error: {}; Retrying...", - ws_endpoint, - err - ); - err - })?; - - Ok(client) - }) - .await?; - - tracing::info!( - target: "chain-listener", - "Successfully connected to websocket endpoint: {}", - ws_endpoint - ); - - Ok(ws_client) - } - async fn subscribe_unit_events( &mut self, commitment_id: &CommitmentId, ) -> Result<(), client::Error> { self.unit_activated = Some( - self.subscribe("logs", self.unit_activated_params(commitment_id)) + self.event_subscription + .unit_activated(commitment_id) .await?, ); self.unit_deactivated = Some( - self.subscribe("logs", self.unit_deactivated_params(commitment_id)) + self.event_subscription + .unit_deactivated(commitment_id) .await?, ); @@ -498,18 +470,15 @@ impl ChainListener { } async fn refresh_subscriptions(&mut self) -> Result<(), client::Error> { - if !self.ws_client.is_connected() { - self.ws_client = - ChainListener::create_ws_client(&self.listener_config.ws_endpoint).await?; - } + self.event_subscription.refresh().await?; // loop because subscriptions can fail and require reconnection, we can't proceed without them loop { let result: Result<(), client::Error> = try { - self.heads = Some(self.subscribe("newHeads", rpc_params!["newHeads"]).await?); + self.heads = Some(self.event_subscription.new_heads().await?); self.commitment_activated = - Some(self.subscribe("logs", self.cc_activated_params()).await?); - self.unit_matched = Some(self.subscribe("logs", self.unit_matched_params()).await?); + Some(self.event_subscription.commitment_activated().await?); + self.unit_matched = Some(self.event_subscription.unit_matched().await?); if let Some(commitment_id) = self.current_commitment.clone() { self.subscribe_unit_events(&commitment_id).await?; } @@ -523,9 +492,7 @@ impl ChainListener { Err(err) => match err { client::Error::RestartNeeded(_) => { tracing::warn!(target: "chain-listener", "Failed to refresh subscriptions: {err}; Restart client..."); - self.ws_client = - ChainListener::create_ws_client(&self.listener_config.ws_endpoint) - .await?; + self.event_subscription.restart().await?; } _ => { tracing::error!(target: "chain-listener", "Failed to refresh subscriptions: {err}; Retrying..."); @@ -586,64 +553,6 @@ impl ChainListener { Ok(()) } - async fn subscribe( - &self, - method: &str, - params: ArrayParams, - ) -> Result, client::Error> { - let sub = retry(ExponentialBackoff::default(), || async { - self - .ws_client - .subscribe("eth_subscribe", params.clone(), "eth_unsubscribe") - .await.map_err(|err| { - if let client::Error::RestartNeeded(_) = err { - tracing::error!(target: "chain-listener", "Failed to subscribe to {method}: {err};"); - Permanent(err) - } else { - tracing::warn!(target: "chain-listener", "Failed to subscribe to {method}: {err}; Retrying..."); - backoff::Error::transient(err) - }}) - }).await?; - - Ok(sub) - } - - fn cc_activated_params(&self) -> ArrayParams { - let topic = CommitmentActivated::SIGNATURE_HASH.to_string(); - let topics = vec![topic, peer_id_to_hex(self.host_id)]; - rpc_params![ - "logs", - json!({"address": self.config.cc_contract_address, "topics": topics}) - ] - } - - fn unit_activated_params(&self, commitment_id: &CommitmentId) -> ArrayParams { - let topic = UnitActivated::SIGNATURE_HASH.to_string(); - rpc_params![ - "logs", - json!({"address": self.config.cc_contract_address, "topics": vec![topic, hex::encode(commitment_id.0)]}) - ] - } - - fn unit_deactivated_params(&self, commitment_id: &CommitmentId) -> ArrayParams { - let topic = UnitDeactivated::SIGNATURE_HASH.to_string(); - rpc_params![ - "logs", - json!({"address": self.config.cc_contract_address, "topics": vec![topic, hex::encode(commitment_id.0)]}) - ] - } - - fn unit_matched_params(&self) -> ArrayParams { - let topics = vec![ - ComputeUnitMatched::SIGNATURE_HASH.to_string(), - peer_id_to_hex(self.host_id), - ]; - rpc_params![ - "logs", - json!({"address": self.config.market_contract_address, "topics": topics}) - ] - } - async fn process_new_header( &mut self, event: Option>, @@ -1386,3 +1295,139 @@ where .inspect(|m| m.observe_ccp_reply(elapsed.as_millis() as f64)); result } + +#[cfg(test)] +mod tests { + use crate::subscription::EventSubscription; + use crate::{ChainListener, ChainListenerConfig}; + use ccp_shared::proof::CCProof; + use ccp_shared::types::{GlobalNonce, CUID}; + use chain_connector::Deal::Status; + use chain_connector::Offer::ComputeUnit; + use chain_connector::{CCInitParams, CCStatus, ChainConnector, CommitmentId, ConnectorError}; + use core_manager::{CoreManager, DummyCoreManager}; + use jsonrpsee::core::client::{Error, Subscription}; + use jsonrpsee::core::{async_trait, JsonValue}; + use std::sync::Arc; + use std::time::Duration; + use types::DealId; + + struct TestEventSubscription; + + #[async_trait] + impl EventSubscription for TestEventSubscription { + async fn unit_activated( + &self, + commitment_id: &CommitmentId, + ) -> Result, Error> { + todo!() + } + + async fn unit_deactivated( + &self, + commitment_id: &CommitmentId, + ) -> Result, Error> { + todo!() + } + + async fn new_heads(&self) -> Result, Error> { + todo!() + } + + async fn commitment_activated(&self) -> Result, Error> { + todo!() + } + + async fn unit_matched(&self) -> Result, Error> { + todo!() + } + + async fn refresh(&mut self) -> Result<(), Error> { + Ok(()) + } + + async fn restart(&mut self) -> Result<(), Error> { + Ok(()) + } + } + + struct TestChainConnector; + + #[async_trait] + impl ChainConnector for TestChainConnector { + async fn get_current_commitment_id(&self) -> Result, ConnectorError> { + todo!() + } + + async fn get_cc_init_params(&self) -> eyre::Result { + todo!() + } + + async fn get_compute_units(&self) -> Result, ConnectorError> { + todo!() + } + + async fn get_commitment_status( + &self, + commitment_id: CommitmentId, + ) -> Result { + todo!() + } + + async fn get_global_nonce(&self) -> Result { + todo!() + } + + async fn submit_proof(&self, proof: CCProof) -> Result { + todo!() + } + + async fn get_deal_statuses( + &self, + deal_ids: Vec, + ) -> Result>, ConnectorError> { + todo!() + } + + async fn exit_deal(&self, cu_id: &CUID) -> Result { + todo!() + } + + async fn get_tx_statuses( + &self, + tx_hashes: Vec, + ) -> Result, ConnectorError>>, ConnectorError> { + todo!() + } + + async fn get_tx_receipts( + &self, + tx_hashes: Vec, + ) -> Result>, ConnectorError> { + todo!() + } + } + + #[tokio::test] + async fn test_activation_flow() { + let tmp_dir = tempfile::tempdir().expect("Could not create temp dir"); + let config = ChainListenerConfig::new(Duration::from_secs(1)); + let subscription = TestEventSubscription; + let subscription = Box::new(subscription); + let connector = TestChainConnector; + let connector = Arc::new(connector); + let core_manager = CoreManager::Dummy(DummyCoreManager::default()); + let core_manager = Arc::new(core_manager); + let listener = ChainListener::new( + config, + subscription, + connector, + core_manager, + None, + tmp_dir.path().join("proofs").to_path_buf(), + None, + ); + + listener.start().await; + } +} diff --git a/crates/chain-listener/src/subscription.rs b/crates/chain-listener/src/subscription.rs new file mode 100644 index 0000000000..c04c1a1bd9 --- /dev/null +++ b/crates/chain-listener/src/subscription.rs @@ -0,0 +1,198 @@ +use crate::event::cc_activated::CommitmentActivated; +use crate::event::{ComputeUnitMatched, UnitActivated, UnitDeactivated}; +use alloy_sol_types::SolEvent; +use backoff::future::retry; +use backoff::Error::Permanent; +use backoff::ExponentialBackoff; +use chain_connector::CommitmentId; +use chain_data::peer_id_to_hex; +use jsonrpsee::core::client::{Error, Subscription, SubscriptionClientT}; +use jsonrpsee::core::params::ArrayParams; +use jsonrpsee::core::{async_trait, JsonValue}; +use jsonrpsee::rpc_params; +use jsonrpsee::ws_client::{WsClient, WsClientBuilder}; +use libp2p_identity::PeerId; +use serde_json::json; + +#[async_trait] +pub trait EventSubscription: Send + Sync { + async fn unit_activated( + &self, + commitment_id: &CommitmentId, + ) -> Result, Error>; + async fn unit_deactivated( + &self, + commitment_id: &CommitmentId, + ) -> Result, Error>; + async fn new_heads(&self) -> Result, Error>; + async fn commitment_activated(&self) -> Result, Error>; + async fn unit_matched(&self) -> Result, Error>; + + + // TODO: remove both methods and encapsulate logic + async fn refresh(&mut self) -> Result<(), Error>; + async fn restart(&mut self) -> Result<(), Error>; +} + +pub struct WsSubscriptionConfig { + host_id: PeerId, + ws_endpoint: String, + cc_contract_address: String, + market_contract_address: String, +} + +impl WsSubscriptionConfig { + pub fn new( + host_id: PeerId, + ws_endpoint: String, + cc_contract_address: String, + market_contract_address: String, + ) -> Self { + Self { + host_id, + ws_endpoint, + cc_contract_address, + market_contract_address, + } + } +} + +pub struct WsEventSubscription { + config: WsSubscriptionConfig, + ws_client: WsClient, +} + +impl WsEventSubscription { + pub async fn new(config: WsSubscriptionConfig) -> Result { + let ws_client = Self::create_ws_client(config.ws_endpoint.as_str()).await?; + Ok(Self { config, ws_client }) + } + + async fn subscribe( + &self, + method: &str, + params: ArrayParams, + ) -> Result, Error> { + let sub = retry(ExponentialBackoff::default(), || async { + self.ws_client + .subscribe("eth_subscribe", params.clone(), "eth_unsubscribe") + .await.map_err(|err| { + if let Error::RestartNeeded(_) = err { + tracing::error!(target: "chain-listener", "Failed to subscribe to {method}: {err};"); + Permanent(err) + } else { + tracing::warn!(target: "chain-listener", "Failed to subscribe to {method}: {err}; Retrying..."); + backoff::Error::transient(err) + }}) + }).await?; + + Ok(sub) + } + + fn unit_activated_params(&self, commitment_id: &CommitmentId) -> ArrayParams { + let topic = UnitActivated::SIGNATURE_HASH.to_string(); + rpc_params![ + "logs", + json!({"address": self.config.cc_contract_address, "topics": vec![topic, hex::encode(commitment_id.0)]}) + ] + } + + fn unit_deactivated_params(&self, commitment_id: &CommitmentId) -> ArrayParams { + let topic = UnitDeactivated::SIGNATURE_HASH.to_string(); + rpc_params![ + "logs", + json!({"address": self.config.cc_contract_address, "topics": vec![topic, hex::encode(commitment_id.0)]}) + ] + } + + fn cc_activated_params(&self) -> ArrayParams { + let topic = CommitmentActivated::SIGNATURE_HASH.to_string(); + let topics = vec![topic, peer_id_to_hex(self.config.host_id)]; + rpc_params![ + "logs", + json!({"address": self.config.cc_contract_address, "topics": topics}) + ] + } + + fn unit_matched_params(&self) -> ArrayParams { + let topics = vec![ + ComputeUnitMatched::SIGNATURE_HASH.to_string(), + peer_id_to_hex(self.config.host_id), + ]; + rpc_params![ + "logs", + json!({"address": self.config.market_contract_address, "topics": topics}) + ] + } + + async fn create_ws_client(ws_endpoint: &str) -> Result { + let ws_client = retry(ExponentialBackoff::default(), || async { + let client = WsClientBuilder::default() + .build(ws_endpoint) + .await + .map_err(|err| { + tracing::warn!( + target: "chain-listener", + "Error connecting to websocket endpoint {}, error: {}; Retrying...", + ws_endpoint, + err + ); + err + })?; + + Ok(client) + }) + .await?; + + tracing::info!( + target: "chain-listener", + "Successfully connected to websocket endpoint: {}", + ws_endpoint + ); + + Ok(ws_client) + } +} + +#[async_trait] +impl EventSubscription for WsEventSubscription { + async fn unit_activated( + &self, + commitment_id: &CommitmentId, + ) -> Result, Error> { + self.subscribe("logs", self.unit_activated_params(commitment_id)) + .await + } + + async fn unit_deactivated( + &self, + commitment_id: &CommitmentId, + ) -> Result, Error> { + self.subscribe("logs", self.unit_deactivated_params(commitment_id)) + .await + } + + async fn new_heads(&self) -> Result, Error> { + self.subscribe("newHeads", rpc_params!["newHeads"]).await + } + + async fn commitment_activated(&self) -> Result, Error> { + self.subscribe("logs", self.cc_activated_params()).await + } + + async fn unit_matched(&self) -> Result, Error> { + self.subscribe("logs", self.unit_matched_params()).await + } + + async fn refresh(&mut self) -> Result<(), Error> { + if !self.ws_client.is_connected() { + self.restart().await? + } + Ok(()) + } + + async fn restart(&mut self) -> Result<(), Error> { + self.ws_client = Self::create_ws_client(&self.config.ws_endpoint).await?; + Ok(()) + } +} diff --git a/nox/src/node.rs b/nox/src/node.rs index 90e393d2b4..b2f47c13d3 100644 --- a/nox/src/node.rs +++ b/nox/src/node.rs @@ -43,7 +43,9 @@ use aquamarine::{ RemoteRoutingEffects, VmPoolConfig, WasmBackendConfig, }; use chain_connector::HttpChainConnector; -use chain_listener::ChainListener; +use chain_listener::{ + ChainListener, ChainListenerConfig, WsEventSubscription, WsSubscriptionConfig, +}; use config_utils::to_peer_id; use connection_pool::ConnectionPoolT; use core_manager::CoreManager; @@ -136,15 +138,23 @@ async fn setup_listener( None }; - let ws_client = ChainListener::create_ws_client(&listener_config.ws_endpoint).await?; let cc_events_dir = config.dir_config.cc_events_dir.clone(); let host_id = config.root_key_pair.get_peer_id(); - let chain_listener = ChainListener::new( - chain_config, - ws_client, - listener_config, + let ws_event_subscription_config = WsSubscriptionConfig::new( host_id, + listener_config.ws_endpoint.clone(), + chain_config.cc_contract_address, + chain_config.market_contract_address, + ); + let event_subscription = WsEventSubscription::new(ws_event_subscription_config).await?; + let event_subscription = Box::new(event_subscription); + + let chain_listener_config = ChainListenerConfig::new(listener_config.proof_poll_period); + + let chain_listener = ChainListener::new( + chain_listener_config, + event_subscription, connector, core_manager, ccp_client, From 0bba9a3b7fc7745f95eb527ae1616961c9cb3ff1 Mon Sep 17 00:00:00 2001 From: Nick Pavlov Date: Fri, 19 Apr 2024 15:59:43 +0300 Subject: [PATCH 02/44] wip --- crates/chain-listener/Cargo.toml | 1 + crates/chain-listener/src/listener.rs | 73 +++++++++++++---------- crates/chain-listener/src/subscription.rs | 65 +++++++++++++------- 3 files changed, 85 insertions(+), 54 deletions(-) diff --git a/crates/chain-listener/Cargo.toml b/crates/chain-listener/Cargo.toml index 2ecf02af25..b074fa082f 100644 --- a/crates/chain-listener/Cargo.toml +++ b/crates/chain-listener/Cargo.toml @@ -43,3 +43,4 @@ peer-metrics = { workspace = true } [dev-dependencies] jsonrpsee = { workspace = true, features = ["server"] } tempfile = { workspace = true } +tokio-stream = { workspace = true } diff --git a/crates/chain-listener/src/listener.rs b/crates/chain-listener/src/listener.rs index 6ba73ac088..f4077d3ce2 100644 --- a/crates/chain-listener/src/listener.rs +++ b/crates/chain-listener/src/listener.rs @@ -2,7 +2,7 @@ use alloy_primitives::{Address, BlockNumber, FixedBytes, Uint, U256}; use backoff::Error::Permanent; use std::collections::{BTreeMap, BTreeSet, HashMap}; use std::future::{pending, Future}; -use std::ops::Add; +use std::ops::{Add, Deref}; use std::path::PathBuf; use std::process::exit; use std::str::FromStr; @@ -17,7 +17,6 @@ use ccp_shared::types::{Difficulty, GlobalNonce, LocalNonce, ResultHash}; use cpu_utils::PhysicalCoreId; use eyre::{eyre, Report}; -use jsonrpsee::core::client::Subscription; use jsonrpsee::core::{client, JsonValue}; use serde::de::DeserializeOwned; use serde_json::Value; @@ -41,7 +40,7 @@ use types::DealId; use crate::event::cc_activated::CommitmentActivated; use crate::event::{ComputeUnitMatched, UnitActivated, UnitDeactivated}; use crate::persistence; -use crate::subscription::EventSubscription; +use crate::subscription::{Error, EventSubscription, Stream}; const PROOF_POLL_LIMIT: usize = 50; @@ -93,17 +92,17 @@ pub struct ChainListener { // TODO: move out to a separate struct, get rid of Option // Subscriptions that are polled when we have commitment - unit_activated: Option>, - unit_deactivated: Option>, + unit_activated: Option>, + unit_deactivated: Option>, // Subscriptions that are polled always - heads: Option>, - commitment_activated: Option>, - unit_matched: Option>, + heads: Option>, + commitment_activated: Option>, + unit_matched: Option>, metrics: Option, } -async fn poll_subscription(s: &mut Option>) -> Option> +async fn poll_subscription(s: &mut Option>) -> Option> where T: DeserializeOwned + Send, { @@ -173,7 +172,7 @@ impl ChainListener { pub fn start(mut self) -> JoinHandle<()> { let result = tokio::task::Builder::new() .name("ChainListener") - .spawn(async move { + .spawn_local(async move { if let Err(err) = self.set_utility_core().await { tracing::error!(target: "chain-listener", "Failed to set utility core: {err}; Stopping..."); @@ -451,10 +450,7 @@ impl ChainListener { } } - async fn subscribe_unit_events( - &mut self, - commitment_id: &CommitmentId, - ) -> Result<(), client::Error> { + async fn subscribe_unit_events(&mut self, commitment_id: &CommitmentId) -> Result<(), Error> { self.unit_activated = Some( self.event_subscription .unit_activated(commitment_id) @@ -469,12 +465,12 @@ impl ChainListener { Ok(()) } - async fn refresh_subscriptions(&mut self) -> Result<(), client::Error> { + async fn refresh_subscriptions(&mut self) -> Result<(), Error> { self.event_subscription.refresh().await?; // loop because subscriptions can fail and require reconnection, we can't proceed without them loop { - let result: Result<(), client::Error> = try { + let result: Result<(), Error> = try { self.heads = Some(self.event_subscription.new_heads().await?); self.commitment_activated = Some(self.event_subscription.commitment_activated().await?); @@ -489,7 +485,7 @@ impl ChainListener { tracing::info!(target: "chain-listener", "Subscriptions refreshed successfully"); break; } - Err(err) => match err { + Err(err) => match err.deref() { client::Error::RestartNeeded(_) => { tracing::warn!(target: "chain-listener", "Failed to refresh subscriptions: {err}; Restart client..."); self.event_subscription.restart().await?; @@ -555,7 +551,7 @@ impl ChainListener { async fn process_new_header( &mut self, - event: Option>, + event: Option>, ) -> eyre::Result<()> { let header = event.ok_or(eyre!("Failed to process newHeads event: got None"))?; @@ -600,7 +596,7 @@ impl ChainListener { async fn process_commitment_activated( &mut self, - event: Option>, + event: Option>, ) -> eyre::Result<()> { let event = event.ok_or(eyre!( "Failed to process CommitmentActivated event: got None" @@ -650,7 +646,7 @@ impl ChainListener { async fn process_unit_activated( &mut self, - event: Option>, + event: Option>, ) -> eyre::Result<()> { let event = event.ok_or(eyre!("Failed to process UnitActivated event: got None"))??; @@ -682,7 +678,7 @@ impl ChainListener { /// Unit goes to Deal async fn process_unit_deactivated( &mut self, - event: Option>, + event: Option>, ) -> eyre::Result<()> { let event = event.ok_or(eyre!("Failed to process UnitDeactivated event: got None"))??; let log = serde_json::from_value::(event.clone()).map_err(|err| { @@ -703,7 +699,7 @@ impl ChainListener { fn process_unit_matched( &mut self, - event: Option>, + event: Option>, ) -> eyre::Result<()> { let event = event.ok_or(eyre!("Failed to process DealMatched event: got None"))??; let log = serde_json::from_value::(event.clone()).map_err(|err| { @@ -1298,7 +1294,7 @@ where #[cfg(test)] mod tests { - use crate::subscription::EventSubscription; + use crate::subscription::{Error, EventSubscription, Stream}; use crate::{ChainListener, ChainListenerConfig}; use ccp_shared::proof::CCProof; use ccp_shared::types::{GlobalNonce, CUID}; @@ -1306,39 +1302,52 @@ mod tests { use chain_connector::Offer::ComputeUnit; use chain_connector::{CCInitParams, CCStatus, ChainConnector, CommitmentId, ConnectorError}; use core_manager::{CoreManager, DummyCoreManager}; - use jsonrpsee::core::client::{Error, Subscription}; + use futures::StreamExt; use jsonrpsee::core::{async_trait, JsonValue}; use std::sync::Arc; use std::time::Duration; + use tokio::sync::broadcast::Sender; + use tokio_stream::wrappers::BroadcastStream; use types::DealId; - struct TestEventSubscription; + struct TestEventSubscription { + new_heads_sender: Sender>, + } + + impl TestEventSubscription { + pub fn new() -> Self { + let (new_heads_sender, _rx) = tokio::sync::broadcast::channel(16); + Self { new_heads_sender } + } + } #[async_trait] impl EventSubscription for TestEventSubscription { async fn unit_activated( &self, commitment_id: &CommitmentId, - ) -> Result, Error> { + ) -> Result, Error> { todo!() } async fn unit_deactivated( &self, commitment_id: &CommitmentId, - ) -> Result, Error> { + ) -> Result, Error> { todo!() } - async fn new_heads(&self) -> Result, Error> { - todo!() + async fn new_heads(&self) -> Result, Error> { + let rx = self.new_heads_sender.subscribe(); + let stream = BroadcastStream::new(rx); + Ok(stream.map(|item| item.unwrap()).boxed()) } - async fn commitment_activated(&self) -> Result, Error> { + async fn commitment_activated(&self) -> Result, Error> { todo!() } - async fn unit_matched(&self) -> Result, Error> { + async fn unit_matched(&self) -> Result, Error> { todo!() } @@ -1412,7 +1421,7 @@ mod tests { async fn test_activation_flow() { let tmp_dir = tempfile::tempdir().expect("Could not create temp dir"); let config = ChainListenerConfig::new(Duration::from_secs(1)); - let subscription = TestEventSubscription; + let subscription = TestEventSubscription::new(); let subscription = Box::new(subscription); let connector = TestChainConnector; let connector = Arc::new(connector); diff --git a/crates/chain-listener/src/subscription.rs b/crates/chain-listener/src/subscription.rs index c04c1a1bd9..9799fb32cc 100644 --- a/crates/chain-listener/src/subscription.rs +++ b/crates/chain-listener/src/subscription.rs @@ -6,28 +6,49 @@ use backoff::Error::Permanent; use backoff::ExponentialBackoff; use chain_connector::CommitmentId; use chain_data::peer_id_to_hex; -use jsonrpsee::core::client::{Error, Subscription, SubscriptionClientT}; +use futures::stream::BoxStream; +use futures::{StreamExt, TryStreamExt}; +use jsonrpsee::core::client::SubscriptionClientT; use jsonrpsee::core::params::ArrayParams; +use jsonrpsee::core::ClientError::RestartNeeded; use jsonrpsee::core::{async_trait, JsonValue}; use jsonrpsee::rpc_params; use jsonrpsee::ws_client::{WsClient, WsClientBuilder}; use libp2p_identity::PeerId; use serde_json::json; +use std::ops::Deref; +use std::sync::Arc; +use thiserror::Error; + +//TODO: make a domain errors +#[derive(Error, Clone, Debug)] +#[error(transparent)] +pub struct Error(#[from] Arc); + +impl Deref for Error { + type Target = jsonrpsee::core::client::Error; + + fn deref(&self) -> &Self::Target { + self.0.deref() + } +} + +impl From for Error { + fn from(value: jsonrpsee::core::client::Error) -> Self { + Self(Arc::new(value)) + } +} + +pub type Stream = BoxStream<'static, Result>; +pub type SubResult = Result, Error>; #[async_trait] pub trait EventSubscription: Send + Sync { - async fn unit_activated( - &self, - commitment_id: &CommitmentId, - ) -> Result, Error>; - async fn unit_deactivated( - &self, - commitment_id: &CommitmentId, - ) -> Result, Error>; - async fn new_heads(&self) -> Result, Error>; - async fn commitment_activated(&self) -> Result, Error>; - async fn unit_matched(&self) -> Result, Error>; - + async fn unit_activated(&self, commitment_id: &CommitmentId) -> SubResult; + async fn unit_deactivated(&self, commitment_id: &CommitmentId) -> SubResult; + async fn new_heads(&self) -> SubResult; + async fn commitment_activated(&self) -> SubResult; + async fn unit_matched(&self) -> SubResult; // TODO: remove both methods and encapsulate logic async fn refresh(&mut self) -> Result<(), Error>; @@ -72,21 +93,21 @@ impl WsEventSubscription { &self, method: &str, params: ArrayParams, - ) -> Result, Error> { + ) -> Result, Error> { let sub = retry(ExponentialBackoff::default(), || async { self.ws_client .subscribe("eth_subscribe", params.clone(), "eth_unsubscribe") .await.map_err(|err| { - if let Error::RestartNeeded(_) = err { + if let RestartNeeded(_) = err { tracing::error!(target: "chain-listener", "Failed to subscribe to {method}: {err};"); Permanent(err) } else { tracing::warn!(target: "chain-listener", "Failed to subscribe to {method}: {err}; Retrying..."); backoff::Error::transient(err) }}) - }).await?; + }).await.map_err(|err| Error::from(err))?; - Ok(sub) + Ok(sub.map_err(|err| err.into()).boxed()) } fn unit_activated_params(&self, commitment_id: &CommitmentId) -> ArrayParams { @@ -159,7 +180,7 @@ impl EventSubscription for WsEventSubscription { async fn unit_activated( &self, commitment_id: &CommitmentId, - ) -> Result, Error> { + ) -> Result, Error> { self.subscribe("logs", self.unit_activated_params(commitment_id)) .await } @@ -167,20 +188,20 @@ impl EventSubscription for WsEventSubscription { async fn unit_deactivated( &self, commitment_id: &CommitmentId, - ) -> Result, Error> { + ) -> Result, Error> { self.subscribe("logs", self.unit_deactivated_params(commitment_id)) .await } - async fn new_heads(&self) -> Result, Error> { + async fn new_heads(&self) -> Result, Error> { self.subscribe("newHeads", rpc_params!["newHeads"]).await } - async fn commitment_activated(&self) -> Result, Error> { + async fn commitment_activated(&self) -> Result, Error> { self.subscribe("logs", self.cc_activated_params()).await } - async fn unit_matched(&self) -> Result, Error> { + async fn unit_matched(&self) -> Result, Error> { self.subscribe("logs", self.unit_matched_params()).await } From 30de5f2960ec7aaee0469a6be88d733bbdaf5505 Mon Sep 17 00:00:00 2001 From: Nick Pavlov Date: Fri, 19 Apr 2024 16:53:00 +0300 Subject: [PATCH 03/44] wip --- Cargo.lock | 10 ++--- Cargo.toml | 6 +-- crates/chain-listener/Cargo.toml | 1 + crates/chain-listener/src/ccp.rs | 60 ++++++++++++++++++++++++++ crates/chain-listener/src/event/mod.rs | 1 - crates/chain-listener/src/lib.rs | 1 + crates/chain-listener/src/listener.rs | 48 +++++++++++++++------ 7 files changed, 104 insertions(+), 23 deletions(-) create mode 100644 crates/chain-listener/src/ccp.rs diff --git a/Cargo.lock b/Cargo.lock index 345f2c91e7..8cbce9d02a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1252,8 +1252,7 @@ dependencies = [ [[package]] name = "ccp-rpc-client" version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dcb551e7eaad87b0447b2a65e2bb2ff1c2ea8184c6b9f6ee69f753556fa9980" +source = "git+https://github.com/fluencelabs/capacity-commitment-prover?branch=main#270a51de9ba388ae9fa43404d1aaa0790e241836" dependencies = [ "ccp-shared", "hex", @@ -1264,8 +1263,7 @@ dependencies = [ [[package]] name = "ccp-shared" version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b87301eb83acefe8c2b241c8aed467ddad7931e63aec1a2d438bba324a18b76d" +source = "git+https://github.com/fluencelabs/capacity-commitment-prover?branch=main#270a51de9ba388ae9fa43404d1aaa0790e241836" dependencies = [ "hex", "newtype_derive", @@ -1386,6 +1384,7 @@ dependencies = [ "libipld", "libp2p-identity", "log", + "log-utils", "peer-metrics", "serde", "serde_json", @@ -1716,8 +1715,7 @@ dependencies = [ [[package]] name = "cpu-utils" version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1214c39c3a71f470eab128fdd2495995cc13401d5a76191f9200ea1020917d29" +source = "git+https://github.com/fluencelabs/capacity-commitment-prover?branch=main#270a51de9ba388ae9fa43404d1aaa0790e241836" dependencies = [ "ccp-shared", "ccp_core_affinity", diff --git a/Cargo.toml b/Cargo.toml index 12767540a8..a6e742734b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -174,9 +174,9 @@ enum_dispatch = "0.3.12" serde_with = "3.7.0" mockito = "1.2.0" clarity = "1.3.0" -cpu-utils = "0.8.0" -ccp-shared = "0.8.0" -ccp-rpc-client = "0.8.0" +cpu-utils = { git = "https://github.com/fluencelabs/capacity-commitment-prover", branch = "main" } +ccp-shared = { git = "https://github.com/fluencelabs/capacity-commitment-prover", branch = "main" } +ccp-rpc-client = { git = "https://github.com/fluencelabs/capacity-commitment-prover", branch = "main" } alloy-sol-types = "0.6.4" alloy-primitives = "0.6.4" alloy_serde_macro = "0.1.2" diff --git a/crates/chain-listener/Cargo.toml b/crates/chain-listener/Cargo.toml index b074fa082f..17731a1876 100644 --- a/crates/chain-listener/Cargo.toml +++ b/crates/chain-listener/Cargo.toml @@ -44,3 +44,4 @@ peer-metrics = { workspace = true } jsonrpsee = { workspace = true, features = ["server"] } tempfile = { workspace = true } tokio-stream = { workspace = true } +log-utils = { workspace = true } \ No newline at end of file diff --git a/crates/chain-listener/src/ccp.rs b/crates/chain-listener/src/ccp.rs new file mode 100644 index 0000000000..d022973a9c --- /dev/null +++ b/crates/chain-listener/src/ccp.rs @@ -0,0 +1,60 @@ +use ccp_rpc_client::{CCPRpcClient, CCPRpcHttpClient, ClientError}; +use ccp_shared::proof::{CCProof, ProofIdx}; +use ccp_shared::types::{Difficulty, GlobalNonce, LogicalCoreId, PhysicalCoreId, CUID}; +use jsonrpsee::core::async_trait; +use std::collections::HashMap; + +#[async_trait] +pub trait CCPClient: Sync + Send { + async fn on_no_active_commitment(&self) -> Result<(), ClientError>; + + async fn realloc_utility_cores( + &self, + utility_core_ids: Vec, + ) -> Result<(), ClientError>; + + async fn on_active_commitment( + &self, + global_nonce: GlobalNonce, + difficulty: Difficulty, + cu_allocation: HashMap, + ) -> Result<(), ClientError>; + + async fn get_proofs_after( + &self, + proof_idx: ProofIdx, + limit: usize, + ) -> Result, ClientError>; +} + +#[async_trait] +impl CCPClient for CCPRpcHttpClient { + async fn on_no_active_commitment(&self) -> Result<(), ClientError> { + self.on_no_active_commitment().await + } + + async fn realloc_utility_cores( + &self, + utility_core_ids: Vec, + ) -> Result<(), ClientError> { + self.realloc_utility_cores(utility_core_ids).await + } + + async fn on_active_commitment( + &self, + global_nonce: GlobalNonce, + difficulty: Difficulty, + cu_allocation: HashMap, + ) -> Result<(), ClientError> { + self.on_active_commitment(global_nonce, difficulty, cu_allocation) + .await + } + + async fn get_proofs_after( + &self, + proof_idx: ProofIdx, + limit: usize, + ) -> Result, ClientError> { + self.get_proofs_after(proof_idx, limit).await + } +} diff --git a/crates/chain-listener/src/event/mod.rs b/crates/chain-listener/src/event/mod.rs index 0d2c0df494..cca4ccfafb 100644 --- a/crates/chain-listener/src/event/mod.rs +++ b/crates/chain-listener/src/event/mod.rs @@ -2,7 +2,6 @@ pub mod cc_activated; mod compute_unit_matched; mod unit_activated; mod unit_deactivated; - pub use compute_unit_matched::ComputeUnitMatched; pub use unit_activated::UnitActivated; pub use unit_deactivated::UnitDeactivated; diff --git a/crates/chain-listener/src/lib.rs b/crates/chain-listener/src/lib.rs index 9db799c296..0542594027 100644 --- a/crates/chain-listener/src/lib.rs +++ b/crates/chain-listener/src/lib.rs @@ -14,5 +14,6 @@ pub use subscription::WsSubscriptionConfig; mod event; mod listener; +mod ccp; mod persistence; mod subscription; diff --git a/crates/chain-listener/src/listener.rs b/crates/chain-listener/src/listener.rs index f4077d3ce2..bd10928dcc 100644 --- a/crates/chain-listener/src/listener.rs +++ b/crates/chain-listener/src/listener.rs @@ -11,7 +11,7 @@ use std::time::Duration; use backoff::future::retry; use backoff::ExponentialBackoff; -use ccp_rpc_client::CCPRpcHttpClient; +use ccp_rpc_client::CCPRpcClient; use ccp_shared::proof::{CCProof, CCProofId, ProofIdx}; use ccp_shared::types::{Difficulty, GlobalNonce, LocalNonce, ResultHash}; use cpu_utils::PhysicalCoreId; @@ -37,6 +37,7 @@ use core_manager::{CoreManager, CoreManagerFunctions, CUID}; use peer_metrics::ChainListenerMetrics; use types::DealId; +use crate::ccp::CCPClient; use crate::event::cc_activated::CommitmentActivated; use crate::event::{ComputeUnitMatched, UnitActivated, UnitDeactivated}; use crate::persistence; @@ -61,7 +62,7 @@ pub struct ChainListener { // To subscribe to chain events event_subscription: Box, - ccp_client: Option, + ccp_client: Option>, core_manager: Arc, @@ -118,7 +119,7 @@ impl ChainListener { event_subscription: Box, chain_connector: Arc, core_manager: Arc, - ccp_client: Option, + ccp_client: Option>, persisted_proof_id_dir: PathBuf, metrics: Option, ) -> Self { @@ -170,9 +171,11 @@ impl ChainListener { } pub fn start(mut self) -> JoinHandle<()> { - let result = tokio::task::Builder::new() - .name("ChainListener") - .spawn_local(async move { + let local = tokio::task::LocalSet::new(); + + // TODO: fix and use spawn instead of spawn_local + let result = local.spawn_local( + async move { if let Err(err) = self.set_utility_core().await { tracing::error!(target: "chain-listener", "Failed to set utility core: {err}; Stopping..."); @@ -245,9 +248,7 @@ impl ChainListener { } } } - }) - .expect("Could not spawn task"); - + }); result } @@ -1304,6 +1305,7 @@ mod tests { use core_manager::{CoreManager, DummyCoreManager}; use futures::StreamExt; use jsonrpsee::core::{async_trait, JsonValue}; + use log_utils::enable_logs; use std::sync::Arc; use std::time::Duration; use tokio::sync::broadcast::Sender; @@ -1312,12 +1314,23 @@ mod tests { struct TestEventSubscription { new_heads_sender: Sender>, + commitment_activated_sender: Sender>, + commitment_deactivated_sender: Sender>, + unit_matched_sender: Sender>, } impl TestEventSubscription { pub fn new() -> Self { let (new_heads_sender, _rx) = tokio::sync::broadcast::channel(16); - Self { new_heads_sender } + let (commitment_activated_sender, _rx) = tokio::sync::broadcast::channel(16); + let (commitment_deactivated_sender, _rx) = tokio::sync::broadcast::channel(16); + let (unit_matched_sender, _rx) = tokio::sync::broadcast::channel(16); + Self { + new_heads_sender, + commitment_activated_sender, + commitment_deactivated_sender, + unit_matched_sender, + } } } @@ -1334,7 +1347,9 @@ mod tests { &self, commitment_id: &CommitmentId, ) -> Result, Error> { - todo!() + let rx = self.commitment_deactivated_sender.subscribe(); + let stream = BroadcastStream::new(rx); + Ok(stream.map(|item| item.unwrap()).boxed()) } async fn new_heads(&self) -> Result, Error> { @@ -1344,11 +1359,15 @@ mod tests { } async fn commitment_activated(&self) -> Result, Error> { - todo!() + let rx = self.commitment_activated_sender.subscribe(); + let stream = BroadcastStream::new(rx); + Ok(stream.map(|item| item.unwrap()).boxed()) } async fn unit_matched(&self) -> Result, Error> { - todo!() + let rx = self.unit_matched_sender.subscribe(); + let stream = BroadcastStream::new(rx); + Ok(stream.map(|item| item.unwrap()).boxed()) } async fn refresh(&mut self) -> Result<(), Error> { @@ -1419,6 +1438,7 @@ mod tests { #[tokio::test] async fn test_activation_flow() { + enable_logs(); let tmp_dir = tempfile::tempdir().expect("Could not create temp dir"); let config = ChainListenerConfig::new(Duration::from_secs(1)); let subscription = TestEventSubscription::new(); @@ -1438,5 +1458,7 @@ mod tests { ); listener.start().await; + + tokio::time::sleep(Duration::from_secs(10)).await; } } From 9a6840da53a762a0f12808f16afcd9c28f7f1909 Mon Sep 17 00:00:00 2001 From: Nick Pavlov Date: Fri, 19 Apr 2024 17:49:10 +0300 Subject: [PATCH 04/44] wip --- crates/chain-listener/src/ccp.rs | 2 +- crates/chain-listener/src/listener.rs | 31 +++++++++++++++-------- crates/chain-listener/src/subscription.rs | 21 ++++++++------- 3 files changed, 33 insertions(+), 21 deletions(-) diff --git a/crates/chain-listener/src/ccp.rs b/crates/chain-listener/src/ccp.rs index d022973a9c..c04738998d 100644 --- a/crates/chain-listener/src/ccp.rs +++ b/crates/chain-listener/src/ccp.rs @@ -1,4 +1,4 @@ -use ccp_rpc_client::{CCPRpcClient, CCPRpcHttpClient, ClientError}; +use ccp_rpc_client::{CCPRpcHttpClient, ClientError}; use ccp_shared::proof::{CCProof, ProofIdx}; use ccp_shared::types::{Difficulty, GlobalNonce, LogicalCoreId, PhysicalCoreId, CUID}; use jsonrpsee::core::async_trait; diff --git a/crates/chain-listener/src/listener.rs b/crates/chain-listener/src/listener.rs index bd10928dcc..b8721498f2 100644 --- a/crates/chain-listener/src/listener.rs +++ b/crates/chain-listener/src/listener.rs @@ -11,7 +11,6 @@ use std::time::Duration; use backoff::future::retry; use backoff::ExponentialBackoff; -use ccp_rpc_client::CCPRpcClient; use ccp_shared::proof::{CCProof, CCProofId, ProofIdx}; use ccp_shared::types::{Difficulty, GlobalNonce, LocalNonce, ResultHash}; use cpu_utils::PhysicalCoreId; @@ -60,9 +59,9 @@ pub struct ChainListener { chain_connector: Arc, // To subscribe to chain events - event_subscription: Box, + event_subscription: Arc, - ccp_client: Option>, + ccp_client: Option>, core_manager: Arc, @@ -116,10 +115,10 @@ where impl ChainListener { pub fn new( listener_config: ChainListenerConfig, - event_subscription: Box, + event_subscription: Arc, chain_connector: Arc, core_manager: Arc, - ccp_client: Option>, + ccp_client: Option>, persisted_proof_id_dir: PathBuf, metrics: Option, ) -> Self { @@ -467,8 +466,6 @@ impl ChainListener { } async fn refresh_subscriptions(&mut self) -> Result<(), Error> { - self.event_subscription.refresh().await?; - // loop because subscriptions can fail and require reconnection, we can't proceed without them loop { let result: Result<(), Error> = try { @@ -1306,8 +1303,10 @@ mod tests { use futures::StreamExt; use jsonrpsee::core::{async_trait, JsonValue}; use log_utils::enable_logs; + use serde_json::{json, Value}; use std::sync::Arc; use std::time::Duration; + use tokio::sync::broadcast::error::SendError; use tokio::sync::broadcast::Sender; use tokio_stream::wrappers::BroadcastStream; use types::DealId; @@ -1332,6 +1331,13 @@ mod tests { unit_matched_sender, } } + + pub fn send_new_heads( + &self, + value: Result, + ) -> Result>> { + self.new_heads_sender.send(value) + } } #[async_trait] @@ -1370,11 +1376,11 @@ mod tests { Ok(stream.map(|item| item.unwrap()).boxed()) } - async fn refresh(&mut self) -> Result<(), Error> { + async fn refresh(&self) -> Result<(), Error> { Ok(()) } - async fn restart(&mut self) -> Result<(), Error> { + async fn restart(&self) -> Result<(), Error> { Ok(()) } } @@ -1442,14 +1448,14 @@ mod tests { let tmp_dir = tempfile::tempdir().expect("Could not create temp dir"); let config = ChainListenerConfig::new(Duration::from_secs(1)); let subscription = TestEventSubscription::new(); - let subscription = Box::new(subscription); + let subscription = Arc::new(subscription); let connector = TestChainConnector; let connector = Arc::new(connector); let core_manager = CoreManager::Dummy(DummyCoreManager::default()); let core_manager = Arc::new(core_manager); let listener = ChainListener::new( config, - subscription, + subscription.clone(), connector, core_manager, None, @@ -1459,6 +1465,9 @@ mod tests { listener.start().await; + tokio::time::sleep(Duration::from_secs(3)); + let _ = subscription.send_new_heads(Ok(json!("test"))).unwrap(); + tokio::time::sleep(Duration::from_secs(10)).await; } } diff --git a/crates/chain-listener/src/subscription.rs b/crates/chain-listener/src/subscription.rs index 9799fb32cc..23df3c92ad 100644 --- a/crates/chain-listener/src/subscription.rs +++ b/crates/chain-listener/src/subscription.rs @@ -19,6 +19,7 @@ use serde_json::json; use std::ops::Deref; use std::sync::Arc; use thiserror::Error; +use tokio::sync::RwLock; //TODO: make a domain errors #[derive(Error, Clone, Debug)] @@ -51,8 +52,8 @@ pub trait EventSubscription: Send + Sync { async fn unit_matched(&self) -> SubResult; // TODO: remove both methods and encapsulate logic - async fn refresh(&mut self) -> Result<(), Error>; - async fn restart(&mut self) -> Result<(), Error>; + async fn refresh(&self) -> Result<(), Error>; + async fn restart(&self) -> Result<(), Error>; } pub struct WsSubscriptionConfig { @@ -80,12 +81,13 @@ impl WsSubscriptionConfig { pub struct WsEventSubscription { config: WsSubscriptionConfig, - ws_client: WsClient, + ws_client: RwLock, } impl WsEventSubscription { pub async fn new(config: WsSubscriptionConfig) -> Result { let ws_client = Self::create_ws_client(config.ws_endpoint.as_str()).await?; + let ws_client = RwLock::new(ws_client); Ok(Self { config, ws_client }) } @@ -95,8 +97,8 @@ impl WsEventSubscription { params: ArrayParams, ) -> Result, Error> { let sub = retry(ExponentialBackoff::default(), || async { - self.ws_client - .subscribe("eth_subscribe", params.clone(), "eth_unsubscribe") + let ws_client = self.ws_client.read().await; + ws_client.subscribe("eth_subscribe", params.clone(), "eth_unsubscribe") .await.map_err(|err| { if let RestartNeeded(_) = err { tracing::error!(target: "chain-listener", "Failed to subscribe to {method}: {err};"); @@ -205,15 +207,16 @@ impl EventSubscription for WsEventSubscription { self.subscribe("logs", self.unit_matched_params()).await } - async fn refresh(&mut self) -> Result<(), Error> { - if !self.ws_client.is_connected() { + async fn refresh(&self) -> Result<(), Error> { + if !self.ws_client.read().await.is_connected() { self.restart().await? } Ok(()) } - async fn restart(&mut self) -> Result<(), Error> { - self.ws_client = Self::create_ws_client(&self.config.ws_endpoint).await?; + async fn restart(&self) -> Result<(), Error> { + let mut ws_client = self.ws_client.write().await; + *ws_client = Self::create_ws_client(&self.config.ws_endpoint).await?; Ok(()) } } From 8cafb89f26c7aedca8e230060ed5331fcba9ca3b Mon Sep 17 00:00:00 2001 From: Nick Pavlov Date: Sun, 21 Apr 2024 19:23:22 +0300 Subject: [PATCH 05/44] wip --- crates/chain-listener/Cargo.toml | 2 +- crates/chain-listener/src/listener.rs | 107 ++++++++++++++-------- crates/chain-listener/src/subscription.rs | 9 +- 3 files changed, 75 insertions(+), 43 deletions(-) diff --git a/crates/chain-listener/Cargo.toml b/crates/chain-listener/Cargo.toml index 17731a1876..cf259038af 100644 --- a/crates/chain-listener/Cargo.toml +++ b/crates/chain-listener/Cargo.toml @@ -44,4 +44,4 @@ peer-metrics = { workspace = true } jsonrpsee = { workspace = true, features = ["server"] } tempfile = { workspace = true } tokio-stream = { workspace = true } -log-utils = { workspace = true } \ No newline at end of file +log-utils = { workspace = true } diff --git a/crates/chain-listener/src/listener.rs b/crates/chain-listener/src/listener.rs index b8721498f2..a1b9d936f7 100644 --- a/crates/chain-listener/src/listener.rs +++ b/crates/chain-listener/src/listener.rs @@ -170,34 +170,33 @@ impl ChainListener { } pub fn start(mut self) -> JoinHandle<()> { - let local = tokio::task::LocalSet::new(); - - // TODO: fix and use spawn instead of spawn_local - let result = local.spawn_local( - async move { - - if let Err(err) = self.set_utility_core().await { - tracing::error!(target: "chain-listener", "Failed to set utility core: {err}; Stopping..."); - exit(1); - } + tokio::task::Builder::new() + .name("ChainListener") + .spawn( + async move { + + if let Err(err) = self.set_utility_core().await { + tracing::error!(target: "chain-listener", "Failed to set utility core: {err}; Stopping..."); + exit(1); + } - tracing::info!(target: "chain-listener", "Subscribing to chain events"); - if let Err(err) = self.refresh_subscriptions().await { - tracing::error!(target: "chain-listener", "Failed to subscribe to chain events: {err}; Stopping..."); - exit(1); - } - tracing::info!(target: "chain-listener", "Subscribed successfully"); + tracing::info!(target: "chain-listener", "Subscribing to chain events"); + if let Err(err) = self.refresh_subscriptions().await { + tracing::error!(target: "chain-listener", "Failed to subscribe to chain events: {err}; Stopping..."); + exit(1); + } + tracing::info!(target: "chain-listener", "Subscribed successfully"); - if let Err(err) = self.refresh_state().await { - tracing::error!(target: "chain-listener", "Failed to refresh state: {err}; Stopping..."); - exit(1); - } + if let Err(err) = self.refresh_state().await { + tracing::error!(target: "chain-listener", "Failed to refresh state: {err}; Stopping..."); + exit(1); + } - tracing::info!(target: "chain-listener", "State successfully refreshed, starting main loop"); - let mut timer = IntervalStream::new(interval(self.listener_config.proof_poll_period)); + tracing::info!(target: "chain-listener", "State successfully refreshed, starting main loop"); + let mut timer = IntervalStream::new(interval(self.listener_config.proof_poll_period)); - loop { - tokio::select! { + loop { + tokio::select! { event = poll_subscription(&mut self.heads) => { if let Err(err) = self.process_new_header(event).await { self.handle_subscription_error("newHeads", err).await; @@ -246,9 +245,8 @@ impl ChainListener { } } } - } - }); - result + } + }) .expect("Could not spawn task") } async fn refresh_current_commitment_id(&mut self) -> eyre::Result<()> { @@ -1294,6 +1292,7 @@ where mod tests { use crate::subscription::{Error, EventSubscription, Stream}; use crate::{ChainListener, ChainListenerConfig}; + use alloy_sol_types::SolType; use ccp_shared::proof::CCProof; use ccp_shared::types::{GlobalNonce, CUID}; use chain_connector::Deal::Status; @@ -1301,6 +1300,7 @@ mod tests { use chain_connector::{CCInitParams, CCStatus, ChainConnector, CommitmentId, ConnectorError}; use core_manager::{CoreManager, DummyCoreManager}; use futures::StreamExt; + use hex::FromHex; use jsonrpsee::core::{async_trait, JsonValue}; use log_utils::enable_logs; use serde_json::{json, Value}; @@ -1308,14 +1308,17 @@ mod tests { use std::time::Duration; use tokio::sync::broadcast::error::SendError; use tokio::sync::broadcast::Sender; + use tokio::sync::Notify; use tokio_stream::wrappers::BroadcastStream; use types::DealId; struct TestEventSubscription { new_heads_sender: Sender>, + new_heads_notify: Notify, commitment_activated_sender: Sender>, commitment_deactivated_sender: Sender>, unit_matched_sender: Sender>, + unit_activated_sender: Sender>, } impl TestEventSubscription { @@ -1324,11 +1327,15 @@ mod tests { let (commitment_activated_sender, _rx) = tokio::sync::broadcast::channel(16); let (commitment_deactivated_sender, _rx) = tokio::sync::broadcast::channel(16); let (unit_matched_sender, _rx) = tokio::sync::broadcast::channel(16); + let (unit_activated_sender, _rx) = tokio::sync::broadcast::channel(16); + let new_heads_notify = Notify::new(); Self { new_heads_sender, + new_heads_notify, commitment_activated_sender, commitment_deactivated_sender, unit_matched_sender, + unit_activated_sender, } } @@ -1338,6 +1345,10 @@ mod tests { ) -> Result>> { self.new_heads_sender.send(value) } + + pub async fn wait_new_head_subscription(&self) { + self.new_heads_notify.notified().await + } } #[async_trait] @@ -1346,7 +1357,9 @@ mod tests { &self, commitment_id: &CommitmentId, ) -> Result, Error> { - todo!() + let rx = self.unit_activated_sender.subscribe(); + let stream = BroadcastStream::new(rx); + Ok(Box::pin(stream.map(|item| item.unwrap()))) } async fn unit_deactivated( @@ -1355,25 +1368,26 @@ mod tests { ) -> Result, Error> { let rx = self.commitment_deactivated_sender.subscribe(); let stream = BroadcastStream::new(rx); - Ok(stream.map(|item| item.unwrap()).boxed()) + Ok(Box::pin(stream.map(|item| item.unwrap()))) } async fn new_heads(&self) -> Result, Error> { let rx = self.new_heads_sender.subscribe(); let stream = BroadcastStream::new(rx); - Ok(stream.map(|item| item.unwrap()).boxed()) + self.new_heads_notify.notify_one(); + Ok(Box::pin(stream.map(|item| item.unwrap()))) } async fn commitment_activated(&self) -> Result, Error> { let rx = self.commitment_activated_sender.subscribe(); let stream = BroadcastStream::new(rx); - Ok(stream.map(|item| item.unwrap()).boxed()) + Ok(Box::pin(stream.map(|item| item.unwrap()))) } async fn unit_matched(&self) -> Result, Error> { let rx = self.unit_matched_sender.subscribe(); let stream = BroadcastStream::new(rx); - Ok(stream.map(|item| item.unwrap()).boxed()) + Ok(Box::pin(stream.map(|item| item.unwrap()))) } async fn refresh(&self) -> Result<(), Error> { @@ -1390,15 +1404,28 @@ mod tests { #[async_trait] impl ChainConnector for TestChainConnector { async fn get_current_commitment_id(&self) -> Result, ConnectorError> { - todo!() + Ok(None) } async fn get_cc_init_params(&self) -> eyre::Result { - todo!() + Ok(CCInitParams { + difficulty: Default::default(), + init_timestamp: Default::default(), + global_nonce: GlobalNonce::from_hex( + "54ae1b506c260367a054f80800a545f23e32c6bc4a8908c9a794cb8dad23e5ea", + ) + .unwrap(), + current_epoch: Default::default(), + epoch_duration: Default::default(), + min_proofs_per_epoch: Default::default(), + max_proofs_per_epoch: Default::default(), + }) } async fn get_compute_units(&self) -> Result, ConnectorError> { - todo!() + let bytes = hex::decode("aa3046a12a1aac6e840625e6329d70b427328fec36dc8d273e5e6454b85633d5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e8") + .unwrap(); + Ok(vec![ComputeUnit::abi_decode(&bytes, true).unwrap()]) } async fn get_commitment_status( @@ -1453,19 +1480,23 @@ mod tests { let connector = Arc::new(connector); let core_manager = CoreManager::Dummy(DummyCoreManager::default()); let core_manager = Arc::new(core_manager); + + let proofs_dir = tmp_dir.path().join("proofs").to_path_buf(); + tokio::fs::create_dir_all(proofs_dir.clone()).await.unwrap(); + let listener = ChainListener::new( config, subscription.clone(), connector, core_manager, None, - tmp_dir.path().join("proofs").to_path_buf(), + proofs_dir, None, ); - listener.start().await; + let _a = listener.start(); - tokio::time::sleep(Duration::from_secs(3)); + subscription.wait_new_head_subscription().await; let _ = subscription.send_new_heads(Ok(json!("test"))).unwrap(); tokio::time::sleep(Duration::from_secs(10)).await; diff --git a/crates/chain-listener/src/subscription.rs b/crates/chain-listener/src/subscription.rs index 23df3c92ad..a9b67b2451 100644 --- a/crates/chain-listener/src/subscription.rs +++ b/crates/chain-listener/src/subscription.rs @@ -6,8 +6,7 @@ use backoff::Error::Permanent; use backoff::ExponentialBackoff; use chain_connector::CommitmentId; use chain_data::peer_id_to_hex; -use futures::stream::BoxStream; -use futures::{StreamExt, TryStreamExt}; +use futures::{TryStreamExt}; use jsonrpsee::core::client::SubscriptionClientT; use jsonrpsee::core::params::ArrayParams; use jsonrpsee::core::ClientError::RestartNeeded; @@ -17,6 +16,7 @@ use jsonrpsee::ws_client::{WsClient, WsClientBuilder}; use libp2p_identity::PeerId; use serde_json::json; use std::ops::Deref; +use std::pin::Pin; use std::sync::Arc; use thiserror::Error; use tokio::sync::RwLock; @@ -40,7 +40,8 @@ impl From for Error { } } -pub type Stream = BoxStream<'static, Result>; +pub type Stream = Pin> + Send + Sync + 'static>>; + pub type SubResult = Result, Error>; #[async_trait] @@ -109,7 +110,7 @@ impl WsEventSubscription { }}) }).await.map_err(|err| Error::from(err))?; - Ok(sub.map_err(|err| err.into()).boxed()) + Ok(Box::pin(sub.map_err(|err| err.into()))) } fn unit_activated_params(&self, commitment_id: &CommitmentId) -> ArrayParams { From f5423bad8864ba86aac7e912425f39af067c1f89 Mon Sep 17 00:00:00 2001 From: Nick Pavlov Date: Mon, 22 Apr 2024 14:06:40 +0300 Subject: [PATCH 06/44] init bevaviour --- Cargo.lock | 1 + crates/chain-listener/Cargo.toml | 1 + crates/chain-listener/src/listener.rs | 60 ++++++++++++++++++----- crates/chain-listener/src/subscription.rs | 2 +- 4 files changed, 52 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8cbce9d02a..73566444bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1385,6 +1385,7 @@ dependencies = [ "libp2p-identity", "log", "log-utils", + "parking_lot", "peer-metrics", "serde", "serde_json", diff --git a/crates/chain-listener/Cargo.toml b/crates/chain-listener/Cargo.toml index cf259038af..7d5d4fcf86 100644 --- a/crates/chain-listener/Cargo.toml +++ b/crates/chain-listener/Cargo.toml @@ -45,3 +45,4 @@ jsonrpsee = { workspace = true, features = ["server"] } tempfile = { workspace = true } tokio-stream = { workspace = true } log-utils = { workspace = true } +parking_lot = { workspace = true } diff --git a/crates/chain-listener/src/listener.rs b/crates/chain-listener/src/listener.rs index a1b9d936f7..1bf5f2ebba 100644 --- a/crates/chain-listener/src/listener.rs +++ b/crates/chain-listener/src/listener.rs @@ -1303,6 +1303,7 @@ mod tests { use hex::FromHex; use jsonrpsee::core::{async_trait, JsonValue}; use log_utils::enable_logs; + use parking_lot::RwLock; use serde_json::{json, Value}; use std::sync::Arc; use std::time::Duration; @@ -1346,7 +1347,7 @@ mod tests { self.new_heads_sender.send(value) } - pub async fn wait_new_head_subscription(&self) { + pub async fn wait_subscriptions(&self) { self.new_heads_notify.notified().await } } @@ -1399,15 +1400,18 @@ mod tests { } } - struct TestChainConnector; + trait Behaviour: Send + Sync { + type Output; - #[async_trait] - impl ChainConnector for TestChainConnector { - async fn get_current_commitment_id(&self) -> Result, ConnectorError> { - Ok(None) - } + fn apply(&self) -> Self::Output; + } - async fn get_cc_init_params(&self) -> eyre::Result { + #[derive(Default)] + struct GetCcInitParamsBehaviour; + impl Behaviour for GetCcInitParamsBehaviour { + type Output = eyre::Result; + + fn apply(&self) -> Self::Output { Ok(CCInitParams { difficulty: Default::default(), init_timestamp: Default::default(), @@ -1421,6 +1425,38 @@ mod tests { max_proofs_per_epoch: Default::default(), }) } + } + + struct TestChainConnector { + get_cc_init_params_behaviour: + RwLock>>>, + } + + impl TestChainConnector { + pub fn new() -> Self { + Self { + get_cc_init_params_behaviour: RwLock::new(Box::new(GetCcInitParamsBehaviour)), + } + } + + pub fn set_get_cc_init_params_behaviour( + &self, + behaviour: impl Behaviour> + 'static, + ) { + let mut lock = self.get_cc_init_params_behaviour.write(); + *lock = Box::new(behaviour); + } + } + + #[async_trait] + impl ChainConnector for TestChainConnector { + async fn get_current_commitment_id(&self) -> Result, ConnectorError> { + Ok(None) + } + + async fn get_cc_init_params(&self) -> eyre::Result { + self.get_cc_init_params_behaviour.read().apply() + } async fn get_compute_units(&self) -> Result, ConnectorError> { let bytes = hex::decode("aa3046a12a1aac6e840625e6329d70b427328fec36dc8d273e5e6454b85633d5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e8") @@ -1476,7 +1512,7 @@ mod tests { let config = ChainListenerConfig::new(Duration::from_secs(1)); let subscription = TestEventSubscription::new(); let subscription = Arc::new(subscription); - let connector = TestChainConnector; + let connector = TestChainConnector::new(); let connector = Arc::new(connector); let core_manager = CoreManager::Dummy(DummyCoreManager::default()); let core_manager = Arc::new(core_manager); @@ -1487,7 +1523,7 @@ mod tests { let listener = ChainListener::new( config, subscription.clone(), - connector, + connector.clone(), core_manager, None, proofs_dir, @@ -1496,7 +1532,9 @@ mod tests { let _a = listener.start(); - subscription.wait_new_head_subscription().await; + connector.set_get_cc_init_params_behaviour(GetCcInitParamsBehaviour); + + subscription.wait_subscriptions().await; let _ = subscription.send_new_heads(Ok(json!("test"))).unwrap(); tokio::time::sleep(Duration::from_secs(10)).await; diff --git a/crates/chain-listener/src/subscription.rs b/crates/chain-listener/src/subscription.rs index a9b67b2451..f24b802ad8 100644 --- a/crates/chain-listener/src/subscription.rs +++ b/crates/chain-listener/src/subscription.rs @@ -6,7 +6,7 @@ use backoff::Error::Permanent; use backoff::ExponentialBackoff; use chain_connector::CommitmentId; use chain_data::peer_id_to_hex; -use futures::{TryStreamExt}; +use futures::TryStreamExt; use jsonrpsee::core::client::SubscriptionClientT; use jsonrpsee::core::params::ArrayParams; use jsonrpsee::core::ClientError::RestartNeeded; From 07b242998c6886d637d3f6b004741d8c8f12dee1 Mon Sep 17 00:00:00 2001 From: Nick Pavlov Date: Mon, 22 Apr 2024 14:14:26 +0300 Subject: [PATCH 07/44] init bevaviour --- crates/chain-listener/src/listener.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/crates/chain-listener/src/listener.rs b/crates/chain-listener/src/listener.rs index 1bf5f2ebba..9f884bb777 100644 --- a/crates/chain-listener/src/listener.rs +++ b/crates/chain-listener/src/listener.rs @@ -1317,8 +1317,10 @@ mod tests { new_heads_sender: Sender>, new_heads_notify: Notify, commitment_activated_sender: Sender>, + commitment_activated_notify: Notify, commitment_deactivated_sender: Sender>, unit_matched_sender: Sender>, + unit_matched_notify: Notify, unit_activated_sender: Sender>, } @@ -1330,13 +1332,17 @@ mod tests { let (unit_matched_sender, _rx) = tokio::sync::broadcast::channel(16); let (unit_activated_sender, _rx) = tokio::sync::broadcast::channel(16); let new_heads_notify = Notify::new(); + let unit_matched_notify = Notify::new(); + let commitment_activated_notify = Notify::new(); Self { new_heads_sender, new_heads_notify, commitment_activated_sender, commitment_deactivated_sender, unit_matched_sender, + unit_matched_notify, unit_activated_sender, + commitment_activated_notify, } } @@ -1348,7 +1354,9 @@ mod tests { } pub async fn wait_subscriptions(&self) { - self.new_heads_notify.notified().await + self.new_heads_notify.notified().await; + self.unit_matched_notify.notified().await; + self.commitment_activated_notify.notified().await; } } @@ -1382,12 +1390,14 @@ mod tests { async fn commitment_activated(&self) -> Result, Error> { let rx = self.commitment_activated_sender.subscribe(); let stream = BroadcastStream::new(rx); + self.commitment_activated_notify.notify_one(); Ok(Box::pin(stream.map(|item| item.unwrap()))) } async fn unit_matched(&self) -> Result, Error> { let rx = self.unit_matched_sender.subscribe(); let stream = BroadcastStream::new(rx); + self.unit_matched_notify.notify_one(); Ok(Box::pin(stream.map(|item| item.unwrap()))) } From eaf24341fca2236c2400bd25896b3bb3b2b2669a Mon Sep 17 00:00:00 2001 From: Nick Pavlov Date: Mon, 22 Apr 2024 15:20:29 +0300 Subject: [PATCH 08/44] init bevaviour --- crates/chain-listener/src/lib.rs | 1 + crates/chain-listener/src/listener.rs | 30 +++++++++++------------ crates/chain-listener/src/subscription.rs | 2 +- nox/src/node.rs | 10 +++++--- 4 files changed, 24 insertions(+), 19 deletions(-) diff --git a/crates/chain-listener/src/lib.rs b/crates/chain-listener/src/lib.rs index 0542594027..df3eb24c5c 100644 --- a/crates/chain-listener/src/lib.rs +++ b/crates/chain-listener/src/lib.rs @@ -6,6 +6,7 @@ extern crate core; +pub use ccp::CCPClient; pub use listener::ChainListener; pub use listener::ChainListenerConfig; pub use subscription::WsEventSubscription; diff --git a/crates/chain-listener/src/listener.rs b/crates/chain-listener/src/listener.rs index 9f884bb777..23409f90cd 100644 --- a/crates/chain-listener/src/listener.rs +++ b/crates/chain-listener/src/listener.rs @@ -1364,7 +1364,7 @@ mod tests { impl EventSubscription for TestEventSubscription { async fn unit_activated( &self, - commitment_id: &CommitmentId, + _commitment_id: &CommitmentId, ) -> Result, Error> { let rx = self.unit_activated_sender.subscribe(); let stream = BroadcastStream::new(rx); @@ -1373,7 +1373,7 @@ mod tests { async fn unit_deactivated( &self, - commitment_id: &CommitmentId, + _commitment_id: &CommitmentId, ) -> Result, Error> { let rx = self.commitment_deactivated_sender.subscribe(); let stream = BroadcastStream::new(rx); @@ -1410,18 +1410,18 @@ mod tests { } } - trait Behaviour: Send + Sync { + trait Behaviour: Send + Sync { type Output; - fn apply(&self) -> Self::Output; + fn apply(&self, params: T) -> Self::Output; } #[derive(Default)] struct GetCcInitParamsBehaviour; - impl Behaviour for GetCcInitParamsBehaviour { + impl Behaviour<()> for GetCcInitParamsBehaviour { type Output = eyre::Result; - fn apply(&self) -> Self::Output { + fn apply(&self, _params: ()) -> Self::Output { Ok(CCInitParams { difficulty: Default::default(), init_timestamp: Default::default(), @@ -1439,7 +1439,7 @@ mod tests { struct TestChainConnector { get_cc_init_params_behaviour: - RwLock>>>, + RwLock>>>, } impl TestChainConnector { @@ -1451,7 +1451,7 @@ mod tests { pub fn set_get_cc_init_params_behaviour( &self, - behaviour: impl Behaviour> + 'static, + behaviour: impl Behaviour<(), Output = eyre::Result> + 'static, ) { let mut lock = self.get_cc_init_params_behaviour.write(); *lock = Box::new(behaviour); @@ -1465,7 +1465,7 @@ mod tests { } async fn get_cc_init_params(&self) -> eyre::Result { - self.get_cc_init_params_behaviour.read().apply() + self.get_cc_init_params_behaviour.read().apply(()) } async fn get_compute_units(&self) -> Result, ConnectorError> { @@ -1476,7 +1476,7 @@ mod tests { async fn get_commitment_status( &self, - commitment_id: CommitmentId, + _commitment_id: CommitmentId, ) -> Result { todo!() } @@ -1485,31 +1485,31 @@ mod tests { todo!() } - async fn submit_proof(&self, proof: CCProof) -> Result { + async fn submit_proof(&self, _proof: CCProof) -> Result { todo!() } async fn get_deal_statuses( &self, - deal_ids: Vec, + _deal_ids: Vec, ) -> Result>, ConnectorError> { todo!() } - async fn exit_deal(&self, cu_id: &CUID) -> Result { + async fn exit_deal(&self, _cu_id: &CUID) -> Result { todo!() } async fn get_tx_statuses( &self, - tx_hashes: Vec, + _tx_hashes: Vec, ) -> Result, ConnectorError>>, ConnectorError> { todo!() } async fn get_tx_receipts( &self, - tx_hashes: Vec, + _tx_hashes: Vec, ) -> Result>, ConnectorError> { todo!() } diff --git a/crates/chain-listener/src/subscription.rs b/crates/chain-listener/src/subscription.rs index f24b802ad8..b16544a321 100644 --- a/crates/chain-listener/src/subscription.rs +++ b/crates/chain-listener/src/subscription.rs @@ -108,7 +108,7 @@ impl WsEventSubscription { tracing::warn!(target: "chain-listener", "Failed to subscribe to {method}: {err}; Retrying..."); backoff::Error::transient(err) }}) - }).await.map_err(|err| Error::from(err))?; + }).await.map_err(Error::from)?; Ok(Box::pin(sub.map_err(|err| err.into()))) } diff --git a/nox/src/node.rs b/nox/src/node.rs index b2f47c13d3..b2c60b98b3 100644 --- a/nox/src/node.rs +++ b/nox/src/node.rs @@ -44,7 +44,7 @@ use aquamarine::{ }; use chain_connector::HttpChainConnector; use chain_listener::{ - ChainListener, ChainListenerConfig, WsEventSubscription, WsSubscriptionConfig, + CCPClient, ChainListener, ChainListenerConfig, WsEventSubscription, WsSubscriptionConfig, }; use config_utils::to_peer_id; use connection_pool::ConnectionPoolT; @@ -125,7 +125,9 @@ async fn setup_listener( config.chain_config.clone(), config.chain_listener_config.clone(), ) { - let ccp_client = if let Some(ccp_endpoint) = listener_config.ccp_endpoint.clone() { + let ccp_client: Option> = if let Some(ccp_endpoint) = + listener_config.ccp_endpoint.clone() + { let ccp_client = CCPRpcHttpClient::new(ccp_endpoint.clone()) .await .map_err(|err| { @@ -133,6 +135,8 @@ async fn setup_listener( err })?; + let ccp_client = Arc::new(ccp_client); + Some(ccp_client) } else { None @@ -148,7 +152,7 @@ async fn setup_listener( chain_config.market_contract_address, ); let event_subscription = WsEventSubscription::new(ws_event_subscription_config).await?; - let event_subscription = Box::new(event_subscription); + let event_subscription = Arc::new(event_subscription); let chain_listener_config = ChainListenerConfig::new(listener_config.proof_poll_period); From b301a5627ada39d698c7265855626997e40e1401 Mon Sep 17 00:00:00 2001 From: Nick Pavlov Date: Mon, 22 Apr 2024 16:00:35 +0300 Subject: [PATCH 09/44] switch to mockall --- Cargo.lock | 72 ++++++++++++ crates/chain-listener/Cargo.toml | 1 + crates/chain-listener/src/listener.rs | 156 +++++++++----------------- 3 files changed, 128 insertions(+), 101 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 73566444bf..76910a407f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1385,6 +1385,7 @@ dependencies = [ "libp2p-identity", "log", "log-utils", + "mockall", "parking_lot", "peer-metrics", "serde", @@ -2242,6 +2243,12 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257" +[[package]] +name = "downcast" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" + [[package]] name = "dtoa" version = "1.0.9" @@ -2659,6 +2666,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fragile" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" + [[package]] name = "fs-set-times" version = "0.20.1" @@ -5408,6 +5421,33 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "mockall" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43766c2b5203b10de348ffe19f7e54564b64f3d6018ff7648d1e2d6d3a0f0a48" +dependencies = [ + "cfg-if", + "downcast", + "fragile", + "lazy_static", + "mockall_derive", + "predicates", + "predicates-tree", +] + +[[package]] +name = "mockall_derive" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af7cbce79ec385a1d4f54baa90a76401eb15d9cab93685f62e7e9f942aa00ae2" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "syn 2.0.46", +] + [[package]] name = "mockito" version = "1.2.0" @@ -6537,6 +6577,32 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "predicates" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68b87bfd4605926cdfefc1c3b5f8fe560e3feca9d5552cf68c466d3d8236c7e8" +dependencies = [ + "anstyle", + "predicates-core", +] + +[[package]] +name = "predicates-core" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" + +[[package]] +name = "predicates-tree" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" +dependencies = [ + "predicates-core", + "termtree", +] + [[package]] name = "primitive-types" version = "0.12.2" @@ -8259,6 +8325,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "termtree" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" + [[package]] name = "test-constants" version = "0.1.0" diff --git a/crates/chain-listener/Cargo.toml b/crates/chain-listener/Cargo.toml index 7d5d4fcf86..462e23a49c 100644 --- a/crates/chain-listener/Cargo.toml +++ b/crates/chain-listener/Cargo.toml @@ -46,3 +46,4 @@ tempfile = { workspace = true } tokio-stream = { workspace = true } log-utils = { workspace = true } parking_lot = { workspace = true } +mockall = "0.12.1" \ No newline at end of file diff --git a/crates/chain-listener/src/listener.rs b/crates/chain-listener/src/listener.rs index 23409f90cd..ab98c0fade 100644 --- a/crates/chain-listener/src/listener.rs +++ b/crates/chain-listener/src/listener.rs @@ -1295,7 +1295,6 @@ mod tests { use alloy_sol_types::SolType; use ccp_shared::proof::CCProof; use ccp_shared::types::{GlobalNonce, CUID}; - use chain_connector::Deal::Status; use chain_connector::Offer::ComputeUnit; use chain_connector::{CCInitParams, CCStatus, ChainConnector, CommitmentId, ConnectorError}; use core_manager::{CoreManager, DummyCoreManager}; @@ -1303,7 +1302,7 @@ mod tests { use hex::FromHex; use jsonrpsee::core::{async_trait, JsonValue}; use log_utils::enable_logs; - use parking_lot::RwLock; + use mockall::mock; use serde_json::{json, Value}; use std::sync::Arc; use std::time::Duration; @@ -1313,6 +1312,45 @@ mod tests { use tokio_stream::wrappers::BroadcastStream; use types::DealId; + mock! { + ChainConnectorStruct {} // Name of the mock struct, less the "Mock" prefix + + #[async_trait] + impl ChainConnector for ChainConnectorStruct { + async fn get_current_commitment_id(&self) -> Result, ConnectorError>; + + async fn get_cc_init_params(&self) -> eyre::Result; + + async fn get_compute_units(&self) -> Result, ConnectorError>; + + async fn get_commitment_status( + &self, + commitment_id: CommitmentId, + ) -> Result; + + async fn get_global_nonce(&self) -> Result; + + async fn submit_proof(&self, proof: CCProof) -> Result; + + async fn get_deal_statuses( + &self, + deal_ids: Vec, + ) -> Result>, ConnectorError>; + + async fn exit_deal(&self, cu_id: &CUID) -> Result; + + async fn get_tx_statuses( + &self, + tx_hashes: Vec, + ) -> Result, ConnectorError>>, ConnectorError>; + + async fn get_tx_receipts( + &self, + tx_hashes: Vec, + ) -> Result>, ConnectorError>; + } + } + struct TestEventSubscription { new_heads_sender: Sender>, new_heads_notify: Notify, @@ -1410,18 +1448,15 @@ mod tests { } } - trait Behaviour: Send + Sync { - type Output; - - fn apply(&self, params: T) -> Self::Output; - } - - #[derive(Default)] - struct GetCcInitParamsBehaviour; - impl Behaviour<()> for GetCcInitParamsBehaviour { - type Output = eyre::Result; - - fn apply(&self, _params: ()) -> Self::Output { + #[tokio::test] + async fn test_activation_flow() { + enable_logs(); + let tmp_dir = tempfile::tempdir().expect("Could not create temp dir"); + let config = ChainListenerConfig::new(Duration::from_secs(1)); + let subscription = TestEventSubscription::new(); + let subscription = Arc::new(subscription); + let mut connector = MockChainConnectorStruct::new(); + connector.expect_get_cc_init_params().return_once(|| { Ok(CCInitParams { difficulty: Default::default(), init_timestamp: Default::default(), @@ -1434,95 +1469,16 @@ mod tests { min_proofs_per_epoch: Default::default(), max_proofs_per_epoch: Default::default(), }) - } - } - - struct TestChainConnector { - get_cc_init_params_behaviour: - RwLock>>>, - } - - impl TestChainConnector { - pub fn new() -> Self { - Self { - get_cc_init_params_behaviour: RwLock::new(Box::new(GetCcInitParamsBehaviour)), - } - } - - pub fn set_get_cc_init_params_behaviour( - &self, - behaviour: impl Behaviour<(), Output = eyre::Result> + 'static, - ) { - let mut lock = self.get_cc_init_params_behaviour.write(); - *lock = Box::new(behaviour); - } - } - - #[async_trait] - impl ChainConnector for TestChainConnector { - async fn get_current_commitment_id(&self) -> Result, ConnectorError> { - Ok(None) - } - - async fn get_cc_init_params(&self) -> eyre::Result { - self.get_cc_init_params_behaviour.read().apply(()) - } - - async fn get_compute_units(&self) -> Result, ConnectorError> { + }); + connector.expect_get_compute_units().return_once(||{ let bytes = hex::decode("aa3046a12a1aac6e840625e6329d70b427328fec36dc8d273e5e6454b85633d5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e8") .unwrap(); Ok(vec![ComputeUnit::abi_decode(&bytes, true).unwrap()]) - } - - async fn get_commitment_status( - &self, - _commitment_id: CommitmentId, - ) -> Result { - todo!() - } - - async fn get_global_nonce(&self) -> Result { - todo!() - } - - async fn submit_proof(&self, _proof: CCProof) -> Result { - todo!() - } - - async fn get_deal_statuses( - &self, - _deal_ids: Vec, - ) -> Result>, ConnectorError> { - todo!() - } - - async fn exit_deal(&self, _cu_id: &CUID) -> Result { - todo!() - } + }); + connector + .expect_get_current_commitment_id() + .return_once(|| Ok(None)); - async fn get_tx_statuses( - &self, - _tx_hashes: Vec, - ) -> Result, ConnectorError>>, ConnectorError> { - todo!() - } - - async fn get_tx_receipts( - &self, - _tx_hashes: Vec, - ) -> Result>, ConnectorError> { - todo!() - } - } - - #[tokio::test] - async fn test_activation_flow() { - enable_logs(); - let tmp_dir = tempfile::tempdir().expect("Could not create temp dir"); - let config = ChainListenerConfig::new(Duration::from_secs(1)); - let subscription = TestEventSubscription::new(); - let subscription = Arc::new(subscription); - let connector = TestChainConnector::new(); let connector = Arc::new(connector); let core_manager = CoreManager::Dummy(DummyCoreManager::default()); let core_manager = Arc::new(core_manager); @@ -1542,8 +1498,6 @@ mod tests { let _a = listener.start(); - connector.set_get_cc_init_params_behaviour(GetCcInitParamsBehaviour); - subscription.wait_subscriptions().await; let _ = subscription.send_new_heads(Ok(json!("test"))).unwrap(); From a02a14c008401a764699d0755d7f77a46b9a4f0b Mon Sep 17 00:00:00 2001 From: Nick Pavlov Date: Mon, 22 Apr 2024 16:38:10 +0300 Subject: [PATCH 10/44] switch to mockall --- crates/chain-listener/src/listener.rs | 138 +++++++--------------- crates/chain-listener/src/subscription.rs | 12 +- 2 files changed, 48 insertions(+), 102 deletions(-) diff --git a/crates/chain-listener/src/listener.rs b/crates/chain-listener/src/listener.rs index ab98c0fade..cced54cf1d 100644 --- a/crates/chain-listener/src/listener.rs +++ b/crates/chain-listener/src/listener.rs @@ -1290,7 +1290,8 @@ where #[cfg(test)] mod tests { - use crate::subscription::{Error, EventSubscription, Stream}; + use crate::subscription::StreamResult; + use crate::subscription::{Error, EventSubscription}; use crate::{ChainListener, ChainListenerConfig}; use alloy_sol_types::SolType; use ccp_shared::proof::CCProof; @@ -1303,12 +1304,9 @@ mod tests { use jsonrpsee::core::{async_trait, JsonValue}; use log_utils::enable_logs; use mockall::mock; - use serde_json::{json, Value}; + use serde_json::Value; use std::sync::Arc; use std::time::Duration; - use tokio::sync::broadcast::error::SendError; - use tokio::sync::broadcast::Sender; - use tokio::sync::Notify; use tokio_stream::wrappers::BroadcastStream; use types::DealId; @@ -1351,100 +1349,24 @@ mod tests { } } - struct TestEventSubscription { - new_heads_sender: Sender>, - new_heads_notify: Notify, - commitment_activated_sender: Sender>, - commitment_activated_notify: Notify, - commitment_deactivated_sender: Sender>, - unit_matched_sender: Sender>, - unit_matched_notify: Notify, - unit_activated_sender: Sender>, - } + mock! { + EventSubscriptionConnectorStruct {} - impl TestEventSubscription { - pub fn new() -> Self { - let (new_heads_sender, _rx) = tokio::sync::broadcast::channel(16); - let (commitment_activated_sender, _rx) = tokio::sync::broadcast::channel(16); - let (commitment_deactivated_sender, _rx) = tokio::sync::broadcast::channel(16); - let (unit_matched_sender, _rx) = tokio::sync::broadcast::channel(16); - let (unit_activated_sender, _rx) = tokio::sync::broadcast::channel(16); - let new_heads_notify = Notify::new(); - let unit_matched_notify = Notify::new(); - let commitment_activated_notify = Notify::new(); - Self { - new_heads_sender, - new_heads_notify, - commitment_activated_sender, - commitment_deactivated_sender, - unit_matched_sender, - unit_matched_notify, - unit_activated_sender, - commitment_activated_notify, - } - } + #[async_trait] + impl EventSubscription for EventSubscriptionConnectorStruct { + async fn unit_activated(&self, commitment_id: &CommitmentId) -> StreamResult; - pub fn send_new_heads( - &self, - value: Result, - ) -> Result>> { - self.new_heads_sender.send(value) - } + async fn unit_deactivated(&self, commitment_id: &CommitmentId) -> StreamResult; - pub async fn wait_subscriptions(&self) { - self.new_heads_notify.notified().await; - self.unit_matched_notify.notified().await; - self.commitment_activated_notify.notified().await; - } - } + async fn new_heads(&self) -> StreamResult; - #[async_trait] - impl EventSubscription for TestEventSubscription { - async fn unit_activated( - &self, - _commitment_id: &CommitmentId, - ) -> Result, Error> { - let rx = self.unit_activated_sender.subscribe(); - let stream = BroadcastStream::new(rx); - Ok(Box::pin(stream.map(|item| item.unwrap()))) - } + async fn commitment_activated(&self) -> StreamResult; - async fn unit_deactivated( - &self, - _commitment_id: &CommitmentId, - ) -> Result, Error> { - let rx = self.commitment_deactivated_sender.subscribe(); - let stream = BroadcastStream::new(rx); - Ok(Box::pin(stream.map(|item| item.unwrap()))) - } + async fn unit_matched(&self) -> StreamResult; - async fn new_heads(&self) -> Result, Error> { - let rx = self.new_heads_sender.subscribe(); - let stream = BroadcastStream::new(rx); - self.new_heads_notify.notify_one(); - Ok(Box::pin(stream.map(|item| item.unwrap()))) - } + async fn refresh(&self) -> Result<(), Error>; - async fn commitment_activated(&self) -> Result, Error> { - let rx = self.commitment_activated_sender.subscribe(); - let stream = BroadcastStream::new(rx); - self.commitment_activated_notify.notify_one(); - Ok(Box::pin(stream.map(|item| item.unwrap()))) - } - - async fn unit_matched(&self) -> Result, Error> { - let rx = self.unit_matched_sender.subscribe(); - let stream = BroadcastStream::new(rx); - self.unit_matched_notify.notify_one(); - Ok(Box::pin(stream.map(|item| item.unwrap()))) - } - - async fn refresh(&self) -> Result<(), Error> { - Ok(()) - } - - async fn restart(&self) -> Result<(), Error> { - Ok(()) + async fn restart(&self) -> Result<(), Error>; } } @@ -1453,8 +1375,31 @@ mod tests { enable_logs(); let tmp_dir = tempfile::tempdir().expect("Could not create temp dir"); let config = ChainListenerConfig::new(Duration::from_secs(1)); - let subscription = TestEventSubscription::new(); - let subscription = Arc::new(subscription); + let mut subscription = MockEventSubscriptionConnectorStruct::new(); + let (new_heads_sender, _rx) = tokio::sync::broadcast::channel(16); + let (commitment_activated_sender, _rx) = tokio::sync::broadcast::channel(16); + let (unit_matched_sender, _rx) = tokio::sync::broadcast::channel(16); + + subscription.expect_new_heads().return_once(move || { + let rx = new_heads_sender.subscribe(); + let stream = BroadcastStream::new(rx); + Ok(Box::pin(stream.map(|item| item.unwrap()))) + }); + + subscription + .expect_commitment_activated() + .return_once(move || { + let rx = commitment_activated_sender.subscribe(); + let stream = BroadcastStream::new(rx); + Ok(Box::pin(stream.map(|item| item.unwrap()))) + }); + + subscription.expect_unit_matched().return_once(move || { + let rx = unit_matched_sender.subscribe(); + let stream = BroadcastStream::new(rx); + Ok(Box::pin(stream.map(|item| item.unwrap()))) + }); + let mut connector = MockChainConnectorStruct::new(); connector.expect_get_cc_init_params().return_once(|| { Ok(CCInitParams { @@ -1480,6 +1425,7 @@ mod tests { .return_once(|| Ok(None)); let connector = Arc::new(connector); + let subscription = Arc::new(subscription); let core_manager = CoreManager::Dummy(DummyCoreManager::default()); let core_manager = Arc::new(core_manager); @@ -1498,8 +1444,8 @@ mod tests { let _a = listener.start(); - subscription.wait_subscriptions().await; - let _ = subscription.send_new_heads(Ok(json!("test"))).unwrap(); + // subscription.wait_subscriptions().await; + // let _ = subscription.send_new_heads(Ok(json!("test"))).unwrap(); tokio::time::sleep(Duration::from_secs(10)).await; } diff --git a/crates/chain-listener/src/subscription.rs b/crates/chain-listener/src/subscription.rs index b16544a321..e9ad838f22 100644 --- a/crates/chain-listener/src/subscription.rs +++ b/crates/chain-listener/src/subscription.rs @@ -42,15 +42,15 @@ impl From for Error { pub type Stream = Pin> + Send + Sync + 'static>>; -pub type SubResult = Result, Error>; +pub type StreamResult = Result, Error>; #[async_trait] pub trait EventSubscription: Send + Sync { - async fn unit_activated(&self, commitment_id: &CommitmentId) -> SubResult; - async fn unit_deactivated(&self, commitment_id: &CommitmentId) -> SubResult; - async fn new_heads(&self) -> SubResult; - async fn commitment_activated(&self) -> SubResult; - async fn unit_matched(&self) -> SubResult; + async fn unit_activated(&self, commitment_id: &CommitmentId) -> StreamResult; + async fn unit_deactivated(&self, commitment_id: &CommitmentId) -> StreamResult; + async fn new_heads(&self) -> StreamResult; + async fn commitment_activated(&self) -> StreamResult; + async fn unit_matched(&self) -> StreamResult; // TODO: remove both methods and encapsulate logic async fn refresh(&self) -> Result<(), Error>; From 0948988632846ed4358a85a05334237c14e9a2b0 Mon Sep 17 00:00:00 2001 From: Nick Pavlov Date: Mon, 22 Apr 2024 17:07:23 +0300 Subject: [PATCH 11/44] switch to mockall --- crates/chain-listener/src/listener.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/chain-listener/src/listener.rs b/crates/chain-listener/src/listener.rs index cced54cf1d..697b61076c 100644 --- a/crates/chain-listener/src/listener.rs +++ b/crates/chain-listener/src/listener.rs @@ -1380,7 +1380,7 @@ mod tests { let (commitment_activated_sender, _rx) = tokio::sync::broadcast::channel(16); let (unit_matched_sender, _rx) = tokio::sync::broadcast::channel(16); - subscription.expect_new_heads().return_once(move || { + subscription.expect_new_heads().returning(move || { let rx = new_heads_sender.subscribe(); let stream = BroadcastStream::new(rx); Ok(Box::pin(stream.map(|item| item.unwrap()))) @@ -1388,20 +1388,20 @@ mod tests { subscription .expect_commitment_activated() - .return_once(move || { + .returning(move || { let rx = commitment_activated_sender.subscribe(); let stream = BroadcastStream::new(rx); Ok(Box::pin(stream.map(|item| item.unwrap()))) }); - subscription.expect_unit_matched().return_once(move || { + subscription.expect_unit_matched().returning(move || { let rx = unit_matched_sender.subscribe(); let stream = BroadcastStream::new(rx); Ok(Box::pin(stream.map(|item| item.unwrap()))) }); let mut connector = MockChainConnectorStruct::new(); - connector.expect_get_cc_init_params().return_once(|| { + connector.expect_get_cc_init_params().returning(|| { Ok(CCInitParams { difficulty: Default::default(), init_timestamp: Default::default(), @@ -1415,14 +1415,14 @@ mod tests { max_proofs_per_epoch: Default::default(), }) }); - connector.expect_get_compute_units().return_once(||{ + connector.expect_get_compute_units().returning(||{ let bytes = hex::decode("aa3046a12a1aac6e840625e6329d70b427328fec36dc8d273e5e6454b85633d5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e8") .unwrap(); Ok(vec![ComputeUnit::abi_decode(&bytes, true).unwrap()]) }); connector .expect_get_current_commitment_id() - .return_once(|| Ok(None)); + .returning(|| Ok(None)); let connector = Arc::new(connector); let subscription = Arc::new(subscription); From 50c8133175444e0bd54fc5b689e9188a11c98ebb Mon Sep 17 00:00:00 2001 From: Nick Pavlov Date: Mon, 22 Apr 2024 19:29:15 +0300 Subject: [PATCH 12/44] switch to mockall --- crates/chain-listener/src/listener.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/crates/chain-listener/src/listener.rs b/crates/chain-listener/src/listener.rs index 697b61076c..3927ea9cd5 100644 --- a/crates/chain-listener/src/listener.rs +++ b/crates/chain-listener/src/listener.rs @@ -1307,6 +1307,7 @@ mod tests { use serde_json::Value; use std::sync::Arc; use std::time::Duration; + use tokio::sync::Notify; use tokio_stream::wrappers::BroadcastStream; use types::DealId; @@ -1379,6 +1380,7 @@ mod tests { let (new_heads_sender, _rx) = tokio::sync::broadcast::channel(16); let (commitment_activated_sender, _rx) = tokio::sync::broadcast::channel(16); let (unit_matched_sender, _rx) = tokio::sync::broadcast::channel(16); + let notifier = Arc::new(Notify::new()); subscription.expect_new_heads().returning(move || { let rx = new_heads_sender.subscribe(); @@ -1394,9 +1396,11 @@ mod tests { Ok(Box::pin(stream.map(|item| item.unwrap()))) }); + let unit_matched_notifier = notifier.clone(); subscription.expect_unit_matched().returning(move || { let rx = unit_matched_sender.subscribe(); let stream = BroadcastStream::new(rx); + unit_matched_notifier.notify_one(); // we now that this call is last Ok(Box::pin(stream.map(|item| item.unwrap()))) }); @@ -1442,11 +1446,9 @@ mod tests { None, ); - let _a = listener.start(); + let _handle = listener.start(); + notifier.notified().await; //wait subscriptions start before sending messages - // subscription.wait_subscriptions().await; - // let _ = subscription.send_new_heads(Ok(json!("test"))).unwrap(); - - tokio::time::sleep(Duration::from_secs(10)).await; + //let _ = subscription.send_new_heads(Ok(json!("test"))).unwrap(); } } From 87ff15e3a127b5bc56a8ef2df5cd7582023b5072 Mon Sep 17 00:00:00 2001 From: Nick Pavlov Date: Mon, 22 Apr 2024 23:13:01 +0300 Subject: [PATCH 13/44] test --- crates/chain-listener/src/listener.rs | 87 ++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 14 deletions(-) diff --git a/crates/chain-listener/src/listener.rs b/crates/chain-listener/src/listener.rs index 3927ea9cd5..1abcfe17e1 100644 --- a/crates/chain-listener/src/listener.rs +++ b/crates/chain-listener/src/listener.rs @@ -1290,21 +1290,25 @@ where #[cfg(test)] mod tests { + use crate::event::cc_activated::CommitmentActivated; use crate::subscription::StreamResult; use crate::subscription::{Error, EventSubscription}; use crate::{ChainListener, ChainListenerConfig}; - use alloy_sol_types::SolType; + use alloy_sol_types::{SolEvent, SolType}; use ccp_shared::proof::CCProof; - use ccp_shared::types::{GlobalNonce, CUID}; + use ccp_shared::types::{Difficulty, GlobalNonce, CUID}; use chain_connector::Offer::ComputeUnit; use chain_connector::{CCInitParams, CCStatus, ChainConnector, CommitmentId, ConnectorError}; + use chain_data::{Log}; use core_manager::{CoreManager, DummyCoreManager}; use futures::StreamExt; use hex::FromHex; use jsonrpsee::core::{async_trait, JsonValue}; + use libp2p_identity::PeerId; use log_utils::enable_logs; use mockall::mock; use serde_json::Value; + use std::str::FromStr; use std::sync::Arc; use std::time::Duration; use tokio::sync::Notify; @@ -1380,18 +1384,27 @@ mod tests { let (new_heads_sender, _rx) = tokio::sync::broadcast::channel(16); let (commitment_activated_sender, _rx) = tokio::sync::broadcast::channel(16); let (unit_matched_sender, _rx) = tokio::sync::broadcast::channel(16); + let (unit_activated_sender, _rx) = tokio::sync::broadcast::channel(16); + let (unit_deactivated_sender, _rx) = tokio::sync::broadcast::channel(16); let notifier = Arc::new(Notify::new()); + let unit_id: [u8; 32] = + hex::decode("aa3046a12a1aac6e840625e6329d70b427328fec36dc8d273e5e6454b85633d5") + .unwrap() + .try_into() + .unwrap(); + subscription.expect_new_heads().returning(move || { let rx = new_heads_sender.subscribe(); let stream = BroadcastStream::new(rx); Ok(Box::pin(stream.map(|item| item.unwrap()))) }); + let sender = commitment_activated_sender.clone(); subscription .expect_commitment_activated() .returning(move || { - let rx = commitment_activated_sender.subscribe(); + let rx = sender.subscribe(); let stream = BroadcastStream::new(rx); Ok(Box::pin(stream.map(|item| item.unwrap()))) }); @@ -1404,29 +1417,51 @@ mod tests { Ok(Box::pin(stream.map(|item| item.unwrap()))) }); + subscription.expect_unit_activated().returning(move |_| { + let rx = unit_activated_sender.subscribe(); + let stream = BroadcastStream::new(rx); + Ok(Box::pin(stream.map(|item| item.unwrap()))) + }); + + subscription.expect_unit_deactivated().returning(move |_| { + let rx = unit_deactivated_sender.subscribe(); + let stream = BroadcastStream::new(rx); + Ok(Box::pin(stream.map(|item| item.unwrap()))) + }); + let mut connector = MockChainConnectorStruct::new(); connector.expect_get_cc_init_params().returning(|| { + let global_nonce = GlobalNonce::from_hex( + "4183468390b09d71644232a1d1ce670bc93897183d3f56c305fabfb16cab806a", + ) + .unwrap(); + let difficulty = Difficulty::from_hex( + "0001afffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + ) + .unwrap(); + Ok(CCInitParams { - difficulty: Default::default(), + difficulty, init_timestamp: Default::default(), - global_nonce: GlobalNonce::from_hex( - "54ae1b506c260367a054f80800a545f23e32c6bc4a8908c9a794cb8dad23e5ea", - ) - .unwrap(), + global_nonce, current_epoch: Default::default(), epoch_duration: Default::default(), min_proofs_per_epoch: Default::default(), max_proofs_per_epoch: Default::default(), }) }); - connector.expect_get_compute_units().returning(||{ - let bytes = hex::decode("aa3046a12a1aac6e840625e6329d70b427328fec36dc8d273e5e6454b85633d5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e8") - .unwrap(); - Ok(vec![ComputeUnit::abi_decode(&bytes, true).unwrap()]) - }); + + connector + .expect_get_compute_units() + .returning(move || { + let data= hex::decode("aa3046a12a1aac6e840625e6329d70b427328fec36dc8d273e5e6454b85633d5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e8").unwrap(); + Ok(vec![ComputeUnit::abi_decode(&data, true).unwrap()]) + }); connector .expect_get_current_commitment_id() .returning(|| Ok(None)); + connector.expect_submit_proof().returning(|_| Ok("tx-1".to_string())); + connector.expect_get_tx_statuses().returning(|_| Ok(vec![Ok(Some(true))])); let connector = Arc::new(connector); let subscription = Arc::new(subscription); @@ -1449,6 +1484,30 @@ mod tests { let _handle = listener.start(); notifier.notified().await; //wait subscriptions start before sending messages - //let _ = subscription.send_new_heads(Ok(json!("test"))).unwrap(); + let data = CommitmentActivated { + peerId: [0; 32].into(), + commitmentId: [0; 32].into(), + startEpoch: alloy_primitives::U256::from(0), + endEpoch: alloy_primitives::U256::from(10), + unitIds: vec![unit_id.into()], + }; + + let _ = commitment_activated_sender + .send(Ok(serde_json::to_value(Log { + data: hex::encode(data.encode_data()), + block_number: "100".to_string(), + removed: false, + topics: vec![ + CommitmentActivated::SIGNATURE_HASH.to_string(), + "0xc586dcbfc973643dc5f885bf1a38e054d2675b03fe283a5b7337d70dda9f7171" + .to_string(), + "0x27e42c090aa007a4f2545547425aaa8ea3566e1f18560803ac48f8e98cb3b0c9" + .to_string(), + ], + }) + .unwrap())) + .unwrap(); + + tokio::time::sleep(Duration::from_secs(10)).await; } } From 7a60b2fd8b48f41ac575af29cfadd572e41b4760 Mon Sep 17 00:00:00 2001 From: Nick Pavlov Date: Wed, 24 Apr 2024 16:42:39 +0300 Subject: [PATCH 14/44] wip --- crates/chain-connector/src/connector.rs | 6 +- crates/chain-listener/src/listener.rs | 185 +++++++++++++++++++----- crates/core-manager/src/dummy.rs | 96 +++++++++++- 3 files changed, 239 insertions(+), 48 deletions(-) diff --git a/crates/chain-connector/src/connector.rs b/crates/chain-connector/src/connector.rs index d68687f16a..10917edd8f 100644 --- a/crates/chain-connector/src/connector.rs +++ b/crates/chain-connector/src/connector.rs @@ -84,7 +84,7 @@ pub struct CCInitParams { pub init_timestamp: U256, pub global_nonce: GlobalNonce, pub current_epoch: U256, - pub epoch_duration: U256, + pub epoch_duration_sec: U256, pub min_proofs_per_epoch: U256, pub max_proofs_per_epoch: U256, } @@ -400,7 +400,7 @@ impl ChainConnector for HttpChainConnector { init_timestamp, global_nonce: GlobalNonce::new(global_nonce.0), current_epoch, - epoch_duration, + epoch_duration_sec: epoch_duration, min_proofs_per_epoch, max_proofs_per_epoch, }) @@ -805,7 +805,7 @@ mod tests { U256::from(0x00000000000000000000000000000000000000000000000000000000000016be) ); assert_eq!( - init_params.epoch_duration, + init_params.epoch_duration_sec, U256::from(0x000000000000000000000000000000000000000000000000000000000000000f) ); assert_eq!(init_params.min_proofs_per_epoch, U256::from(5)); diff --git a/crates/chain-listener/src/listener.rs b/crates/chain-listener/src/listener.rs index 1abcfe17e1..61ed189c8a 100644 --- a/crates/chain-listener/src/listener.rs +++ b/crates/chain-listener/src/listener.rs @@ -697,6 +697,7 @@ impl ChainListener { &mut self, event: Option>, ) -> eyre::Result<()> { + tracing::info!("zalupa {:?}", event); let event = event.ok_or(eyre!("Failed to process DealMatched event: got None"))??; let log = serde_json::from_value::(event.clone()).map_err(|err| { tracing::error!(target: "chain-listener", "Failed to parse DealMatched event: {err}, data: {event}"); @@ -1293,22 +1294,24 @@ mod tests { use crate::event::cc_activated::CommitmentActivated; use crate::subscription::StreamResult; use crate::subscription::{Error, EventSubscription}; - use crate::{ChainListener, ChainListenerConfig}; + use crate::{CCPClient, ChainListener, ChainListenerConfig}; use alloy_sol_types::{SolEvent, SolType}; + use ccp_rpc_client::ClientError; use ccp_shared::proof::CCProof; + use ccp_shared::proof::ProofIdx; use ccp_shared::types::{Difficulty, GlobalNonce, CUID}; + use ccp_shared::types::{LogicalCoreId, PhysicalCoreId}; use chain_connector::Offer::ComputeUnit; use chain_connector::{CCInitParams, CCStatus, ChainConnector, CommitmentId, ConnectorError}; - use chain_data::{Log}; + use chain_data::Log; use core_manager::{CoreManager, DummyCoreManager}; use futures::StreamExt; use hex::FromHex; use jsonrpsee::core::{async_trait, JsonValue}; - use libp2p_identity::PeerId; use log_utils::enable_logs; use mockall::mock; - use serde_json::Value; - use std::str::FromStr; + use serde_json::{json, Value}; + use std::collections::HashMap; use std::sync::Arc; use std::time::Duration; use tokio::sync::Notify; @@ -1375,6 +1378,32 @@ mod tests { } } + mock! { + CCPClientStruct {} + + #[async_trait] + impl CCPClient for CCPClientStruct { + async fn on_no_active_commitment(&self) -> Result<(), ClientError>; + async fn realloc_utility_cores( + &self, + utility_core_ids: Vec, + ) -> Result<(), ClientError>; + + async fn on_active_commitment( + &self, + global_nonce: GlobalNonce, + difficulty: Difficulty, + cu_allocation: HashMap, + ) -> Result<(), ClientError>; + + async fn get_proofs_after( + &self, + proof_idx: ProofIdx, + limit: usize, + ) -> Result, ClientError>; + } + } + #[tokio::test] async fn test_activation_flow() { enable_logs(); @@ -1388,14 +1417,40 @@ mod tests { let (unit_deactivated_sender, _rx) = tokio::sync::broadcast::channel(16); let notifier = Arc::new(Notify::new()); - let unit_id: [u8; 32] = - hex::decode("aa3046a12a1aac6e840625e6329d70b427328fec36dc8d273e5e6454b85633d5") - .unwrap() - .try_into() + let (test_result_sender, mut test_result_receiver) = + tokio::sync::mpsc::channel::<(GlobalNonce, Difficulty, HashMap)>( + 16, + ); + + let global_nonce = GlobalNonce::from_hex( + "4183468390b09d71644232a1d1ce670bc93897183d3f56c305fabfb16cab806a", + ) + .unwrap(); + let difficulty = Difficulty::from_hex( + "0001afffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + ) + .unwrap(); + + let unit_id_1: CUID = + CUID::from_hex("aa3046a12a1aac6e840625e6329d70b427328fec36dc8d273e5e6454b85633d5") + .unwrap(); + + let unit_id_2: CUID = + CUID::from_hex("bb3046a12a1aac6e840625e6329d70b427328fec36dc8d273e5e6454b85633d5") .unwrap(); + let unit_id_3: CUID = + CUID::from_hex("cc3046a12a1aac6e840625e6329d70b427328fec36dc8d273e5e6454b85633d5") + .unwrap(); + + let unit_id_4: CUID = + CUID::from_hex("dd3046a12a1aac6e840625e6329d70b427328fec36dc8d273e5e6454b85633d5") + .unwrap(); + + let sender = new_heads_sender.clone(); + subscription.expect_new_heads().returning(move || { - let rx = new_heads_sender.subscribe(); + let rx = sender.subscribe(); let stream = BroadcastStream::new(rx); Ok(Box::pin(stream.map(|item| item.unwrap()))) }); @@ -1403,7 +1458,7 @@ mod tests { let sender = commitment_activated_sender.clone(); subscription .expect_commitment_activated() - .returning(move || { + .return_once(move || { let rx = sender.subscribe(); let stream = BroadcastStream::new(rx); Ok(Box::pin(stream.map(|item| item.unwrap()))) @@ -1430,24 +1485,24 @@ mod tests { }); let mut connector = MockChainConnectorStruct::new(); - connector.expect_get_cc_init_params().returning(|| { - let global_nonce = GlobalNonce::from_hex( + connector.expect_get_global_nonce().return_once(|| { + Ok(GlobalNonce::from_hex( "4183468390b09d71644232a1d1ce670bc93897183d3f56c305fabfb16cab806a", ) - .unwrap(); - let difficulty = Difficulty::from_hex( - "0001afffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - ) - .unwrap(); + .unwrap()) + }); + let cc_init_difficulty = difficulty.clone(); + let cc_init_global_nonce = global_nonce.clone(); + connector.expect_get_cc_init_params().returning(move || { Ok(CCInitParams { - difficulty, - init_timestamp: Default::default(), - global_nonce, - current_epoch: Default::default(), - epoch_duration: Default::default(), - min_proofs_per_epoch: Default::default(), - max_proofs_per_epoch: Default::default(), + difficulty: cc_init_difficulty, + init_timestamp: alloy_primitives::U256::from(0), + global_nonce: cc_init_global_nonce, + current_epoch: alloy_primitives::U256::from(0), + epoch_duration_sec: alloy_primitives::U256::from(100), + min_proofs_per_epoch: alloy_primitives::U256::from(1), + max_proofs_per_epoch: alloy_primitives::U256::from(3), }) }); @@ -1460,23 +1515,45 @@ mod tests { connector .expect_get_current_commitment_id() .returning(|| Ok(None)); - connector.expect_submit_proof().returning(|_| Ok("tx-1".to_string())); - connector.expect_get_tx_statuses().returning(|_| Ok(vec![Ok(Some(true))])); - let connector = Arc::new(connector); - let subscription = Arc::new(subscription); + let mut ccp_client = MockCCPClientStruct::new(); + ccp_client + .expect_realloc_utility_cores() + .returning(|_| Ok(())); + + ccp_client + .expect_on_no_active_commitment() + .returning(|| Ok(())); + + ccp_client.expect_on_active_commitment().returning( + move |global_nonce, difficulty, cu_allocation| { + test_result_sender + .try_send((global_nonce, difficulty, cu_allocation)) + .unwrap(); + Ok(()) + }, + ); + + ccp_client + .expect_get_proofs_after() + .returning(|_, _| Ok(vec![])); + let core_manager = CoreManager::Dummy(DummyCoreManager::default()); - let core_manager = Arc::new(core_manager); + + let connector = Arc::new(connector); + let subscription_arc = Arc::new(subscription); + let core_manager_arc = Arc::new(core_manager); + let ccp_client_arc = Arc::new(ccp_client); let proofs_dir = tmp_dir.path().join("proofs").to_path_buf(); tokio::fs::create_dir_all(proofs_dir.clone()).await.unwrap(); let listener = ChainListener::new( config, - subscription.clone(), + subscription_arc.clone(), connector.clone(), - core_manager, - None, + core_manager_arc, + Some(ccp_client_arc), proofs_dir, None, ); @@ -1487,15 +1564,20 @@ mod tests { let data = CommitmentActivated { peerId: [0; 32].into(), commitmentId: [0; 32].into(), - startEpoch: alloy_primitives::U256::from(0), + startEpoch: alloy_primitives::U256::from(1), endEpoch: alloy_primitives::U256::from(10), - unitIds: vec![unit_id.into()], + unitIds: vec![ + unit_id_1.as_ref().into(), + unit_id_2.as_ref().into(), + unit_id_3.as_ref().into(), + unit_id_4.as_ref().into(), + ], }; let _ = commitment_activated_sender .send(Ok(serde_json::to_value(Log { data: hex::encode(data.encode_data()), - block_number: "100".to_string(), + block_number: "1".to_string(), removed: false, topics: vec![ CommitmentActivated::SIGNATURE_HASH.to_string(), @@ -1508,6 +1590,35 @@ mod tests { .unwrap())) .unwrap(); - tokio::time::sleep(Duration::from_secs(10)).await; + let _ = new_heads_sender + .send(Ok(json!({ + "timestamp": "101", + "number": "0x2", + }))) + .unwrap(); + + if let Some((result_global_nonce, result_difficulty, result_cores)) = + test_result_receiver.recv().await + { + assert_eq!(result_global_nonce, global_nonce); + assert_eq!(result_difficulty, difficulty); + assert_eq!(result_cores.len(), 4); + assert_eq!( + result_cores.get(&PhysicalCoreId::from(0)).cloned(), + Some(unit_id_1) + ); + assert_eq!( + result_cores.get(&PhysicalCoreId::from(1)).cloned(), + Some(unit_id_2) + ); + assert_eq!( + result_cores.get(&PhysicalCoreId::from(2)).cloned(), + Some(unit_id_3) + ); + assert_eq!( + result_cores.get(&PhysicalCoreId::from(3)).cloned(), + Some(unit_id_4) + ); + } } } diff --git a/crates/core-manager/src/dummy.rs b/crates/core-manager/src/dummy.rs index 594f4ff877..8d9e9bfa56 100644 --- a/crates/core-manager/src/dummy.rs +++ b/crates/core-manager/src/dummy.rs @@ -1,18 +1,98 @@ -use crate::errors::AcquireError; -use crate::manager::CoreManagerFunctions; -use crate::types::{AcquireRequest, Assignment}; -use crate::Map; +use std::collections::{BTreeSet, VecDeque}; + use async_trait::async_trait; use ccp_shared::types::{LogicalCoreId, PhysicalCoreId, CUID}; use fxhash::FxBuildHasher; -use rand::prelude::IteratorRandom; -use std::collections::BTreeSet; +use parking_lot::RwLock; + +use crate::errors::{AcquireError, CurrentAssignment}; +use crate::manager::CoreManagerFunctions; +use crate::types::{AcquireRequest, Assignment, Cores}; +use crate::Map; #[derive(Default)] -pub struct DummyCoreManager {} +pub struct DummyCoreManager { + state: RwLock, +} + +struct State { + available: VecDeque, + used: Map, +} + +impl Default for State { + fn default() -> Self { + let topology: Vec = (0..16) + .map(|index| { + let physical_core_id = PhysicalCoreId::from(index); + let logical_core_ids = LogicalCoreId::from(index); + Cores { + physical_core_id, + logical_core_ids: vec![logical_core_ids], + } + }) + .collect(); + + Self { + available: topology.into_iter().collect(), + used: Map::with_hasher(FxBuildHasher::default()), + } + } +} impl DummyCoreManager { - fn all_cores(&self) -> Assignment { + pub fn new(topology: Vec) -> Self { + let state = State { + available: topology.into_iter().collect(), + used: Map::with_hasher(FxBuildHasher::default()), + }; + Self { + state: RwLock::new(state), + } + } +} + +#[async_trait] +impl CoreManagerFunctions for DummyCoreManager { + fn acquire_worker_core( + &self, + assign_request: AcquireRequest, + ) -> Result { + let mut state = self.state.write(); + let available = state.available.len(); + let required = assign_request.unit_ids.len(); + if required > available { + return Err(AcquireError::NotFoundAvailableCores { + required, + available, + current_assignment: CurrentAssignment::new(vec![]), + }); + } + + let mut physical_core_ids = BTreeSet::new(); + let mut logical_core_ids = BTreeSet::new(); + let mut cuid_cores = Map::with_hasher(FxBuildHasher::default()); + + for cuid in assign_request.unit_ids { + let core = state.available.pop_front().unwrap(); + physical_core_ids.insert(core.physical_core_id); + for logical_core_id in core.logical_core_ids.clone() { + logical_core_ids.insert(logical_core_id); + } + state.used.insert(cuid, core.clone()); + cuid_cores.insert(cuid, core); + } + + Ok(Assignment { + physical_core_ids, + logical_core_ids, + cuid_cores, + }) + } + + fn release(&self, _unit_ids: Vec) {} + + fn get_system_cpu_assignment(&self) -> Assignment { let physical_core_ids = (0..num_cpus::get_physical()) .map(|v| PhysicalCoreId::from(v as u32)) .collect(); From 84844e0400f136d30ca9fcd48826f22005bd414e Mon Sep 17 00:00:00 2001 From: Nick Pavlov Date: Wed, 24 Apr 2024 16:59:13 +0300 Subject: [PATCH 15/44] fix test --- crates/chain-listener/src/listener.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/crates/chain-listener/src/listener.rs b/crates/chain-listener/src/listener.rs index 61ed189c8a..17c07e7cb7 100644 --- a/crates/chain-listener/src/listener.rs +++ b/crates/chain-listener/src/listener.rs @@ -1509,8 +1509,15 @@ mod tests { connector .expect_get_compute_units() .returning(move || { - let data= hex::decode("aa3046a12a1aac6e840625e6329d70b427328fec36dc8d273e5e6454b85633d5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e8").unwrap(); - Ok(vec![ComputeUnit::abi_decode(&data, true).unwrap()]) + let data= hex::decode("aa3046a12a1aac6e840625e6329d70b427328fec36dc8d273e5e6454b85633d500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002").unwrap(); + let cu_1 = ComputeUnit::abi_decode(&data, true).unwrap(); + let data= hex::decode("bb3046a12a1aac6e840625e6329d70b427328fec36dc8d273e5e6454b85633d500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002").unwrap(); + let cu_2 = ComputeUnit::abi_decode(&data, true).unwrap(); + let data= hex::decode("cc3046a12a1aac6e840625e6329d70b427328fec36dc8d273e5e6454b85633d500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002").unwrap(); + let cu_3 = ComputeUnit::abi_decode(&data, true).unwrap(); + let data= hex::decode("dd3046a12a1aac6e840625e6329d70b427328fec36dc8d273e5e6454b85633d500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002").unwrap(); + let cu_4 = ComputeUnit::abi_decode(&data, true).unwrap(); + Ok(vec![cu_1, cu_2, cu_3,cu_4]) }); connector .expect_get_current_commitment_id() From a6aedbe71edd314c5c6309b371014ef059e4d2b0 Mon Sep 17 00:00:00 2001 From: Nick Pavlov Date: Wed, 24 Apr 2024 17:02:05 +0300 Subject: [PATCH 16/44] fix test --- crates/chain-listener/src/listener.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/chain-listener/src/listener.rs b/crates/chain-listener/src/listener.rs index 17c07e7cb7..7e36701fa3 100644 --- a/crates/chain-listener/src/listener.rs +++ b/crates/chain-listener/src/listener.rs @@ -1517,7 +1517,7 @@ mod tests { let cu_3 = ComputeUnit::abi_decode(&data, true).unwrap(); let data= hex::decode("dd3046a12a1aac6e840625e6329d70b427328fec36dc8d273e5e6454b85633d500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002").unwrap(); let cu_4 = ComputeUnit::abi_decode(&data, true).unwrap(); - Ok(vec![cu_1, cu_2, cu_3,cu_4]) + Ok(vec![cu_1, cu_2, cu_3, cu_4]) }); connector .expect_get_current_commitment_id() @@ -1571,7 +1571,7 @@ mod tests { let data = CommitmentActivated { peerId: [0; 32].into(), commitmentId: [0; 32].into(), - startEpoch: alloy_primitives::U256::from(1), + startEpoch: alloy_primitives::U256::from(2), endEpoch: alloy_primitives::U256::from(10), unitIds: vec![ unit_id_1.as_ref().into(), From 0776e1c3488832133b8dca658d5f02a109ce6ac4 Mon Sep 17 00:00:00 2001 From: Nick Pavlov Date: Wed, 24 Apr 2024 17:36:38 +0300 Subject: [PATCH 17/44] fix test --- crates/chain-listener/src/listener.rs | 230 +++++++++++++++++++++++++- 1 file changed, 229 insertions(+), 1 deletion(-) diff --git a/crates/chain-listener/src/listener.rs b/crates/chain-listener/src/listener.rs index 7e36701fa3..23189153e8 100644 --- a/crates/chain-listener/src/listener.rs +++ b/crates/chain-listener/src/listener.rs @@ -1304,6 +1304,7 @@ mod tests { use chain_connector::Offer::ComputeUnit; use chain_connector::{CCInitParams, CCStatus, ChainConnector, CommitmentId, ConnectorError}; use chain_data::Log; + use core_manager::types::Cores; use core_manager::{CoreManager, DummyCoreManager}; use futures::StreamExt; use hex::FromHex; @@ -1405,7 +1406,7 @@ mod tests { } #[tokio::test] - async fn test_activation_flow() { + async fn test_cc_activation_flow() { enable_logs(); let tmp_dir = tempfile::tempdir().expect("Could not create temp dir"); let config = ChainListenerConfig::new(Duration::from_secs(1)); @@ -1628,4 +1629,231 @@ mod tests { ); } } + + #[tokio::test] + async fn test_cc_overflow_activation_flow() { + enable_logs(); + let tmp_dir = tempfile::tempdir().expect("Could not create temp dir"); + let config = ChainListenerConfig::new(Duration::from_secs(1)); + let mut subscription = MockEventSubscriptionConnectorStruct::new(); + let (new_heads_sender, _rx) = tokio::sync::broadcast::channel(16); + let (commitment_activated_sender, _rx) = tokio::sync::broadcast::channel(16); + let (unit_matched_sender, _rx) = tokio::sync::broadcast::channel(16); + let (unit_activated_sender, _rx) = tokio::sync::broadcast::channel(16); + let (unit_deactivated_sender, _rx) = tokio::sync::broadcast::channel(16); + let notifier = Arc::new(Notify::new()); + + let (test_result_sender, mut test_result_receiver) = + tokio::sync::mpsc::channel::<(GlobalNonce, Difficulty, HashMap)>( + 16, + ); + + let global_nonce = GlobalNonce::from_hex( + "4183468390b09d71644232a1d1ce670bc93897183d3f56c305fabfb16cab806a", + ) + .unwrap(); + let difficulty = Difficulty::from_hex( + "0001afffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + ) + .unwrap(); + + let unit_id_1: CUID = + CUID::from_hex("aa3046a12a1aac6e840625e6329d70b427328fec36dc8d273e5e6454b85633d5") + .unwrap(); + + let unit_id_2: CUID = + CUID::from_hex("bb3046a12a1aac6e840625e6329d70b427328fec36dc8d273e5e6454b85633d5") + .unwrap(); + + let unit_id_3: CUID = + CUID::from_hex("cc3046a12a1aac6e840625e6329d70b427328fec36dc8d273e5e6454b85633d5") + .unwrap(); + + let unit_id_4: CUID = + CUID::from_hex("dd3046a12a1aac6e840625e6329d70b427328fec36dc8d273e5e6454b85633d5") + .unwrap(); + + let sender = new_heads_sender.clone(); + + subscription.expect_new_heads().returning(move || { + let rx = sender.subscribe(); + let stream = BroadcastStream::new(rx); + Ok(Box::pin(stream.map(|item| item.unwrap()))) + }); + + let sender = commitment_activated_sender.clone(); + subscription + .expect_commitment_activated() + .return_once(move || { + let rx = sender.subscribe(); + let stream = BroadcastStream::new(rx); + Ok(Box::pin(stream.map(|item| item.unwrap()))) + }); + + let unit_matched_notifier = notifier.clone(); + subscription.expect_unit_matched().returning(move || { + let rx = unit_matched_sender.subscribe(); + let stream = BroadcastStream::new(rx); + unit_matched_notifier.notify_one(); // we now that this call is last + Ok(Box::pin(stream.map(|item| item.unwrap()))) + }); + + subscription.expect_unit_activated().returning(move |_| { + let rx = unit_activated_sender.subscribe(); + let stream = BroadcastStream::new(rx); + Ok(Box::pin(stream.map(|item| item.unwrap()))) + }); + + subscription.expect_unit_deactivated().returning(move |_| { + let rx = unit_deactivated_sender.subscribe(); + let stream = BroadcastStream::new(rx); + Ok(Box::pin(stream.map(|item| item.unwrap()))) + }); + + let mut connector = MockChainConnectorStruct::new(); + connector.expect_get_global_nonce().return_once(|| { + Ok(GlobalNonce::from_hex( + "4183468390b09d71644232a1d1ce670bc93897183d3f56c305fabfb16cab806a", + ) + .unwrap()) + }); + + let cc_init_difficulty = difficulty.clone(); + let cc_init_global_nonce = global_nonce.clone(); + connector.expect_get_cc_init_params().returning(move || { + Ok(CCInitParams { + difficulty: cc_init_difficulty, + init_timestamp: alloy_primitives::U256::from(0), + global_nonce: cc_init_global_nonce, + current_epoch: alloy_primitives::U256::from(0), + epoch_duration_sec: alloy_primitives::U256::from(100), + min_proofs_per_epoch: alloy_primitives::U256::from(1), + max_proofs_per_epoch: alloy_primitives::U256::from(3), + }) + }); + + connector + .expect_get_compute_units() + .returning(move || { + let data= hex::decode("aa3046a12a1aac6e840625e6329d70b427328fec36dc8d273e5e6454b85633d500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002").unwrap(); + let cu_1 = ComputeUnit::abi_decode(&data, true).unwrap(); + let data= hex::decode("bb3046a12a1aac6e840625e6329d70b427328fec36dc8d273e5e6454b85633d500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002").unwrap(); + let cu_2 = ComputeUnit::abi_decode(&data, true).unwrap(); + let data= hex::decode("cc3046a12a1aac6e840625e6329d70b427328fec36dc8d273e5e6454b85633d500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002").unwrap(); + let cu_3 = ComputeUnit::abi_decode(&data, true).unwrap(); + let data= hex::decode("dd3046a12a1aac6e840625e6329d70b427328fec36dc8d273e5e6454b85633d500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002").unwrap(); + let cu_4 = ComputeUnit::abi_decode(&data, true).unwrap(); + Ok(vec![cu_1, cu_2, cu_3, cu_4]) + }); + connector + .expect_get_current_commitment_id() + .returning(|| Ok(None)); + + let mut ccp_client = MockCCPClientStruct::new(); + ccp_client + .expect_realloc_utility_cores() + .returning(|_| Ok(())); + + ccp_client + .expect_on_no_active_commitment() + .returning(|| Ok(())); + + ccp_client.expect_on_active_commitment().returning( + move |global_nonce, difficulty, cu_allocation| { + test_result_sender + .try_send((global_nonce, difficulty, cu_allocation)) + .unwrap(); + Ok(()) + }, + ); + + ccp_client + .expect_get_proofs_after() + .returning(|_, _| Ok(vec![])); + + let topology = vec![ + Cores { + physical_core_id: PhysicalCoreId::from(0), + logical_core_ids: vec![LogicalCoreId::from(0)], + }, + Cores { + physical_core_id: PhysicalCoreId::from(1), + logical_core_ids: vec![LogicalCoreId::from(1)], + }, + ]; + let core_manager = CoreManager::Dummy(DummyCoreManager::new(topology)); + + let connector = Arc::new(connector); + let subscription_arc = Arc::new(subscription); + let core_manager_arc = Arc::new(core_manager); + let ccp_client_arc = Arc::new(ccp_client); + + let proofs_dir = tmp_dir.path().join("proofs").to_path_buf(); + tokio::fs::create_dir_all(proofs_dir.clone()).await.unwrap(); + + let listener = ChainListener::new( + config, + subscription_arc.clone(), + connector.clone(), + core_manager_arc, + Some(ccp_client_arc), + proofs_dir, + None, + ); + + let _handle = listener.start(); + notifier.notified().await; //wait subscriptions start before sending messages + + let data = CommitmentActivated { + peerId: [0; 32].into(), + commitmentId: [0; 32].into(), + startEpoch: alloy_primitives::U256::from(2), + endEpoch: alloy_primitives::U256::from(10), + unitIds: vec![ + unit_id_1.as_ref().into(), + unit_id_2.as_ref().into(), + unit_id_3.as_ref().into(), + unit_id_4.as_ref().into(), + ], + }; + + let _ = commitment_activated_sender + .send(Ok(serde_json::to_value(Log { + data: hex::encode(data.encode_data()), + block_number: "1".to_string(), + removed: false, + topics: vec![ + CommitmentActivated::SIGNATURE_HASH.to_string(), + "0xc586dcbfc973643dc5f885bf1a38e054d2675b03fe283a5b7337d70dda9f7171" + .to_string(), + "0x27e42c090aa007a4f2545547425aaa8ea3566e1f18560803ac48f8e98cb3b0c9" + .to_string(), + ], + }) + .unwrap())) + .unwrap(); + + let _ = new_heads_sender + .send(Ok(json!({ + "timestamp": "101", + "number": "0x2", + }))) + .unwrap(); + + if let Some((result_global_nonce, result_difficulty, result_cores)) = + test_result_receiver.recv().await + { + assert_eq!(result_global_nonce, global_nonce); + assert_eq!(result_difficulty, difficulty); + assert_eq!(result_cores.len(), 2); + assert_eq!( + result_cores.get(&PhysicalCoreId::from(0)).cloned(), + Some(unit_id_1) + ); + assert_eq!( + result_cores.get(&PhysicalCoreId::from(1)).cloned(), + Some(unit_id_2) + ); + } + } } From c06c2e8d12d25fd9fec246e83a817a935715c0dd Mon Sep 17 00:00:00 2001 From: Nick Pavlov Date: Thu, 25 Apr 2024 11:48:54 +0300 Subject: [PATCH 18/44] fixes --- Cargo.toml | 6 +++--- crates/chain-connector/Cargo.toml | 1 - crates/chain-listener/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a6e742734b..3dd984a166 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -174,9 +174,9 @@ enum_dispatch = "0.3.12" serde_with = "3.7.0" mockito = "1.2.0" clarity = "1.3.0" -cpu-utils = { git = "https://github.com/fluencelabs/capacity-commitment-prover", branch = "main" } -ccp-shared = { git = "https://github.com/fluencelabs/capacity-commitment-prover", branch = "main" } -ccp-rpc-client = { git = "https://github.com/fluencelabs/capacity-commitment-prover", branch = "main" } +cpu-utils = "0.9.0" +ccp-shared = "0.9.0" +ccp-rpc-client = "0.9.0" alloy-sol-types = "0.6.4" alloy-primitives = "0.6.4" alloy_serde_macro = "0.1.2" diff --git a/crates/chain-connector/Cargo.toml b/crates/chain-connector/Cargo.toml index f7b17da68c..7922a8846b 100644 --- a/crates/chain-connector/Cargo.toml +++ b/crates/chain-connector/Cargo.toml @@ -15,7 +15,6 @@ eyre = { workspace = true } fluence-libp2p = { workspace = true } serde_json = { workspace = true } hex = { workspace = true } -server-config = { workspace = true } clarity = { workspace = true } tokio = { workspace = true, features = ["rt", "macros"] } hex-utils = { workspace = true } diff --git a/crates/chain-listener/Cargo.toml b/crates/chain-listener/Cargo.toml index 462e23a49c..b596637c57 100644 --- a/crates/chain-listener/Cargo.toml +++ b/crates/chain-listener/Cargo.toml @@ -46,4 +46,4 @@ tempfile = { workspace = true } tokio-stream = { workspace = true } log-utils = { workspace = true } parking_lot = { workspace = true } -mockall = "0.12.1" \ No newline at end of file +mockall = "0.12.1" From 6a70628464ddd11aa2943c8855336212ea533668 Mon Sep 17 00:00:00 2001 From: Nick Pavlov Date: Thu, 25 Apr 2024 17:51:32 +0300 Subject: [PATCH 19/44] config fix --- Cargo.lock | 16 +++++---- crates/chain-connector/src/connector.rs | 45 ++++++++++++++++++++++--- crates/chain-connector/src/lib.rs | 1 + nox/src/node.rs | 20 +++++++++-- 4 files changed, 69 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 76910a407f..72c404a65d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1251,8 +1251,9 @@ dependencies = [ [[package]] name = "ccp-rpc-client" -version = "0.8.0" -source = "git+https://github.com/fluencelabs/capacity-commitment-prover?branch=main#270a51de9ba388ae9fa43404d1aaa0790e241836" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2888e0529487437677d06c31dfc581bb8bea06d0fc007db0a8484307be9d7de5" dependencies = [ "ccp-shared", "hex", @@ -1262,8 +1263,9 @@ dependencies = [ [[package]] name = "ccp-shared" -version = "0.8.0" -source = "git+https://github.com/fluencelabs/capacity-commitment-prover?branch=main#270a51de9ba388ae9fa43404d1aaa0790e241836" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ccecad3bb44270ec5497788954232de0c55564ceadc2eca4f0a45da0b3a77e2" dependencies = [ "hex", "newtype_derive", @@ -1335,7 +1337,6 @@ dependencies = [ "particle-execution", "serde", "serde_json", - "server-config", "thiserror", "tokio", "tracing", @@ -1716,8 +1717,9 @@ dependencies = [ [[package]] name = "cpu-utils" -version = "0.8.0" -source = "git+https://github.com/fluencelabs/capacity-commitment-prover?branch=main#270a51de9ba388ae9fa43404d1aaa0790e241836" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8efb8938379cbf7f471035078b25e10e6b12bd8e0eeacba4dbbf92e1be39fedb" dependencies = [ "ccp-shared", "ccp_core_affinity", diff --git a/crates/chain-connector/src/connector.rs b/crates/chain-connector/src/connector.rs index 10917edd8f..cb26a8ecd4 100644 --- a/crates/chain-connector/src/connector.rs +++ b/crates/chain-connector/src/connector.rs @@ -9,7 +9,7 @@ use std::sync::Arc; use ccp_shared::proof::CCProof; use ccp_shared::types::{Difficulty, GlobalNonce, CUID}; -use clarity::{Transaction, Uint256}; +use clarity::{PrivateKey, Transaction, Uint256}; use eyre::eyre; use futures::FutureExt; use jsonrpsee::core::async_trait; @@ -29,7 +29,6 @@ use hex_utils::decode_hex; use particle_args::{Args, JError}; use particle_builtins::{wrap, CustomService}; use particle_execution::{ParticleParams, ServiceFunction}; -use server_config::ChainConfig; use types::DealId; use crate::error::{process_response, ConnectorError}; @@ -72,9 +71,47 @@ pub trait ChainConnector: Send + Sync { ) -> Result>, ConnectorError>; } +#[derive(Clone)] +pub struct HttpChainConnectorConfig { + pub http_endpoint: String, + pub core_contract_address: String, + pub cc_contract_address: String, + pub market_contract_address: String, + pub network_id: u64, + pub wallet_key: PrivateKey, + /// If none, comes from the chain + pub default_base_fee: Option, + /// If none, comes from the chain + pub default_priority_fee: Option, +} + +impl HttpChainConnectorConfig { + pub fn new( + http_endpoint: String, + core_contract_address: String, + cc_contract_address: String, + market_contract_address: String, + network_id: u64, + wallet_key: PrivateKey, + default_base_fee: Option, + default_priority_fee: Option, + ) -> Self { + Self { + http_endpoint, + core_contract_address, + cc_contract_address, + market_contract_address, + network_id, + wallet_key, + default_base_fee, + default_priority_fee, + } + } +} + pub struct HttpChainConnector { client: Arc, - config: ChainConfig, + config: HttpChainConnectorConfig, tx_nonce_mutex: Arc>, host_id: PeerId, } @@ -91,7 +128,7 @@ pub struct CCInitParams { impl HttpChainConnector { pub fn new( - config: ChainConfig, + config: HttpChainConnectorConfig, host_id: PeerId, ) -> eyre::Result<(Arc, HashMap)> { tracing::info!(target: "chain-connector","Connecting to chain via {}", config.http_endpoint); diff --git a/crates/chain-connector/src/lib.rs b/crates/chain-connector/src/lib.rs index 0caaed297a..a5d7254914 100644 --- a/crates/chain-connector/src/lib.rs +++ b/crates/chain-connector/src/lib.rs @@ -8,5 +8,6 @@ mod function; pub use connector::CCInitParams; pub use connector::ChainConnector; pub use connector::HttpChainConnector; +pub use connector::HttpChainConnectorConfig; pub use error::ConnectorError; pub use function::*; diff --git a/nox/src/node.rs b/nox/src/node.rs index b2c60b98b3..69f40be89e 100644 --- a/nox/src/node.rs +++ b/nox/src/node.rs @@ -42,7 +42,7 @@ use aquamarine::{ AquaRuntime, AquamarineApi, AquamarineApiError, AquamarineBackend, DataStoreConfig, RemoteRoutingEffects, VmPoolConfig, WasmBackendConfig, }; -use chain_connector::HttpChainConnector; +use chain_connector::{HttpChainConnector, HttpChainConnectorConfig}; use chain_listener::{ CCPClient, ChainListener, ChainListenerConfig, WsEventSubscription, WsSubscriptionConfig, }; @@ -411,7 +411,8 @@ impl Node { let services = builtins.services.clone(); let modules = builtins.modules.clone(); - let connector = if let Some(chain_config) = config.chain_config.clone() { + let chain_config = chain_connector_config(&config); + let connector = if let Some(chain_config) = chain_config { let host_id = scopes.get_host_peer_id(); let (chain_connector, chain_builtins) = HttpChainConnector::new(chain_config.clone(), host_id).map_err(|err| { @@ -780,6 +781,21 @@ fn avm_wasm_backend_config(config: &ResolvedConfig) -> WasmBackendConfig { } } +fn chain_connector_config(config: &ResolvedConfig) -> Option { + config.chain_config.clone().map(|config| { + HttpChainConnectorConfig::new( + config.http_endpoint, + config.core_contract_address, + config.cc_contract_address, + config.market_contract_address, + config.network_id, + config.wallet_key, + config.default_base_fee, + config.default_base_fee, + ) + }) +} + fn services_wasm_backend_config(config: &ResolvedConfig) -> WasmBackendConfig { WasmBackendConfig { debug_info: config.node_config.services.wasm_backend.debug_info, From e235124d4b5025aff5c2c76b91e3eaa4c75a3b63 Mon Sep 17 00:00:00 2001 From: Nick Pavlov Date: Thu, 25 Apr 2024 18:17:12 +0300 Subject: [PATCH 20/44] fix test --- crates/chain-connector/src/connector.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/crates/chain-connector/src/connector.rs b/crates/chain-connector/src/connector.rs index cb26a8ecd4..70399ffd9d 100644 --- a/crates/chain-connector/src/connector.rs +++ b/crates/chain-connector/src/connector.rs @@ -629,14 +629,11 @@ mod tests { use chain_data::peer_id_from_hex; use hex_utils::decode_hex; - use crate::{ - is_commitment_not_active, CCStatus, ChainConnector, CommitmentId, ConnectorError, - HttpChainConnector, - }; + use crate::{is_commitment_not_active, CCStatus, ChainConnector, CommitmentId, ConnectorError, HttpChainConnector, HttpChainConnectorConfig}; fn get_connector(url: &str) -> Arc { let (connector, _) = HttpChainConnector::new( - server_config::ChainConfig { + HttpChainConnectorConfig { http_endpoint: url.to_string(), cc_contract_address: "0x0E62f5cfA5189CA34E79CCB03829C064405790aD".to_string(), core_contract_address: "0x2f5224b7Cb8bd98d9Ef61c247F4741758E8E873d".to_string(), From 539e4d2ee3efce6df19095ff0043e2956c7c4f68 Mon Sep 17 00:00:00 2001 From: Nick Pavlov Date: Thu, 25 Apr 2024 21:55:48 +0300 Subject: [PATCH 21/44] fix fmt --- crates/chain-connector/src/connector.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/chain-connector/src/connector.rs b/crates/chain-connector/src/connector.rs index 70399ffd9d..895dc91471 100644 --- a/crates/chain-connector/src/connector.rs +++ b/crates/chain-connector/src/connector.rs @@ -629,7 +629,10 @@ mod tests { use chain_data::peer_id_from_hex; use hex_utils::decode_hex; - use crate::{is_commitment_not_active, CCStatus, ChainConnector, CommitmentId, ConnectorError, HttpChainConnector, HttpChainConnectorConfig}; + use crate::{ + is_commitment_not_active, CCStatus, ChainConnector, CommitmentId, ConnectorError, + HttpChainConnector, HttpChainConnectorConfig, + }; fn get_connector(url: &str) -> Arc { let (connector, _) = HttpChainConnector::new( From eb6a46f3f8ed8ea69848c9d46880cf93b25fb362 Mon Sep 17 00:00:00 2001 From: Nick Pavlov Date: Fri, 26 Apr 2024 12:28:03 +0300 Subject: [PATCH 22/44] review fixes --- crates/chain-listener/src/event/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/chain-listener/src/event/mod.rs b/crates/chain-listener/src/event/mod.rs index cca4ccfafb..0d2c0df494 100644 --- a/crates/chain-listener/src/event/mod.rs +++ b/crates/chain-listener/src/event/mod.rs @@ -2,6 +2,7 @@ pub mod cc_activated; mod compute_unit_matched; mod unit_activated; mod unit_deactivated; + pub use compute_unit_matched::ComputeUnitMatched; pub use unit_activated::UnitActivated; pub use unit_deactivated::UnitDeactivated; From a8cabcb1b87bbf2533dced37b6fce9dd4f303e0c Mon Sep 17 00:00:00 2001 From: Nick Pavlov Date: Fri, 26 Apr 2024 12:38:34 +0300 Subject: [PATCH 23/44] review fixes --- crates/chain-listener/src/listener.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/crates/chain-listener/src/listener.rs b/crates/chain-listener/src/listener.rs index 23189153e8..130e9f6472 100644 --- a/crates/chain-listener/src/listener.rs +++ b/crates/chain-listener/src/listener.rs @@ -1405,6 +1405,12 @@ mod tests { } } + /// # Test: Commitment Chain Activation Flow + /// + /// This test focuses on the commitment chain activation flow within a blockchain context. + /// It simulates the activation process, including initializing the chain, handling relevant + /// events, and validating the correct allocation of compute units. + /// #[tokio::test] async fn test_cc_activation_flow() { enable_logs(); @@ -1630,6 +1636,13 @@ mod tests { } } + /// # Test: Commitment Chain Activation Flow + /// + /// This test examines the overflow scenario within the commitment chain activation flow when + /// CU count in commitment is bigger than the real available CU count. + /// It simulates a commitment activation process in a blockchain context, validating that + /// the correct events are triggered and compute units are properly allocated during this + /// specific edge case. #[tokio::test] async fn test_cc_overflow_activation_flow() { enable_logs(); From c428e8548b5c021150668a7dafec1733c5f7f247 Mon Sep 17 00:00:00 2001 From: Nick Pavlov Date: Fri, 26 Apr 2024 12:45:55 +0300 Subject: [PATCH 24/44] fix fmt --- crates/chain-listener/src/listener.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/chain-listener/src/listener.rs b/crates/chain-listener/src/listener.rs index 130e9f6472..be78e039a4 100644 --- a/crates/chain-listener/src/listener.rs +++ b/crates/chain-listener/src/listener.rs @@ -1410,7 +1410,7 @@ mod tests { /// This test focuses on the commitment chain activation flow within a blockchain context. /// It simulates the activation process, including initializing the chain, handling relevant /// events, and validating the correct allocation of compute units. - /// + /// #[tokio::test] async fn test_cc_activation_flow() { enable_logs(); @@ -1638,10 +1638,10 @@ mod tests { /// # Test: Commitment Chain Activation Flow /// - /// This test examines the overflow scenario within the commitment chain activation flow when + /// This test examines the overflow scenario within the commitment chain activation flow when /// CU count in commitment is bigger than the real available CU count. - /// It simulates a commitment activation process in a blockchain context, validating that - /// the correct events are triggered and compute units are properly allocated during this + /// It simulates a commitment activation process in a blockchain context, validating that + /// the correct events are triggered and compute units are properly allocated during this /// specific edge case. #[tokio::test] async fn test_cc_overflow_activation_flow() { From f2b0fcfe0ba878ab8a1e6db5c8a70d7b1274e733 Mon Sep 17 00:00:00 2001 From: Nick Pavlov Date: Fri, 26 Apr 2024 16:12:04 +0300 Subject: [PATCH 25/44] fix logging target --- crates/chain-listener/src/listener.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/chain-listener/src/listener.rs b/crates/chain-listener/src/listener.rs index be78e039a4..52ec191ea9 100644 --- a/crates/chain-listener/src/listener.rs +++ b/crates/chain-listener/src/listener.rs @@ -431,7 +431,7 @@ impl ChainListener { } ).await?; - tracing::info!("Utility core {utility_core} successfully reallocated"); + tracing::info!(target: "chain-listener", "Utility core {utility_core} successfully reallocated"); } Ok(()) } From 067c8a76f0e4df3d7794d207092ba07896621c41 Mon Sep 17 00:00:00 2001 From: Nick Pavlov Date: Fri, 26 Apr 2024 17:31:00 +0300 Subject: [PATCH 26/44] fix accuire --- crates/core-manager/src/dummy.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/core-manager/src/dummy.rs b/crates/core-manager/src/dummy.rs index 8d9e9bfa56..1a0425b1ee 100644 --- a/crates/core-manager/src/dummy.rs +++ b/crates/core-manager/src/dummy.rs @@ -90,7 +90,7 @@ impl CoreManagerFunctions for DummyCoreManager { }) } - fn release(&self, _unit_ids: Vec) {} + fn release(&self, _unit_ids: &Vec) {} fn get_system_cpu_assignment(&self) -> Assignment { let physical_core_ids = (0..num_cpus::get_physical()) From 781e46d9749623d7ff9b437a4f4922783e3b2922 Mon Sep 17 00:00:00 2001 From: Nick Pavlov Date: Fri, 26 Apr 2024 17:38:11 +0300 Subject: [PATCH 27/44] fix accuire --- crates/core-manager/src/dev.rs | 4 ++-- crates/core-manager/src/dummy.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/core-manager/src/dev.rs b/crates/core-manager/src/dev.rs index 2dc2d3ee85..e0b3fb921f 100644 --- a/crates/core-manager/src/dev.rs +++ b/crates/core-manager/src/dev.rs @@ -301,7 +301,7 @@ impl CoreManagerFunctions for DevCoreManager { fn release(&self, unit_ids: &[CUID]) { let mut lock = self.state.write(); for unit_id in unit_ids { - if let Some(physical_core_id) = lock.unit_id_core_mapping.remove(&unit_id) { + if let Some(physical_core_id) = lock.unit_id_core_mapping.remove(unit_id) { let mapping = lock.core_unit_id_mapping.get_vec_mut(&physical_core_id); if let Some(mapping) = mapping { let index = mapping.iter().position(|x| x == unit_id).unwrap(); @@ -310,7 +310,7 @@ impl CoreManagerFunctions for DevCoreManager { lock.core_unit_id_mapping.remove(&physical_core_id); } } - lock.work_type_mapping.remove(&unit_id); + lock.work_type_mapping.remove(unit_id); } } } diff --git a/crates/core-manager/src/dummy.rs b/crates/core-manager/src/dummy.rs index 1a0425b1ee..bd76b7b0d1 100644 --- a/crates/core-manager/src/dummy.rs +++ b/crates/core-manager/src/dummy.rs @@ -90,7 +90,7 @@ impl CoreManagerFunctions for DummyCoreManager { }) } - fn release(&self, _unit_ids: &Vec) {} + fn release(&self, _unit_ids: &[CUID]) {} fn get_system_cpu_assignment(&self) -> Assignment { let physical_core_ids = (0..num_cpus::get_physical()) From fdb939584dfcaf15fbc43bdd374cf9b7458ddeea Mon Sep 17 00:00:00 2001 From: Nick Pavlov Date: Tue, 30 Apr 2024 13:16:16 +0300 Subject: [PATCH 28/44] cli tests timeout change --- .github/workflows/e2e.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 5bc46f7af9..dc90dd467d 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -85,6 +85,7 @@ jobs: uses: fluencelabs/cli/.github/workflows/tests.yml@main with: nox-image: "${{ needs.nox-snapshot.outputs.nox-image }}" + ref: "timeout" js-client: needs: From b532fd89291466df01d53394d45e40e73dea7648 Mon Sep 17 00:00:00 2001 From: Nick Date: Wed, 1 May 2024 12:17:26 +0300 Subject: [PATCH 29/44] fix accuire --- Cargo.lock | 4 ++++ Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 72c404a65d..631dea7352 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -312,6 +312,10 @@ version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" +[[package]] +name = "aqua" +version = "0.1.0" + [[package]] name = "aqua-ipfs-distro" version = "0.6.0" diff --git a/Cargo.toml b/Cargo.toml index 3dd984a166..77fac7c007 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,7 @@ members = [ "crates/chain-data", "crates/types", "crates/core-manager", - "crates/log-format", + "crates/log-format", "~/projects/fluencelabs/aqua-sandbox/aqua", ] exclude = [ "nox/tests/tetraplets", From 2bd7f7a0936fab7d03c6b703771f23c479cf24bd Mon Sep 17 00:00:00 2001 From: Nick Date: Mon, 13 May 2024 18:11:49 +0300 Subject: [PATCH 30/44] wip --- Cargo.lock | 4 ---- Cargo.toml | 2 +- crates/workers/src/workers.rs | 16 +++++++++++++++- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 631dea7352..72c404a65d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -312,10 +312,6 @@ version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" -[[package]] -name = "aqua" -version = "0.1.0" - [[package]] name = "aqua-ipfs-distro" version = "0.6.0" diff --git a/Cargo.toml b/Cargo.toml index 77fac7c007..3dd984a166 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,7 @@ members = [ "crates/chain-data", "crates/types", "crates/core-manager", - "crates/log-format", "~/projects/fluencelabs/aqua-sandbox/aqua", + "crates/log-format", ] exclude = [ "nox/tests/tetraplets", diff --git a/crates/workers/src/workers.rs b/crates/workers/src/workers.rs index c450410f42..d8963ad978 100644 --- a/crates/workers/src/workers.rs +++ b/crates/workers/src/workers.rs @@ -238,8 +238,22 @@ impl Workers { .await .map_err(|_err| WorkersError::FailedToNotifySubsystem { worker_id }); match result { - Ok(_) => Ok(()), + Ok(_) => { + tracing::info!( + target = "worker-registry", + worker_id = worker_id.to_string(), + "Worker {worker_id} created" + ); + Ok(()) + } Err(err) => { + tracing::warn!( + target = "worker-registry", + worker_id = worker_id.to_string(), + "Failed to notify subsystem for {worker_id}: {}", + err + ); + let mut worker_ids = self.worker_ids.write(); let mut worker_infos = self.worker_infos.write(); let mut runtimes = self.runtimes.write(); From 7cf0076cea86e7dc6d66ef07e0ce2ea67d52d326 Mon Sep 17 00:00:00 2001 From: Nick Date: Mon, 13 May 2024 18:17:57 +0300 Subject: [PATCH 31/44] wip --- crates/workers/src/workers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/workers/src/workers.rs b/crates/workers/src/workers.rs index d8963ad978..b98bd55a50 100644 --- a/crates/workers/src/workers.rs +++ b/crates/workers/src/workers.rs @@ -247,7 +247,7 @@ impl Workers { Ok(()) } Err(err) => { - tracing::warn!( + tracing::error!( target = "worker-registry", worker_id = worker_id.to_string(), "Failed to notify subsystem for {worker_id}: {}", From 853060eef6ac0e3ef4242947481bd4c4f6f7dcf2 Mon Sep 17 00:00:00 2001 From: Nick Date: Mon, 13 May 2024 21:52:36 +0300 Subject: [PATCH 32/44] wip --- crates/workers/src/workers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/workers/src/workers.rs b/crates/workers/src/workers.rs index b98bd55a50..acc52d97f6 100644 --- a/crates/workers/src/workers.rs +++ b/crates/workers/src/workers.rs @@ -242,7 +242,7 @@ impl Workers { tracing::info!( target = "worker-registry", worker_id = worker_id.to_string(), - "Worker {worker_id} created" + "Worker created {worker_id}" ); Ok(()) } From 3ce6213484858be71a3cac25004282af529a7920 Mon Sep 17 00:00:00 2001 From: Nick Date: Tue, 14 May 2024 14:09:46 +0300 Subject: [PATCH 33/44] wip --- .github/workflows/e2e.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index dc90dd467d..dcb1ff8d77 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -82,7 +82,7 @@ jobs: cli: needs: - nox-snapshot - uses: fluencelabs/cli/.github/workflows/tests.yml@main + uses: fluencelabs/cli/.github/workflows/tests.yml@timeout with: nox-image: "${{ needs.nox-snapshot.outputs.nox-image }}" ref: "timeout" From a13b0b8c7eb8cf14568e647e39ca68b810ebaa77 Mon Sep 17 00:00:00 2001 From: Nick Date: Tue, 14 May 2024 21:06:48 +0300 Subject: [PATCH 34/44] fix --- Cargo.lock | 6 +++--- crates/system-services/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 72c404a65d..ab101b3ad0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2082,9 +2082,9 @@ dependencies = [ [[package]] name = "decider-distro" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ff1a872b211111a9b67000c1251591e06fa8525ad2f97e406d72fd7dc8fbf68" +version = "0.6.12-release-please-f353905-942-1.0" +source = "registry+git://crates.fluence.dev/index" +checksum = "1ccdb8cda3c899c17949f4315b5a11137997ccc3a2317385119e52907a98d1bf" dependencies = [ "built 0.7.1", "fluence-spell-dtos", diff --git a/crates/system-services/Cargo.toml b/crates/system-services/Cargo.toml index 78277d7549..8158083d26 100644 --- a/crates/system-services/Cargo.toml +++ b/crates/system-services/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] aqua-ipfs-distro = "=0.6.0" -decider-distro = "=0.6.11" +decider-distro = { version = "0.6.12-qfix-c80c01a-1003-1.0", registry = "fluence" } registry-distro = "=0.9.4" trust-graph-distro = "=0.4.11" From f1c143694392b916eec0707495c0a30dcb794871 Mon Sep 17 00:00:00 2001 From: Nick Date: Tue, 14 May 2024 21:30:18 +0300 Subject: [PATCH 35/44] fix --- crates/chain-listener/src/listener.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/chain-listener/src/listener.rs b/crates/chain-listener/src/listener.rs index 52ec191ea9..4df476789d 100644 --- a/crates/chain-listener/src/listener.rs +++ b/crates/chain-listener/src/listener.rs @@ -70,7 +70,7 @@ pub struct ChainListener { difficulty: Difficulty, // The time when the first epoch starts (aka the contract was deployed) init_timestamp: U256, - epoch_duration: U256, + epoch_duration_sec: U256, min_proofs_per_epoch: U256, max_proofs_per_epoch: U256, // These settings are changed each epoch @@ -134,7 +134,7 @@ impl ChainListener { init_timestamp: U256::ZERO, global_nonce: GlobalNonce::new([0; 32]), current_epoch: U256::ZERO, - epoch_duration: U256::ZERO, + epoch_duration_sec: U256::ZERO, min_proofs_per_epoch: U256::ZERO, max_proofs_per_epoch: U256::ZERO, proof_counter: BTreeMap::new(), @@ -283,12 +283,12 @@ impl ChainListener { err })?; - tracing::info!(target: "chain-listener","Commitment initial params: difficulty {}, global nonce {}, init_timestamp {}, epoch_duration {}, current_epoch {}, min_proofs_per_epoch {}, max_proofs_per_epoch {}", init_params.difficulty, init_params.global_nonce, init_params.init_timestamp, init_params.epoch_duration, init_params.current_epoch, init_params.min_proofs_per_epoch, init_params.max_proofs_per_epoch); + tracing::info!(target: "chain-listener","Commitment initial params: difficulty {}, global nonce {}, init_timestamp {}, epoch_duration {}, current_epoch {}, min_proofs_per_epoch {}, max_proofs_per_epoch {}", init_params.difficulty, init_params.global_nonce, init_params.init_timestamp, init_params.epoch_duration_sec, init_params.current_epoch, init_params.min_proofs_per_epoch, init_params.max_proofs_per_epoch); self.difficulty = init_params.difficulty; self.init_timestamp = init_params.init_timestamp; self.global_nonce = init_params.global_nonce; - self.epoch_duration = init_params.epoch_duration; + self.epoch_duration_sec = init_params.epoch_duration_sec; self.min_proofs_per_epoch = init_params.min_proofs_per_epoch; self.max_proofs_per_epoch = init_params.max_proofs_per_epoch; @@ -556,7 +556,7 @@ impl ChainListener { // `epoch_number = 1 + (block_timestamp - init_timestamp) / epoch_duration` let epoch_number = - U256::from(1) + (block_timestamp - self.init_timestamp) / self.epoch_duration; + U256::from(1) + (block_timestamp - self.init_timestamp) / self.epoch_duration_sec; let epoch_changed = epoch_number > self.current_epoch; if epoch_changed { From 325f4f842b089f577f17022f3673932dd51a7c4e Mon Sep 17 00:00:00 2001 From: Nick Date: Tue, 14 May 2024 23:34:40 +0300 Subject: [PATCH 36/44] update decider --- Cargo.lock | 6 +++--- crates/system-services/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ab101b3ad0..bfc944900b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2082,9 +2082,9 @@ dependencies = [ [[package]] name = "decider-distro" -version = "0.6.12-release-please-f353905-942-1.0" -source = "registry+git://crates.fluence.dev/index" -checksum = "1ccdb8cda3c899c17949f4315b5a11137997ccc3a2317385119e52907a98d1bf" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe66aa706ae0e5af6d8ae8b6a6190cbd0a54d6a476e04ae2c4badcdc408ae816" dependencies = [ "built 0.7.1", "fluence-spell-dtos", diff --git a/crates/system-services/Cargo.toml b/crates/system-services/Cargo.toml index 8158083d26..82913ca4e0 100644 --- a/crates/system-services/Cargo.toml +++ b/crates/system-services/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] aqua-ipfs-distro = "=0.6.0" -decider-distro = { version = "0.6.12-qfix-c80c01a-1003-1.0", registry = "fluence" } +decider-distro = "=0.6.12" registry-distro = "=0.9.4" trust-graph-distro = "=0.4.11" From 09231939b72ff2aad0710c63d6a2117cfa62b0a2 Mon Sep 17 00:00:00 2001 From: Nick Date: Wed, 15 May 2024 13:49:11 +0300 Subject: [PATCH 37/44] wip --- nox/src/layers.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/nox/src/layers.rs b/nox/src/layers.rs index 3712cf5a7d..1d3ed99438 100644 --- a/nox/src/layers.rs +++ b/nox/src/layers.rs @@ -40,6 +40,11 @@ where .add_directive("cranelift_codegen=error".parse().unwrap()) .add_directive("tracing=error".parse().unwrap()) .add_directive("avm_server::runner=error".parse().unwrap()) + //TODO: remove after debug + .add_directive("run-console=info".parse().unwrap()) + .add_directive("expired=info".parse().unwrap()) + + } pub fn log_layer() -> (impl Layer, WorkerGuard) From 9385327ee3686dcd749ac761cdff57582bece415 Mon Sep 17 00:00:00 2001 From: Nick Date: Wed, 15 May 2024 13:58:56 +0300 Subject: [PATCH 38/44] wip --- aquamarine/src/log.rs | 9 +++++++++ nox/src/layers.rs | 3 --- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/aquamarine/src/log.rs b/aquamarine/src/log.rs index d5aff69ea4..5665b70ef9 100644 --- a/aquamarine/src/log.rs +++ b/aquamarine/src/log.rs @@ -12,6 +12,15 @@ fn truncate(s: &str) -> &str { pub fn builtin_log_fn(service: &str, args: &str, elapsed: FormattedDuration, particle_id: String) { let args = truncate(args); match service { + "run-console" => { + tracing::event!( + tracing::Level::INFO, + "Executed host call {} ({}) [{}]", + args, + elapsed, + particle_id + ) + } "array" | "cmp" | "debug" | "math" | "op" | "getDataSrv" | "run-console" | "json" => { tracing::event!( tracing::Level::TRACE, diff --git a/nox/src/layers.rs b/nox/src/layers.rs index 1d3ed99438..b0f73a3c50 100644 --- a/nox/src/layers.rs +++ b/nox/src/layers.rs @@ -41,10 +41,7 @@ where .add_directive("tracing=error".parse().unwrap()) .add_directive("avm_server::runner=error".parse().unwrap()) //TODO: remove after debug - .add_directive("run-console=info".parse().unwrap()) .add_directive("expired=info".parse().unwrap()) - - } pub fn log_layer() -> (impl Layer, WorkerGuard) From 58bb8e7452ec5a15afe722c7db550a7c675fccde Mon Sep 17 00:00:00 2001 From: Nick Date: Wed, 15 May 2024 14:02:48 +0300 Subject: [PATCH 39/44] wip --- nox/src/layers.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/nox/src/layers.rs b/nox/src/layers.rs index b0f73a3c50..3712cf5a7d 100644 --- a/nox/src/layers.rs +++ b/nox/src/layers.rs @@ -40,8 +40,6 @@ where .add_directive("cranelift_codegen=error".parse().unwrap()) .add_directive("tracing=error".parse().unwrap()) .add_directive("avm_server::runner=error".parse().unwrap()) - //TODO: remove after debug - .add_directive("expired=info".parse().unwrap()) } pub fn log_layer() -> (impl Layer, WorkerGuard) From f69b1dfe25edbc5fe02ba0b5b4b204b89879ad64 Mon Sep 17 00:00:00 2001 From: Nick Date: Wed, 15 May 2024 14:12:51 +0300 Subject: [PATCH 40/44] wip --- aquamarine/src/log.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aquamarine/src/log.rs b/aquamarine/src/log.rs index 5665b70ef9..2466add1ed 100644 --- a/aquamarine/src/log.rs +++ b/aquamarine/src/log.rs @@ -21,7 +21,7 @@ pub fn builtin_log_fn(service: &str, args: &str, elapsed: FormattedDuration, par particle_id ) } - "array" | "cmp" | "debug" | "math" | "op" | "getDataSrv" | "run-console" | "json" => { + "array" | "cmp" | "debug" | "math" | "op" | "getDataSrv" | "json" => { tracing::event!( tracing::Level::TRACE, "Executed host call {} ({}) [{}]", From 6f8355f14db9d24d7567b5acfe736bbc900c1042 Mon Sep 17 00:00:00 2001 From: Nick Date: Fri, 17 May 2024 12:18:52 +0300 Subject: [PATCH 41/44] fmt fix --- crates/core-manager/src/dummy.rs | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/crates/core-manager/src/dummy.rs b/crates/core-manager/src/dummy.rs index bd76b7b0d1..9cbec1eaa0 100644 --- a/crates/core-manager/src/dummy.rs +++ b/crates/core-manager/src/dummy.rs @@ -106,32 +106,3 @@ impl CoreManagerFunctions for DummyCoreManager { } } } - -#[async_trait] -impl CoreManagerFunctions for DummyCoreManager { - fn acquire_worker_core( - &self, - assign_request: AcquireRequest, - ) -> Result { - let all_cores = self.all_cores(); - - let logical_core_ids: BTreeSet = BTreeSet::from_iter( - all_cores - .logical_core_ids - .into_iter() - .choose_multiple(&mut rand::thread_rng(), assign_request.unit_ids.len()), - ); - - Ok(Assignment { - physical_core_ids: BTreeSet::new(), - logical_core_ids, - cuid_cores: Map::with_hasher(FxBuildHasher::default()), - }) - } - - fn release(&self, _unit_ids: &[CUID]) {} - - fn get_system_cpu_assignment(&self) -> Assignment { - self.all_cores() - } -} From ad79f59d7c902e3bd8e0c016fe259b7036c268b4 Mon Sep 17 00:00:00 2001 From: Nick Date: Fri, 17 May 2024 18:16:46 +0300 Subject: [PATCH 42/44] fix --- Cargo.lock | 1 + crates/core-manager/Cargo.toml | 2 +- crates/core-manager/src/core_range.rs | 11 +++++++++++ crates/core-manager/src/dev.rs | 4 ++++ crates/core-manager/src/errors.rs | 2 ++ crates/core-manager/src/strict.rs | 4 ++++ 6 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index bfc944900b..9cb1cc7f25 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1683,6 +1683,7 @@ dependencies = [ "hex-utils", "multimap 0.10.0", "newtype_derive", + "nonempty", "num_cpus", "parking_lot", "rand 0.8.5", diff --git a/crates/core-manager/Cargo.toml b/crates/core-manager/Cargo.toml index d6bb6288f2..e9ed8fac17 100644 --- a/crates/core-manager/Cargo.toml +++ b/crates/core-manager/Cargo.toml @@ -29,7 +29,7 @@ rand = "0.8.5" hex.workspace = true serde_with = { workspace = true } hex-utils = { workspace = true, features = ["serde_with"] } - +nonempty = "0.9.0" [dev-dependencies] tempfile = { workspace = true } diff --git a/crates/core-manager/src/core_range.rs b/crates/core-manager/src/core_range.rs index 240a403e77..e5b9f75a01 100644 --- a/crates/core-manager/src/core_range.rs +++ b/crates/core-manager/src/core_range.rs @@ -1,3 +1,5 @@ +use ccp_shared::types::PhysicalCoreId; +use nonempty::NonEmpty; use range_set_blaze::RangeSetBlaze; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::fmt::{Debug, Display, Formatter}; @@ -7,6 +9,15 @@ use thiserror::Error; #[derive(Clone, PartialEq)] pub struct CoreRange(pub(crate) RangeSetBlaze); +impl CoreRange { + pub fn is_subset(&self, cores: &NonEmpty) -> bool { + let range: RangeSetBlaze = + RangeSetBlaze::from_iter(cores.into_iter().map(|core| ::from(core.clone()))); + + self.0.is_subset(&range) + } +} + impl Debug for CoreRange { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.write_str(self.0.to_string().as_str()) diff --git a/crates/core-manager/src/dev.rs b/crates/core-manager/src/dev.rs index e0b3fb921f..824e64b13b 100644 --- a/crates/core-manager/src/dev.rs +++ b/crates/core-manager/src/dev.rs @@ -105,6 +105,10 @@ impl DevCoreManager { .physical_cores() .map_err(|err| CreateError::CollectCoresData { err })?; + if !core_range.is_subset(&physical_cores) { + return Err(CreateError::WrongCpuRange); + } + let mut cores_mapping: MultiMap = MultiMap::with_capacity_and_hasher(available_core_count, FxBuildHasher::default()); diff --git a/crates/core-manager/src/errors.rs b/crates/core-manager/src/errors.rs index 732196627c..76ea443b3c 100644 --- a/crates/core-manager/src/errors.rs +++ b/crates/core-manager/src/errors.rs @@ -10,6 +10,8 @@ pub enum CreateError { IllegalSystemCoreCount, #[error("Too much system cores needed. Required: {required}, available: {required}")] NotEnoughCores { available: usize, required: usize }, + #[error("The specified CPU range exceeds the available CPU count")] + WrongCpuRange, #[error("Failed to create CPU topology {err}")] CreateTopology { err: CPUTopologyError }, #[error("Failed to collect cores data from OS {err:?}")] diff --git a/crates/core-manager/src/strict.rs b/crates/core-manager/src/strict.rs index f08cf110c8..c3e691cf21 100644 --- a/crates/core-manager/src/strict.rs +++ b/crates/core-manager/src/strict.rs @@ -102,6 +102,10 @@ impl StrictCoreManager { .physical_cores() .map_err(|err| CreateError::CollectCoresData { err })?; + if !core_range.is_subset(&physical_cores) { + return Err(CreateError::WrongCpuRange); + } + let mut cores_mapping: MultiMap = MultiMap::with_capacity_and_hasher(available_core_count, FxBuildHasher::default()); From 530ed0cd9f8132fd923a0c59d1bcf61a66b2895b Mon Sep 17 00:00:00 2001 From: Nick Date: Fri, 17 May 2024 18:22:21 +0300 Subject: [PATCH 43/44] fix --- crates/core-manager/src/dev.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/core-manager/src/dev.rs b/crates/core-manager/src/dev.rs index 824e64b13b..629a303a65 100644 --- a/crates/core-manager/src/dev.rs +++ b/crates/core-manager/src/dev.rs @@ -108,7 +108,7 @@ impl DevCoreManager { if !core_range.is_subset(&physical_cores) { return Err(CreateError::WrongCpuRange); } - + let mut cores_mapping: MultiMap = MultiMap::with_capacity_and_hasher(available_core_count, FxBuildHasher::default()); From 144a444863a85f199cf9a1d14d5c4f56eea5e869 Mon Sep 17 00:00:00 2001 From: Nick Date: Fri, 17 May 2024 18:33:06 +0300 Subject: [PATCH 44/44] clippy fixes --- crates/chain-listener/src/listener.rs | 8 ++++---- crates/core-manager/src/core_range.rs | 2 +- crates/core-manager/src/strict.rs | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/chain-listener/src/listener.rs b/crates/chain-listener/src/listener.rs index 4df476789d..53aabaefb6 100644 --- a/crates/chain-listener/src/listener.rs +++ b/crates/chain-listener/src/listener.rs @@ -1499,8 +1499,8 @@ mod tests { .unwrap()) }); - let cc_init_difficulty = difficulty.clone(); - let cc_init_global_nonce = global_nonce.clone(); + let cc_init_difficulty = difficulty; + let cc_init_global_nonce = global_nonce; connector.expect_get_cc_init_params().returning(move || { Ok(CCInitParams { difficulty: cc_init_difficulty, @@ -1731,8 +1731,8 @@ mod tests { .unwrap()) }); - let cc_init_difficulty = difficulty.clone(); - let cc_init_global_nonce = global_nonce.clone(); + let cc_init_difficulty = difficulty; + let cc_init_global_nonce = global_nonce; connector.expect_get_cc_init_params().returning(move || { Ok(CCInitParams { difficulty: cc_init_difficulty, diff --git a/crates/core-manager/src/core_range.rs b/crates/core-manager/src/core_range.rs index e5b9f75a01..3bbce958b2 100644 --- a/crates/core-manager/src/core_range.rs +++ b/crates/core-manager/src/core_range.rs @@ -12,7 +12,7 @@ pub struct CoreRange(pub(crate) RangeSetBlaze); impl CoreRange { pub fn is_subset(&self, cores: &NonEmpty) -> bool { let range: RangeSetBlaze = - RangeSetBlaze::from_iter(cores.into_iter().map(|core| ::from(core.clone()))); + RangeSetBlaze::from_iter(cores.into_iter().map(|core| ::from(*core))); self.0.is_subset(&range) } diff --git a/crates/core-manager/src/strict.rs b/crates/core-manager/src/strict.rs index c3e691cf21..65cbbebaba 100644 --- a/crates/core-manager/src/strict.rs +++ b/crates/core-manager/src/strict.rs @@ -306,9 +306,9 @@ impl CoreManagerFunctions for StrictCoreManager { fn release(&self, unit_ids: &[CUID]) { let mut lock = self.state.write(); for unit_id in unit_ids { - if let Some((physical_core_id, _)) = lock.unit_id_mapping.remove_by_right(&unit_id) { + if let Some((physical_core_id, _)) = lock.unit_id_mapping.remove_by_right(unit_id) { lock.available_cores.insert(physical_core_id); - lock.work_type_mapping.remove(&unit_id); + lock.work_type_mapping.remove(unit_id); } } }