Implemented block adding check. Cleared many warnings, cleaned code.
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
"chain_name": "test",
|
"chain_name": "test",
|
||||||
"origin": "",
|
"origin": "",
|
||||||
"version": 0,
|
"version": 0,
|
||||||
"key_file": "default3.key",
|
"key_file": "default.key",
|
||||||
"listen": "127.0.0.1:4244",
|
"listen": "127.0.0.1:4244",
|
||||||
"public": true,
|
"public": true,
|
||||||
"peers": [
|
"peers": [
|
||||||
|
|||||||
@@ -4,10 +4,7 @@ extern crate num_bigint;
|
|||||||
extern crate num_traits;
|
extern crate num_traits;
|
||||||
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use chrono::Utc;
|
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use num_bigint::BigUint;
|
|
||||||
use num_traits::One;
|
|
||||||
use crypto::sha2::Sha256;
|
use crypto::sha2::Sha256;
|
||||||
use crypto::digest::Digest;
|
use crypto::digest::Digest;
|
||||||
use crate::keys::Bytes;
|
use crate::keys::Bytes;
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
use chrono::Utc;
|
use sqlite::{Connection, State, Statement};
|
||||||
use sqlite::{Connection, Error, Readable, State, Statement};
|
|
||||||
|
|
||||||
use crate::{Block, Bytes, Keystore, Transaction};
|
use crate::{Block, Bytes, Keystore, Transaction, Settings};
|
||||||
|
|
||||||
const DB_NAME: &str = "blockchain.db";
|
const DB_NAME: &str = "blockchain.db";
|
||||||
|
|
||||||
pub struct Blockchain {
|
pub struct Blockchain {
|
||||||
origin: String,
|
origin: Bytes,
|
||||||
pub version: u32,
|
pub version: u32,
|
||||||
pub blocks: Vec<Block>,
|
pub blocks: Vec<Block>,
|
||||||
last_block: Option<Block>,
|
last_block: Option<Block>,
|
||||||
@@ -14,7 +13,10 @@ pub struct Blockchain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Blockchain {
|
impl Blockchain {
|
||||||
pub fn new(origin: String, version: u32) -> Self {
|
pub fn new(settings: &Settings) -> Self {
|
||||||
|
let origin = settings.get_origin();
|
||||||
|
let version = settings.version;
|
||||||
|
|
||||||
let db = sqlite::open(DB_NAME).expect("Unable to open blockchain DB");
|
let db = sqlite::open(DB_NAME).expect("Unable to open blockchain DB");
|
||||||
let mut blockchain = Blockchain{ origin, version, blocks: Vec::new(), last_block: None, db};
|
let mut blockchain = Blockchain{ origin, version, blocks: Vec::new(), last_block: None, db};
|
||||||
blockchain.init_db();
|
blockchain.init_db();
|
||||||
@@ -59,62 +61,65 @@ impl Blockchain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_block(&mut self, block: Block) {
|
pub fn add_block(&mut self, block: Block) -> Result<(), &str> {
|
||||||
if self.check_block(&block, &self.last_block) {
|
if !self.check_block(&block, &self.last_block) {
|
||||||
println!("Adding block:\n{:?}", &block);
|
println!("Bad block found, ignoring:\n{:?}", &block);
|
||||||
self.blocks.push(block.clone());
|
return Err("Bad block found, ignoring");
|
||||||
self.last_block = Some(block.clone());
|
}
|
||||||
let transaction = block.transaction.clone();
|
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
|
// Adding block to DB
|
||||||
let mut statement = self.db.prepare("INSERT INTO blocks (\
|
let mut statement = self.db.prepare("INSERT INTO blocks (\
|
||||||
id, timestamp, version, difficulty, random,\
|
id, timestamp, version, difficulty, random,\
|
||||||
nonce, 'transaction', prev_block_hash, hash)\
|
nonce, 'transaction', prev_block_hash, hash)\
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);").unwrap();
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);").unwrap();
|
||||||
statement.bind(1, block.index as i64);
|
statement.bind(1, block.index as i64).expect("Error in bind");
|
||||||
statement.bind(2, block.timestamp as i64);
|
statement.bind(2, block.timestamp as i64).expect("Error in bind");
|
||||||
statement.bind(3, block.version as i64);
|
statement.bind(3, block.version as i64).expect("Error in bind");
|
||||||
statement.bind(4, block.difficulty as i64);
|
statement.bind(4, block.difficulty as i64).expect("Error in bind");
|
||||||
statement.bind(5, block.random as i64);
|
statement.bind(5, block.random as i64).expect("Error in bind");
|
||||||
statement.bind(6, block.nonce as i64);
|
statement.bind(6, block.nonce as i64).expect("Error in bind");
|
||||||
match &transaction {
|
|
||||||
None => { statement.bind(7, ""); }
|
|
||||||
Some(transaction) => {
|
|
||||||
statement.bind(7, transaction.to_string().as_ref() as &str);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
statement.bind(8, block.prev_block_hash.as_bytes());
|
|
||||||
statement.bind(9, block.hash.as_bytes());
|
|
||||||
statement.next().expect("Error adding block to DB");
|
|
||||||
}
|
|
||||||
|
|
||||||
match &transaction {
|
match &transaction {
|
||||||
None => {}
|
None => { statement.bind(7, "").expect("Error in bind"); }
|
||||||
Some(transaction) => {
|
Some(transaction) => {
|
||||||
self.add_transaction(transaction);
|
statement.bind(7, transaction.to_string().as_ref() as &str).expect("Error in bind");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
statement.bind(8, block.prev_block_hash.as_bytes()).expect("Error in bind");
|
||||||
println!("Bad block found, ignoring:\n{:?}", &block);
|
statement.bind(9, block.hash.as_bytes()).expect("Error in bind");
|
||||||
|
statement.next().expect("Error adding block to DB");
|
||||||
|
}
|
||||||
|
|
||||||
|
match &transaction {
|
||||||
|
None => {
|
||||||
|
Err("Error adding transaction!")
|
||||||
|
}
|
||||||
|
Some(transaction) => {
|
||||||
|
self.add_transaction(transaction);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_transaction(&mut self, t: &Transaction) {
|
fn add_transaction(&mut self, t: &Transaction) {
|
||||||
let mut statement = self.db.prepare("INSERT INTO transactions (identity, confirmation, 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(1, t.identity.as_bytes()).expect("Error in bind");
|
||||||
statement.bind(2, t.confirmation.as_bytes());
|
statement.bind(2, t.confirmation.as_bytes()).expect("Error in bind");
|
||||||
statement.bind(3, t.method.as_ref() as &str);
|
statement.bind(3, t.method.as_ref() as &str).expect("Error in bind");
|
||||||
statement.bind(4, t.data.as_ref() as &str);
|
statement.bind(4, t.data.as_ref() as &str).expect("Error in bind");
|
||||||
statement.bind(5, t.pub_key.as_bytes());
|
statement.bind(5, t.pub_key.as_bytes()).expect("Error in bind");
|
||||||
statement.bind(6, t.signature.as_bytes());
|
statement.bind(6, t.signature.as_bytes()).expect("Error in bind");
|
||||||
statement.next().expect("Error adding transaction to DB");
|
statement.next().expect("Error adding transaction to DB");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_block(&self, index: u64) -> Option<Block> {
|
pub fn get_block(&self, index: u64) -> Option<Block> {
|
||||||
match self.db.prepare("SELECT * FROM blocks WHERE id=? LIMIT 1;") {
|
match self.db.prepare("SELECT * FROM blocks WHERE id=? LIMIT 1;") {
|
||||||
Ok(mut statement) => {
|
Ok(mut statement) => {
|
||||||
statement.bind(1, index as i64);
|
statement.bind(1, index as i64).expect("Error in bind");
|
||||||
while statement.next().unwrap() == State::Row {
|
while statement.next().unwrap() == State::Row {
|
||||||
return match Self::get_block_from_statement(&mut statement) {
|
return match Self::get_block_from_statement(&mut statement) {
|
||||||
None => {
|
None => {
|
||||||
@@ -142,7 +147,7 @@ impl Blockchain {
|
|||||||
}
|
}
|
||||||
let identity_hash = Transaction::hash_identity(domain);
|
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();
|
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());
|
statement.bind(1, identity_hash.as_bytes()).expect("Error in bind");
|
||||||
while let State::Row = statement.next().unwrap() {
|
while let State::Row = statement.next().unwrap() {
|
||||||
let pub_key = Bytes::from_bytes(statement.read::<Vec<u8>>(0).unwrap().as_slice());
|
let pub_key = Bytes::from_bytes(statement.read::<Vec<u8>>(0).unwrap().as_slice());
|
||||||
if !pub_key.eq(&keystore.get_public()) {
|
if !pub_key.eq(&keystore.get_public()) {
|
||||||
@@ -159,7 +164,7 @@ impl Blockchain {
|
|||||||
// Checking for available zone, for this domain
|
// Checking for available zone, for this domain
|
||||||
let identity_hash = Transaction::hash_identity(parts.first().unwrap());
|
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();
|
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());
|
statement.bind(1, identity_hash.as_bytes()).expect("Error in bind");
|
||||||
while let State::Row = statement.next().unwrap() {
|
while let State::Row = statement.next().unwrap() {
|
||||||
// If there is such a zone
|
// If there is such a zone
|
||||||
return true;
|
return true;
|
||||||
@@ -196,15 +201,36 @@ impl Blockchain {
|
|||||||
}*/
|
}*/
|
||||||
|
|
||||||
fn check_block(&self, block: &Block, prev_block: &Option<Block>) -> bool {
|
fn check_block(&self, block: &Block, prev_block: &Option<Block>) -> bool {
|
||||||
// TODO check if it is already stored, or its height is more than we need
|
if !check_block_hash(block) {
|
||||||
if !Self::check_block_hash(block) {
|
println!("{:?} has wrong hash! Ignoring!", &block);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if prev_block.is_none() {
|
// TODO make transaction not Optional
|
||||||
return true;
|
let transaction = block.transaction.as_ref().unwrap();
|
||||||
|
if !check_transaction_signature(&transaction) {
|
||||||
|
println!("{:?} has wrong signature! Ignoring block!", &transaction);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
match prev_block {
|
||||||
|
None => {
|
||||||
|
if block.index != 0 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return block.prev_block_hash == prev_block.as_ref().unwrap().hash;
|
if self.origin.is_zero() && block.index > 0 {
|
||||||
|
panic!("Error adding block {} without origin! Please, fill in origin in config!", block.index);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.origin.is_zero() || block.hash.eq(&self.origin)
|
||||||
|
}
|
||||||
|
Some(prev) => {
|
||||||
|
if block.index != prev.index + 1 {
|
||||||
|
println!("Discarding block with index {} as not needed now", block.index);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
block.prev_block_hash.eq(&prev.hash)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_block_from_statement(statement: &mut Statement) -> Option<Block> {
|
fn get_block_from_statement(statement: &mut Statement) -> Option<Block> {
|
||||||
@@ -219,12 +245,18 @@ impl Blockchain {
|
|||||||
let hash = Bytes::from_bytes(statement.read::<Vec<u8>>(8).unwrap().as_slice());
|
let hash = Bytes::from_bytes(statement.read::<Vec<u8>>(8).unwrap().as_slice());
|
||||||
Some(Block::from_all_params(index, timestamp, version, difficulty, random, nonce, prev_block_hash, hash, transaction))
|
Some(Block::from_all_params(index, timestamp, version, 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 :(
|
pub fn check_block_hash(block: &Block) -> bool {
|
||||||
let mut copy: Block = block.clone();
|
let mut copy: Block = block.clone();
|
||||||
copy.hash = Bytes::default();
|
copy.hash = Bytes::default();
|
||||||
let data = serde_json::to_string(©).unwrap();
|
let data = serde_json::to_string(©).unwrap();
|
||||||
Block::hash(data.as_bytes()) == block.hash
|
Block::hash(data.as_bytes()) == block.hash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn check_transaction_signature(transaction: &Transaction) -> bool {
|
||||||
|
let mut copy = transaction.clone();
|
||||||
|
copy.signature = Bytes::zero64();
|
||||||
|
let data = copy.get_bytes();
|
||||||
|
Keystore::check(data.as_slice(), copy.pub_key.as_bytes(), transaction.signature.as_bytes())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,12 +85,12 @@ impl fmt::Debug for Transaction {
|
|||||||
impl Serialize for Transaction {
|
impl Serialize for Transaction {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error> where S: Serializer {
|
fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error> where S: Serializer {
|
||||||
let mut structure = serializer.serialize_struct("Transaction", 6).unwrap();
|
let mut structure = serializer.serialize_struct("Transaction", 6).unwrap();
|
||||||
structure.serialize_field("identity", &self.identity);
|
structure.serialize_field("identity", &self.identity)?;
|
||||||
structure.serialize_field("confirmation", &self.confirmation);
|
structure.serialize_field("confirmation", &self.confirmation)?;
|
||||||
structure.serialize_field("method", &self.method);
|
structure.serialize_field("method", &self.method)?;
|
||||||
structure.serialize_field("data", &self.data);
|
structure.serialize_field("data", &self.data)?;
|
||||||
structure.serialize_field("pub_key", &self.pub_key);
|
structure.serialize_field("pub_key", &self.pub_key)?;
|
||||||
structure.serialize_field("signature", &self.signature);
|
structure.serialize_field("signature", &self.signature)?;
|
||||||
structure.end()
|
structure.end()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+5
-4
@@ -1,8 +1,6 @@
|
|||||||
use crate::{Keystore, Blockchain, Bus, Bytes};
|
use crate::{Keystore, Blockchain, Bus, Bytes};
|
||||||
use crate::event::Event;
|
use crate::event::Event;
|
||||||
use std::collections::HashMap;
|
use serde::{Serialize, Deserialize};
|
||||||
use serde::{Serialize, Deserialize, Serializer, Deserializer};
|
|
||||||
use serde::de::Error;
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
|
||||||
@@ -65,7 +63,7 @@ impl Settings {
|
|||||||
match File::open(file_name) {
|
match File::open(file_name) {
|
||||||
Ok(mut file) => {
|
Ok(mut file) => {
|
||||||
let mut text = String::new();
|
let mut text = String::new();
|
||||||
file.read_to_string(&mut text);
|
file.read_to_string(&mut text).unwrap();
|
||||||
let loaded = serde_json::from_str(&text);
|
let loaded = serde_json::from_str(&text);
|
||||||
return if loaded.is_ok() {
|
return if loaded.is_ok() {
|
||||||
Some(loaded.unwrap())
|
Some(loaded.unwrap())
|
||||||
@@ -78,6 +76,9 @@ impl Settings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_origin(&self) -> Bytes {
|
pub fn get_origin(&self) -> Bytes {
|
||||||
|
if self.origin.eq("") {
|
||||||
|
return Bytes::zero32();
|
||||||
|
}
|
||||||
let origin = crate::from_hex(&self.origin).expect("Wrong origin in settings");
|
let origin = crate::from_hex(&self.origin).expect("Wrong origin in settings");
|
||||||
Bytes::from_bytes(origin.as_slice())
|
Bytes::from_bytes(origin.as_slice())
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-7
@@ -7,7 +7,7 @@ use rand::{thread_rng, Rng};
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Read, Write};
|
use std::io::Write;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use serde::export::fmt::Error;
|
use serde::export::fmt::Error;
|
||||||
use serde::{Serialize, Deserialize, Serializer, Deserializer};
|
use serde::{Serialize, Deserialize, Serializer, Deserializer};
|
||||||
@@ -26,7 +26,7 @@ pub struct Keystore {
|
|||||||
|
|
||||||
impl Keystore {
|
impl Keystore {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let mut buf = [0u8; 64];
|
let mut buf = [0u8; 32];
|
||||||
let mut rng = thread_rng();
|
let mut rng = thread_rng();
|
||||||
rng.fill(&mut buf);
|
rng.fill(&mut buf);
|
||||||
let (private, public) = keypair(&buf);
|
let (private, public) = keypair(&buf);
|
||||||
@@ -50,11 +50,11 @@ impl Keystore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//TODO Implement error conditions
|
//TODO Implement error conditions
|
||||||
pub fn save(&self, filename: &str, password: &str) {
|
pub fn save(&self, filename: &str, _password: &str) {
|
||||||
match File::create(Path::new(filename)) {
|
match File::create(Path::new(filename)) {
|
||||||
Ok(mut f) => {
|
Ok(mut f) => {
|
||||||
//TODO implement key encryption
|
//TODO implement key encryption
|
||||||
f.write_all(&self.seed);
|
f.write_all(&self.seed).expect("Error saving keystore");
|
||||||
}
|
}
|
||||||
Err(_) => { println!("Error saving key file!"); }
|
Err(_) => { println!("Error saving key file!"); }
|
||||||
}
|
}
|
||||||
@@ -69,10 +69,10 @@ impl Keystore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn sign(&self, message: &[u8]) -> [u8; 64] {
|
pub fn sign(&self, message: &[u8]) -> [u8; 64] {
|
||||||
signature(message, &self.private_key.data)
|
signature(message, self.private_key.data.as_slice())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check(&self, message: &[u8], public_key: &[u8], signature: &[u8]) -> bool {
|
pub fn check(message: &[u8], public_key: &[u8], signature: &[u8]) -> bool {
|
||||||
verify(message, public_key, signature)
|
verify(message, public_key, signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +117,7 @@ impl Bytes {
|
|||||||
|
|
||||||
/// Returns a byte slice of the hash contents.
|
/// Returns a byte slice of the hash contents.
|
||||||
pub fn as_bytes(&self) -> &[u8] {
|
pub fn as_bytes(&self) -> &[u8] {
|
||||||
&self.data
|
self.data.as_slice()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn zero32() -> Self {
|
pub fn zero32() -> Self {
|
||||||
@@ -189,3 +189,12 @@ impl<'dd> Deserialize<'dd> for Bytes {
|
|||||||
deserializer.deserialize_str(BytesVisitor)
|
deserializer.deserialize_str(BytesVisitor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_signature() {
|
||||||
|
let keystore: Keystore = Keystore::new();
|
||||||
|
let data = b"{ identity: 178135D209C697625E3EC71DA5C760382E54936F824EE5083908DA66B14ECE18,\
|
||||||
|
confirmation: A4A0AFECD1A511825226F0D3437C6C6BDAE83554040AA7AEB49DEFEAB0AE9EA4 }";
|
||||||
|
let signature = keystore.sign(data);
|
||||||
|
assert!(Keystore::check(data, keystore.get_public().as_bytes(), &signature), "Wrong signature!")
|
||||||
|
}
|
||||||
|
|||||||
+15
-17
@@ -1,16 +1,15 @@
|
|||||||
#![windows_subsystem = "windows"]
|
#![windows_subsystem = "windows"]
|
||||||
extern crate web_view;
|
extern crate web_view;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
||||||
use rand::{Rng, RngCore};
|
use rand::RngCore;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize};
|
||||||
use web_view::*;
|
use web_view::*;
|
||||||
|
|
||||||
use alfis::{Block, Blockchain, Bytes, Context, Keystore, Settings, Transaction};
|
use alfis::{Blockchain, Bytes, Context, Keystore, Settings, Transaction};
|
||||||
use alfis::event::Event;
|
use alfis::event::Event;
|
||||||
use alfis::miner::Miner;
|
use alfis::miner::Miner;
|
||||||
use alfis::p2p::Network;
|
use alfis::p2p::Network;
|
||||||
@@ -31,7 +30,7 @@ fn main() {
|
|||||||
None => { generate_key(KEYSTORE_DIFFICULTY, Arc::new(AtomicBool::new(true))).expect("Could not load or generate keypair") }
|
None => { generate_key(KEYSTORE_DIFFICULTY, Arc::new(AtomicBool::new(true))).expect("Could not load or generate keypair") }
|
||||||
Some(keystore) => { keystore }
|
Some(keystore) => { keystore }
|
||||||
};
|
};
|
||||||
let blockchain: Blockchain = Blockchain::new(settings.origin.clone(), settings.version);
|
let blockchain: Blockchain = Blockchain::new(&settings);
|
||||||
let context: Arc<Mutex<Context>> = Arc::new(Mutex::new(Context::new(settings, keystore, blockchain)));
|
let context: Arc<Mutex<Context>> = Arc::new(Mutex::new(Context::new(settings, keystore, blockchain)));
|
||||||
|
|
||||||
let mut miner_obj = Miner::new(context.clone());
|
let mut miner_obj = Miner::new(context.clone());
|
||||||
@@ -39,7 +38,7 @@ fn main() {
|
|||||||
let miner: Arc<Mutex<Miner>> = Arc::new(Mutex::new(miner_obj));
|
let miner: Arc<Mutex<Miner>> = Arc::new(Mutex::new(miner_obj));
|
||||||
|
|
||||||
let mut network = Network::new(context.clone());
|
let mut network = Network::new(context.clone());
|
||||||
network.start();
|
network.start().expect("Error starting network component");
|
||||||
|
|
||||||
create_genesis_if_needed(&context, &miner);
|
create_genesis_if_needed(&context, &miner);
|
||||||
run_interface(context.clone(), miner.clone());
|
run_interface(context.clone(), miner.clone());
|
||||||
@@ -76,8 +75,8 @@ fn run_interface(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>) {
|
|||||||
println!("Command {}", arg);
|
println!("Command {}", arg);
|
||||||
match serde_json::from_str(arg).unwrap() {
|
match serde_json::from_str(arg).unwrap() {
|
||||||
Loaded => {
|
Loaded => {
|
||||||
web_view.eval("showMiningIndicator(false);");
|
web_view.eval("showMiningIndicator(false);").expect("Error evaluating!");
|
||||||
let mut handle = web_view.handle();
|
let handle = web_view.handle();
|
||||||
let mut c = context.lock().unwrap();
|
let mut c = context.lock().unwrap();
|
||||||
c.bus.register(move |_uuid, e| {
|
c.bus.register(move |_uuid, e| {
|
||||||
println!("Got event from bus {:?}", &e);
|
println!("Got event from bus {:?}", &e);
|
||||||
@@ -89,9 +88,9 @@ fn run_interface(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>) {
|
|||||||
_ => { false }
|
_ => { false }
|
||||||
};
|
};
|
||||||
handle.dispatch(move |web_view| {
|
handle.dispatch(move |web_view| {
|
||||||
web_view.eval(&format!("showMiningIndicator({});", visible));
|
web_view.eval(&format!("showMiningIndicator({});", visible)).expect("Error evaluating!");
|
||||||
return WVResult::Ok(());
|
return WVResult::Ok(());
|
||||||
});
|
}).expect("Error dispatching!");
|
||||||
true
|
true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -112,11 +111,11 @@ fn run_interface(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>) {
|
|||||||
CheckDomain { name} => {
|
CheckDomain { name} => {
|
||||||
let c = context.lock().unwrap();
|
let c = context.lock().unwrap();
|
||||||
let available = c.get_blockchain().is_domain_available(&name, &c.get_keystore());
|
let available = c.get_blockchain().is_domain_available(&name, &c.get_keystore());
|
||||||
web_view.eval(&format!("domainAvailable({})", available));
|
web_view.eval(&format!("domainAvailable({})", available)).expect("Error evaluating!");
|
||||||
}
|
}
|
||||||
CreateDomain { name, records, tags } => {
|
CreateDomain { name, records, tags } => {
|
||||||
let keystore = {
|
let keystore = {
|
||||||
let mut guard = context.lock().unwrap();
|
let guard = context.lock().unwrap();
|
||||||
guard.get_keystore()
|
guard.get_keystore()
|
||||||
};
|
};
|
||||||
create_domain(miner.clone(), name, records, &keystore);
|
create_domain(miner.clone(), name, records, &keystore);
|
||||||
@@ -152,7 +151,7 @@ fn create_domain<S: Into<String>>(miner: Arc<Mutex<Miner>>, name: S, data: S, ke
|
|||||||
println!("Generating domain {}", name);
|
println!("Generating domain {}", name);
|
||||||
//let rec_vector: Vec<String> = records.into().trim().split("\n").map(|s| s.trim()).map(String::from).collect();
|
//let rec_vector: Vec<String> = records.into().trim().split("\n").map(|s| s.trim()).map(String::from).collect();
|
||||||
//let tags_vector: Vec<String> = tags.into().trim().split(",").map(|s| s.trim()).map(String::from).collect();
|
//let tags_vector: Vec<String> = tags.into().trim().split(",").map(|s| s.trim()).map(String::from).collect();
|
||||||
let mut transaction = { create_transaction(keystore, name, "domain".into(), data.into()) };
|
let transaction = { create_transaction(keystore, name, "domain".into(), data.into()) };
|
||||||
let mut miner_guard = miner.lock().unwrap();
|
let mut miner_guard = miner.lock().unwrap();
|
||||||
miner_guard.add_transaction(transaction);
|
miner_guard.add_transaction(transaction);
|
||||||
}
|
}
|
||||||
@@ -168,10 +167,10 @@ fn create_transaction<S: Into<String>>(keystore: &Keystore, name: S, method: S,
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn create_key(context: Arc<Mutex<Context>>, filename: &str, password: &str) {
|
fn create_key(context: Arc<Mutex<Context>>, filename: &str, password: &str) {
|
||||||
let mut mining = Arc::new(AtomicBool::new(true));
|
let mining = Arc::new(AtomicBool::new(true));
|
||||||
|
{ context.lock().unwrap().bus.post(Event::KeyGeneratorStarted); }
|
||||||
for _ in 0..num_cpus::get() {
|
for _ in 0..num_cpus::get() {
|
||||||
let context = context.clone();
|
let context = context.clone();
|
||||||
{ context.lock().unwrap().bus.post(Event::KeyGeneratorStarted); }
|
|
||||||
let filename= filename.to_owned();
|
let filename= filename.to_owned();
|
||||||
let password= password.to_owned();
|
let password= password.to_owned();
|
||||||
let mining = mining.clone();
|
let mining = mining.clone();
|
||||||
@@ -201,7 +200,7 @@ fn create_key(context: Arc<Mutex<Context>>, filename: &str, password: &str) {
|
|||||||
|
|
||||||
fn generate_key(difficulty: usize, mining: Arc<AtomicBool>) -> Option<Keystore> {
|
fn generate_key(difficulty: usize, mining: Arc<AtomicBool>) -> Option<Keystore> {
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
let mut buf = [0u8; 64];
|
let mut buf = [0u8; 32];
|
||||||
loop {
|
loop {
|
||||||
rng.fill_bytes(&mut buf);
|
rng.fill_bytes(&mut buf);
|
||||||
let keystore = Keystore::from_bytes(&buf);
|
let keystore = Keystore::from_bytes(&buf);
|
||||||
@@ -213,7 +212,6 @@ fn generate_key(difficulty: usize, mining: Arc<AtomicBool>) -> Option<Keystore>
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
|||||||
+11
-40
@@ -8,15 +8,12 @@ use crypto::digest::Digest;
|
|||||||
use crypto::sha2::Sha256;
|
use crypto::sha2::Sha256;
|
||||||
use num_cpus;
|
use num_cpus;
|
||||||
|
|
||||||
use crate::{Block, Bytes, Context, hash_is_good, Keystore, Transaction};
|
use crate::{Block, Bytes, Context, hash_is_good, Transaction};
|
||||||
use crate::event::Event;
|
use crate::event::Event;
|
||||||
|
|
||||||
pub struct Miner {
|
pub struct Miner {
|
||||||
context: Arc<Mutex<Context>>,
|
context: Arc<Mutex<Context>>,
|
||||||
keystore: Keystore,
|
|
||||||
version: u32,
|
|
||||||
transactions: Arc<Mutex<Vec<Transaction>>>,
|
transactions: Arc<Mutex<Vec<Transaction>>>,
|
||||||
last_block: Option<Block>,
|
|
||||||
running: Arc<AtomicBool>,
|
running: Arc<AtomicBool>,
|
||||||
mining: Arc<AtomicBool>,
|
mining: Arc<AtomicBool>,
|
||||||
cond_var: Arc<Condvar>
|
cond_var: Arc<Condvar>
|
||||||
@@ -24,13 +21,9 @@ pub struct Miner {
|
|||||||
|
|
||||||
impl Miner {
|
impl Miner {
|
||||||
pub fn new(context: Arc<Mutex<Context>>) -> Self {
|
pub fn new(context: Arc<Mutex<Context>>) -> Self {
|
||||||
let c = context.lock().unwrap();
|
|
||||||
Miner {
|
Miner {
|
||||||
context: context.clone(),
|
context: context.clone(),
|
||||||
keystore: c.keystore.clone(),
|
|
||||||
version: c.settings.version,
|
|
||||||
transactions: Arc::new(Mutex::new(Vec::new())),
|
transactions: Arc::new(Mutex::new(Vec::new())),
|
||||||
last_block: c.blockchain.blocks.last().cloned(),
|
|
||||||
running: Arc::new(AtomicBool::new(false)),
|
running: Arc::new(AtomicBool::new(false)),
|
||||||
mining: Arc::new(AtomicBool::new(false)),
|
mining: Arc::new(AtomicBool::new(false)),
|
||||||
cond_var: Arc::new(Condvar::new())
|
cond_var: Arc::new(Condvar::new())
|
||||||
@@ -65,19 +58,17 @@ impl Miner {
|
|||||||
|
|
||||||
let mut lock = transactions.lock().unwrap();
|
let mut lock = transactions.lock().unwrap();
|
||||||
if lock.len() > 0 {
|
if lock.len() > 0 {
|
||||||
println!("Starting to mine some transaction");
|
println!("Got new transaction to mine");
|
||||||
let transaction = lock.remove(0);
|
let transaction = lock.remove(0);
|
||||||
mining.store(true, Ordering::Relaxed);
|
mining.store(true, Ordering::Relaxed);
|
||||||
Miner::mine_internal(context.clone(), transactions.clone(), transaction, mining.clone(), cond_var.clone());
|
Miner::mine_internal(context.clone(), transactions.clone(), transaction, mining.clone(), cond_var.clone());
|
||||||
} else {
|
} else {
|
||||||
println!("Waiting for transactions");
|
let _ = cond_var.wait(lock).expect("Error in wait lock!");
|
||||||
cond_var.wait(lock);
|
|
||||||
println!("Got notified on new transaction");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let mining = self.mining.clone();
|
let mining = self.mining.clone();
|
||||||
self.context.lock().unwrap().bus.register(move |uuid, e| {
|
self.context.lock().unwrap().bus.register(move |_uuid, e| {
|
||||||
if e == Event::ActionStopMining {
|
if e == Event::ActionStopMining {
|
||||||
mining.store(false, Ordering::Relaxed);
|
mining.store(false, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
@@ -90,13 +81,11 @@ impl Miner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn mine_internal(context: Arc<Mutex<Context>>, transactions: Arc<Mutex<Vec<Transaction>>>, mut transaction: Transaction, mining: Arc<AtomicBool>, cond_var: Arc<Condvar>) {
|
fn mine_internal(context: Arc<Mutex<Context>>, transactions: Arc<Mutex<Vec<Transaction>>>, mut transaction: Transaction, mining: Arc<AtomicBool>, cond_var: Arc<Condvar>) {
|
||||||
let mut last_block_time = 0i64;
|
let version= {
|
||||||
let mut version= 0u32;
|
|
||||||
{
|
|
||||||
let mut c = context.lock().unwrap();
|
let mut c = context.lock().unwrap();
|
||||||
c.bus.post(Event::MinerStarted);
|
c.bus.post(Event::MinerStarted);
|
||||||
version = c.settings.version;
|
c.settings.version
|
||||||
}
|
};
|
||||||
let block = {
|
let block = {
|
||||||
if transaction.signature.is_zero() {
|
if transaction.signature.is_zero() {
|
||||||
// Signing it with private key from Keystore
|
// Signing it with private key from Keystore
|
||||||
@@ -114,7 +103,6 @@ impl Miner {
|
|||||||
Block::new(0, Utc::now().timestamp(), version, Bytes::zero32(), Some(transaction.clone()))
|
Block::new(0, Utc::now().timestamp(), version, Bytes::zero32(), Some(transaction.clone()))
|
||||||
},
|
},
|
||||||
Some(block) => {
|
Some(block) => {
|
||||||
last_block_time = block.timestamp;
|
|
||||||
// Creating a block with that signed transaction
|
// Creating a block with that signed transaction
|
||||||
Block::new(block.index + 1, Utc::now().timestamp(), version, block.hash.clone(), Some(transaction.clone()))
|
Block::new(block.index + 1, Utc::now().timestamp(), version, block.hash.clone(), Some(transaction.clone()))
|
||||||
},
|
},
|
||||||
@@ -134,11 +122,10 @@ impl Miner {
|
|||||||
let cond_var = cond_var.clone();
|
let cond_var = cond_var.clone();
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
live_threads.fetch_add(1, Ordering::Relaxed);
|
live_threads.fetch_add(1, Ordering::Relaxed);
|
||||||
let mut count = 0u32;
|
match find_hash(&mut Sha256::new(), block, mining.clone()) {
|
||||||
match find_hash(&mut Sha256::new(), block, last_block_time, mining.clone()) {
|
|
||||||
None => {
|
None => {
|
||||||
println!("Mining did not find suitable hash or was stopped");
|
println!("Mining did not find suitable hash or was stopped");
|
||||||
count = live_threads.fetch_sub(1, Ordering::Relaxed);
|
let count = live_threads.fetch_sub(1, Ordering::Relaxed);
|
||||||
// If this is the last thread, but mining was not stopped by another thread
|
// If this is the last thread, but mining was not stopped by another thread
|
||||||
if count == 0 && mining.load(Ordering::Relaxed) {
|
if count == 0 && mining.load(Ordering::Relaxed) {
|
||||||
// If all threads came empty with mining we return transaction to the queue
|
// If all threads came empty with mining we return transaction to the queue
|
||||||
@@ -148,9 +135,8 @@ impl Miner {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Some(block) => {
|
Some(block) => {
|
||||||
count = live_threads.fetch_sub(1, Ordering::Relaxed);
|
|
||||||
let mut context = context.lock().unwrap();
|
let mut context = context.lock().unwrap();
|
||||||
context.blockchain.add_block(block);
|
context.blockchain.add_block(block).expect("Error adding fresh mined block!");
|
||||||
context.bus.post(Event::MinerStopped);
|
context.bus.post(Event::MinerStopped);
|
||||||
mining.store(false, Ordering::Relaxed);
|
mining.store(false, Ordering::Relaxed);
|
||||||
},
|
},
|
||||||
@@ -160,22 +146,16 @@ impl Miner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_hash(digest: &mut dyn Digest, mut block: Block, prev_block_time: i64, running: Arc<AtomicBool>) -> Option<Block> {
|
fn find_hash(digest: &mut dyn Digest, mut block: Block, running: Arc<AtomicBool>) -> Option<Block> {
|
||||||
let mut buf: [u8; 32] = [0; 32];
|
let mut buf: [u8; 32] = [0; 32];
|
||||||
block.random = rand::random();
|
block.random = rand::random();
|
||||||
println!("Mining block {}", serde_json::to_string(&block).unwrap());
|
println!("Mining block {}", serde_json::to_string(&block).unwrap());
|
||||||
//let start_difficulty = block.difficulty;
|
|
||||||
for nonce in 0..std::u64::MAX {
|
for nonce in 0..std::u64::MAX {
|
||||||
if !running.load(Ordering::Relaxed) {
|
if !running.load(Ordering::Relaxed) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
block.timestamp = Utc::now().timestamp();
|
block.timestamp = Utc::now().timestamp();
|
||||||
block.nonce = nonce;
|
block.nonce = nonce;
|
||||||
// if nonce % 1000 == 0 {
|
|
||||||
// println!("Nonce {}", nonce);
|
|
||||||
// }
|
|
||||||
// TODO uncomment for real run
|
|
||||||
//block.difficulty = start_difficulty + get_time_difficulty(prev_block_time, block.timestamp);
|
|
||||||
|
|
||||||
digest.reset();
|
digest.reset();
|
||||||
digest.input(serde_json::to_string(&block).unwrap().as_bytes());
|
digest.input(serde_json::to_string(&block).unwrap().as_bytes());
|
||||||
@@ -186,13 +166,4 @@ fn find_hash(digest: &mut dyn Digest, mut block: Block, prev_block_time: i64, ru
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
|
||||||
|
|
||||||
fn get_time_difficulty(prev_time: i64, now: i64) -> usize {
|
|
||||||
let diff = now - prev_time;
|
|
||||||
if diff < 900_000 {
|
|
||||||
(900_000 as usize - diff as usize) / 60_000
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,6 @@ extern crate serde;
|
|||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use crate::p2p::peer::Peer;
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub enum Message {
|
pub enum Message {
|
||||||
|
|||||||
+24
-23
@@ -2,7 +2,6 @@ extern crate serde;
|
|||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
|
|
||||||
use std::{io, thread};
|
use std::{io, thread};
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@@ -11,11 +10,9 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
|||||||
use mio::{Events, Interest, Poll, Registry, Token};
|
use mio::{Events, Interest, Poll, Registry, Token};
|
||||||
use mio::event::Event;
|
use mio::event::Event;
|
||||||
use mio::net::{TcpListener, TcpStream};
|
use mio::net::{TcpListener, TcpStream};
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::{Context, Block, p2p::Message, p2p::State, p2p::Peer, p2p::Peers};
|
use crate::{Context, Block, p2p::Message, p2p::State, p2p::Peer, p2p::Peers};
|
||||||
use std::net::{SocketAddr, IpAddr, SocketAddrV4};
|
use std::net::{SocketAddr, IpAddr, SocketAddrV4};
|
||||||
use std::borrow::BorrowMut;
|
|
||||||
|
|
||||||
const SERVER: Token = Token(0);
|
const SERVER: Token = Token(0);
|
||||||
const POLL_TIMEOUT: Option<Duration> = Some(Duration::from_millis(3000));
|
const POLL_TIMEOUT: Option<Duration> = Some(Duration::from_millis(3000));
|
||||||
@@ -88,7 +85,7 @@ impl Network {
|
|||||||
}
|
}
|
||||||
token => {
|
token => {
|
||||||
match peers.get_mut_peer(&token) {
|
match peers.get_mut_peer(&token) {
|
||||||
Some(peer) => {
|
Some(_peer) => {
|
||||||
match handle_connection_event(context.clone(), &mut peers, &poll.registry(), &event) {
|
match handle_connection_event(context.clone(), &mut peers, &poll.registry(), &event) {
|
||||||
Ok(result) => {
|
Ok(result) => {
|
||||||
if !result {
|
if !result {
|
||||||
@@ -123,7 +120,7 @@ fn handle_connection_event(context: Arc<Mutex<Context>>, peers: &mut Peers, regi
|
|||||||
|
|
||||||
if event.is_readable() {
|
if event.is_readable() {
|
||||||
let data = {
|
let data = {
|
||||||
let mut peer = peers.get_mut_peer(&event.token()).expect("Error getting peer for connection");
|
let peer = peers.get_mut_peer(&event.token()).expect("Error getting peer for connection");
|
||||||
let mut stream = peer.get_stream();
|
let mut stream = peer.get_stream();
|
||||||
read_message(&mut stream)
|
read_message(&mut stream)
|
||||||
};
|
};
|
||||||
@@ -134,8 +131,8 @@ fn handle_connection_event(context: Arc<Mutex<Context>>, peers: &mut Peers, regi
|
|||||||
Ok(message) => {
|
Ok(message) => {
|
||||||
println!("Got message from socket {}: {:?}", &event.token().0, &message);
|
println!("Got message from socket {}: {:?}", &event.token().0, &message);
|
||||||
let new_state = handle_message(context.clone(), message, peers, &event.token());
|
let new_state = handle_message(context.clone(), message, peers, &event.token());
|
||||||
let mut peer = peers.get_mut_peer(&event.token()).unwrap();
|
let peer = peers.get_mut_peer(&event.token()).unwrap();
|
||||||
let mut stream = peer.get_stream();
|
let stream = peer.get_stream();
|
||||||
match new_state {
|
match new_state {
|
||||||
State::Message { data } => {
|
State::Message { data } => {
|
||||||
if event.is_writable() {
|
if event.is_writable() {
|
||||||
@@ -154,7 +151,7 @@ fn handle_connection_event(context: Arc<Mutex<Context>>, peers: &mut Peers, regi
|
|||||||
State::Error => {}
|
State::Error => {}
|
||||||
State::Banned => {}
|
State::Banned => {}
|
||||||
State::Offline { .. } => {
|
State::Offline { .. } => {
|
||||||
peer.set_state(State::offline(1));
|
peer.set_state(State::offline());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -175,7 +172,7 @@ fn handle_connection_event(context: Arc<Mutex<Context>>, peers: &mut Peers, regi
|
|||||||
State::Connecting => {
|
State::Connecting => {
|
||||||
println!("Sending hello to socket {}", event.token().0);
|
println!("Sending hello to socket {}", event.token().0);
|
||||||
let data: String = {
|
let data: String = {
|
||||||
let mut c = context.lock().unwrap();
|
let c = context.lock().unwrap();
|
||||||
let message = Message::hand(&c.settings.origin, c.settings.version, c.settings.public);
|
let message = Message::hand(&c.settings.origin, c.settings.version, c.settings.public);
|
||||||
serde_json::to_string(&message).unwrap()
|
serde_json::to_string(&message).unwrap()
|
||||||
};
|
};
|
||||||
@@ -191,7 +188,7 @@ fn handle_connection_event(context: Arc<Mutex<Context>>, peers: &mut Peers, regi
|
|||||||
println!("Odd version of pings :)");
|
println!("Odd version of pings :)");
|
||||||
if from.elapsed().as_secs() >= 30 {
|
if from.elapsed().as_secs() >= 30 {
|
||||||
let data: String = {
|
let data: String = {
|
||||||
let mut c = context.lock().unwrap();
|
let c = context.lock().unwrap();
|
||||||
let message = Message::ping(c.blockchain.height());
|
let message = Message::ping(c.blockchain.height());
|
||||||
serde_json::to_string(&message).unwrap()
|
serde_json::to_string(&message).unwrap()
|
||||||
};
|
};
|
||||||
@@ -232,7 +229,7 @@ fn read_message(stream: &mut &mut TcpStream) -> Result<Vec<u8>, Vec<u8>> {
|
|||||||
Err(ref err) if would_block(err) => break,
|
Err(ref err) if would_block(err) => break,
|
||||||
Err(ref err) if interrupted(err) => continue,
|
Err(ref err) if interrupted(err) => continue,
|
||||||
// Other errors we'll consider fatal.
|
// Other errors we'll consider fatal.
|
||||||
Err(err) => return Err(buf),
|
Err(_) => return Err(buf),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if buf.len() == data_size {
|
if buf.len() == data_size {
|
||||||
@@ -244,29 +241,30 @@ fn read_message(stream: &mut &mut TcpStream) -> Result<Vec<u8>, Vec<u8>> {
|
|||||||
|
|
||||||
fn send_message(connection: &mut TcpStream, data: &Vec<u8>) {
|
fn send_message(connection: &mut TcpStream, data: &Vec<u8>) {
|
||||||
// TODO handle errors
|
// TODO handle errors
|
||||||
connection.write_u32::<BigEndian>(data.len() as u32);
|
connection.write_u32::<BigEndian>(data.len() as u32).expect("Error sending message");
|
||||||
connection.write_all(&data).expect("Error writing to socket");
|
connection.write_all(&data).expect("Error writing to socket");
|
||||||
connection.flush();
|
connection.flush().expect("Error sending message");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_message(context: Arc<Mutex<Context>>, message: Message, peers: &mut Peers, token: &Token) -> State {
|
fn handle_message(context: Arc<Mutex<Context>>, message: Message, peers: &mut Peers, token: &Token) -> State {
|
||||||
let my_height = {
|
let (my_height, my_origin, my_version) = {
|
||||||
let context = context.lock().unwrap();
|
let context = context.lock().unwrap();
|
||||||
context.blockchain.height()
|
(context.blockchain.height(), &context.settings.origin.clone(), context.settings.version)
|
||||||
};
|
};
|
||||||
match message {
|
match message {
|
||||||
Message::Hand { origin: origin, version, public } => {
|
Message::Hand { origin, version, public } => {
|
||||||
let context = context.lock().unwrap();
|
if origin.eq(my_origin) && version == my_version {
|
||||||
if origin == context.settings.origin && version == context.settings.version {
|
let peer = peers.get_mut_peer(token).unwrap();
|
||||||
let mut peer = peers.get_mut_peer(token).unwrap();
|
|
||||||
peer.set_public(public);
|
peer.set_public(public);
|
||||||
State::message(Message::shake(&context.settings.origin, context.settings.version, true, context.blockchain.height()))
|
State::message(Message::shake(&origin, version, true, my_height))
|
||||||
} else {
|
} else {
|
||||||
State::Error
|
State::Error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::Shake { origin, version, ok, height } => {
|
Message::Shake { origin, version, ok, height } => {
|
||||||
// TODO check origin and version for compatibility
|
if origin.ne(my_origin) || version != my_version {
|
||||||
|
return State::Error;
|
||||||
|
}
|
||||||
if ok {
|
if ok {
|
||||||
if height > my_height {
|
if height > my_height {
|
||||||
State::message(Message::GetBlock { index: my_height + 1u64 })
|
State::message(Message::GetBlock { index: my_height + 1u64 })
|
||||||
@@ -308,6 +306,7 @@ fn handle_message(context: Arc<Mutex<Context>>, message: Message, peers: &mut Pe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::Block { index, block } => {
|
Message::Block { index, block } => {
|
||||||
|
println!("Received block {}", index);
|
||||||
let block: Block = match serde_json::from_str(&block) {
|
let block: Block = match serde_json::from_str(&block) {
|
||||||
Ok(block) => block,
|
Ok(block) => block,
|
||||||
Err(_) => return State::Error
|
Err(_) => return State::Error
|
||||||
@@ -316,8 +315,10 @@ fn handle_message(context: Arc<Mutex<Context>>, message: Message, peers: &mut Pe
|
|||||||
let context = context.clone();
|
let context = context.clone();
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let mut context = context.lock().unwrap();
|
let mut context = context.lock().unwrap();
|
||||||
context.blockchain.add_block(block);
|
match context.blockchain.add_block(block) {
|
||||||
context.bus.post(crate::event::Event::BlockchainChanged)
|
Ok(_) => { context.bus.post(crate::event::Event::BlockchainChanged); }
|
||||||
|
Err(_) => { println!("Error adding received block"); }
|
||||||
|
}
|
||||||
});
|
});
|
||||||
State::idle()
|
State::idle()
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-3
@@ -1,7 +1,6 @@
|
|||||||
use crate::p2p::State;
|
use crate::p2p::State;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use mio::net::TcpStream;
|
use mio::net::TcpStream;
|
||||||
use std::sync::RwLock;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Peer {
|
pub struct Peer {
|
||||||
@@ -49,9 +48,9 @@ impl Peer {
|
|||||||
self.state.disabled()
|
self.state.disabled()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If loopback address then we care about ip and port.
|
||||||
|
/// If regular address then we only care about the ip and ignore the port.
|
||||||
pub fn equals(&self, addr: &SocketAddr) -> bool {
|
pub fn equals(&self, addr: &SocketAddr) -> bool {
|
||||||
/// If loopback address then we care about ip and port.
|
|
||||||
/// If regular address then we only care about the ip and ignore the port.
|
|
||||||
if self.addr.ip().is_loopback() {
|
if self.addr.ip().is_loopback() {
|
||||||
self.addr == *addr
|
self.addr == *addr
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+2
-2
@@ -80,7 +80,7 @@ impl Peers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_pings(&mut self, registry: &Registry, height: u64) {
|
pub fn send_pings(&mut self, registry: &Registry, height: u64) {
|
||||||
for (token, mut peer) in self.peers.iter_mut() {
|
for (token, peer) in self.peers.iter_mut() {
|
||||||
match peer.get_state() {
|
match peer.get_state() {
|
||||||
State::Idle { from } => {
|
State::Idle { from } => {
|
||||||
if from.elapsed().as_secs() >= PING_PERIOD {
|
if from.elapsed().as_secs() >= PING_PERIOD {
|
||||||
@@ -93,7 +93,7 @@ impl Peers {
|
|||||||
};
|
};
|
||||||
|
|
||||||
peer.set_state(State::message(message));
|
peer.set_state(State::message(message));
|
||||||
let mut stream = peer.get_stream();
|
let stream = peer.get_stream();
|
||||||
registry.reregister(stream, token.clone(), Interest::WRITABLE).unwrap();
|
registry.reregister(stream, token.clone(), Interest::WRITABLE).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-15
@@ -9,7 +9,7 @@ pub enum State {
|
|||||||
Message { data: Vec<u8> },
|
Message { data: Vec<u8> },
|
||||||
Error,
|
Error,
|
||||||
Banned,
|
Banned,
|
||||||
Offline { from: Instant, attempts: usize },
|
Offline { from: Instant },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
@@ -17,19 +17,8 @@ impl State {
|
|||||||
Self::Idle { from: Instant::now() }
|
Self::Idle { from: Instant::now() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn offline(attempts: usize) -> Self {
|
pub fn offline() -> Self {
|
||||||
Self::Offline { attempts, from: Instant::now() }
|
Self::Offline { from: Instant::now() }
|
||||||
}
|
|
||||||
|
|
||||||
pub fn still_offline(state: Self) -> Self {
|
|
||||||
match state {
|
|
||||||
State::Offline { attempts, from } => {
|
|
||||||
Self::Offline { attempts: attempts + 1, from }
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
Self::Offline { attempts: 1, from: Instant::now() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn message(message: Message) -> Self {
|
pub fn message(message: Message) -> Self {
|
||||||
@@ -51,7 +40,7 @@ impl State {
|
|||||||
match self {
|
match self {
|
||||||
State::Error => { true }
|
State::Error => { true }
|
||||||
State::Banned => { true }
|
State::Banned => { true }
|
||||||
State::Offline { from, attempts } => {
|
State::Offline { from} => {
|
||||||
from.elapsed().as_secs() < 60 // We check offline peers to become online every 5 minutes
|
from.elapsed().as_secs() < 60 // We check offline peers to become online every 5 minutes
|
||||||
}
|
}
|
||||||
_ => { false }
|
_ => { false }
|
||||||
|
|||||||
+4
-6
@@ -1,4 +1,3 @@
|
|||||||
use crate::event::Event;
|
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
@@ -11,7 +10,7 @@ impl<T: Clone> Bus<T> {
|
|||||||
Bus { listeners: HashMap::new() }
|
Bus { listeners: HashMap::new() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register<F>(&mut self, mut closure: F) -> Uuid where F: FnMut(&Uuid, T) -> bool + Send + Sync + 'static {
|
pub fn register<F>(&mut self, closure: F) -> Uuid where F: FnMut(&Uuid, T) -> bool + Send + Sync + 'static {
|
||||||
let uuid = Uuid::new_v4();
|
let uuid = Uuid::new_v4();
|
||||||
self.listeners.insert(uuid.clone(), Box::new(closure));
|
self.listeners.insert(uuid.clone(), Box::new(closure));
|
||||||
uuid
|
uuid
|
||||||
@@ -30,7 +29,6 @@ impl<T: Clone> Bus<T> {
|
|||||||
|
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::sync::atomic::{AtomicI32, Ordering};
|
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
@@ -39,8 +37,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test1() {
|
fn test1() {
|
||||||
let mut string = Arc::new(Mutex::new(String::from("start")));
|
let string = Arc::new(Mutex::new(String::from("start")));
|
||||||
let mut bus = Arc::new(Mutex::new(Bus::new()));
|
let bus = Arc::new(Mutex::new(Bus::new()));
|
||||||
let string_copy = string.clone();
|
let string_copy = string.clone();
|
||||||
{
|
{
|
||||||
bus.lock().unwrap().register(move |_uuid, e| {
|
bus.lock().unwrap().register(move |_uuid, e| {
|
||||||
@@ -56,7 +54,7 @@ mod tests {
|
|||||||
bus2.lock().unwrap().post(Event::BlockchainChanged);
|
bus2.lock().unwrap().post(Event::BlockchainChanged);
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut guard = string.lock().unwrap();
|
let guard = string.lock().unwrap();
|
||||||
thread::sleep(Duration::from_millis(100));
|
thread::sleep(Duration::from_millis(100));
|
||||||
println!("string = {}", &guard);
|
println!("string = {}", &guard);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user