#![deny(non_upper_case_globals)]
#![deny(non_camel_case_types)]
#![deny(non_snake_case)]
#![deny(unused_mut)]
use chrono;
use num;
#[macro_use]
mod common;
pub mod cuckaroo;
pub mod cuckatoo;
mod error;
#[allow(dead_code)]
pub mod lean;
pub mod md5;
pub mod progpow;
pub mod randomx;
mod siphash;
mod types;
use crate::core::{Block, BlockHeader};
use crate::genesis;
use crate::global;
use chrono::{NaiveDateTime, TimeZone, Utc};
pub use self::common::EdgeType;
pub use self::types::*;
pub use crate::pow::cuckaroo::{new_cuckaroo_ctx, CuckarooContext};
pub use crate::pow::cuckatoo::{new_cuckatoo_ctx, CuckatooContext};
pub use crate::pow::error::Error;
pub use crate::pow::md5::{new_md5_ctx, MD5Context};
pub use crate::pow::progpow::{new_progpow_ctx, ProgPowContext};
pub use crate::pow::randomx::{new_randomx_ctx, RXContext};
const MAX_SOLS: u32 = 10;
pub fn verify_size(bh: &BlockHeader) -> Result<(), Error> {
let mut ctx = match bh.pow.proof {
Proof::ProgPowProof { .. } => new_progpow_ctx(),
Proof::RandomXProof { .. } => new_randomx_ctx(bh.pow.seed),
Proof::MD5Proof { .. } => new_md5_ctx(bh.pow.edge_bits(), global::proofsize(), MAX_SOLS),
Proof::CuckooProof { ref nonces, .. } => Ok(global::create_pow_context::<u64>(
bh.height,
bh.pow.edge_bits(),
nonces.len(),
MAX_SOLS,
)?),
}
.unwrap();
if let Proof::CuckooProof { .. } = bh.pow.proof {
ctx.set_header_nonce(bh.pre_pow(), None, Some(bh.height), false)?;
} else {
ctx.set_header_nonce(bh.pre_pow(), Some(bh.pow.nonce), Some(bh.height), false)?;
}
ctx.verify(&bh.pow.proof)
}
pub fn mine_genesis_block() -> Result<Block, Error> {
let mut gen = genesis::genesis_dev();
if global::is_user_testing_mode() {
gen.header.timestamp = Utc::now();
}
let genesis_difficulty = gen.header.pow.total_difficulty.clone();
let sz = global::min_edge_bits();
let proof_size = global::proofsize();
pow_size(&mut gen.header, genesis_difficulty, proof_size, sz)?;
Ok(gen)
}
pub fn pow_size(
bh: &mut BlockHeader,
diff: Difficulty,
proof_size: usize,
sz: u8,
) -> Result<(), Error> {
let start_nonce = bh.pow.nonce;
if bh.height == 0 && global::is_user_testing_mode() {
bh.pow.nonce = global::get_genesis_nonce();
}
loop {
let mut ctx = global::create_pow_context::<u32>(bh.height, sz, proof_size, MAX_SOLS)?;
ctx.set_header_nonce(bh.pre_pow(), None, None, true)?;
if let Ok(proofs) = ctx.pow_solve() {
bh.pow.proof = proofs[0].clone();
if bh
.pow
.to_difficulty(&bh.pre_pow(), bh.height, bh.pow.nonce)
.to_num(PoWType::Cuckatoo)
>= diff.to_num(PoWType::Cuckatoo)
{
return Ok(());
}
}
let (res, _) = bh.pow.nonce.overflowing_add(1);
bh.pow.nonce = res;
if bh.pow.nonce == start_nonce {
bh.timestamp = TimeZone::from_utc_datetime(
&Utc,
&NaiveDateTime::from_timestamp_opt(0, 0).unwrap(),
);
}
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::genesis;
use crate::global;
use crate::global::ChainTypes;
#[test]
fn genesis_pow() {
global::set_mining_mode(ChainTypes::UserTesting);
let mut b = genesis::genesis_dev();
b.header.pow.nonce = 28106;
if let Proof::CuckooProof {
ref mut edge_bits, ..
} = b.header.pow.proof
{
*edge_bits = global::min_edge_bits();
}
println!("proof {}", global::proofsize());
pow_size(
&mut b.header,
Difficulty::min(),
global::proofsize(),
global::min_edge_bits(),
)
.unwrap();
println!("nonce {}", b.header.pow.nonce);
assert_ne!(b.header.pow.nonce, 310);
assert!(
b.header
.pow
.to_difficulty(&b.header.pre_pow(), b.header.height, b.header.pow.nonce)
>= Difficulty::min()
);
assert!(verify_size(&b.header).is_ok());
}
}