From 562c004b0d6feff1ef7daf0e8c20fc8ae3a00857 Mon Sep 17 00:00:00 2001 From: Revertron Date: Sat, 30 Jan 2021 14:18:37 +0100 Subject: [PATCH] Implemented and added usage of eventbus. Added a lot of UI interaction. Added a lot of DB work. --- Cargo.toml | 2 +- src/blockchain.rs | 128 ++++++++++++++++++++++++++++++++------------- src/bulma.css | 7 ++- src/context.rs | 6 ++- src/event.rs | 10 ++++ src/index.html | 26 +++++++-- src/lib.rs | 4 ++ src/loader.css | 33 ++++++++++++ src/main.rs | 77 +++++++++++++++++++++------ src/miner.rs | 29 +++++++--- src/scripts.js | 56 ++++++++++++++++++++ src/simplebus.rs | 63 ++++++++++++++++++++++ src/transaction.rs | 15 ++++-- 13 files changed, 385 insertions(+), 71 deletions(-) create mode 100644 src/event.rs create mode 100644 src/loader.css create mode 100644 src/simplebus.rs diff --git a/Cargo.toml b/Cargo.toml index 5783d7b..4c22ab7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ base64 = "0.11.0" chrono = "0.4.9" rand = "0.7.2" sqlite = "0.25.3" -eventbus = "0.5.1" +uuid = { version = "0.8.2", features = ["serde", "v4"] } [build-dependencies] winres = "0.1" diff --git a/src/blockchain.rs b/src/blockchain.rs index 46ad187..6c919c0 100644 --- a/src/blockchain.rs +++ b/src/blockchain.rs @@ -1,4 +1,4 @@ -use crate::{Block, Transaction, Bytes}; +use crate::{Block, Transaction, Bytes, Keystore}; use chrono::Utc; use sqlite::{Connection, State, Readable, Statement, Error}; @@ -25,7 +25,7 @@ impl Blockchain { match self.db.prepare("SELECT * FROM blocks ORDER BY id DESC LIMIT 1;") { Ok(mut statement) => { while statement.next().unwrap() == State::Row { - match Self::get_block(&mut statement) { + match Self::get_block_from_statement(&mut statement) { None => { println!("Something wrong with block in DB!"); } Some(block) => { println!("Loaded last block: {:?}", &block); @@ -52,56 +52,100 @@ impl Blockchain { 'prev_block_hash' BINARY, 'hash' BINARY ); - CREATE INDEX block_index ON blocks (id);" + CREATE INDEX block_index ON blocks (id); + CREATE TABLE transactions (id INTEGER PRIMARY KEY AUTOINCREMENT, identity BINARY, method TEXT, data TEXT, pub_key BINARY, signature BINARY); + CREATE INDEX ids ON transactions (identity);" ).expect("Error creating blocks table"); } } } - fn get_block(statement: &mut Statement) -> Option { - let index = statement.read::(0).unwrap() as u64; - let timestamp = statement.read::(1).unwrap(); - let chain_name = statement.read::(2).unwrap(); - let version_flags = statement.read::(3).unwrap() as u32; - let difficulty = statement.read::(4).unwrap() as usize; - let random = statement.read::(5).unwrap() as u32; - let nonce = statement.read::(6).unwrap() as u64; - let transaction = Transaction::from_json(&statement.read::(7).unwrap()); - let prev_block_hash = Bytes::from_bytes(statement.read::>(8).unwrap().as_slice()); - let hash = Bytes::from_bytes(statement.read::>(9).unwrap().as_slice()); - Some(Block::from_all_params(index, timestamp, &chain_name, version_flags, difficulty, random, nonce, prev_block_hash, hash, transaction)) - } - pub fn add_block(&mut self, block: Block) { if self.check_block(&block, &self.last_block) { println!("Adding block:\n{:?}", &block); self.blocks.push(block.clone()); self.last_block = Some(block.clone()); + let transaction = block.transaction.clone(); - // Adding block to DB - let mut statement = self.db.prepare("INSERT INTO blocks (\ - id, timestamp, chain_name, version_flags, difficulty,\ - random, nonce, 'transaction', prev_block_hash, hash)\ - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)").unwrap(); - statement.bind(1, block.index as i64); - statement.bind(2, block.timestamp as i64); - statement.bind(3, &*block.chain_name); - statement.bind(4, block.version_flags as i64); - statement.bind(5, block.difficulty as i64); - statement.bind(6, block.random as i64); - statement.bind(7, block.nonce as i64); - match block.transaction { - None => { statement.bind(8, ""); } - Some(transaction) => { statement.bind(8, &*transaction.to_string()); } + { + // Adding block to DB + let mut statement = self.db.prepare("INSERT INTO blocks (\ + id, timestamp, chain_name, version_flags, difficulty,\ + random, nonce, 'transaction', prev_block_hash, hash)\ + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);").unwrap(); + statement.bind(1, block.index as i64); + statement.bind(2, block.timestamp as i64); + statement.bind(3, block.chain_name.as_ref() as &str); + statement.bind(4, block.version_flags as i64); + statement.bind(5, block.difficulty as i64); + statement.bind(6, block.random as i64); + statement.bind(7, block.nonce as i64); + match &transaction { + None => { statement.bind(8, ""); } + Some(transaction) => { + statement.bind(8, transaction.to_string().as_ref() as &str); + } + } + statement.bind(9, block.prev_block_hash.as_bytes()); + statement.bind(10, block.hash.as_bytes()); + statement.next().expect("Error adding block to DB"); + } + + match &transaction { + None => {} + Some(transaction) => { + self.add_transaction(transaction); + } } - statement.bind(9, block.prev_block_hash.as_bytes()); - statement.bind(10, block.hash.as_bytes()); - statement.next().expect("Error adding block to DB"); } else { println!("Bad block found, ignoring:\n{:?}", &block); } } + fn add_transaction(&mut self, t: &Transaction) { + let mut statement = self.db.prepare("INSERT INTO transactions (identity, method, data, pub_key, signature) VALUES (?, ?, ?, ?, ?)").unwrap(); + statement.bind(1, t.identity.as_bytes()); + statement.bind(2, t.method.as_ref() as &str); + statement.bind(3, t.data.as_ref() as &str); + statement.bind(4, t.pub_key.as_bytes()); + statement.bind(5, t.signature.as_bytes()); + statement.next().expect("Error adding transaction to DB"); + } + + pub fn is_domain_available(&self, domain: &str, keystore: &Keystore) -> bool { + if domain.is_empty() { + return false; + } + let identity_hash = Transaction::hash_identity(domain); + let mut statement = self.db.prepare("SELECT pub_key FROM transactions WHERE identity = ? ORDER BY id DESC LIMIT 1;").unwrap(); + statement.bind(1, identity_hash.as_bytes()); + while let State::Row = statement.next().unwrap() { + let pub_key = Bytes::from_bytes(statement.read::>(0).unwrap().as_slice()); + if !pub_key.eq(&keystore.get_public()) { + return false; + } + } + + let parts: Vec<&str> = domain.rsplitn(2, ".").collect(); + if parts.len() > 1 { + // We do not support third level domains + if parts.last().unwrap().contains(".") { + return false; + } + // Checking for available zone, for this domain + let identity_hash = Transaction::hash_identity(parts.first().unwrap()); + let mut statement = self.db.prepare("SELECT identity FROM transactions WHERE identity = ? ORDER BY id DESC LIMIT 1;").unwrap(); + statement.bind(1, identity_hash.as_bytes()); + while let State::Row = statement.next().unwrap() { + // If there is such a zone + return true; + } + return false; + } + + true + } + pub fn get_last_block(&self) -> Option { self.last_block.clone() } @@ -129,6 +173,20 @@ impl Blockchain { return block.prev_block_hash == prev_block.as_ref().unwrap().hash; } + fn get_block_from_statement(statement: &mut Statement) -> Option { + let index = statement.read::(0).unwrap() as u64; + let timestamp = statement.read::(1).unwrap(); + let chain_name = statement.read::(2).unwrap(); + let version_flags = statement.read::(3).unwrap() as u32; + let difficulty = statement.read::(4).unwrap() as usize; + let random = statement.read::(5).unwrap() as u32; + let nonce = statement.read::(6).unwrap() as u64; + let transaction = Transaction::from_json(&statement.read::(7).unwrap()); + let prev_block_hash = Bytes::from_bytes(statement.read::>(8).unwrap().as_slice()); + let hash = Bytes::from_bytes(statement.read::>(9).unwrap().as_slice()); + Some(Block::from_all_params(index, timestamp, &chain_name, version_flags, difficulty, random, nonce, prev_block_hash, hash, transaction)) + } + pub fn check_block_hash(block: &Block) -> bool { // We need to clear Hash value to rehash it without it for check :( let mut copy: Block = block.clone(); diff --git a/src/bulma.css b/src/bulma.css index cb7c647..9eb983f 100644 --- a/src/bulma.css +++ b/src/bulma.css @@ -10829,4 +10829,9 @@ label.panel-block:hover { background-color: #fafafa; padding: 3rem 1.5rem 6rem; } -/*# sourceMappingURL=bulma.css.map */ \ No newline at end of file +/*# sourceMappingURL=bulma.css.map */ + +// TODO move to another file +.container { + margin: 10pt; +} \ No newline at end of file diff --git a/src/context.rs b/src/context.rs index 1bbae95..bf3dfa0 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,4 +1,5 @@ -use crate::{Keystore, Blockchain}; +use crate::{Keystore, Blockchain, Bus}; +use crate::event::Event; use std::collections::HashMap; use serde::{Serialize, Deserialize, Serializer, Deserializer}; use serde::de::Error; @@ -9,12 +10,13 @@ pub struct Context { pub(crate) settings: Settings, pub(crate) keystore: Keystore, pub(crate) blockchain: Blockchain, + pub bus: Bus, } impl Context { /// Creating an essential context to work with pub fn new(settings: Settings, keystore: Keystore, blockchain: Blockchain) -> Context { - Context { settings, keystore, blockchain } + Context { settings, keystore, blockchain, bus: Bus::new() } } /// Load keystore and return Context diff --git a/src/event.rs b/src/event.rs new file mode 100644 index 0000000..e500601 --- /dev/null +++ b/src/event.rs @@ -0,0 +1,10 @@ +#[derive(Clone, PartialEq, Debug)] +pub enum Event { + MinerStarted, + MinerStopped, + KeyGeneratorStarted, + KeyGeneratorStopped, + NewBlockReceived, + BlockchainChanged, + ActionStopMining, +} diff --git a/src/index.html b/src/index.html index a0b7058..d288ba8 100644 --- a/src/index.html +++ b/src/index.html @@ -8,9 +8,27 @@ {scripts} - + +
+ + +
+ + +
-