Skip to content

Commit

Permalink
Merge pull request #1195 from plebhash/nominal-hashrate-multiplier
Browse files Browse the repository at this point in the history
add `--nominal-hashrate-multiplier` to `mining-device`
  • Loading branch information
plebhash authored Oct 9, 2024
2 parents c05d8cd + 1ae28db commit e65cb32
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 23 deletions.
55 changes: 47 additions & 8 deletions roles/test-utils/mining-device/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,58 @@
Header only sv2 cpu miner.

```
Usage: mining-device [OPTIONS] --address-pool <ADDRESS_POOL>
Usage: mining_device [OPTIONS] --address-pool <ADDRESS_POOL>
Options:
-p, --pubkey-pool <PUBKEY_POOL> Pool pub key, when left empty the pool certificate is not checked
-i, --id-device <ID_DEVICE> Sometimes used by the pool to identify the device
-a, --address-pool <ADDRESS_POOL> Address of the pool in this format ip:port or domain:port
--handicap <HANDICAP> This value is used to slow down the cpu miner, it represents the number of micro-seconds that are awaited between hashes [default: 0]
--id-user <ID_USER> User id, used when a new channel is opened, it can be used by the pool to identify the miner
-h, --help Print help
-V, --version Print version
-p, --pubkey-pool <PUBKEY_POOL>
Pool pub key, when left empty the pool certificate is not checked
-i, --id-device <ID_DEVICE>
Sometimes used by the pool to identify the device
-a, --address-pool <ADDRESS_POOL>
Address of the pool in this format ip:port or domain:port
--handicap <HANDICAP>
This value is used to slow down the cpu miner, it represents the number of micro-seconds that are awaited between hashes [default: 0]
--id-user <ID_USER>
User id, used when a new channel is opened, it can be used by the pool to identify the miner
--nominal-hashrate-multiplier <NOMINAL_HASHRATE_MULTIPLIER>
This floating point number is used to modify the advertised nominal hashrate when opening a channel with the upstream.
If 0.0 < nominal_hashrate_multiplier < 1.0, the CPU miner will advertise a nominal hashrate that is smaller than its real capacity.
If nominal_hashrate_multiplier > 1.0, the CPU miner will advertise a nominal hashrate that is bigger than its real capacity.
If empty, the CPU miner will simply advertise its real capacity.
-h, --help
Print help
-V, --version
Print version
```

Usage example:
```
cargo run --release -- --address-pool 127.0.0.1:20000 --id-device device_id::SOLO::bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh
```

## handicap

CPU mining could damage the system due to excessive heat.

The `--handicap` parameter should be used as a safety mechanism to slow down the hashrate in order to preserve hardware.

## nominal hashrate multiplier

Let's imagine that:
- the upstream wants to receive shares every ~100s (on average)
- the CPU miner nominal hashrate is 1k H/s

Maybe we want to do a test where we don't want to wait ~100s before a share is submitted by the CPU miner.

In that case, we need the CPU miner to advertise a smaller hashrate, which will force the upstream to set a lower
difficulty target.

The `--nominal-hashrate-multiplier` can be used to advertise a custom nominal hashrate.

In the scenario described above, we could launch the CPU miner with `--nominal-hashrate-multiplier 0.01`.

The CPU miner would advertise 0.01k H/s, which would cause the upstream to set the difficulty target such that the CPU miner would find a share within ~1s.

This feature can also be used to advertise a bigger nominal hashrate by using values above `1.0`.

