From f5dbd5ba79339cde88903931fca1d4762745eb61 Mon Sep 17 00:00:00 2001 From: YeahNotSewerSide Date: Sat, 4 May 2024 20:43:10 +0300 Subject: [PATCH] MINE --- Cargo.toml | 1 + examples/mine.rs | 73 +++++++++++++++++++++++++++++++++ src/block.rs | 2 - src/blockchaintree.rs | 93 ++++++++++++++++++++++++++++++------------- src/chain.rs | 75 +++++++++++++--------------------- src/static_values.rs | 4 +- 6 files changed, 169 insertions(+), 79 deletions(-) create mode 100644 examples/mine.rs diff --git a/Cargo.toml b/Cargo.toml index 28fd020..ed2f928 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ tokio = { version = "1.37.0", features = ["full"] } zstd = "0.13.1" primitive-types = "0.12.2" async-trait = "0.1.80" +parking_lot = "0.12.2" [dev-dependencies] rand = "0.8.5" diff --git a/examples/mine.rs b/examples/mine.rs new file mode 100644 index 0000000..2b40c03 --- /dev/null +++ b/examples/mine.rs @@ -0,0 +1,73 @@ +use blockchaintree::static_values::BLOCKS_PER_EPOCH; +use blockchaintree::tools; +use blockchaintree::{blockchaintree::BlockChainTree, static_values}; +use primitive_types::U256; +use std::time::{SystemTime, UNIX_EPOCH}; + +fn main() { + let rt = tokio::runtime::Runtime::new().unwrap(); + + let mut tree = BlockChainTree::new().unwrap(); + + let main_chain = tree.get_main_chain(); + + let wallet = [1u8; 33]; + + loop { + println!("Current height: {}", main_chain.get_height()); + println!( + "Current miner balance: {}", + tree.get_amount(&wallet).unwrap() + ); + println!( + "Current root balance: {}", + tree.get_amount(&static_values::ROOT_PUBLIC_ADDRESS) + .unwrap() + ); + let mut nonce = U256::zero(); + let last_block = main_chain.get_last_block().unwrap().unwrap(); + let prev_hash = last_block.hash().unwrap(); + let difficulty = last_block.get_info().difficulty; + println!( + "Current difficulty: {}", + tools::count_leading_zeros(&difficulty) + ); + while nonce < U256::MAX { + let mut pow = [0u8; 32]; + nonce.to_big_endian(&mut pow); + if tools::check_pow(&prev_hash, &difficulty, &pow) { + let timestamp = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs(); + + println!("Found nonce! {}", nonce); + + let transactions: &[[u8; 32]] = + if ((last_block.get_info().height + 1) % BLOCKS_PER_EPOCH).is_zero() { + println!("Cycle ended!"); + &[] + } else { + &[[25u8; 32]] + }; + + let block = rt + .block_on(tree.emmit_new_main_block(&pow, &wallet, transactions, timestamp)) + .unwrap(); + + tree.send_amount( + &static_values::ROOT_PUBLIC_ADDRESS, + &wallet, + *static_values::MAIN_CHAIN_PAYMENT, + ) + .unwrap(); + + println!("Added new block! {:?}\n", block.hash().unwrap()); + + rt.block_on(tree.flush()).unwrap(); + break; + } + nonce += U256::one(); + } + } +} diff --git a/src/block.rs b/src/block.rs index 91c12e7..45d6724 100644 --- a/src/block.rs +++ b/src/block.rs @@ -205,8 +205,6 @@ impl TransactionBlock { index += fee_size + 1; - println!("{:?}", data.len() - index); - if (data.len() - index) % 32 != 0 { return Err( Report::new(BlockError::TransactionBlock(TxBlockErrorKind::Parse)) diff --git a/src/blockchaintree.rs b/src/blockchaintree.rs index 7d227e7..2859a31 100644 --- a/src/blockchaintree.rs +++ b/src/blockchaintree.rs @@ -6,7 +6,8 @@ use crate::{ errors::{BCTreeErrorKind, BlockChainTreeError}, merkletree, static_values::{ - AMMOUNT_SUMMARY, BLOCKS_PER_EPOCH, GAS_SUMMARY, OLD_AMMOUNT_SUMMARY, OLD_GAS_SUMMARY, + AMMOUNT_SUMMARY, BLOCKS_PER_EPOCH, COINS_PER_CYCLE, GAS_SUMMARY, MAIN_CHAIN_PAYMENT, + OLD_AMMOUNT_SUMMARY, OLD_GAS_SUMMARY, ROOT_PUBLIC_ADDRESS, }, tools, transaction::Transaction, @@ -19,7 +20,7 @@ use sled::Db; use std::fs; pub struct BlockChainTree { - pub main_chain: chain::MainChain, + main_chain: chain::MainChain, pub derivative_chains: HashMap<[u8; 32], chain::DerivativeChain>, summary_db: Db, old_summary_db: Db, @@ -28,7 +29,7 @@ pub struct BlockChainTree { } impl BlockChainTree { - pub async fn new() -> Result> { + pub fn new() -> Result> { let path_summary = Path::new(AMMOUNT_SUMMARY); let path_summary_old = Path::new(OLD_AMMOUNT_SUMMARY); let path_gas = Path::new(GAS_SUMMARY); @@ -52,9 +53,23 @@ impl BlockChainTree { let old_gas_db = sled::open(path_gas_old) .change_context(BlockChainTreeError::BlockChainTree(BCTreeErrorKind::Init)) .attach_printable("failed to open old gas db")?; - + let main_chain = chain::MainChain::new()?; + + if main_chain.get_height() == U256::one() { + summary_db + .transaction( + |db| -> Result<(), sled::transaction::ConflictableTransactionError<()>> { + let mut buf: Vec = + Vec::with_capacity(tools::u256_size(&COINS_PER_CYCLE)); + tools::dump_u256(&COINS_PER_CYCLE, &mut buf).unwrap(); + db.insert(&(ROOT_PUBLIC_ADDRESS) as &[u8], buf)?; + Ok(()) + }, + ) + .unwrap(); + } Ok(Self { - main_chain: chain::MainChain::new().await?, + main_chain, derivative_chains: HashMap::new(), summary_db, old_summary_db, @@ -63,7 +78,11 @@ impl BlockChainTree { }) } - pub async fn add_amount( + pub fn get_main_chain(&self) -> chain::MainChain { + self.main_chain.clone() + } + + pub fn add_amount( &self, owner: &[u8], amount: U256, @@ -87,7 +106,26 @@ impl BlockChainTree { Ok(()) } - pub async fn sub_amount( + pub fn set_amount( + &self, + owner: &[u8], + amount: U256, + ) -> Result<(), Report> { + self.summary_db + .transaction( + |db| -> Result<(), sled::transaction::ConflictableTransactionError<()>> { + let mut buf: Vec = Vec::with_capacity(tools::u256_size(&amount)); + tools::dump_u256(&amount, &mut buf).unwrap(); + db.insert(owner, buf)?; + Ok(()) + }, + ) + .unwrap(); + + Ok(()) + } + + pub fn sub_amount( &self, owner: &[u8], amount: U256, @@ -113,7 +151,7 @@ impl BlockChainTree { Ok(()) } - pub async fn get_amount(&self, owner: &[u8; 33]) -> Result> { + pub fn get_amount(&self, owner: &[u8; 33]) -> Result> { match self .summary_db .get(owner) @@ -127,7 +165,7 @@ impl BlockChainTree { } } - pub async fn send_amount( + pub fn send_amount( &self, from: &[u8], to: &[u8], @@ -166,7 +204,7 @@ impl BlockChainTree { Ok(()) } - pub async fn add_gas_amount( + pub fn add_gas_amount( &self, owner: &[u8], amount: U256, @@ -189,7 +227,7 @@ impl BlockChainTree { Ok(()) } - pub async fn sub_gas_amount( + pub fn sub_gas_amount( &self, owner: &[u8], amount: U256, @@ -215,10 +253,7 @@ impl BlockChainTree { Ok(()) } - pub async fn get_gas_amount( - &self, - owner: &[u8; 33], - ) -> Result> { + pub fn get_gas_amount(&self, owner: &[u8; 33]) -> Result> { match self .gas_db .get(owner) @@ -232,7 +267,7 @@ impl BlockChainTree { } } - pub async fn send_gas( + pub fn send_gas( &self, from: &[u8], to: &[u8], @@ -271,14 +306,14 @@ impl BlockChainTree { Ok(()) } - pub async fn add_new_block( + pub fn add_new_block( &self, block: BlockArc, transactions: &[Transaction], ) -> Result<(), Report> { - self.main_chain.add_block(block).await?; + self.main_chain.add_block(block)?; - self.main_chain.add_transactions(transactions).await + self.main_chain.add_transactions(transactions) } fn summarize(&self) -> Result<[u8; 32], Report> { @@ -316,18 +351,18 @@ impl BlockChainTree { pub async fn emmit_new_main_block( &mut self, - pow: [u8; 32], - founder: [u8; 33], + pow: &[u8; 32], + founder: &[u8; 33], transactions: &[Hash], timestamp: u64, ) -> Result> { - let last_block = self.main_chain.get_last_block().await?.unwrap(); // practically cannot fail + let last_block = self.main_chain.get_last_block()?.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(&prev_hash, &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 mut difficulty = last_block.get_info().difficulty; @@ -335,11 +370,11 @@ impl BlockChainTree { let fee = tools::recalculate_fee(&difficulty); let default_info = block::BasicInfo { timestamp, - pow, + pow: *pow, previous_hash: prev_hash, - height: last_block.get_info().height, + height: last_block.get_info().height + 1, difficulty, - founder, + founder: *founder, }; let new_block: block::BlockArc = if ((last_block.get_info().height + 1) % BLOCKS_PER_EPOCH).is_zero() { @@ -358,6 +393,8 @@ impl BlockChainTree { }); self.rotate_dbs().await?; + self.set_amount(&ROOT_PUBLIC_ADDRESS as &[u8], *COINS_PER_CYCLE)?; + summarize_block } else { if transactions.len() == 0 { @@ -377,7 +414,7 @@ impl BlockChainTree { transaction_block }; - self.main_chain.add_block(new_block.clone()).await?; + self.main_chain.add_block(new_block.clone())?; Ok(new_block) } @@ -410,7 +447,7 @@ impl BlockChainTree { Ok(()) } - pub async fn rotate_dbs(&mut self) -> Result<(), Report> { + async fn rotate_dbs(&mut self) -> Result<(), Report> { self.flush().await?; let path_summary = Path::new(AMMOUNT_SUMMARY); diff --git a/src/chain.rs b/src/chain.rs index 663f56c..8b88c3e 100644 --- a/src/chain.rs +++ b/src/chain.rs @@ -2,9 +2,10 @@ use std::{fs::File, io::Read, path::Path, sync::Arc}; use async_trait::async_trait; use error_stack::{Report, ResultExt}; +use parking_lot::RwLock; use primitive_types::U256; use sled::Db; -use tokio::{fs::OpenOptions, io::AsyncWriteExt, sync::RwLock}; +use tokio::{fs::OpenOptions, io::AsyncWriteExt}; use crate::block::{BlockArc, DerivativeBlock}; use crate::dump_headers::Headers; @@ -47,6 +48,7 @@ pub trait Chain { ) -> Result>, Report>; } +#[derive(Clone)] pub struct MainChain { blocks: Db, height_reference: Db, @@ -56,7 +58,7 @@ pub struct MainChain { } impl MainChain { - pub async fn new() -> Result> { + pub fn new() -> Result> { let root = String::from(MAIN_CHAIN_DIRECTORY); let path_blocks_st = root.clone() + BLOCKS_FOLDER; @@ -132,7 +134,6 @@ impl MainChain { default_info: info, merkle_tree_root: *merkle_tree.get_root(), })) - .await .change_context(BlockChainTreeError::Chain(ChainErrorKind::Init)) .attach_printable("Failed to insert inception block")?; } @@ -154,13 +155,13 @@ impl MainChain { .await .change_context(BlockChainTreeError::Chain(ChainErrorKind::DumpConfig))?; let mut buffer_32_bytes: [u8; 32] = [0; 32]; - self.height.read().await.to_big_endian(&mut buffer_32_bytes); + self.height.read().to_big_endian(&mut buffer_32_bytes); file.write_all(&buffer_32_bytes) .await .change_context(BlockChainTreeError::Chain(ChainErrorKind::DumpConfig)) .attach_printable("failed to write height")?; - file.write_all(self.difficulty.read().await.as_ref()) + file.write_all(self.difficulty.read().as_ref()) .await .change_context(BlockChainTreeError::Chain(ChainErrorKind::DumpConfig)) .attach_printable("failed to write difficulty")?; @@ -168,8 +169,8 @@ impl MainChain { Ok(()) } - pub async fn get_height(&self) -> U256 { - *self.height.read().await + pub fn get_height(&self) -> U256 { + *self.height.read() } /// Flushes all DBs and config @@ -197,7 +198,7 @@ impl MainChain { Ok(()) } - pub async fn add_transactions( + pub fn add_transactions( &self, transactions: &[impl transaction::Transactionable], ) -> Result<(), Report> { @@ -214,13 +215,6 @@ impl MainChain { )) .attach_printable("Failed to insert transaction")?; } - self.transactions - .flush_async() - .await - .change_context(BlockChainTreeError::Chain( - ChainErrorKind::AddingTransaction, - )) - .attach_printable("Failed to insert transaction")?; Ok(()) } @@ -268,14 +262,14 @@ impl MainChain { /// Adds block and sets height reference for it /// /// Checks for blocks validity, adds it directly to the end of the chain - pub async fn add_block(&self, block: BlockArc) -> Result<(), Report> { + pub fn add_block(&self, block: BlockArc) -> Result<(), Report> { let dump = block .dump() .change_context(BlockChainTreeError::Chain(ChainErrorKind::AddingBlock))?; let hash = tools::hash(&dump); - let mut height = self.height.write().await; + let mut height = self.height.write(); if block.get_info().height != *height { return Err(BlockChainTreeError::Chain(ChainErrorKind::AddingBlock)).attach_printable( @@ -298,27 +292,15 @@ impl MainChain { *height += U256::one(); - self.blocks - .flush_async() - .await - .change_context(BlockChainTreeError::Chain(ChainErrorKind::AddingBlock)) - .attach_printable("Failed to flush blocks db")?; - - self.height_reference - .flush_async() - .await - .change_context(BlockChainTreeError::Chain(ChainErrorKind::AddingBlock)) - .attach_printable("Failed to flush height reference db")?; - Ok(()) } /// Get serialized block by it's height - pub async fn find_raw_by_height( + pub fn find_raw_by_height( &self, height: &U256, ) -> Result>, Report> { - let chain_height = self.height.read().await; + let chain_height = self.height.read(); if height > &chain_height { return Ok(None); } @@ -338,7 +320,7 @@ impl MainChain { } /// Get serialized block by it's hash - pub async fn find_raw_by_hash( + pub fn find_raw_by_hash( &self, hash: &[u8; 32], ) -> Result>, Report> { @@ -355,17 +337,16 @@ impl MainChain { let block = self .find_raw_by_height(&height) - .await .change_context(BlockChainTreeError::Chain(ChainErrorKind::FindByHashE))?; Ok(block) } - pub async fn find_by_hash( + pub fn find_by_hash( &self, hash: &[u8; 32], ) -> Result>, Report> { - let dump = self.find_raw_by_hash(hash).await?; + let dump = self.find_raw_by_hash(hash)?; let deserialized = if let Some(data) = dump { Some( @@ -384,19 +365,19 @@ impl MainChain { } /// Get serialized last block of the chain - pub async fn get_last_raw_block(&self) -> Result>, Report> { - let height = self.height.read().await; + pub fn get_last_raw_block(&self) -> Result>, Report> { + let height = self.height.read(); let last_block_index = *height - 1; drop(height); - self.find_raw_by_height(&last_block_index).await + self.find_raw_by_height(&last_block_index) } /// Get deserialized latest block - pub async fn get_last_block( + pub fn get_last_block( &self, ) -> Result>, Report> { - let dump = self.get_last_raw_block().await?; + let dump = self.get_last_raw_block()?; let deserialized = if let Some(data) = dump { Some( @@ -412,11 +393,11 @@ impl MainChain { } /// Get deserialized block by height - pub async fn find_by_height( + pub fn find_by_height( &self, height: &U256, ) -> Result>, Report> { - let dump = self.find_raw_by_height(height).await?; + let dump = self.find_raw_by_height(height)?; let deserialized = if let Some(data) = dump { Some( @@ -533,13 +514,13 @@ impl DerivativeChain { .await .change_context(BlockChainTreeError::Chain(ChainErrorKind::DumpConfig))?; let mut buffer_32_bytes: [u8; 32] = [0; 32]; - self.height.read().await.to_big_endian(&mut buffer_32_bytes); + self.height.read().to_big_endian(&mut buffer_32_bytes); file.write_all(&buffer_32_bytes) .await .change_context(BlockChainTreeError::Chain(ChainErrorKind::DumpConfig)) .attach_printable("failed to write height")?; - file.write_all(self.difficulty.read().await.as_ref()) + file.write_all(self.difficulty.read().as_ref()) .await .change_context(BlockChainTreeError::Chain(ChainErrorKind::DumpConfig)) .attach_printable("failed to write difficulty")?; @@ -647,7 +628,7 @@ impl DerivativeChain { let hash = tools::hash(&dump); - let mut height = self.height.write().await; + let mut height = self.height.write(); if block.get_info().height != *height { return Err(BlockChainTreeError::Chain(ChainErrorKind::AddingBlock)).attach_printable( @@ -690,7 +671,7 @@ impl DerivativeChain { &self, height: &U256, ) -> Result>, Report> { - let chain_height = self.height.read().await; + let chain_height = self.height.read(); if height > &chain_height { return Ok(None); } @@ -757,7 +738,7 @@ impl DerivativeChain { /// Get serialized last block of the chain pub async fn get_last_raw_block(&self) -> Result>, Report> { - let height = self.height.read().await; + let height = self.height.read(); let last_block_index = *height - 1; drop(height); diff --git a/src/static_values.rs b/src/static_values.rs index 171fe15..3dd2934 100644 --- a/src/static_values.rs +++ b/src/static_values.rs @@ -40,9 +40,9 @@ pub static ROOT_PUBLIC_ADDRESS: [u8; 33] = [ pub static INCEPTION_TIMESTAMP: u64 = 1597924800; -pub static BLOCKS_PER_EPOCH: usize = 1000000; +pub static BLOCKS_PER_EPOCH: usize = 4; -pub static TIME_PER_BLOCK: u64 = 600; +pub static TIME_PER_BLOCK: u64 = 4; lazy_static! { pub static ref COIN_FRACTIONS: U256 = U256::from_dec_str("1000000000000000000").unwrap();