use rand::Rng;
use sha3::{Sha3_256, Digest};
use serde::{Serialize, Deserialize};
use crate::validate;
use crate::utils::*;
use crate::transaction::{Type, Transaction, group_transactions};
use crate::state::State;
pub const GENESIS_HASH: &str =
"E12BA98A17FD8F70608668AA32AEB3BE1F202B4BD69880A6C0CFE855B1A0706B";
pub const COMPLEXITY: usize = 24;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Block {
pub offset: u64,
pub size: u64,
pub hash_prev: U256,
pub validator: U256,
pub nonce: U256,
pub hash: U256,
}
impl Block {
pub fn new(offset: u64, size: u64, hash_prev: U256, validator: U256,
nonce: U256, hash: U256) -> Self {
Self { offset, size, hash_prev, validator, nonce, hash }
}
pub fn validate(&self, transactions: &[Transaction],
block_info_prev: &BlockInfo, complexity: usize,
state: &State, senders: &[U256]) -> UqoinResult<()> {
validate!(block_info_prev.hash == self.hash_prev,
BlockPreviousHashMismatch)?;
validate!(block_info_prev.offset == self.offset,
BlockOffsetMismatch)?;
Self::validate_transactions(transactions, &self.validator, state,
senders)?;
let msg = Self::calc_msg(&self.hash_prev, &self.validator,
transactions);
let hash = Self::calc_hash(&msg, &self.nonce);
validate!(hash == self.hash, BlockInvalidHash)?;
Self::validate_hash_complexity(&self.hash, transactions.len(),
complexity)?;
Ok(())
}
pub fn build(block_info_prev: &BlockInfo, validator: U256,
transactions: &[Transaction], nonce: U256,
complexity: usize, state: &State,
senders: &[U256]) -> UqoinResult<Self> {
Self::validate_transactions(transactions, &validator, state, senders)?;
let msg = Self::calc_msg(&block_info_prev.hash, &validator,
transactions);
let hash = Self::calc_hash(&msg, &nonce);
Self::validate_hash_complexity(&hash, transactions.len(), complexity)?;
Ok(Self::new(block_info_prev.offset,
transactions.len() as u64,
block_info_prev.hash.clone(),
validator, nonce, hash))
}
#[deprecated(since="0.1.0", note="use groups and check_unique instead")]
pub fn validate_coins(transactions: &[Transaction], state: &State,
senders: &[U256]) -> UqoinResult<()> {
validate!(check_unique(transactions.iter().map(|tr| &tr.coin)),
CoinNotUnique)?;
for (transaction, sender) in transactions.iter().zip(senders.iter()) {
transaction.validate_coin(state, sender)?;
}
Ok(())
}
pub fn validate_transactions(transactions: &[Transaction], validator: &U256,
state: &State, senders: &[U256]) ->
UqoinResult<()> {
validate!(check_unique(transactions.iter().map(|tr| &tr.coin)),
CoinNotUnique)?;
let mut countdown = transactions.len();
for (offset, group, ext) in group_transactions(transactions.to_vec(),
state, senders) {
let group_senders = &senders[offset .. offset + group.len()];
let ext_senders = &senders[
offset + group.len() .. offset + group.len() + ext.len()
];
if let Some(ext_sender) = ext.get_sender(ext_senders) {
validate!(&ext_sender == validator, BlockValidatorMismatch)?;
}
if ext.get_type() != Type::Transfer {
validate!(group.get_order(state, group_senders)
== ext.get_order(state, ext_senders), BlockOrderMismatch)?;
}
countdown -= group.len() + ext.len();
}
validate!(countdown == 0, BlockBroken)?;
Ok(())
}
pub fn validate_hash_complexity(hash: &U256, size: usize,
complexity: usize) -> UqoinResult<()> {
let limit_hash = Self::calc_limit_hash(size, complexity);
validate!(Self::is_hash_valid(&hash.to_bytes(), &limit_hash),
BlockInvalidHashComplexity)
}
pub fn calc_msg(block_hash_prev: &U256, validator: &U256,
transactions: &[Transaction]) -> U256 {
let mut elems = vec![block_hash_prev.clone(), validator.clone()];
elems.extend(transactions.iter().map(|tr| tr.get_hash()));
hash_of_u256(elems.iter())
}
pub fn calc_hash(msg: &U256, nonce: &U256) -> U256 {
hash_of_u256([msg, nonce].into_iter())
}
pub fn is_hash_valid(hash_bytes: &[u8], limit_hash_bytes: &[u8]) -> bool {
hash_bytes <= limit_hash_bytes
}
pub fn mine<R: Rng>(rng: &mut R, block_hash_prev: &U256, validator: &U256,
transactions: &[Transaction],
complexity: usize,
iterations: Option<usize>) -> Option<[u8; 32]> {
let msg = Self::calc_msg(block_hash_prev, validator, transactions);
let size = transactions.len();
let limit_hash = Self::calc_limit_hash(size, complexity);
let mut hasher = Sha3_256::new();
hasher.update(msg.to_bytes());
for iteration in 0.. {
if let Some(iterations) = iterations {
if iteration >= iterations {
break;
}
}
let mut hasher_clone = hasher.clone();
let nonce_bytes: [u8; 32] = rng.random();
hasher_clone.update(nonce_bytes);
let hash_bytes = hasher_clone.finalize();
if Self::is_hash_valid(&hash_bytes, &limit_hash) {
return Some(nonce_bytes);
}
}
None
}
fn calc_limit_hash(size: usize, complexity: usize) -> Vec<u8> {
assert!(complexity > 0);
let mut num = U256::from(1);
num <<= 256 - complexity;
let bytes = if size > 1 {
num.divide_unit(size as u64).unwrap().0.to_bytes()
} else {
num.to_bytes()
};
bytes.into_iter().rev().collect::<Vec<u8>>()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BlockInfo {
pub bix: u64,
pub offset: u64,
pub hash: U256,
}
impl BlockInfo {
pub fn genesis() -> Self {
Self {
bix: 0,
offset: 0,
hash: U256::from_hex(GENESIS_HASH),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BlockData {
pub bix: u64,
pub block: Block,
pub transactions: Vec<Transaction>,
}
impl BlockData {
pub fn genesis() -> Self {
Self {
bix: 0,
block: Block {
offset: 0,
size: 0,
hash_prev: U256::from(0),
validator: U256::from(0),
nonce: U256::from(0),
hash: U256::from_hex(GENESIS_HASH),
},
transactions: Vec::new(),
}
}
pub fn get_block_info(&self) -> BlockInfo {
BlockInfo {
bix: self.bix,
offset: self.block.offset + self.block.size,
hash: self.block.hash.clone(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use test::Bencher;
use crate::schema::Schema;
#[test]
fn test_mine() {
let complexity = 8;
let mut rng = rand::rng();
let schema = Schema::new();
let block_hash_prev: U256 = rng.random();
let validator: U256 = schema.gen_pair(&mut rng).1;
let transactions: Vec<Transaction> = vec![];
let nonce_bytes = Block::mine(&mut rng, &block_hash_prev, &validator,
&transactions, complexity,
Some(10000)).unwrap();
let msg = Block::calc_msg(&block_hash_prev, &validator, &transactions);
let nonce = U256::from_bytes(&nonce_bytes);
let hash = hash_of_u256([&msg, &nonce].into_iter());
let limit_hash = Block::calc_limit_hash(transactions.len(), complexity);
assert!(hash.to_bytes() <= limit_hash);
assert!(Block::is_hash_valid(&hash.to_bytes(), &limit_hash));
}
#[bench]
fn bench_mine_10(bencher: &mut Bencher) {
let size = 10;
let mut rng = rand::rng();
let schema = Schema::new();
let block_hash_prev: U256 = rng.random();
let validator: U256 = schema.gen_pair(&mut rng).1;
let coin: U256 = rng.random();
let addr: U256 = rng.random();
let key: U256 = schema.gen_key(&mut rng);
let transactions: Vec<Transaction> = vec![
Transaction::build(
&mut rng, coin.clone(), addr.clone(), &key, 0, &schema
);
size
];
bencher.iter(|| {
let _nonce = Block::mine(&mut rng, &block_hash_prev, &validator,
&transactions, 1, None);
});
}
}