mirror of
https://github.com/hinto-janai/cuprate.git
synced 2024-12-22 19:49:33 +00:00
This commit is contained in:
parent
6f85531966
commit
e6c96a69fc
5 changed files with 260 additions and 171 deletions
|
@ -40,7 +40,7 @@ async fn main() {
|
||||||
let count = constants::TESTED_BLOCK_COUNT.load(Ordering::Acquire);
|
let count = constants::TESTED_BLOCK_COUNT.load(Ordering::Acquire);
|
||||||
|
|
||||||
if top_height == count {
|
if top_height == count {
|
||||||
println!("finished, took {}s", now.elapsed().as_secs());
|
println!("Finished, took {}s", now.elapsed().as_secs());
|
||||||
std::process::exit(0);
|
std::process::exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,27 +9,12 @@ pub fn randomx_vm_default(seed_hash: &[u8; 32]) -> RandomXVM {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a [`RandomXVM`] with most optimization flags.
|
/// Returns a [`RandomXVM`] with most optimization flags.
|
||||||
|
#[expect(dead_code)]
|
||||||
pub fn randomx_vm_optimized(seed_hash: &[u8; 32]) -> RandomXVM {
|
pub fn randomx_vm_optimized(seed_hash: &[u8; 32]) -> RandomXVM {
|
||||||
// TODO: conditional FLAG_LARGE_PAGES, FLAG_JIT
|
// TODO: conditional FLAG_LARGE_PAGES, FLAG_JIT
|
||||||
|
|
||||||
let mut vm_flag = RandomXFlag::FLAG_FULL_MEM;
|
let vm_flag = RandomXFlag::get_recommended_flags() | RandomXFlag::FLAG_FULL_MEM;
|
||||||
let mut cache_flag = RandomXFlag::empty();
|
let cache_flag = RandomXFlag::get_recommended_flags();
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
|
||||||
for flag in [&mut vm_flag, &mut cache_flag] {
|
|
||||||
if is_x86_feature_detected!("aes") {
|
|
||||||
*flag |= RandomXFlag::FLAG_HARD_AES;
|
|
||||||
}
|
|
||||||
|
|
||||||
match (
|
|
||||||
is_x86_feature_detected!("ssse3"),
|
|
||||||
is_x86_feature_detected!("avx2"),
|
|
||||||
) {
|
|
||||||
(true, _) => *flag |= RandomXFlag::FLAG_ARGON2_SSSE3,
|
|
||||||
(_, true) => *flag |= RandomXFlag::FLAG_ARGON2_AVX2,
|
|
||||||
(_, _) => *flag |= RandomXFlag::FLAG_ARGON2,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let hash = hex::encode(seed_hash);
|
let hash = hex::encode(seed_hash);
|
||||||
|
|
||||||
|
|
|
@ -180,13 +180,7 @@ impl RpcClient {
|
||||||
.try_into()
|
.try_into()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let seed_hash = this
|
let seed_hash = this.get_block(seed_height).await.block_header.hash;
|
||||||
.get_block(seed_height)
|
|
||||||
.await
|
|
||||||
.block_header
|
|
||||||
.hash
|
|
||||||
.try_into()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
(seed_height, seed_hash)
|
(seed_height, seed_hash)
|
||||||
};
|
};
|
||||||
|
|
|
@ -47,7 +47,7 @@ pub struct GetBlockResponse {
|
||||||
pub block_header: BlockHeader,
|
pub block_header: BlockHeader,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize)]
|
#[derive(Debug, Copy, Clone, Deserialize)]
|
||||||
pub(crate) struct BlockHeader {
|
pub(crate) struct BlockHeader {
|
||||||
#[serde(deserialize_with = "deserialize")]
|
#[serde(deserialize_with = "deserialize")]
|
||||||
pub hash: [u8; 32],
|
pub hash: [u8; 32],
|
||||||
|
|
|
@ -6,6 +6,8 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crossbeam::channel::Receiver;
|
use crossbeam::channel::Receiver;
|
||||||
|
use monero_serai::block::Block;
|
||||||
|
use randomx_rs::RandomXVM;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
constants::{RANDOMX_START_HEIGHT, TESTED_BLOCK_COUNT, TESTED_TX_COUNT},
|
constants::{RANDOMX_START_HEIGHT, TESTED_BLOCK_COUNT, TESTED_TX_COUNT},
|
||||||
|
@ -13,13 +15,19 @@ use crate::{
|
||||||
types::{BlockHeader, GetBlockResponse, RpcBlockData, RpcTxData},
|
types::{BlockHeader, GetBlockResponse, RpcBlockData, RpcTxData},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[expect(
|
struct Verifier {
|
||||||
clippy::needless_pass_by_value,
|
id: usize,
|
||||||
clippy::cast_precision_loss,
|
now: Instant,
|
||||||
clippy::cast_possible_truncation,
|
thread_count: NonZeroUsize,
|
||||||
clippy::cast_sign_loss,
|
update: NonZeroU64,
|
||||||
clippy::significant_drop_tightening
|
top_height: u64,
|
||||||
)]
|
rx: Receiver<RpcBlockData>,
|
||||||
|
seed_hash: [u8; 32],
|
||||||
|
timestamp: u64,
|
||||||
|
randomx_vm: Option<RandomXVM>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[expect(clippy::needless_pass_by_value)]
|
||||||
pub fn spawn_verify_pool(
|
pub fn spawn_verify_pool(
|
||||||
thread_count: NonZeroUsize,
|
thread_count: NonZeroUsize,
|
||||||
update: NonZeroU64,
|
update: NonZeroU64,
|
||||||
|
@ -28,167 +36,271 @@ pub fn spawn_verify_pool(
|
||||||
) {
|
) {
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
|
|
||||||
for i in 0..thread_count.get() {
|
for id in 0..thread_count.get() {
|
||||||
let rx = rx.clone();
|
let rx = rx.clone();
|
||||||
|
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
let mut current_seed_hash = [0; 32];
|
Verifier {
|
||||||
let mut randomx_vm = None;
|
id,
|
||||||
|
now,
|
||||||
|
thread_count,
|
||||||
|
update,
|
||||||
|
top_height,
|
||||||
|
rx,
|
||||||
|
seed_hash: [0; 32],
|
||||||
|
timestamp: 0,
|
||||||
|
randomx_vm: None,
|
||||||
|
}
|
||||||
|
.loop_listen_verify();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
loop {
|
impl Verifier {
|
||||||
let Ok(data) = rx.recv() else {
|
fn loop_listen_verify(mut self) {
|
||||||
println!("Exiting verify thread {i}/{thread_count}");
|
loop {
|
||||||
return;
|
let Ok(data) = self.rx.recv() else {
|
||||||
};
|
println!("Exiting verify thread {}/{}", self.id, self.thread_count);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
// Panic info.
|
self.verify(data);
|
||||||
let p = format!("data: {data:#?}");
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let RpcBlockData {
|
fn verify(&mut self, data: RpcBlockData) {
|
||||||
get_block_response,
|
//----------------------------------------------- Create panic info.
|
||||||
block,
|
let p = format!("data: {data:#?}");
|
||||||
seed_height,
|
|
||||||
seed_hash,
|
|
||||||
txs,
|
|
||||||
} = data;
|
|
||||||
let GetBlockResponse { blob, block_header } = get_block_response;
|
|
||||||
let BlockHeader {
|
|
||||||
block_weight,
|
|
||||||
hash,
|
|
||||||
pow_hash,
|
|
||||||
height,
|
|
||||||
major_version,
|
|
||||||
minor_version,
|
|
||||||
miner_tx_hash,
|
|
||||||
nonce,
|
|
||||||
num_txes,
|
|
||||||
prev_hash,
|
|
||||||
reward,
|
|
||||||
timestamp,
|
|
||||||
} = block_header;
|
|
||||||
|
|
||||||
// Test block properties.
|
//----------------------------------------------- Extract data.
|
||||||
assert_eq!(blob, block.serialize(), "{p:#?}");
|
let RpcBlockData {
|
||||||
|
get_block_response,
|
||||||
|
block,
|
||||||
|
seed_height,
|
||||||
|
seed_hash,
|
||||||
|
txs,
|
||||||
|
} = data;
|
||||||
|
let GetBlockResponse { blob, block_header } = get_block_response;
|
||||||
|
|
||||||
assert!(
|
//----------------------------------------------- Calculate some data.
|
||||||
!block.miner_transaction.prefix().outputs.is_empty(),
|
let calculated_block_reward = block
|
||||||
"miner_tx has no outputs\n{p:#?}"
|
.miner_transaction
|
||||||
);
|
.prefix()
|
||||||
|
.outputs
|
||||||
|
.iter()
|
||||||
|
.map(|o| o.amount.unwrap())
|
||||||
|
.sum::<u64>();
|
||||||
|
let calculated_block_weight = txs
|
||||||
|
.iter()
|
||||||
|
.map(|RpcTxData { tx, .. }| tx.weight())
|
||||||
|
.sum::<usize>();
|
||||||
|
let calculated_pow_data = block.serialize_pow_hash();
|
||||||
|
let miner_tx_weight = block.miner_transaction.weight();
|
||||||
|
|
||||||
let block_reward = block
|
//----------------------------------------------- Verify.
|
||||||
.miner_transaction
|
Self::verify_block_properties(&blob, &block, calculated_block_reward, &p);
|
||||||
.prefix()
|
Self::verify_all_transactions_are_unique(&txs, &p);
|
||||||
.outputs
|
Self::verify_transaction_properties(txs, &p);
|
||||||
.iter()
|
|
||||||
.map(|o| o.amount.unwrap())
|
|
||||||
.sum::<u64>();
|
|
||||||
assert_ne!(block_reward, 0, "block reward is 0\n{p:#?}");
|
|
||||||
|
|
||||||
let total_block_weight = txs
|
self.verify_block_fields(
|
||||||
.iter()
|
calculated_block_weight,
|
||||||
.map(|RpcTxData { tx, .. }| tx.weight())
|
calculated_block_reward,
|
||||||
.sum::<usize>();
|
&block,
|
||||||
|
&p,
|
||||||
|
block_header,
|
||||||
|
);
|
||||||
|
|
||||||
// Test all transactions are unique.
|
let algo = self.verify_pow(
|
||||||
{
|
block_header.height,
|
||||||
static TX_SET: LazyLock<Mutex<HashSet<[u8; 32]>>> =
|
seed_hash,
|
||||||
LazyLock::new(|| Mutex::new(HashSet::new()));
|
block_header.pow_hash,
|
||||||
|
&calculated_pow_data,
|
||||||
|
&p,
|
||||||
|
);
|
||||||
|
|
||||||
let mut tx_set = TX_SET.lock().unwrap();
|
//----------------------------------------------- Print progress.
|
||||||
|
self.print_progress(algo, seed_height, miner_tx_weight, block_header);
|
||||||
|
}
|
||||||
|
|
||||||
for tx_hash in txs.iter().map(|RpcTxData { tx_hash, .. }| tx_hash) {
|
fn verify_block_properties(
|
||||||
assert!(
|
block_blob: &[u8],
|
||||||
tx_set.insert(*tx_hash),
|
block: &Block,
|
||||||
"duplicated tx_hash: {}, {p:#?}",
|
calculated_block_reward: u64,
|
||||||
hex::encode(tx_hash),
|
p: &str,
|
||||||
);
|
) {
|
||||||
}
|
// Test block properties.
|
||||||
}
|
assert_eq!(block_blob, block.serialize(), "{p}");
|
||||||
|
|
||||||
// Test transaction properties.
|
assert!(
|
||||||
for RpcTxData {
|
!block.miner_transaction.prefix().outputs.is_empty(),
|
||||||
tx,
|
"miner_tx has no outputs\n{p}"
|
||||||
tx_blob,
|
);
|
||||||
tx_hash,
|
|
||||||
} in txs
|
|
||||||
{
|
|
||||||
assert_eq!(tx_hash, tx.hash(), "{p:#?}, tx: {tx:#?}");
|
|
||||||
assert_ne!(tx.weight(), 0, "{p:#?}, tx: {tx:#?}");
|
|
||||||
assert!(!tx.prefix().inputs.is_empty(), "{p:#?}, tx: {tx:#?}");
|
|
||||||
assert_eq!(tx_blob, tx.serialize(), "{p:#?}, tx: {tx:#?}");
|
|
||||||
assert!(matches!(tx.version(), 1 | 2), "{p:#?}, tx: {tx:#?}");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test block fields are correct.
|
assert_ne!(calculated_block_reward, 0, "block reward is 0\n{p}");
|
||||||
assert_eq!(block_weight, total_block_weight, "{p:#?}");
|
}
|
||||||
assert_ne!(block.miner_transaction.weight(), 0, "{p:#?}");
|
|
||||||
assert_eq!(hash, block.hash(), "{p:#?}");
|
|
||||||
assert_eq!(
|
|
||||||
height,
|
|
||||||
u64::try_from(block.number().unwrap()).unwrap(),
|
|
||||||
"{p:#?}"
|
|
||||||
);
|
|
||||||
assert_eq!(major_version, block.header.hardfork_version, "{p:#?}");
|
|
||||||
assert_eq!(minor_version, block.header.hardfork_signal, "{p:#?}");
|
|
||||||
assert_eq!(miner_tx_hash, block.miner_transaction.hash(), "{p:#?}");
|
|
||||||
assert_eq!(nonce, block.header.nonce, "{p:#?}");
|
|
||||||
assert_eq!(num_txes, block.transactions.len(), "{p:#?}");
|
|
||||||
assert_eq!(prev_hash, block.header.previous, "{p:#?}");
|
|
||||||
assert_eq!(reward, block_reward, "{p:#?}");
|
|
||||||
assert_eq!(timestamp, block.header.timestamp, "{p:#?}");
|
|
||||||
|
|
||||||
//
|
#[expect(clippy::significant_drop_tightening)]
|
||||||
let pow_data = block.serialize_pow_hash();
|
fn verify_all_transactions_are_unique(txs: &[RpcTxData], p: &str) {
|
||||||
|
static TX_SET: LazyLock<Mutex<HashSet<[u8; 32]>>> =
|
||||||
|
LazyLock::new(|| Mutex::new(HashSet::new()));
|
||||||
|
|
||||||
let (algo, calculated_pow_hash) = if height < RANDOMX_START_HEIGHT {
|
let mut tx_set = TX_SET.lock().unwrap();
|
||||||
CryptoNightHash::hash(&pow_data, height)
|
|
||||||
} else {
|
|
||||||
if current_seed_hash != seed_hash {
|
|
||||||
randomx_vm = None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let randomx_vm = randomx_vm.get_or_insert_with(|| {
|
for tx_hash in txs.iter().map(|RpcTxData { tx_hash, .. }| tx_hash) {
|
||||||
current_seed_hash = seed_hash;
|
assert!(
|
||||||
// crate::randomx::randomx_vm_optimized(&seed_hash)
|
tx_set.insert(*tx_hash),
|
||||||
crate::randomx::randomx_vm_default(&seed_hash)
|
"duplicated tx_hash: {}, {p}",
|
||||||
});
|
hex::encode(tx_hash),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let pow_hash = randomx_vm
|
fn verify_transaction_properties(txs: Vec<RpcTxData>, p: &str) {
|
||||||
.calculate_hash(&pow_data)
|
// Test transaction properties.
|
||||||
.unwrap()
|
for RpcTxData {
|
||||||
.try_into()
|
tx,
|
||||||
.unwrap();
|
tx_blob,
|
||||||
|
tx_hash,
|
||||||
|
} in txs
|
||||||
|
{
|
||||||
|
assert_eq!(tx_hash, tx.hash(), "{p}, tx: {tx:#?}");
|
||||||
|
assert_ne!(tx.weight(), 0, "{p}, tx: {tx:#?}");
|
||||||
|
assert!(!tx.prefix().inputs.is_empty(), "{p}, tx: {tx:#?}");
|
||||||
|
assert_eq!(tx_blob, tx.serialize(), "{p}, tx: {tx:#?}");
|
||||||
|
assert!(matches!(tx.version(), 1 | 2), "{p}, tx: {tx:#?}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
("randomx", pow_hash)
|
fn verify_block_fields(
|
||||||
};
|
&mut self,
|
||||||
|
calculated_block_weight: usize,
|
||||||
|
calculated_block_reward: u64,
|
||||||
|
block: &Block,
|
||||||
|
p: &str,
|
||||||
|
BlockHeader {
|
||||||
|
block_weight,
|
||||||
|
hash,
|
||||||
|
pow_hash: _,
|
||||||
|
height,
|
||||||
|
major_version,
|
||||||
|
minor_version,
|
||||||
|
miner_tx_hash,
|
||||||
|
nonce,
|
||||||
|
num_txes,
|
||||||
|
prev_hash,
|
||||||
|
reward,
|
||||||
|
timestamp,
|
||||||
|
}: BlockHeader,
|
||||||
|
) {
|
||||||
|
// Test block fields are correct.
|
||||||
|
assert_eq!(block_weight, calculated_block_weight, "{p}");
|
||||||
|
assert_ne!(block.miner_transaction.weight(), 0, "{p}");
|
||||||
|
assert_eq!(hash, block.hash(), "{p}");
|
||||||
|
assert_eq!(
|
||||||
|
height,
|
||||||
|
u64::try_from(block.number().unwrap()).unwrap(),
|
||||||
|
"{p}"
|
||||||
|
);
|
||||||
|
assert_eq!(major_version, block.header.hardfork_version, "{p}");
|
||||||
|
assert_eq!(minor_version, block.header.hardfork_signal, "{p}");
|
||||||
|
assert_eq!(miner_tx_hash, block.miner_transaction.hash(), "{p}");
|
||||||
|
assert_eq!(nonce, block.header.nonce, "{p}");
|
||||||
|
assert_eq!(num_txes, block.transactions.len(), "{p}");
|
||||||
|
assert_eq!(prev_hash, block.header.previous, "{p}");
|
||||||
|
assert_eq!(reward, calculated_block_reward, "{p}");
|
||||||
|
assert_eq!(timestamp, block.header.timestamp, "{p}");
|
||||||
|
|
||||||
assert_eq!(calculated_pow_hash, pow_hash, "{p:#?}",);
|
if timestamp != 0 {
|
||||||
|
assert!(timestamp > self.timestamp, "{p}");
|
||||||
|
self.timestamp = timestamp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let count = TESTED_BLOCK_COUNT.fetch_add(1, Ordering::Release) + 1;
|
fn verify_pow(
|
||||||
let total_tx_count = TESTED_TX_COUNT.fetch_add(num_txes, Ordering::Release) + 1;
|
&mut self,
|
||||||
|
height: u64,
|
||||||
|
seed_hash: [u8; 32],
|
||||||
|
pow_hash: [u8; 32],
|
||||||
|
calculated_pow_data: &[u8],
|
||||||
|
p: &str,
|
||||||
|
) -> &'static str {
|
||||||
|
let (algo, calculated_pow_hash) = if height < RANDOMX_START_HEIGHT {
|
||||||
|
CryptoNightHash::hash(calculated_pow_data, height)
|
||||||
|
} else {
|
||||||
|
if self.seed_hash != seed_hash {
|
||||||
|
self.randomx_vm = None;
|
||||||
|
}
|
||||||
|
|
||||||
if count % update.get() != 0 {
|
let randomx_vm = self.randomx_vm.get_or_insert_with(|| {
|
||||||
continue;
|
self.seed_hash = seed_hash;
|
||||||
}
|
// crate::randomx::randomx_vm_optimized(&seed_hash)
|
||||||
|
crate::randomx::randomx_vm_default(&seed_hash)
|
||||||
|
});
|
||||||
|
|
||||||
let pow_hash = hex::encode(pow_hash);
|
let pow_hash = randomx_vm
|
||||||
let seed_hash = hex::encode(seed_hash);
|
.calculate_hash(calculated_pow_data)
|
||||||
let percent = (count as f64 / top_height as f64) * 100.0;
|
.unwrap()
|
||||||
|
.try_into()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let elapsed = now.elapsed().as_secs_f64();
|
("randomx", pow_hash)
|
||||||
let secs_per_hash = elapsed / count as f64;
|
};
|
||||||
let bps = count as f64 / elapsed;
|
|
||||||
let remaining_secs = (top_height as f64 - count as f64) * secs_per_hash;
|
|
||||||
let h = (remaining_secs / 60.0 / 60.0) as u64;
|
|
||||||
let m = (remaining_secs / 60.0 % 60.0) as u64;
|
|
||||||
let s = (remaining_secs % 60.0) as u64;
|
|
||||||
|
|
||||||
let block_hash = hex::encode(hash);
|
assert_eq!(calculated_pow_hash, pow_hash, "{p}",);
|
||||||
let miner_tx_hash = hex::encode(miner_tx_hash);
|
|
||||||
let prev_hash = hex::encode(prev_hash);
|
|
||||||
let miner_tx_weight = block.miner_transaction.weight();
|
|
||||||
|
|
||||||
println!("progress | {count}/{top_height} ({percent:.2}%, {algo}, {bps:.2} blocks/sec, {h}h {m}m {s}s left)
|
algo
|
||||||
|
}
|
||||||
|
|
||||||
|
#[expect(
|
||||||
|
clippy::cast_precision_loss,
|
||||||
|
clippy::cast_possible_truncation,
|
||||||
|
clippy::cast_sign_loss
|
||||||
|
)]
|
||||||
|
fn print_progress(
|
||||||
|
&self,
|
||||||
|
algo: &'static str,
|
||||||
|
seed_height: u64,
|
||||||
|
miner_tx_weight: usize,
|
||||||
|
BlockHeader {
|
||||||
|
block_weight,
|
||||||
|
hash,
|
||||||
|
pow_hash,
|
||||||
|
height,
|
||||||
|
major_version,
|
||||||
|
minor_version,
|
||||||
|
miner_tx_hash,
|
||||||
|
nonce,
|
||||||
|
num_txes,
|
||||||
|
prev_hash,
|
||||||
|
reward,
|
||||||
|
timestamp,
|
||||||
|
}: BlockHeader,
|
||||||
|
) {
|
||||||
|
let count = TESTED_BLOCK_COUNT.fetch_add(1, Ordering::Release) + 1;
|
||||||
|
let total_tx_count = TESTED_TX_COUNT.fetch_add(num_txes, Ordering::Release) + 1;
|
||||||
|
|
||||||
|
if count % self.update.get() != 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let top_height = self.top_height;
|
||||||
|
|
||||||
|
let percent = (count as f64 / top_height as f64) * 100.0;
|
||||||
|
|
||||||
|
let elapsed = self.now.elapsed().as_secs_f64();
|
||||||
|
let secs_per_hash = elapsed / count as f64;
|
||||||
|
let bps = count as f64 / elapsed;
|
||||||
|
let remaining_secs = (top_height as f64 - count as f64) * secs_per_hash;
|
||||||
|
let h = (remaining_secs / 60.0 / 60.0) as u64;
|
||||||
|
let m = (remaining_secs / 60.0 % 60.0) as u64;
|
||||||
|
let s = (remaining_secs % 60.0) as u64;
|
||||||
|
|
||||||
|
let pow_hash = hex::encode(pow_hash);
|
||||||
|
let seed_hash = hex::encode(self.seed_hash);
|
||||||
|
let block_hash = hex::encode(hash);
|
||||||
|
let miner_tx_hash = hex::encode(miner_tx_hash);
|
||||||
|
let prev_hash = hex::encode(prev_hash);
|
||||||
|
|
||||||
|
println!("progress | {count}/{top_height} ({percent:.2}%, {algo}, {bps:.2} blocks/sec, {h}h {m}m {s}s left)
|
||||||
seed_hash | {seed_hash}
|
seed_hash | {seed_hash}
|
||||||
pow_hash | {pow_hash}
|
pow_hash | {pow_hash}
|
||||||
block_hash | {block_hash}
|
block_hash | {block_hash}
|
||||||
|
@ -206,7 +318,5 @@ major_version | {major_version}
|
||||||
minor_version | {minor_version}
|
minor_version | {minor_version}
|
||||||
num_txes | {num_txes}\n",
|
num_txes | {num_txes}\n",
|
||||||
);
|
);
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue