Skip to content

Commit

Permalink
feat: generate and use private key from environment variable and add …
Browse files Browse the repository at this point in the history
…support for dnsaddr seed peers (#27)

Description
---
In order to generate a private key earlier that can be used at any start
from env vars, we needed a solution.
Now there is a new cli option called `--generate-identity`. With this
option, you can generate a new identity (an encoded libp2p private key)
that can be used to set value later for `SHA_P2POOL_IDENTITY`
environment variable (the command outputs a json where `private_key`
field is the one need to use).
If that var is set, when starting p2pool with `--stable-peer` flag, it
will look for first for this env var and tries to decode and use it.
Also `/dnsaddr/*` seed peer addresses were not supported, now it is
supported, so p2pool will parse all the TXT DNS records and add them to
kademlia to bootstrap.

Motivation and Context
---

How Has This Been Tested?
---
```sh
cargo build --release
export SHA_P2POOL_IDENTITY=$(./target/release/sha_p2pool --generate-identity | jq -r '.private_key')
./target/release/sha_p2pool --stable-peer
```

After starting/stopping many times p2pool, the peer ID remains the same.

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

Breaking Changes
---

- [x] None
- [ ] Requires data directory on base node to be deleted
- [ ] Requires hard fork
- [ ] Other - Please specify
  • Loading branch information
ksrichard authored Aug 8, 2024
1 parent 4363494 commit 2a94f40
Show file tree
Hide file tree
Showing 9 changed files with 201 additions and 19 deletions.
39 changes: 35 additions & 4 deletions Cargo.lock

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

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ log4rs = "1.3.0"
axum = "0.7.5"
itertools = "0.13.0"
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"] }

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

use std::env;
use std::path::PathBuf;

use clap::{
builder::{styling::AnsiColor, Styles},
Parser,
};
use libp2p::identity::Keypair;
use tari_common::configuration::Network;
use tari_common::initialize_logging;

use crate::server::p2p;
use crate::sharechain::in_memory::InMemoryShareChain;

mod server;
Expand Down Expand Up @@ -48,9 +52,14 @@ struct Cli {
/// (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!
/// Please note that these addresses must be in libp2p multi address format and must contain peer ID
/// or use a dnsaddr multi address!
///
/// e.g.: /ip4/127.0.0.1/tcp/52313/p2p/12D3KooWCUNCvi7PBPymgsHx39JWErYdSoT3EFPrn3xoVff4CHFu
/// By default a Tari provided seed peer is added.
///
/// e.g.:
/// /ip4/127.0.0.1/tcp/52313/p2p/12D3KooWCUNCvi7PBPymgsHx39JWErYdSoT3EFPrn3xoVff4CHFu
/// /dnsaddr/esme.p2pool.tari.com
#[arg(short, long, value_name = "seed-peers")]
seed_peers: Option<Vec<String>>,

Expand Down Expand Up @@ -91,6 +100,13 @@ struct Cli {
/// If set, local stats HTTP server is disabled.
#[arg(long, value_name = "stats-server-disabled", default_value_t = false)]
stats_server_disabled: bool,

/// Generate identity
///
/// If set, sha_p2pool will only generate a private key in `--private-key-folder`
/// and output a stable peer ID, that could be used later when running as a stable peer.
#[arg(long, value_name = "generate-identity", default_value_t = false)]
generate_identity: bool,
}

impl Cli {
Expand All @@ -105,6 +121,13 @@ impl Cli {
async fn main() -> anyhow::Result<()> {
let cli = Cli::parse();

// generate identity
if cli.generate_identity {
let result = p2p::util::generate_identity().await?;
print!("{}", serde_json::to_value(result)?);
return Ok(());
}

// logger setup
if let Err(e) = initialize_logging(
&cli.base_dir().join("configs/logs.yml"),
Expand All @@ -122,11 +145,29 @@ async fn main() -> anyhow::Result<()> {
if let Some(p2p_port) = cli.p2p_port {
config_builder.with_p2p_port(p2p_port);
}
if let Some(seed_peers) = cli.seed_peers.clone() {
config_builder.with_seed_peers(seed_peers);

// set default tari network specific seed peer address
let mut seed_peers = vec![];
let network = Network::get_current_or_user_setting_or_default();
if network != Network::LocalNet {
let default_seed_peer = format!("/dnsaddr/{}.p2pool.tari.com", network.as_key_str());
seed_peers.push(default_seed_peer);
}
if let Some(cli_seed_peers) = cli.seed_peers.clone() {
seed_peers.extend(cli_seed_peers.iter().cloned());
}
config_builder.with_seed_peers(seed_peers);

config_builder.with_stable_peer(cli.stable_peer);
config_builder.with_private_key_folder(cli.private_key_folder.clone());

// try to extract env var based private key
if let Ok(identity_cbor) = env::var("SHA_P2POOL_IDENTITY") {
let identity_raw = hex::decode(identity_cbor.as_bytes())?;
let private_key = Keypair::from_protobuf_encoding(identity_raw.as_slice())?;
config_builder.with_private_key(Some(private_key));
}

config_builder.with_mining_enabled(!cli.mining_disabled);
config_builder.with_mdns_enabled(!cli.mdns_disabled);
config_builder.with_stats_server_enabled(!cli.stats_server_disabled);
Expand Down
7 changes: 7 additions & 0 deletions src/server/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

use std::{path::PathBuf, time::Duration};

use libp2p::identity::Keypair;

use crate::server::http::stats;
use crate::server::{p2p, p2p::peer_store::PeerStoreConfig};

Expand Down Expand Up @@ -88,6 +90,11 @@ impl ConfigBuilder {
self
}

pub fn with_private_key(&mut self, config: Option<Keypair>) -> &mut Self {
self.config.p2p_service.private_key = config;
self
}

pub fn with_mining_enabled(&mut self, config: bool) -> &mut Self {
self.config.mining_enabled = config;
self
Expand Down
8 changes: 8 additions & 0 deletions src/server/p2p/error.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright 2024 The Tari Project
// SPDX-License-Identifier: BSD-3-Clause

use std::string::FromUtf8Error;

use libp2p::{
gossipsub::PublishError, identity::DecodingError, kad::NoKnownPeers, multiaddr, noise, swarm::DialError,
TransportError,
Expand All @@ -27,6 +29,8 @@ pub enum LibP2PError {
Noise(#[from] noise::Error),
#[error("Multi address parse error: {0}")]
MultiAddrParse(#[from] multiaddr::Error),
#[error("Multi address empty")]
MultiAddrEmpty,
#[error("Transport error: {0}")]
Transport(#[from] TransportError<std::io::Error>),
#[error("I/O error: {0}")]
Expand All @@ -43,4 +47,8 @@ pub enum LibP2PError {
MissingPeerId(String),
#[error("Key decode error: {0}")]
KeyDecoding(#[from] DecodingError),
#[error("Invalid DNS entry: {0}")]
InvalidDnsEntry(String),
#[error("Failed to convert bytes to string: {0}")]
ConvertBytesToString(#[from] FromUtf8Error),
}
1 change: 1 addition & 0 deletions src/server/p2p/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ mod error;
pub mod messages;
mod network;
pub mod peer_store;
pub mod util;
Loading

0 comments on commit 2a94f40

Please sign in to comment.