Skip to content

Commit

Permalink
feat: add tribes and graceful shutdown (#28)
Browse files Browse the repository at this point in the history
Description
---
We needed tribes to let people mine together in a smaller group called
tribe. P2pool must allow this functionality.
Also we should have the chance to list all current tribes, cli of p2pool
should support this.
As a plus p2pool should support graceful shutdown.

Motivation and Context
---

How Has This Been Tested?
---

**Testing tribes**

1. Start p2pool node on tribe `a`: `export TARI_NETWORK="esmeralda" &&
./target/release/sha_p2pool start -g 18145 --tribe a`
2. Start mining on this p2pool node
3. Start another p2pool node on tribe `b`: `export
TARI_NETWORK="esmeralda" && ./target/release/sha_p2pool start -g 18146
--tribe b`
4. Start mining on this other p2pool node
5. It should be visible from the logs that the 2 pools have a different
share chain

**Testing list tribes**
Simply run `sha_p2pool list-tribes`
Example output:
```json
["default","a"]
```

What process can a PR reviewer use to test or verify this change?
---
See tests


Breaking Changes
---

- [ ] None
- [ ] Requires data directory on base node to be deleted
- [ ] Requires hard fork
- [x] Other - Peer info contains tribe now

BREAKING CHANGE: Seed peers needs to be updated to the latest version as
Peer info contains tribe now
  • Loading branch information
ksrichard authored Aug 15, 2024
1 parent 74bc5c3 commit 7b3568b
Show file tree
Hide file tree
Showing 19 changed files with 712 additions and 291 deletions.
24 changes: 23 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "sha_p2pool"
version = "0.1.0"
version = "0.1.3"
edition = "2021"

[dependencies]
Expand All @@ -9,6 +9,7 @@ minotari_node_grpc_client = { git = "https://github.com/tari-project/tari.git" }
tari_common_types = { git = "https://github.com/tari-project/tari.git" }
tari_common = { git = "https://github.com/tari-project/tari.git" }
tari_core = { git = "https://github.com/tari-project/tari.git" }
tari_shutdown = { git = "https://github.com/tari-project/tari.git" }

tari_crypto = "0.20.1"
tari_utilities = { version = "0.7", features = ["borsh"] }
Expand All @@ -33,7 +34,7 @@ tokio = { version = "1.38.0", features = ["full"] }
thiserror = "1.0"
serde = "1.0.203"
anyhow = "1.0"
log = "0.4.21"
log = { version = "0.4.21", features = ["kv"] }
tonic = "0.8.3"
async-trait = "0.1.80"
serde_cbor = "0.11.2"
Expand All @@ -50,6 +51,8 @@ num = { version = "0.4.3", features = ["default", "num-bigint", "serde"] }
hex = "0.4.3"
serde_json = "1.0.122"
hickory-resolver = { version = "*", features = ["dns-over-rustls"] }
convert_case = "0.6.0"
signal-hook = "0.3.17"

[package.metadata.cargo-machete]
ignored = ["log4rs"]
151 changes: 151 additions & 0 deletions src/cli/args.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
// Copyright 2024 The Tari Project
// SPDX-License-Identifier: BSD-3-Clause

use std::path::PathBuf;
use std::sync::Arc;

use clap::{Parser, Subcommand};
use tari_shutdown::ShutdownSignal;

use crate::cli::commands;
use crate::cli::util::cli_styles;
use crate::cli::util::validate_tribe;

#[allow(clippy::struct_excessive_bools)]
#[derive(Clone, Parser, Debug)]
pub struct StartArgs {
/// (Optional) gRPC port to use.
#[arg(short, long, value_name = "grpc-port")]
pub grpc_port: Option<u16>,

/// (Optional) p2p port to use. It is used to connect p2pool nodes.
#[arg(short, long, value_name = "p2p-port")]
pub p2p_port: Option<u16>,

/// (Optional) stats server port to use.
#[arg(long, value_name = "stats-server-port")]
pub stats_server_port: Option<u16>,

/// (Optional) seed peers.
/// Any amount of seed peers can be added to join a p2pool network.
///
/// Please note that these addresses must be in libp2p multi address format and must contain peer ID
/// or use a dnsaddr multi address!
///
/// By default a Tari provided seed peer is added.
///
/// e.g.:
/// /ip4/127.0.0.1/tcp/52313/p2p/12D3KooWCUNCvi7PBPymgsHx39JWErYdSoT3EFPrn3xoVff4CHFu
/// /dnsaddr/esmeralda.p2pool.tari.com
#[arg(short, long, value_name = "seed-peers")]
pub seed_peers: Option<Vec<String>>,

/// If set, Tari provided seed peers will NOT be automatically added to seed peers list.
#[arg(long, value_name = "no-default-seed-peers", default_value_t = false)]
pub no_default_seed_peers: bool,

/// Starts the node as a stable peer.
///
/// Identity of the peer will be saved locally (to --private-key-location)
/// and ID of the Peer remains the same.
#[arg(long, value_name = "stable-peer", default_value_t = false)]
pub stable_peer: bool,

/// Tribe to enter (a team of miners).
/// A tribe can have any name.
#[arg(
long, value_name = "tribe", default_value = "default", value_parser = validate_tribe
)]
pub tribe: String,

/// Private key folder.
///
/// Needs --stable-peer to be set.
#[arg(
long,
value_name = "private-key-folder",
requires = "stable_peer",
default_value = "."
)]
pub private_key_folder: PathBuf,

/// Mining disabled
///
/// In case it is set, the node will only handle p2p operations,
/// will be syncing with share chain, but not starting gRPC services and no Tari base node needed.
/// By setting this it can be used as a stable node for routing only.
#[arg(long, value_name = "mining-disabled", default_value_t = false)]
pub mining_disabled: bool,

