use binary_sv2::U256;
use bitcoin::{hash_types::BlockHash, hashes::Hash};
use mining_sv2::Target;
use primitive_types::U256 as U256Primitive;
use std::{cmp::max, convert::TryInto, fmt::Write, ops::Div};
pub fn target_to_difficulty(target: Target) -> f64 {
let max_target_bytes = [
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00,
];
let max_target = U256Primitive::from_little_endian(&max_target_bytes);
let target_u256: U256<'static> = target.into();
let mut target_bytes = [0u8; 32];
target_bytes.copy_from_slice(target_u256.inner_as_ref());
let target = U256Primitive::from_little_endian(&target_bytes);
let max_target_high = (max_target >> 128).low_u128() as f64;
let max_target_low = max_target.low_u128() as f64;
let target_high = (target >> 128).low_u128() as f64;
let target_low = target.low_u128() as f64;
let max_target_f64 = max_target_high * (2.0f64.powi(128)) + max_target_low;
let target_f64 = target_high * (2.0f64.powi(128)) + target_low;
max_target_f64 / target_f64
}
pub fn u256_to_block_hash(v: U256<'static>) -> BlockHash {
let hash: [u8; 32] = v.to_vec().try_into().unwrap();
let hash = Hash::from_slice(&hash).unwrap();
BlockHash::from_raw_hash(hash)
}
pub fn bytes_to_hex(bytes: &[u8]) -> String {
let mut s = String::with_capacity(bytes.len() * 2);
for &b in bytes {
write!(&mut s, "{b:02x}")
.expect("Writing hex bytes to pre-allocated string should never fail");
}
s
}
pub fn hash_rate_to_target(
hashrate: f64,
share_per_min: f64,
) -> Result<U256<'static>, HashRateToTargetError> {
if share_per_min == 0.0 {
return Err(HashRateToTargetError::DivisionByZero);
}
if share_per_min.is_sign_negative() {
return Err(HashRateToTargetError::NegativeInput);
};
if hashrate.is_sign_negative() {
return Err(HashRateToTargetError::NegativeInput);
};
let shares_occurrency_frequence = 60_f64 / share_per_min;
let h_times_s = hashrate * shares_occurrency_frequence;
let h_times_s = h_times_s as u128;
let h_times_s_plus_one = max(h_times_s, h_times_s + 1);
let h_times_s_plus_one = from_u128_to_u256(h_times_s_plus_one);
let denominator = h_times_s_plus_one;
let two_to_256_minus_one = [255_u8; 32];
let two_to_256_minus_one = U256Primitive::from_big_endian(two_to_256_minus_one.as_ref());
let mut h_times_s_array = [0u8; 32];
h_times_s_array[16..].copy_from_slice(&h_times_s.to_be_bytes());
let numerator = two_to_256_minus_one - U256Primitive::from_big_endian(h_times_s_array.as_ref());
let mut target = numerator.div(denominator).to_big_endian();
target.reverse();
Ok(U256::<'static>::from(target))
}
pub fn from_u128_to_u256(input: u128) -> U256Primitive {
let input: [u8; 16] = input.to_be_bytes();
let mut be_bytes = [0_u8; 32];
for (i, b) in input.iter().enumerate() {
be_bytes[16 + i] = *b;
}
U256Primitive::from_big_endian(be_bytes.as_ref())
}
pub enum HashRateToTargetError {
DivisionByZero,
NegativeInput,
}