Skip to content

Commit

Permalink
feat(coinbase-extra): add coinbase extra field (#67)
Browse files Browse the repository at this point in the history
Description
---
Coinbase extra field is cached now (locally) and use other miners'
coinbase extra when possible from share chain for their shares.

Motivation and Context
---
Coinbase extra field was not supported to be passed to p2pool before, so
in order to let miners pass any extra data they want, we need to be able
to do that.

Specs for the format of p2pool coinbase extra field:
#56

How Has This Been Tested?
---

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

<!-- Checklist -->
<!-- 1. Is the title of your PR in the form that would make nice release
notes? The title, excluding the conventional commit
tag, will be included exactly as is in the CHANGELOG, so please think
about it carefully. -->


Breaking Changes
---

- [ ] None
- [ ] Requires data directory on base node to be deleted
- [ ] Requires hard fork
- [x] Other - Please specify - P2pool should be updated at all clients
  • Loading branch information
ksrichard authored Sep 24, 2024
1 parent cd06b20 commit 0139691
Show file tree
Hide file tree
Showing 20 changed files with 492 additions and 316 deletions.
279 changes: 147 additions & 132 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 1 addition & 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.8"
version = "0.1.9"
edition = "2021"

[dependencies]
Expand All @@ -10,7 +10,6 @@ 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 Down
30 changes: 15 additions & 15 deletions src/cli/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use tari_shutdown::ShutdownSignal;

use crate::cli::{
commands,
util::{cli_styles, validate_tribe},
util::{cli_styles, validate_squad},
};

#[allow(clippy::struct_excessive_bools)]
Expand Down Expand Up @@ -63,12 +63,12 @@ pub struct StartArgs {
#[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.
/// Squad to enter (a team of miners).
/// A squad can have any name.
#[arg(
long, value_name = "tribe", default_value = "default", value_parser = validate_tribe
long, alias = "tribe", value_name = "squad", default_value = "default", value_parser = validate_squad
)]
pub tribe: String,
pub squad: String,

/// Private key folder.
///
Expand Down Expand Up @@ -110,10 +110,10 @@ pub struct StartArgs {
}

#[derive(Clone, Parser, Debug)]
pub struct ListTribeArgs {
/// List tribe command timeout in seconds.
pub struct ListSquadArgs {
/// List squad command timeout in seconds.
///
/// The list-tribes commands tries to look for all the currently available tribes
/// The list-squads commands tries to look for all the currently available squads
/// for this amount of time maximum.
#[arg(long, value_name = "timeout", default_value_t = 15)]
pub timeout: u64,
Expand All @@ -130,13 +130,13 @@ pub enum Commands {
/// Generating new identity.
GenerateIdentity,

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

#[clap(flatten)]
list_tribe_args: ListTribeArgs,
list_squad_args: ListSquadArgs,
},
}

Expand All @@ -157,9 +157,9 @@ impl Cli {
.clone()
.unwrap_or_else(|| dirs::home_dir().unwrap().join(".tari/p2pool")),
Commands::GenerateIdentity => dirs::home_dir().unwrap().join(".tari/p2pool"),
Commands::ListTribes {
Commands::ListSquads {
args,
list_tribe_args: _list_tribe_args,
list_squad_args: _list_squad_args,
} => args
.base_dir
.clone()
Expand All @@ -180,8 +180,8 @@ impl Cli {
Commands::GenerateIdentity => {
commands::handle_generate_identity().await?;
},
Commands::ListTribes { args, list_tribe_args } => {
commands::handle_list_tribes(cli_ref.clone(), args, list_tribe_args, cli_shutdown.clone()).await?;
Commands::ListSquads { args, list_squad_args } => {
commands::handle_list_squads(cli_ref.clone(), args, list_squad_args, cli_shutdown.clone()).await?;
},
}

Expand Down
22 changes: 11 additions & 11 deletions src/cli/commands/list_tribes.rs → src/cli/commands/list_squads.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ use tokio::{select, sync::oneshot, task::JoinHandle, time};

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

pub async fn handle_list_tribes(
pub async fn handle_list_squads(
cli: Arc<Cli>,
args: &StartArgs,
list_tribe_args: &ListTribeArgs,
list_squad_args: &ListSquadArgs,
cli_shutdown_signal: ShutdownSignal,
) -> anyhow::Result<()> {
// start server asynchronously
Expand All @@ -43,9 +43,9 @@ pub async fn handle_list_tribes(
// wait for peer store from started server
let peer_store = peer_store_channel_rx.await?;

// collect tribes for the given timeout
let mut tribes = vec![];
let timeout = time::sleep(Duration::from_secs(list_tribe_args.timeout));
// collect squads for the given timeout
let mut squads = vec![];
let timeout = time::sleep(Duration::from_secs(list_squad_args.timeout));
tokio::pin!(timeout);
tokio::pin!(cli_shutdown_signal);
loop {
Expand All @@ -56,9 +56,9 @@ pub async fn handle_list_tribes(
() = &mut timeout => {
break;
}
current_tribes = peer_store.tribes() => {
tribes = current_tribes;
if tribes.len() > 1 {
current_squads = peer_store.squads() => {
squads = current_squads;
if squads.len() > 1 {
break;
}
}
Expand All @@ -67,8 +67,8 @@ pub async fn handle_list_tribes(
shutdown.trigger();
handle.await??;

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

Ok(())
}
4 changes: 2 additions & 2 deletions src/cli/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
// SPDX-License-Identifier: BSD-3-Clause

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

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

use std::{env, sync::Arc};
use std::{collections::HashMap, env, sync::Arc};

use libp2p::identity::Keypair;
use log::info;
Expand All @@ -12,11 +12,12 @@ use tari_core::{
};
use tari_shutdown::ShutdownSignal;
use tari_utilities::hex::Hex;
use tokio::sync::RwLock;

use crate::{
cli::args::{Cli, StartArgs},
server as main_server,
server::{p2p::Tribe, Server},
server::{p2p::Squad, Server},
sharechain::{in_memory::InMemoryShareChain, BlockValidationParams, MAX_BLOCKS_COUNT},
};

Expand Down Expand Up @@ -46,7 +47,7 @@ pub async fn server(
config_builder.with_p2p_port(p2p_port);
}

config_builder.with_tribe(Tribe::from(args.tribe.clone()));
config_builder.with_squad(Squad::from(args.squad.clone()));

// set default tari network specific seed peer address
let mut seed_peers = vec![];
Expand Down Expand Up @@ -99,14 +100,30 @@ genesis_block_hash.to_hex());
consensus_manager.clone(),
genesis_block_hash,
));
let share_chain_sha3x =
InMemoryShareChain::new(MAX_BLOCKS_COUNT, PowAlgorithm::Sha3x, None, consensus_manager.clone())?;
let coinbase_extras_sha3x = Arc::new(RwLock::new(HashMap::<String, Vec<u8>>::new()));
let share_chain_sha3x = InMemoryShareChain::new(
MAX_BLOCKS_COUNT,
PowAlgorithm::Sha3x,
None,
consensus_manager.clone(),
coinbase_extras_sha3x.clone(),
)?;
let coinbase_extras_random_x = Arc::new(RwLock::new(HashMap::<String, Vec<u8>>::new()));
let share_chain_random_x = InMemoryShareChain::new(
MAX_BLOCKS_COUNT,
PowAlgorithm::RandomX,
Some(block_validation_params.clone()),
consensus_manager,
coinbase_extras_random_x.clone(),
)?;

Ok(Server::new(config, share_chain_sha3x, share_chain_random_x, shutdown_signal).await?)
Ok(Server::new(
config,
share_chain_sha3x,
share_chain_random_x,
coinbase_extras_sha3x.clone(),
coinbase_extras_random_x.clone(),
shutdown_signal,
)
.await?)
}
8 changes: 4 additions & 4 deletions src/cli/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ pub fn cli_styles() -> Styles {
.valid(AnsiColor::BrightGreen.on_default())
}

pub fn validate_tribe(tribe: &str) -> Result<String, String> {
if tribe.trim().is_empty() {
return Err(String::from("tribe must be set"));
pub fn validate_squad(squad: &str) -> Result<String, String> {
if squad.trim().is_empty() {
return Err(String::from("squad must be set"));
}

Ok(String::from(tribe))
Ok(String::from(squad))
}
6 changes: 3 additions & 3 deletions src/server/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use libp2p::identity::Keypair;
use crate::server::{
http,
p2p,
p2p::{peer_store::PeerStoreConfig, Tribe},
p2p::{peer_store::PeerStoreConfig, Squad},
};

/// Config is the server configuration struct.
Expand Down Expand Up @@ -68,8 +68,8 @@ impl ConfigBuilder {
self
}

pub fn with_tribe(&mut self, tribe: Tribe) -> &mut Self {
self.config.p2p_service.tribe = tribe;
pub fn with_squad(&mut self, squad: Squad) -> &mut Self {
self.config.p2p_service.squad = squad;
self
}

Expand Down
41 changes: 33 additions & 8 deletions src/server/grpc/p2pool.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2024 The Tari Project
// SPDX-License-Identifier: BSD-3-Clause

use std::{collections::HashMap, sync::Arc, time::Instant};
use std::{collections::HashMap, str::FromStr, sync::Arc, time::Instant};

use log::{debug, error, info, warn};
use minotari_app_grpc::tari_rpc::{
Expand All @@ -16,7 +16,7 @@ use minotari_app_grpc::tari_rpc::{
SubmitBlockResponse,
};
use num_format::{Locale, ToFormattedString};
use tari_common_types::types::FixedHash;
use tari_common_types::{tari_address::TariAddress, types::FixedHash};
use tari_core::{
consensus::ConsensusManager,
proof_of_work::{randomx_difficulty, randomx_factory::RandomXFactory, sha3x_difficulty, Difficulty, PowAlgorithm},
Expand All @@ -37,6 +37,7 @@ use crate::{
P2POOL_STAT_REJECTED_BLOCKS_COUNT,
},
p2p,
p2p::Squad,
stats_store::StatsStore,
},
sharechain::{block::Block, BlockValidationParams, ShareChain, SHARE_COUNT},
Expand Down Expand Up @@ -77,6 +78,9 @@ where S: ShareChain
stats_max_difficulty_since_last_success: Arc<RwLock<Difficulty>>,
consensus_manager: ConsensusManager,
submit_block_semaphore: Arc<Semaphore>,
squad: Squad,
coinbase_extras_sha3x: Arc<RwLock<HashMap<String, Vec<u8>>>>,
coinbase_extras_random_x: Arc<RwLock<HashMap<String, Vec<u8>>>>,
}

impl<S> ShaP2PoolGrpc<S>
Expand All @@ -92,6 +96,9 @@ where S: ShareChain
random_x_factory: RandomXFactory,
consensus_manager: ConsensusManager,
genesis_block_hash: FixedHash,
squad: Squad,
coinbase_extras_sha3x: Arc<RwLock<HashMap<String, Vec<u8>>>>,
coinbase_extras_random_x: Arc<RwLock<HashMap<String, Vec<u8>>>>,
) -> Result<Self, Error> {
Ok(Self {
client: Arc::new(RwLock::new(
Expand All @@ -111,6 +118,9 @@ where S: ShareChain
stats_max_difficulty_since_last_success: Arc::new(RwLock::new(Difficulty::min())),
consensus_manager,
submit_block_semaphore: Arc::new(Semaphore::new(1)),
squad,
coinbase_extras_sha3x,
coinbase_extras_random_x,
})
}

Expand Down Expand Up @@ -153,16 +163,16 @@ where S: ShareChain
{
/// Returns a new block (that can be mined) which contains all the shares generated
/// from the current share chain as coinbase transactions.
#[allow(clippy::too_many_lines)]
async fn get_new_block(
&self,
request: Request<GetNewBlockRequest>,
) -> Result<Response<GetNewBlockResponse>, Status> {
let timer = Instant::now();
let grpc_req = request.into_inner();

// extract pow algo
let grpc_block_header_pow = request
.into_inner()
.pow
.ok_or(Status::invalid_argument("missing pow in request"))?;
let grpc_block_header_pow = grpc_req.pow.ok_or(Status::invalid_argument("missing pow in request"))?;
let grpc_pow_algo = PowAlgos::from_i32(grpc_block_header_pow.pow_algo)
.ok_or_else(|| Status::internal("invalid block header pow algo in request"))?;
let pow_algo = match grpc_pow_algo {
Expand All @@ -187,12 +197,26 @@ where S: ShareChain
.ok_or_else(|| Status::internal("missing miner data"))?;
// let reward = miner_data.reward;

// update coinbase extras cache
let wallet_payment_address = TariAddress::from_str(grpc_req.wallet_payment_address.as_str())
.map_err(|error| Status::failed_precondition(format!("Invalid wallet payment address: {}", error)))?;
let mut coinbase_extras_lock = match pow_algo {
PowAlgorithm::RandomX => self.coinbase_extras_random_x.write().await,
PowAlgorithm::Sha3x => self.coinbase_extras_sha3x.write().await,
};
coinbase_extras_lock.insert(
wallet_payment_address.to_base58(),
util::convert_coinbase_extra(self.squad.clone(), grpc_req.coinbase_extra)
.map_err(|error| Status::internal(format!("failed to convert coinbase extra {error:?}")))?,
);
drop(coinbase_extras_lock);

// request new block template with shares as coinbases
let share_chain = match pow_algo {
PowAlgorithm::RandomX => self.share_chain_random_x.clone(),
PowAlgorithm::Sha3x => self.share_chain_sha3x.clone(),
};
let shares = share_chain.generate_shares().await;
let shares = share_chain.generate_shares(self.squad.clone()).await;

let mut response = self
.client
Expand Down Expand Up @@ -257,6 +281,7 @@ where S: ShareChain
if timer.elapsed() > MAX_ACCEPTABLE_GRPC_TIMEOUT {
warn!(target: LOG_TARGET, "get_new_block took {}ms", timer.elapsed().as_millis());
}

Ok(Response::new(GetNewBlockResponse {
block: Some(response),
target_difficulty: target_difficulty.as_u64(),
Expand Down Expand Up @@ -307,7 +332,7 @@ where S: ShareChain
PowAlgorithm::Sha3x => self.share_chain_sha3x.clone(),
};
let mut block = share_chain
.new_block(grpc_block)
.new_block(grpc_block, self.squad.clone())
.await
.map_err(|error| Status::internal(error.to_string()))?;

Expand Down
Loading

0 comments on commit 0139691

Please sign in to comment.