From 0ff08d00c40358174495fa24f29a69b43b0c908f Mon Sep 17 00:00:00 2001 From: Chris O'Neil Date: Wed, 10 Jan 2024 21:20:10 +0000 Subject: [PATCH] ci: use node manager for running local testnets The local testnet action now uses the node manager to launch local networks. The churn tests were updated to parse the node manager's inventory, which they use to restart nodes. The node registry from the node manager has been transferred to the `sn_protocol` crate to reduce duplication between `safe_network` and `sn-node-manager`, because they both need access to these data structures. The local network deployment inventory is represented using the node registry. --- .github/workflows/benchmark-prs.yml | 1 - .github/workflows/memcheck.yml | 3 +- .github/workflows/merge.yml | 12 --- .github/workflows/release.yml | 5 -- sn_node/tests/common/client.rs | 20 ++--- sn_protocol/Cargo.toml | 6 +- sn_protocol/src/error.rs | 4 + sn_protocol/src/lib.rs | 2 + sn_protocol/src/node_registry.rs | 125 ++++++++++++++++++++++++++++ 9 files changed, 143 insertions(+), 35 deletions(-) create mode 100644 sn_protocol/src/node_registry.rs diff --git a/.github/workflows/benchmark-prs.yml b/.github/workflows/benchmark-prs.yml index 9eeac7683f..99e23211d1 100644 --- a/.github/workflows/benchmark-prs.yml +++ b/.github/workflows/benchmark-prs.yml @@ -54,7 +54,6 @@ jobs: node-path: target/release/safenode faucet-path: target/release/faucet platform: ubuntu-latest - build: true - name: Check SAFE_PEERS was set shell: bash diff --git a/.github/workflows/memcheck.yml b/.github/workflows/memcheck.yml index 19ed865d8a..842067ee43 100644 --- a/.github/workflows/memcheck.yml +++ b/.github/workflows/memcheck.yml @@ -65,7 +65,7 @@ jobs: - name: Start a local network env: - SN_LOG: all + SN_LOG: "all" uses: maidsafe/sn-local-testnet-action@main with: action: start @@ -74,7 +74,6 @@ jobs: faucet-path: target/release/faucet platform: ubuntu-latest set-safe-peers: false - build: true join: true # In this case we did *not* want SAFE_PEERS to be set to another value by starting the testnet diff --git a/.github/workflows/merge.yml b/.github/workflows/merge.yml index dae183ef05..d1a9e9562a 100644 --- a/.github/workflows/merge.yml +++ b/.github/workflows/merge.yml @@ -153,7 +153,6 @@ jobs: node-path: target/release/safenode faucet-path: target/release/faucet platform: ${{ matrix.os }} - build: true - name: Check SAFE_PEERS was set shell: bash @@ -279,7 +278,6 @@ jobs: action: stop log_file_prefix: safe_test_logs_e2e platform: ${{ matrix.os }} - build: true gossipsub: if: "!startsWith(github.event.head_commit.message, 'chore(release):')" @@ -311,7 +309,6 @@ jobs: node-path: target/release/safenode faucet-path: target/release/faucet platform: ${{ matrix.os }} - build: true - name: Gossipsub - nodes to subscribe to topics, and publish messages run: cargo test --release -p sn_node --features local-discovery --test msgs_over_gossipsub -- --nocapture @@ -324,7 +321,6 @@ jobs: action: stop log_file_prefix: safe_test_logs_gossipsub_e2e platform: ${{ matrix.os }} - build: true spend_test: if: "!startsWith(github.event.head_commit.message, 'chore(release):')" @@ -357,7 +353,6 @@ jobs: node-path: target/release/safenode faucet-path: target/release/faucet platform: ${{ matrix.os }} - build: true - name: Check SAFE_PEERS was set shell: bash @@ -396,7 +391,6 @@ jobs: action: stop log_file_prefix: safe_test_logs_spend platform: ${{ matrix.os }} - build: true churn: if: "!startsWith(github.event.head_commit.message, 'chore(release):')" @@ -437,7 +431,6 @@ jobs: node-path: target/release/safenode faucet-path: target/release/faucet platform: ${{ matrix.os }} - build: true - name: Check SAFE_PEERS was set shell: bash @@ -464,7 +457,6 @@ jobs: action: stop log_file_prefix: safe_test_logs_churn platform: ${{ matrix.os }} - build: true - name: Verify restart of nodes using rg shell: bash @@ -559,7 +551,6 @@ jobs: node-path: target/release/safenode faucet-path: target/release/faucet platform: ${{ matrix.os }} - build: true - name: Check SAFE_PEERS was set shell: bash @@ -593,7 +584,6 @@ jobs: action: stop log_file_prefix: safe_test_logs_data_location platform: ${{ matrix.os }} - build: true - name: Verify restart of nodes using rg shell: bash @@ -769,7 +759,6 @@ jobs: node-path: target/release/safenode faucet-path: target/release/faucet platform: ubuntu-latest - build: true - name: Check SAFE_PEERS was set shell: bash @@ -861,4 +850,3 @@ jobs: action: stop log_file_prefix: safe_test_logs_heavy_replicate_bench platform: ubuntu-latest - build: true \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2f80084efc..9d0d7dd560 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -38,9 +38,6 @@ jobs: target: aarch64-unknown-linux-musl steps: - uses: actions/checkout@v4 - - - - uses: dtolnay/rust-toolchain@stable # It's quite slow to install just by building it, but here we need a cross-platform solution. - shell: bash @@ -75,8 +72,6 @@ jobs: GH_TOKEN: ${{ secrets.VERSION_BUMP_COMMIT_PAT }} steps: - - - uses: actions/checkout@v4 with: fetch-depth: "0" diff --git a/sn_node/tests/common/client.rs b/sn_node/tests/common/client.rs index ffbd81c30f..8a33eb5320 100644 --- a/sn_node/tests/common/client.rs +++ b/sn_node/tests/common/client.rs @@ -10,6 +10,7 @@ use eyre::{bail, Result}; use lazy_static::lazy_static; use sn_client::{send, Client}; use sn_peers_acquisition::parse_peer_addr; +use sn_protocol::node_registry::{get_local_node_registry_path, NodeRegistry}; use sn_protocol::test_utils::DeploymentInventory; use sn_transfers::{create_faucet_wallet, LocalWallet, NanoTokens, Transfer}; use std::{ @@ -53,18 +54,13 @@ pub fn get_all_rpc_addresses() -> Result> { match DeploymentInventory::load() { Ok(inventory) => Ok(inventory.rpc_endpoints), Err(_) => { - let starting_port = match std::env::var("CHURN_TEST_START_PORT") { - Ok(val) => val.parse()?, - Err(_) => 12000, - }; - let mut addresses = Vec::new(); - for i in 1..LOCAL_NODE_COUNT + 1 { - let addr = SocketAddr::new( - IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), - starting_port + i as u16, - ); - addresses.push(addr); - } + let local_node_reg_path = &get_local_node_registry_path()?; + let local_node_registry = NodeRegistry::load(local_node_reg_path)?; + let addresses = local_node_registry + .nodes + .iter() + .map(|n| SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), n.rpc_port)) + .collect::>(); Ok(addresses) } } diff --git a/sn_protocol/Cargo.toml b/sn_protocol/Cargo.toml index f3273970d4..f4df6c16e2 100644 --- a/sn_protocol/Cargo.toml +++ b/sn_protocol/Cargo.toml @@ -10,7 +10,7 @@ repository = "https://github.com/maidsafe/safe_network" version = "0.10.7" [features] -test-utils=["dirs-next", "serde_json"] +test-utils=[] [dependencies] bls = { package = "blsttc", version = "8.0.1" } @@ -18,12 +18,12 @@ bytes = { version = "1.0.1", features = ["serde"] } color-eyre = "0.6.2" crdts = { version = "7.3", default-features = false, features = ["merkle"] } custom_debug = "~0.5.0" -dirs-next = { version = "~2.0.0", optional = true } +dirs-next = "~2.0.0" hex = "~0.4.3" libp2p = { version="0.53", features = ["identify", "kad"] } rmp-serde = "1.1.1" serde = { version = "1.0.133", features = [ "derive", "rc" ]} -serde_json = {version = "1.0", optional = true } +serde_json = "1.0" sha2 = "0.10.7" sn_transfers = { path = "../sn_transfers", version = "0.14.37" } sn_registers = { path = "../sn_registers", version = "0.3.7" } diff --git a/sn_protocol/src/error.rs b/sn_protocol/src/error.rs index 87d2dea4af..7200a59e07 100644 --- a/sn_protocol/src/error.rs +++ b/sn_protocol/src/error.rs @@ -17,6 +17,10 @@ pub type Result = std::result::Result; #[derive(Error, Clone, PartialEq, Eq, Serialize, Deserialize, custom_debug::Debug)] #[non_exhaustive] pub enum Error { + // ---------- Misc errors + #[error("Could not obtain user's data directory")] + UserDataDirectoryNotObtainable, + // ---------- Chunk Proof errors #[error("Chunk does not exist {0:?}")] ChunkDoesNotExist(NetworkAddress), diff --git a/sn_protocol/src/lib.rs b/sn_protocol/src/lib.rs index 194e716080..1686ea9cc2 100644 --- a/sn_protocol/src/lib.rs +++ b/sn_protocol/src/lib.rs @@ -13,6 +13,8 @@ extern crate tracing; pub mod error; /// Messages types pub mod messages; +/// Data structures for node management. +pub mod node_registry; /// RPC commands to node pub mod node_rpc; /// Storage types for spends, chunks and registers. diff --git a/sn_protocol/src/node_registry.rs b/sn_protocol/src/node_registry.rs new file mode 100644 index 0000000000..4e96e52e46 --- /dev/null +++ b/sn_protocol/src/node_registry.rs @@ -0,0 +1,125 @@ +// Copyright (C) 2024 MaidSafe.net limited. +// +// This SAFE Network Software is licensed to you under The General Public License (GPL), version 3. +// Unless required by applicable law or agreed to in writing, the SAFE Network Software distributed +// under the GPL Licence is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. Please review the Licences for the specific language governing +// permissions and limitations relating to use of the SAFE Network Software. + +use crate::Error; +use color_eyre::Result; +use libp2p::{Multiaddr, PeerId}; +use serde::de::Error as DeError; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use std::io::{Read, Write}; +use std::path::{Path, PathBuf}; +use std::str::FromStr; + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub enum NodeStatus { + /// The node service has been added but not started for the first time + Added, + /// Last time we checked the service was running + Running, + /// The node service has been stopped + Stopped, + /// The node service has been removed + Removed, +} + +fn serialize_peer_id(value: &Option, serializer: S) -> Result +where + S: Serializer, +{ + if let Some(peer_id) = value { + return serializer.serialize_str(&peer_id.to_string()); + } + serializer.serialize_none() +} + +fn deserialize_peer_id<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + let s: Option = Option::deserialize(deserializer)?; + if let Some(peer_id_str) = s { + PeerId::from_str(&peer_id_str) + .map(Some) + .map_err(DeError::custom) + } else { + Ok(None) + } +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Node { + pub genesis: bool, + pub version: String, + pub service_name: String, + pub user: String, + pub number: u16, + pub port: u16, + pub rpc_port: u16, + pub status: NodeStatus, + pub pid: Option, + #[serde( + serialize_with = "serialize_peer_id", + deserialize_with = "deserialize_peer_id" + )] + pub peer_id: Option, + pub data_dir_path: Option, + pub log_dir_path: Option, + pub safenode_path: Option, +} + +impl Node { + pub fn get_multiaddr(&self) -> Option { + if let Some(peer_id) = self.peer_id { + let peer = format!("/ip4/127.0.0.1/tcp/{}/p2p/{}", self.port, peer_id); + match peer.parse() { + Ok(p) => return Some(p), + Err(_) => return None, + } + } + None + } +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct NodeRegistry { + pub save_path: PathBuf, + pub nodes: Vec, + pub faucet_pid: Option, +} + +impl NodeRegistry { + pub fn save(&self) -> Result<()> { + let json = serde_json::to_string(self)?; + let mut file = std::fs::File::create(self.save_path.clone())?; + file.write_all(json.as_bytes())?; + Ok(()) + } + + pub fn load(path: &Path) -> Result { + if !path.exists() { + return Ok(NodeRegistry { + save_path: path.to_path_buf(), + nodes: vec![], + faucet_pid: None, + }); + } + let mut file = std::fs::File::open(path)?; + let mut contents = String::new(); + file.read_to_string(&mut contents)?; + let registry = serde_json::from_str(&contents)?; + Ok(registry) + } +} + +pub fn get_local_node_registry_path() -> Result { + let path = dirs_next::data_dir() + .ok_or_else(|| Error::UserDataDirectoryNotObtainable)? + .join("safe") + .join("local_node_registry.json"); + Ok(path) +}