diff --git a/src/block.rs b/src/block.rs index 62f05a0..3675f47 100644 --- a/src/block.rs +++ b/src/block.rs @@ -27,7 +27,7 @@ macro_rules! bytes_to_u64 { #[derive(Debug, Clone)] pub struct BasicInfo { pub timestamp: u64, - pub pow: U256, + pub pow: [u8; 32], pub previous_hash: Hash, pub height: U256, pub difficulty: Hash, @@ -37,7 +37,7 @@ pub struct BasicInfo { impl BasicInfo { pub fn new( timestamp: u64, - pow: U256, + pow: [u8; 32], previous_hash: Hash, height: U256, difficulty: Hash, @@ -54,7 +54,7 @@ impl BasicInfo { } pub fn get_dump_size(&self) -> usize { - 8 + tools::u256_size(&self.pow) + 32 + tools::u256_size(&self.height) + 32 + 33 + 8 + 32 + 32 + tools::u256_size(&self.height) + 32 + 33 } pub fn dump(&self, buffer: &mut Vec) -> Result<(), BlockError> { // dumping timestamp @@ -67,6 +67,9 @@ impl BasicInfo { buffer.push(*byte); } + // dumping pow + buffer.extend(self.pow); + // dumping difficulty buffer.extend(self.difficulty); @@ -76,9 +79,6 @@ impl BasicInfo { // dumping height tools::dump_u256(&self.height, buffer).unwrap(); - // dumping PoW - tools::dump_u256(&self.pow, buffer).unwrap(); - Ok(()) } @@ -100,6 +100,10 @@ impl BasicInfo { let previous_hash: Hash = unsafe { data[index..index + 32].try_into().unwrap_unchecked() }; index += 32; + // parsing difficulty + let pow: Hash = unsafe { data[index..index + 32].try_into().unwrap_unchecked() }; + index += 32; + // parsing difficulty let difficulty: Hash = unsafe { data[index..index + 32].try_into().unwrap_unchecked() }; index += 32; @@ -113,10 +117,6 @@ impl BasicInfo { .change_context(BlockError::BasicInfo(BasicInfoErrorKind::Parse))?; index += height_size + 1; - // parsing POW - let (pow, _) = tools::load_u256(&data[index..]) - .change_context(BlockError::BasicInfo(BasicInfoErrorKind::Parse))?; - Ok(BasicInfo { timestamp, pow, @@ -317,13 +317,10 @@ impl Block for DerivativeBlock { return Ok(false); } - let mut pow: [u8; 32] = [0; 32]; - self.default_info.pow.to_big_endian(&mut pow); - if !check_pow( &self.get_merkle_root(), &prev_block.get_info().difficulty, - &pow, + &self.default_info.pow, ) { return Ok(false); } @@ -413,13 +410,10 @@ impl Block for TransactionBlock { return Ok(false); } - let mut pow: [u8; 32] = [0; 32]; - self.default_info.pow.to_big_endian(&mut pow); - if !check_pow( &self.merkle_tree_root, &prev_block.get_info().difficulty, - &pow, + &self.default_info.pow, ) { return Ok(false); } @@ -547,13 +541,10 @@ impl Block for SummarizeBlock { return Ok(false); } - let mut pow: [u8; 32] = [0; 32]; - self.default_info.pow.to_big_endian(&mut pow); - if !check_pow( &self.merkle_tree_root, &prev_block.get_info().difficulty, - &pow, + &self.default_info.pow, ) { return Ok(false); } diff --git a/src/blockchaintree.rs b/src/blockchaintree.rs index 0235978..bb47e75 100644 --- a/src/blockchaintree.rs +++ b/src/blockchaintree.rs @@ -1,10 +1,10 @@ use std::{collections::HashMap, path::Path}; use crate::{ - block::{BlockArc, TransactionBlock}, + block::{self, BlockArc, TransactionBlock}, chain, errors::{BCTreeErrorKind, BlockChainTreeError}, - tools, + merkletree, tools, transaction::Transaction, txpool, }; @@ -42,12 +42,14 @@ static MAX_DIFFICULTY: [u8; 32] = [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 128, ]; +pub static FEE_STEP: u64 = 1000000; + pub static ROOT_PRIVATE_ADDRESS: [u8; 32] = [1u8; 32]; pub static ROOT_PUBLIC_ADDRESS: [u8; 33] = [ 3, 27, 132, 197, 86, 123, 18, 100, 64, 153, 93, 62, 213, 170, 186, 5, 101, 215, 30, 24, 52, 96, 72, 25, 255, 156, 23, 245, 233, 213, 221, 7, 143, ]; - +pub static BLOCKS_PER_EPOCH: u64 = 100000; pub static INCEPTION_TIMESTAMP: u64 = 1597924800; pub struct BlockChainTree { @@ -313,24 +315,81 @@ impl BlockChainTree { self.main_chain.add_transactions(transactions).await } + fn summarize(&self) -> Result<[u8; 32], Report> { + let mut hashes: Vec<[u8; 32]> = Vec::with_capacity(self.summary_db.len()); + for res in self.summary_db.iter() { + let (address, amount) = res + .change_context(BlockChainTreeError::BlockChainTree( + BCTreeErrorKind::GetFunds, + )) + .attach_printable("failed to get funds from summary_db")?; + let gas_amount = self + .gas_db + .get(&address) + .change_context(BlockChainTreeError::BlockChainTree( + BCTreeErrorKind::GetFunds, + )) + .attach_printable("failed to get funds from summary_db")? + .map(|val| val.to_vec()) + .unwrap_or(Vec::with_capacity(0)); + let mut data_to_hash: Vec = + Vec::with_capacity(address.len() + amount.len() + gas_amount.len() + 2); + data_to_hash.extend(address.iter()); + data_to_hash.push(b'|'); + data_to_hash.extend(amount.iter()); + data_to_hash.push(b'|'); + data_to_hash.extend(gas_amount.iter()); + + hashes.push(tools::hash(&data_to_hash)); + } + + let merkle_tree = merkletree::MerkleTree::build_tree(&hashes); + + Ok(*merkle_tree.get_root()) + } + pub async fn emmit_new_main_block( &self, - pow: &[u8], + pow: [u8; 32], founder: [u8; 33], - ) -> Result<[u8; 33], Report> { + transactions: &[Transaction], + timestamp: u64, + ) -> Result<[u8; 32], Report> { let last_block = self.main_chain.get_last_block().await?.unwrap(); // practically cannot fail + let prev_hash = last_block + .hash() + .change_context(BlockChainTreeError::BlockChainTree(BCTreeErrorKind::DumpDb)) + .attach_printable("failed to hash block")?; - if !tools::check_pow( - &last_block - .hash() - .change_context(BlockChainTreeError::BlockChainTree(BCTreeErrorKind::DumpDb)) - .attach_printable("failed to hash block")?, - &last_block.get_info().difficulty, - pow, - ) { + if !tools::check_pow(&prev_hash, &last_block.get_info().difficulty, &pow) { return Err(BlockChainTreeError::BlockChainTree(BCTreeErrorKind::WrongPow).into()); }; + let default_info = block::BasicInfo { + timestamp, + pow, + previous_hash: prev_hash, + height: last_block.get_info().height, + difficulty: last_block.get_info().difficulty, + founder, + }; + if ((last_block.get_info().height + 1) % BLOCKS_PER_EPOCH).is_zero() { + if transactions.len() != 0 { + return Err(BlockChainTreeError::BlockChainTree( + BCTreeErrorKind::SummarizeBlockWrongTransactionsAmount, + ) + .into()); + } + + let summarized_hash = self.summarize()?; + + //let merkle_tree = merkletree::MerkleTree::build_tree() + //block::SummarizeBlock { + // default_info, + // merkle_tree_root: todo!(), + //}; + } + todo!() } diff --git a/src/chain.rs b/src/chain.rs index 0417324..663f56c 100644 --- a/src/chain.rs +++ b/src/chain.rs @@ -113,7 +113,7 @@ impl MainChain { if height.is_zero() { let info = BasicInfo::new( INCEPTION_TIMESTAMP, - U256::zero(), + [0; 32], [0u8; 32], U256::zero(), BEGINNING_DIFFICULTY, @@ -121,8 +121,10 @@ impl MainChain { ); let mut initial_amount = Vec::::new(); initial_amount.extend(ROOT_PUBLIC_ADDRESS.iter()); - initial_amount.extend([0u8; 32]); - COINS_PER_CYCLE.to_big_endian(&mut initial_amount[33..]); + initial_amount.push(b'|'); + initial_amount.extend(COINS_PER_CYCLE.to_string().as_bytes().iter()); + initial_amount.push(b'|'); + initial_amount.push(b'0'); let merkle_tree = MerkleTree::build_tree(&[tools::hash(&initial_amount)]); chain diff --git a/src/errors.rs b/src/errors.rs index 006f4cd..1ffa56b 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -174,6 +174,7 @@ sub_errors![ MoveSummaryDB: "failed to move summary database", NewTransaction: "failed to create new transaction", CreateMainChainBlock: "failed to create new block for the main chain", - WrongPow: "supplied pow does not satisfy requirements" + WrongPow: "supplied pow does not satisfy requirements", + SummarizeBlockWrongTransactionsAmount: "summarization block should not have transactions" } ]; diff --git a/tests/block_test.rs b/tests/block_test.rs index 7fce1fe..835e8b0 100644 --- a/tests/block_test.rs +++ b/tests/block_test.rs @@ -7,7 +7,7 @@ use primitive_types::U256; fn dump_parse_basic_info() { let basic_data = block::BasicInfo { timestamp: 160000, - pow: U256::from_dec_str("10000000000000000000001000000001").unwrap(), + pow: [0; 32], previous_hash: [5; 32], height: U256::from_dec_str("6378216378216387213672813821736").unwrap(), difficulty: [101; 32], @@ -34,7 +34,7 @@ fn dump_parse_basic_info() { fn dump_parse_block() { let basic_data = block::BasicInfo { timestamp: 160000, - pow: U256::from_dec_str("10000000000000000000001000000001").unwrap(), + pow: [0; 32], previous_hash: [5; 32], height: U256::from_dec_str("6378216378216387213672813821736").unwrap(), difficulty: [101; 32], @@ -81,7 +81,7 @@ fn dump_parse_block() { fn dump_parse_summarize_block() { let basic_data = block::BasicInfo { timestamp: 160000, - pow: U256::from_dec_str("10000000000000000000001000000001").unwrap(), + pow: [0; 32], previous_hash: [5; 32], height: U256::from_dec_str("6378216378216387213672813821736").unwrap(), difficulty: [101; 32], @@ -124,7 +124,7 @@ fn dump_parse_summarize_block() { fn validate_block_test() { let basic_data = block::BasicInfo { timestamp: 160000, - pow: U256::from_dec_str("10000000000000000000001000000001").unwrap(), + pow: [0; 32], previous_hash: [5; 32], height: U256::from_dec_str("1").unwrap(), difficulty: [101; 32], @@ -139,7 +139,7 @@ fn validate_block_test() { let basic_data = block::BasicInfo { timestamp: 160000, - pow: U256::from_dec_str("10000000000000000000001000000001").unwrap(), + pow: [0; 32], previous_hash: prev_block.hash().unwrap(), height: U256::from_dec_str("2").unwrap(), difficulty: [101; 32], @@ -159,7 +159,7 @@ fn validate_block_test() { fn dump_parse_derivative_block() { let basic_data = block::BasicInfo { timestamp: 160000, - pow: U256::from_dec_str("10000000000000000000001000000001").unwrap(), + pow: [0; 32], previous_hash: unsafe { [0; 32].try_into().unwrap_unchecked() }, height: U256::from_dec_str("2").unwrap(), difficulty: [101; 32], @@ -208,7 +208,7 @@ fn validate_derivative_block() { let payment_transaction = [0; 32]; let basic_data = block::BasicInfo { timestamp: 160000, - pow: U256::from_dec_str("10000000000000000000001000000001").unwrap(), + pow: [0; 32], previous_hash: unsafe { [0; 32].try_into().unwrap_unchecked() }, height: U256::from_dec_str("2").unwrap(), difficulty: [101; 32], @@ -221,7 +221,7 @@ fn validate_derivative_block() { let payment_transaction = [0; 32]; let basic_data = block::BasicInfo { timestamp: 160000, - pow: U256::from_dec_str("10000000000000000000001000000001").unwrap(), + pow: [0; 32], previous_hash: unsafe { [0; 32].try_into().unwrap_unchecked() }, height: U256::from_dec_str("2").unwrap(), difficulty: [101; 32], diff --git a/tests/chain_test.rs b/tests/chain_test.rs index b9d5431..5c8bf1b 100644 --- a/tests/chain_test.rs +++ b/tests/chain_test.rs @@ -21,7 +21,7 @@ async fn init_flush_get_block_by_height_chain_test() { // generate block let basic_data = block::BasicInfo { timestamp: 160000, - pow: U256::from_dec_str("11").unwrap(), + pow: [0; 32], previous_hash: unsafe { [0; 32].try_into().unwrap_unchecked() }, height, difficulty: [101; 32], @@ -45,7 +45,7 @@ async fn init_flush_get_block_by_height_chain_test() { assert_eq!([6; 33], *block.get_founder()); assert_eq!(160000, block.get_info().timestamp); - assert_eq!(U256::from_dec_str("11").unwrap(), block.get_info().pow); + assert_eq!([0; 32], block.get_info().pow); assert_eq!(height - 1, block.get_info().height); assert_eq!([101; 32], block.get_info().difficulty); assert_eq!(U256::from_dec_str("1").unwrap(), block.get_fee()); @@ -113,7 +113,7 @@ async fn init_flush_get_block_by_height_deriv_chain_test() { // generate block let basic_data = block::BasicInfo { timestamp: 160000, - pow: U256::from_dec_str("10000000000000000000001000000001").unwrap(), + pow: [0; 32], previous_hash: unsafe { [0; 32].try_into().unwrap_unchecked() }, height: U256::from_dec_str("0").unwrap(), difficulty: [101; 32],