/// mDNS disabled
///
/// If set, mDNS local peer discovery is disabled.
#[arg(long, value_name = "mdns-disabled", default_value_t = false)]
pub mdns_disabled: bool,

/// Stats server disabled
///
/// If set, local stats HTTP server is disabled.
#[arg(long, value_name = "stats-server-disabled", default_value_t = false)]
pub stats_server_disabled: bool,
}

#[derive(Subcommand, Clone, Debug)]
pub enum Commands {
/// Starts sha-p2pool node.
Start {
#[clap(flatten)]
args: StartArgs,
},

/// Generating new identity.
GenerateIdentity,

/// Listing all tribes that are present on the network.
ListTribes {
#[clap(flatten)]
args: StartArgs,
},
}

#[derive(Clone, Parser)]
#[command(version)]
#[command(styles = cli_styles())]
#[command(about = "⛏ Decentralized mining pool for Tari network ⛏", long_about = None)]
pub struct Cli {
#[command(subcommand)]
pub command: Commands,

/// (Optional) base dir.
#[arg(short, long, value_name = "base-dir")]
base_dir: Option<PathBuf>,
}

impl Cli {
pub fn base_dir(&self) -> PathBuf {
self.base_dir
.clone()
.unwrap_or_else(|| dirs::home_dir().unwrap().join(".tari/p2pool"))
}

/// Handles CLI command.
/// [`Cli::parse`] must be called (to have all the args and params set properly)
/// before calling this method.
pub async fn handle_command(&self, cli_shutdown: ShutdownSignal) -> anyhow::Result<()> {
let cli_ref = Arc::new(self.clone());

match &self.command {
Commands::Start { args } => {
commands::handle_start(cli_ref.clone(), args, cli_shutdown.clone()).await?;
},
Commands::GenerateIdentity => {
commands::handle_generate_identity().await?;
},
Commands::ListTribes { args } => {
commands::handle_list_tribes(cli_ref.clone(), args, cli_shutdown.clone()).await?;
},
}

Ok(())
}
}
10 changes: 10 additions & 0 deletions src/cli/commands/generate_identity.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright 2024 The Tari Project
// SPDX-License-Identifier: BSD-3-Clause

use crate::server::p2p;

pub async fn handle_generate_identity() -> anyhow::Result<()> {
let result = p2p::util::generate_identity().await?;
print!("{}", serde_json::to_value(result)?);
Ok(())
}
72 changes: 72 additions & 0 deletions src/cli/commands/list_tribes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright 2024 The Tari Project
// SPDX-License-Identifier: BSD-3-Clause

use std::sync::Arc;
use std::time::Duration;

use anyhow::anyhow;
use itertools::Itertools;
use tari_shutdown::{Shutdown, ShutdownSignal};
use tokio::sync::oneshot;
use tokio::task::JoinHandle;
use tokio::{select, time};

use crate::cli::args::{Cli, StartArgs};
use crate::cli::commands::util;
use crate::server::p2p::peer_store::PeerStore;

pub async fn handle_list_tribes(
cli: Arc<Cli>,
args: &StartArgs,
cli_shutdown_signal: ShutdownSignal,
) -> anyhow::Result<()> {
// start server asynchronously
let cli_ref = cli.clone();
let mut args_clone = args.clone();
args_clone.mining_disabled = true;
args_clone.stats_server_disabled = true;
let mut shutdown = Shutdown::new();
let shutdown_signal = shutdown.to_signal();
let (peer_store_channel_tx, peer_store_channel_rx) = oneshot::channel::<Arc<PeerStore>>();
let handle: JoinHandle<anyhow::Result<()>> = tokio::spawn(async move {
let mut server = util::server(cli_ref, &args_clone, shutdown_signal, false).await?;
match peer_store_channel_tx.send(server.p2p_service().network_peer_store().clone()) {
Ok(_) => server.start().await?,
Err(_) => return Err(anyhow!("Failed to start server")),
}

Ok(())
});

// wait for peer store from started server
let peer_store = peer_store_channel_rx.await?;

// collect tribes for 30 seconds
let mut tribes = vec![];
let timeout = time::sleep(Duration::from_secs(30));
tokio::pin!(timeout);
tokio::pin!(cli_shutdown_signal);
loop {
select! {
_ = &mut cli_shutdown_signal => {
break;
}
() = &mut timeout => {
break;
}
current_tribes = peer_store.tribes() => {
tribes = current_tribes;
if tribes.len() > 1 {
break;
}
}
}
}
shutdown.trigger();
handle.await??;

let tribes = tribes.iter().map(|tribe| tribe.to_string()).collect_vec();
print!("{}", serde_json::to_value(tribes)?);

Ok(())
}
11 changes: 11 additions & 0 deletions src/cli/commands/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright 2024 The Tari Project
// SPDX-License-Identifier: BSD-3-Clause

pub use generate_identity::*;
pub use list_tribes::*;
pub use start::*;

mod generate_identity;
mod list_tribes;
mod start;
mod util;
17 changes: 17 additions & 0 deletions src/cli/commands/start.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright 2024 The Tari Project
// SPDX-License-Identifier: BSD-3-Clause

use std::sync::Arc;

use tari_shutdown::ShutdownSignal;

use crate::cli::args::{Cli, StartArgs};
use crate::cli::commands::util;

pub async fn handle_start(cli: Arc<Cli>, args: &StartArgs, cli_shutdown_signal: ShutdownSignal) -> anyhow::Result<()> {
util::server(cli, args, cli_shutdown_signal, true)
.await?
.start()
.await?;
Ok(())
}
Loading

0 comments on commit 7b3568b

Please sign in to comment.