diff --git a/alfis.cfg b/alfis.cfg index a254567..4de36d3 100644 --- a/alfis.cfg +++ b/alfis.cfg @@ -1,7 +1,8 @@ { "chain_name": "test", - "version_flags": 0, - "key_file": "default.key", + "origin": "", + "version": 0, + "key_file": "default3.key", "listen": "127.0.0.1:4244", "public": true, "peers": [ diff --git a/src/blockchain/block.rs b/src/blockchain/block.rs index 191655c..5a4f0ef 100644 --- a/src/blockchain/block.rs +++ b/src/blockchain/block.rs @@ -17,8 +17,7 @@ use crate::Transaction; pub struct Block { pub index: u64, pub timestamp: i64, - pub chain_name: String, - pub version_flags: u32, + pub version: u32, pub difficulty: usize, pub random: u32, pub nonce: u64, @@ -31,12 +30,11 @@ pub struct Block { } impl Block { - pub fn new(index: u64, timestamp: i64, chain_name: &str, version_flags: u32, prev_block_hash: Bytes, transaction: Option) -> Self { + pub fn new(index: u64, timestamp: i64, version: u32, prev_block_hash: Bytes, transaction: Option) -> Self { Block { index, timestamp, - chain_name: chain_name.to_owned(), - version_flags, + version, // TODO make difficulty parameter difficulty: 20, random: 0, @@ -47,12 +45,11 @@ impl Block { } } - pub fn from_all_params(index: u64, timestamp: i64, chain_name: &str, version_flags: u32, difficulty: usize, random: u32, nonce: u64, prev_block_hash: Bytes, hash: Bytes, transaction: Option) -> Self { + pub fn from_all_params(index: u64, timestamp: i64, version: u32, difficulty: usize, random: u32, nonce: u64, prev_block_hash: Bytes, hash: Bytes, transaction: Option) -> Self { Block { index, timestamp, - chain_name: chain_name.to_owned(), - version_flags, + version, difficulty, random, nonce, diff --git a/src/blockchain/blockchain.rs b/src/blockchain/blockchain.rs index a6184cd..e5e0b2b 100644 --- a/src/blockchain/blockchain.rs +++ b/src/blockchain/blockchain.rs @@ -6,17 +6,17 @@ use crate::{Block, Bytes, Keystore, Transaction}; const DB_NAME: &str = "blockchain.db"; pub struct Blockchain { - pub chain_name: String, - pub version_flags: u32, + origin: String, + pub version: u32, pub blocks: Vec, last_block: Option, db: Connection, } impl Blockchain { - pub fn new(chain_name: &str, version_flags: u32) -> Self { + pub fn new(origin: String, version: u32) -> Self { let db = sqlite::open(DB_NAME).expect("Unable to open blockchain DB"); - let mut blockchain = Blockchain{ chain_name: chain_name.to_owned(), version_flags, blocks: Vec::new(), last_block: None, db}; + let mut blockchain = Blockchain{ origin, version, blocks: Vec::new(), last_block: None, db}; blockchain.init_db(); blockchain } @@ -30,12 +30,11 @@ impl Blockchain { None => { println!("Something wrong with block in DB!"); } Some(block) => { println!("Loaded last block: {:?}", &block); - self.chain_name = block.chain_name.clone(); - self.version_flags = block.version_flags; + self.version = block.version; self.last_block = Some(block); } } - println!("Loaded from DB: chain_name = {}, version_flags = {}", self.chain_name, self.version_flags); + println!("Blockchain version from DB = {}", self.version); } } Err(_) => { @@ -44,8 +43,7 @@ impl Blockchain { CREATE TABLE blocks ( 'id' BIGINT, 'timestamp' BIGINT, - 'chain_name' TEXT, - 'version_flags' TEXT, + 'version' TEXT, 'difficulty' INTEGER, 'random' INTEGER, 'nonce' INTEGER, @@ -54,7 +52,7 @@ impl Blockchain { 'hash' BINARY ); 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 TABLE transactions (id INTEGER PRIMARY KEY AUTOINCREMENT, identity BINARY, confirmation BINARY, method TEXT, data TEXT, pub_key BINARY, signature BINARY); CREATE INDEX ids ON transactions (identity);" ).expect("Error creating blocks table"); } @@ -71,24 +69,23 @@ impl Blockchain { { // 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(); + id, timestamp, version, 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); + statement.bind(3, block.version as i64); + statement.bind(4, block.difficulty as i64); + statement.bind(5, block.random as i64); + statement.bind(6, block.nonce as i64); match &transaction { - None => { statement.bind(8, ""); } + None => { statement.bind(7, ""); } Some(transaction) => { - statement.bind(8, transaction.to_string().as_ref() as &str); + statement.bind(7, transaction.to_string().as_ref() as &str); } } - statement.bind(9, block.prev_block_hash.as_bytes()); - statement.bind(10, block.hash.as_bytes()); + statement.bind(8, block.prev_block_hash.as_bytes()); + statement.bind(9, block.hash.as_bytes()); statement.next().expect("Error adding block to DB"); } @@ -104,12 +101,13 @@ impl Blockchain { } fn add_transaction(&mut self, t: &Transaction) { - let mut statement = self.db.prepare("INSERT INTO transactions (identity, method, data, pub_key, signature) VALUES (?, ?, ?, ?, ?)").unwrap(); + let mut statement = self.db.prepare("INSERT INTO transactions (identity, confirmation, 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.bind(2, t.confirmation.as_bytes()); + statement.bind(3, t.method.as_ref() as &str); + statement.bind(4, t.data.as_ref() as &str); + statement.bind(5, t.pub_key.as_bytes()); + statement.bind(6, t.signature.as_bytes()); statement.next().expect("Error adding transaction to DB"); } @@ -212,15 +210,14 @@ impl Blockchain { 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)) + let version = statement.read::(2).unwrap() as u32; + let difficulty = statement.read::(3).unwrap() as usize; + let random = statement.read::(4).unwrap() as u32; + let nonce = statement.read::(5).unwrap() as u64; + let transaction = Transaction::from_json(&statement.read::(6).unwrap()); + let prev_block_hash = Bytes::from_bytes(statement.read::>(7).unwrap().as_slice()); + let hash = Bytes::from_bytes(statement.read::>(8).unwrap().as_slice()); + Some(Block::from_all_params(index, timestamp, version, difficulty, random, nonce, prev_block_hash, hash, transaction)) } pub fn check_block_hash(block: &Block) -> bool { diff --git a/src/blockchain/transaction.rs b/src/blockchain/transaction.rs index 04070cb..8d623e7 100644 --- a/src/blockchain/transaction.rs +++ b/src/blockchain/transaction.rs @@ -12,6 +12,7 @@ use crypto::digest::Digest; #[derive(Clone, Deserialize, PartialEq)] pub struct Transaction { pub identity: Bytes, + pub confirmation: Bytes, pub method: String, pub data: String, pub pub_key: Bytes, @@ -20,12 +21,13 @@ pub struct Transaction { impl Transaction { pub fn from_str(identity: String, method: String, data: String, pub_key: Bytes) -> Self { - let bytes = Self::hash_identity(&identity); - return Self::new(bytes, method, data, pub_key); + let hash = Self::hash_identity(&identity); + let confirmation = Self::hash_with_key(&identity, &pub_key); + return Self::new(hash, confirmation, method, data, pub_key); } - pub fn new(identity: Bytes, method: String, data: String, pub_key: Bytes) -> Self { - Transaction { identity, method, data, pub_key, signature: Bytes::zero64() } + pub fn new(identity: Bytes, confirmation: Bytes, method: String, data: String, pub_key: Bytes) -> Self { + Transaction { identity, confirmation, method, data, pub_key, signature: Bytes::zero64() } } pub fn from_json(json: &str) -> Option { @@ -56,12 +58,22 @@ impl Transaction { digest.result(&mut buf); Bytes::from_bytes(&buf) } + + pub fn hash_with_key(identity: &str, key: &Bytes) -> Bytes { + let mut buf: [u8; 32] = [0; 32]; + let mut digest = Sha256::new(); + digest.input_str(identity); + digest.input(key.as_bytes()); + digest.result(&mut buf); + Bytes::from_bytes(&buf) + } } impl fmt::Debug for Transaction { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("Transaction") .field("identity", &self.identity) + .field("confirmation", &self.confirmation) .field("method", &self.method) .field("data", &self.data) .field("pub", &&self.pub_key) @@ -71,10 +83,10 @@ impl fmt::Debug for Transaction { } impl Serialize for Transaction { - fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> where - S: Serializer { - let mut structure = serializer.serialize_struct("Transaction", 3).unwrap(); + fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> where S: Serializer { + let mut structure = serializer.serialize_struct("Transaction", 6).unwrap(); structure.serialize_field("identity", &self.identity); + structure.serialize_field("confirmation", &self.confirmation); structure.serialize_field("method", &self.method); structure.serialize_field("data", &self.data); structure.serialize_field("pub_key", &self.pub_key); diff --git a/src/context.rs b/src/context.rs index c1bf4e0..4fe0354 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,4 +1,4 @@ -use crate::{Keystore, Blockchain, Bus}; +use crate::{Keystore, Blockchain, Bus, Bytes}; use crate::event::Event; use std::collections::HashMap; use serde::{Serialize, Deserialize, Serializer, Deserializer}; @@ -7,9 +7,9 @@ use std::fs::File; use std::io::Read; pub struct Context { - pub(crate) settings: Settings, - pub(crate) keystore: Keystore, - pub(crate) blockchain: Blockchain, + pub settings: Settings, + pub keystore: Keystore, + pub blockchain: Blockchain, pub bus: Bus, } @@ -48,8 +48,8 @@ impl Context { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Settings { - pub chain_name: String, - pub version_flags: u32, + pub origin: String, + pub version: u32, pub key_file: String, pub listen: String, pub public: bool, @@ -76,4 +76,9 @@ impl Settings { Err(..) => None } } + + pub fn get_origin(&self) -> Bytes { + let origin = crate::from_hex(&self.origin).expect("Wrong origin in settings"); + Bytes::from_bytes(origin.as_slice()) + } } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index e696749..51249b3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -31,7 +31,7 @@ fn main() { None => { generate_key(KEYSTORE_DIFFICULTY, Arc::new(AtomicBool::new(true))).expect("Could not load or generate keypair") } Some(keystore) => { keystore } }; - let blockchain: Blockchain = Blockchain::new(&settings.chain_name, settings.version_flags); + let blockchain: Blockchain = Blockchain::new(settings.origin.clone(), settings.version); let context: Arc> = Arc::new(Mutex::new(Context::new(settings, keystore, blockchain))); let mut miner_obj = Miner::new(context.clone()); @@ -46,11 +46,14 @@ fn main() { } fn create_genesis_if_needed(context: &Arc>, miner: &Arc>) { - // TODO check settings and if there is no mention of bootstrap nodes, generate genesis block - let context_guard = context.lock().unwrap(); - if context_guard.get_blockchain().last_block().is_none() { + // If there is no origin in settings and no blockchain in DB, generate genesis block + let context = context.lock().unwrap(); + // TODO compare first block's hash to origin + let last_block = context.get_blockchain().last_block(); + let origin = context.settings.origin.clone(); + if origin.eq("") && last_block.is_none() { // If blockchain is empty, we are going to mine a Genesis block - create_genesis(miner.clone(), GENESIS_ZONE, &context_guard.get_keystore(), GENESIS_ZONE_DIFFICULTY); + create_genesis(miner.clone(), GENESIS_ZONE, &context.get_keystore(), GENESIS_ZONE_DIFFICULTY); } } diff --git a/src/miner.rs b/src/miner.rs index b8491a9..2431431 100644 --- a/src/miner.rs +++ b/src/miner.rs @@ -14,8 +14,7 @@ use crate::event::Event; pub struct Miner { context: Arc>, keystore: Keystore, - chain_name: String, - version_flags: u32, + version: u32, transactions: Arc>>, last_block: Option, running: Arc, @@ -29,8 +28,7 @@ impl Miner { Miner { context: context.clone(), keystore: c.keystore.clone(), - chain_name: c.settings.chain_name.clone(), - version_flags: c.settings.version_flags, + version: c.settings.version, transactions: Arc::new(Mutex::new(Vec::new())), last_block: c.blockchain.blocks.last().cloned(), running: Arc::new(AtomicBool::new(false)), @@ -93,13 +91,11 @@ impl Miner { fn mine_internal(context: Arc>, transactions: Arc>>, mut transaction: Transaction, mining: Arc, cond_var: Arc) { let mut last_block_time = 0i64; - let mut chain_name= String::new(); - let mut version_flags= 0u32; + let mut version= 0u32; { let mut c = context.lock().unwrap(); c.bus.post(Event::MinerStarted); - chain_name = c.settings.chain_name.clone(); - version_flags = c.settings.version_flags; + version = c.settings.version; } let block = { if transaction.signature.is_zero() { @@ -115,12 +111,12 @@ impl Miner { None => { println!("Mining genesis block"); // Creating a block with that signed transaction - Block::new(0, Utc::now().timestamp(), &chain_name, version_flags, Bytes::zero32(), Some(transaction.clone())) + Block::new(0, Utc::now().timestamp(), version, Bytes::zero32(), Some(transaction.clone())) }, Some(block) => { last_block_time = block.timestamp; // Creating a block with that signed transaction - Block::new(block.index + 1, Utc::now().timestamp(), &chain_name, version_flags, block.hash.clone(), Some(transaction.clone())) + Block::new(block.index + 1, Utc::now().timestamp(), version, block.hash.clone(), Some(transaction.clone())) }, } }; diff --git a/src/p2p/message.rs b/src/p2p/message.rs index 3733f99..c5d841f 100644 --- a/src/p2p/message.rs +++ b/src/p2p/message.rs @@ -7,8 +7,8 @@ use crate::p2p::peer::Peer; #[derive(Debug, Serialize, Deserialize)] pub enum Message { Error, - Hand { chain: String, version: u32, public: bool }, - Shake { ok: bool, height: u64 }, + Hand { origin: String, version: u32, public: bool }, + Shake { origin: String, version: u32, ok: bool, height: u64 }, Ping { height: u64 }, Pong { height: u64 }, GetPeers, @@ -26,12 +26,12 @@ impl Message { } } - pub fn hand(chain: &str, version: u32, public: bool) -> Self { - Message::Hand { chain: chain.to_owned(), version, public } + pub fn hand(origin: &str, version: u32, public: bool) -> Self { + Message::Hand { origin: origin.to_owned(), version, public } } - pub fn shake(ok: bool, height: u64) -> Self { - Message::Shake { ok, height } + pub fn shake(origin: &str, version: u32, ok: bool, height: u64) -> Self { + Message::Shake { origin: origin.to_owned(), version, ok, height } } pub fn ping(height: u64) -> Self { diff --git a/src/p2p/network.rs b/src/p2p/network.rs index 482cdb0..553b22d 100644 --- a/src/p2p/network.rs +++ b/src/p2p/network.rs @@ -176,7 +176,7 @@ fn handle_connection_event(context: Arc>, peers: &mut Peers, regi println!("Sending hello to socket {}", event.token().0); let data: String = { let mut c = context.lock().unwrap(); - let message = Message::hand(&c.settings.chain_name, c.settings.version_flags, c.settings.public); + let message = Message::hand(&c.settings.origin, c.settings.version, c.settings.public); serde_json::to_string(&message).unwrap() }; send_message(peer.get_stream(), &data.into_bytes()); @@ -255,17 +255,18 @@ fn handle_message(context: Arc>, message: Message, peers: &mut Pe context.blockchain.height() }; match message { - Message::Hand { chain, version, public } => { + Message::Hand { origin: origin, version, public } => { let context = context.lock().unwrap(); - if chain == context.settings.chain_name && version == context.settings.version_flags { + if origin == context.settings.origin && version == context.settings.version { let mut peer = peers.get_mut_peer(token).unwrap(); peer.set_public(public); - State::message(Message::shake(true, context.blockchain.height())) + State::message(Message::shake(&context.settings.origin, context.settings.version, true, context.blockchain.height())) } else { State::Error } } - Message::Shake { ok, height } => { + Message::Shake { origin, version, ok, height } => { + // TODO check origin and version for compatibility if ok { if height > my_height { State::message(Message::GetBlock { index: my_height + 1u64 })