That can also be useful for testing difficulty adjustment algorithms on Sv2 upstreams.
52 changes: 37 additions & 15 deletions roles/test-utils/mining-device/src/lib/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use std::{
atomic::{AtomicBool, Ordering},
Arc,
},
thread::available_parallelism,
time::Duration,
};
use tokio::net::TcpStream;
Expand Down Expand Up @@ -42,6 +43,7 @@ pub async fn connect(
device_id: Option<String>,
user_id: Option<String>,
handicap: u32,
nominal_hashrate_multiplier: Option<f32>,
) {
let address = address
.clone()
Expand Down Expand Up @@ -77,7 +79,16 @@ pub async fn connect(
.await
.unwrap();
info!("Pool noise connection established at {}", address);
Device::start(receiver, sender, address, device_id, user_id, handicap).await
Device::start(
receiver,
sender,
address,
device_id,
user_id,
handicap,
nominal_hashrate_multiplier,
)
.await
}

pub type Message = MiningDeviceMessages<'static>;
Expand Down Expand Up @@ -193,13 +204,21 @@ pub struct Device {
notify_changes_to_mining_thread: NewWorkNotifier,
}

fn open_channel(device_id: Option<String>) -> OpenStandardMiningChannel<'static> {
fn open_channel(
device_id: Option<String>,
nominal_hashrate_multiplier: Option<f32>,
handicap: u32,
) -> OpenStandardMiningChannel<'static> {
let user_identity = device_id.unwrap_or_default().try_into().unwrap();
let id: u32 = 10;
info!("Measuring CPU hashrate");
let p = std::thread::available_parallelism().unwrap().get() as u32 - 3;
let nominal_hash_rate = measure_hashrate(5) as f32 * p as f32;
info!("Pc hashrate is {}", nominal_hash_rate);
let measured_hashrate = measure_hashrate(5, handicap) as f32;
info!("Measured CPU hashrate is {}", measured_hashrate);
let nominal_hash_rate = match nominal_hashrate_multiplier {
Some(m) => measured_hashrate * m,
None => measured_hashrate,
};

info!("MINING DEVICE: send open channel with request id {}", id);
OpenStandardMiningChannel {
request_id: id.into(),
Expand All @@ -217,6 +236,7 @@ impl Device {
device_id: Option<String>,
user_id: Option<String>,
handicap: u32,
nominal_hashrate_multiplier: Option<f32>,
) {
let setup_connection_handler = Arc::new(Mutex::new(SetupConnectionHandler::new()));
SetupConnectionHandler::setup(
Expand Down Expand Up @@ -244,8 +264,9 @@ impl Device {
sender: notify_changes_to_mining_thread,
},
};
let open_channel =
MiningDeviceMessages::Mining(Mining::OpenStandardMiningChannel(open_channel(user_id)));
let open_channel = MiningDeviceMessages::Mining(Mining::OpenStandardMiningChannel(
open_channel(user_id, nominal_hashrate_multiplier, handicap),
));
let frame: StdFrame = open_channel.try_into().unwrap();
self_.sender.send(frame.into()).await.unwrap();
let self_mutex = std::sync::Arc::new(Mutex::new(self_));
Expand Down Expand Up @@ -597,7 +618,7 @@ impl NextShareOutcome {
}

// returns hashrate based on how fast the device hashes over the given duration
fn measure_hashrate(duration_secs: u64) -> f64 {
fn measure_hashrate(duration_secs: u64, handicap: u32) -> f64 {
let mut rng = thread_rng();
let prev_hash: [u8; 32] = generate_random_32_byte_array().to_vec().try_into().unwrap();
let prev_hash = Hash::from_inner(prev_hash);
Expand All @@ -619,7 +640,7 @@ fn measure_hashrate(duration_secs: u64) -> f64 {
let start_time = Instant::now();
let mut hashes: u64 = 0;
let duration = Duration::from_secs(duration_secs);
let mut miner = Miner::new(0);
let mut miner = Miner::new(handicap);
// We put the target to 0 we are only interested in how many hashes per unit of time we can do
// and do not want to be botherd by messages about valid shares found.
miner.new_target(vec![0_u8; 32]);
Expand All @@ -631,7 +652,12 @@ fn measure_hashrate(duration_secs: u64) -> f64 {
}

let elapsed_secs = start_time.elapsed().as_secs_f64();
hashes as f64 / elapsed_secs
let hashrate_single_thread = hashes as f64 / elapsed_secs;

// we just measured for a single thread, need to multiply by the available parallelism
let p = available_parallelism().unwrap().get();

hashrate_single_thread * p as f64
}
fn generate_random_32_byte_array() -> [u8; 32] {
let mut rng = thread_rng();
Expand All @@ -648,11 +674,7 @@ fn start_mining_threads(
tokio::task::spawn(async move {
let mut killers: Vec<Arc<AtomicBool>> = vec![];
loop {
let available_parallelism = u32::max(
2,
std::thread::available_parallelism().unwrap().get() as u32,
);
let p = available_parallelism - 1;
let p = available_parallelism().unwrap().get() as u32;
let unit = u32::MAX / p;
while have_new_job.recv().await.is_ok() {
while let Some(killer) = killers.pop() {
Expand Down
9 changes: 9 additions & 0 deletions roles/test-utils/mining-device/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ struct Args {
help = "User id, used when a new channel is opened, it can be used by the pool to identify the miner"
)]
id_user: Option<String>,
#[arg(
long,
help = "This floating point number is used to modify the advertised nominal hashrate when opening a channel with the upstream.\
\nIf 0.0 < nominal_hashrate_multiplier < 1.0, the CPU miner will advertise a nominal hashrate that is smaller than its real capacity.\
\nIf nominal_hashrate_multiplier > 1.0, the CPU miner will advertise a nominal hashrate that is bigger than its real capacity.\
\nIf empty, the CPU miner will simply advertise its real capacity."
)]
nominal_hashrate_multiplier: Option<f32>,
}

#[tokio::main(flavor = "current_thread")]
Expand All @@ -52,6 +60,7 @@ async fn main() {
args.id_device,
args.id_user,
args.handicap,
args.nominal_hashrate_multiplier,
)
.await;
}

0 comments on commit e65cb32

Please sign in to comment.