#[cfg(not(target_family = "wasm"))]
use crate::pow::miner::{Miner, MinerBuilder, MinerCancel};
#[cfg(target_family = "wasm")]
use crate::pow::wasm_miner::{SingleThreadedMiner, SingleThreadedMinerBuilder};
use crate::{
client::{ClientInner, Error, Result},
types::block::{parent::Parents, payload::Payload, Block, BlockBuilder, Error as BlockError},
};
impl ClientInner {
pub async fn finish_block_builder(&self, parents: Option<Parents>, payload: Option<Payload>) -> Result<Block> {
if self.get_local_pow().await {
self.finish_pow(parents, payload).await
} else {
let parents = match parents {
Some(parents) => parents,
None => Parents::from_vec(self.get_tips().await?)?,
};
Ok(BlockBuilder::new(parents).with_payload(payload).finish()?)
}
}
pub async fn finish_pow(&self, parents: Option<Parents>, payload: Option<Payload>) -> Result<Block> {
#[cfg(not(target_family = "wasm"))]
let block = self.finish_multi_threaded_pow(parents, payload).await?;
#[cfg(target_family = "wasm")]
let block = self.finish_single_threaded_pow(parents, payload).await?;
Ok(block)
}
#[cfg(not(target_family = "wasm"))]
async fn finish_multi_threaded_pow(&self, parents: Option<Parents>, payload: Option<Payload>) -> Result<Block> {
let pow_worker_count = *self.pow_worker_count.read().await;
let min_pow_score = self.get_min_pow_score().await?;
let tips_interval = self.get_tips_interval().await;
loop {
let cancel = MinerCancel::new();
let cancel_2 = cancel.clone();
let payload_ = payload.clone();
let parents = match &parents {
Some(parents) => parents.clone(),
None => Parents::from_vec(self.get_tips().await?)?,
};
let time_thread = std::thread::spawn(move || Ok(pow_timeout(tips_interval, cancel)));
let pow_thread = std::thread::spawn(move || {
let mut client_miner = MinerBuilder::new().with_cancel(cancel_2);
if let Some(worker_count) = pow_worker_count {
client_miner = client_miner.with_num_workers(worker_count);
}
do_pow(client_miner.finish(), min_pow_score, payload_, parents).map(Some)
});
for t in [pow_thread, time_thread] {
match t.join().expect("failed to join threads.") {
Ok(block) => {
if let Some(block) = block {
return Ok(block);
}
}
Err(Error::Block(BlockError::NonceNotFound)) => {}
Err(err) => {
return Err(err);
}
}
}
}
}
#[cfg(target_family = "wasm")]
async fn finish_single_threaded_pow(&self, parents: Option<Parents>, payload: Option<Payload>) -> Result<Block> {
let min_pow_score: u32 = self.get_min_pow_score().await?;
let tips_interval: u64 = self.get_tips_interval().await;
loop {
let parents = match &parents {
Some(parents) => parents.clone(),
None => Parents::from_vec(self.get_tips().await?)?,
};
let single_threaded_miner = SingleThreadedMinerBuilder::new()
.with_timeout_in_seconds(tips_interval)
.finish();
match do_pow(single_threaded_miner, min_pow_score, payload.clone(), parents) {
Ok(block) => {
return Ok(block);
}
Err(Error::Block(BlockError::NonceNotFound)) => {}
Err(err) => {
return Err(err);
}
}
}
}
}
fn do_pow(
#[cfg(not(target_family = "wasm"))] miner: Miner,
#[cfg(target_family = "wasm")] miner: SingleThreadedMiner,
min_pow_score: u32,
payload: Option<Payload>,
parents: Parents,
) -> Result<Block> {
Ok(BlockBuilder::new(parents)
.with_payload(payload)
.finish_nonce(|bytes| miner.nonce(bytes, min_pow_score))?)
}
#[cfg(not(target_family = "wasm"))]
fn pow_timeout(after_seconds: u64, cancel: MinerCancel) -> Option<Block> {
std::thread::sleep(std::time::Duration::from_secs(after_seconds));
cancel.trigger();
None
}