Implemented loading Settings from file. Implemented mining of Keystore (key pair). Changed Transaction structure a lot. Added an icon to windows build. Changed some HTML.

This commit is contained in:
Revertron
2021-01-18 00:18:35 +01:00
parent 4703ae6f49
commit 70b3a833b9
15 changed files with 11036 additions and 299 deletions
+11 -2
View File
@@ -3,6 +3,7 @@ name = "alfis"
version = "0.1.0" version = "0.1.0"
authors = ["Revertron <rev@revertron.com>"] authors = ["Revertron <rev@revertron.com>"]
edition = "2018" edition = "2018"
build = "build.rs"
#![windows_subsystem = "windows"] #![windows_subsystem = "windows"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -10,7 +11,7 @@ edition = "2018"
rust-crypto = "^0.2" rust-crypto = "^0.2"
num_cpus = "1.13.0" num_cpus = "1.13.0"
byteorder = "1.3.2" byteorder = "1.3.2"
web-view = { version = "0.5.4", features = [] } web-view = { version = "0.7.2", features = [] }
serde = { version = "1.0.102", features = ["derive"] } serde = { version = "1.0.102", features = ["derive"] }
serde_json = "1.0.42" serde_json = "1.0.42"
num-bigint = "0.2" num-bigint = "0.2"
@@ -20,7 +21,15 @@ groestl = "0.8.0"
base64 = "0.11.0" base64 = "0.11.0"
chrono = "0.4.9" chrono = "0.4.9"
rand = "0.7.2" rand = "0.7.2"
eventbus = "0.5.1"
[build-dependencies]
winres = "0.1"
[dev-dependencies] [dev-dependencies]
serde_bytes = "0.11.2" serde_bytes = "0.11.2"
serde_derive = "1.0.27" serde_derive = "1.0.27"
[package.metadata.winres]
ProductName="ALFIS"
FileDescription="Alternative Free Identity System for independent DNS and more."
+5
View File
@@ -0,0 +1,5 @@
{
"chain_id": 42,
"version": 0,
"key_file": "default.key"
}
+9
View File
@@ -0,0 +1,9 @@
extern crate winres;
fn main() {
if cfg!(target_os = "windows") {
let mut res = winres::WindowsResource::new();
res.set_icon("globe_icon.ico");
res.compile().unwrap();
}
}
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

+10 -32
View File
@@ -11,7 +11,7 @@ use num_bigint::BigUint;
use num_traits::One; use num_traits::One;
use crypto::sha2::Sha256; use crypto::sha2::Sha256;
use crypto::digest::Digest; use crypto::digest::Digest;
use crate::keys::Key; use crate::keys::Bytes;
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)] #[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
pub struct Block { pub struct Block {
@@ -24,14 +24,14 @@ pub struct Block {
pub nonce: u64, pub nonce: u64,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub transaction: Option<Transaction>, pub transaction: Option<Transaction>,
#[serde(default, skip_serializing_if = "Key::is_zero")] #[serde(default, skip_serializing_if = "Bytes::is_zero")]
pub prev_block_hash: Key, pub prev_block_hash: Bytes,
#[serde(default, skip_serializing_if = "Key::is_zero")] #[serde(default, skip_serializing_if = "Bytes::is_zero")]
pub hash: Key, pub hash: Bytes,
} }
impl Block { impl Block {
pub fn new(index: u64, timestamp: i64, chain_id: u32, version: u32, prev_block_hash: Key, transaction: Option<Transaction>) -> Self { pub fn new(index: u64, timestamp: i64, chain_id: u32, version: u32, prev_block_hash: Bytes, transaction: Option<Transaction>) -> Self {
Block { Block {
index, index,
timestamp, timestamp,
@@ -43,41 +43,19 @@ impl Block {
nonce: 0, nonce: 0,
transaction, transaction,
prev_block_hash, prev_block_hash,
hash: Key::default(), hash: Bytes::default(),
} }
} }
pub fn mine(&mut self) { pub fn hash(data: &[u8]) -> Bytes {
self.random = rand::random();
let data = serde_json::to_string(&self).unwrap();
println!("Mining block:\n{}", data);
for nonce_attempt in 0..std::u64::MAX {
self.nonce = nonce_attempt;
self.timestamp = Utc::now().timestamp();
let hash = Self::hash(serde_json::to_string(&self).unwrap().as_bytes());
if hash_is_good(&hash.as_bytes(), self.difficulty) {
self.hash = hash;
return;
}
}
}
pub fn hash(data: &[u8]) -> Key {
let mut buf: [u8; 32] = [0; 32]; let mut buf: [u8; 32] = [0; 32];
let mut digest = Sha256::new(); let mut digest = Sha256::new();
digest.input(data); digest.input(data);
digest.result(&mut buf); digest.result(&mut buf);
Key::new(buf.to_vec()) Bytes::new(buf.to_vec())
} }
pub fn is_genesis(&self) -> bool { pub fn is_genesis(&self) -> bool {
self.index == 0 && self.transaction.is_none() && self.prev_block_hash == Key::default() self.index == 0 && self.transaction.is_none() && self.prev_block_hash == Bytes::default()
} }
}
fn hash_is_good(hash: &[u8], difficulty: usize) -> bool {
let target = BigUint::one() << ((hash.len() << 3) - difficulty);
let hash_int = BigUint::from_bytes_be(&hash);
return hash_int < target;
} }
+2 -2
View File
@@ -1,4 +1,4 @@
use crate::{Block, Transaction, Key}; use crate::{Block, Transaction, Bytes};
use chrono::Utc; use chrono::Utc;
pub struct Blockchain { pub struct Blockchain {
@@ -54,7 +54,7 @@ impl Blockchain {
pub fn check_block_hash(block: &Block) -> bool { pub fn check_block_hash(block: &Block) -> bool {
// We need to clear Hash value to rehash it without it for check :( // We need to clear Hash value to rehash it without it for check :(
let mut copy: Block = block.clone(); let mut copy: Block = block.clone();
copy.hash = Key::default(); copy.hash = Bytes::default();
let data = serde_json::to_string(&copy).unwrap(); let data = serde_json::to_string(&copy).unwrap();
Block::hash(data.as_bytes()) == block.hash Block::hash(data.as_bytes()) == block.hash
} }
+10832
View File
File diff suppressed because it is too large Load Diff
+24 -8
View File
@@ -1,5 +1,9 @@
use crate::{Keystore, Blockchain}; use crate::{Keystore, Blockchain};
use std::collections::HashMap; use std::collections::HashMap;
use serde::{Serialize, Deserialize, Serializer, Deserializer};
use serde::de::Error;
use std::fs::File;
use std::io::Read;
pub struct Context { pub struct Context {
pub(crate) settings: Settings, pub(crate) settings: Settings,
@@ -38,21 +42,33 @@ impl Context {
pub fn get_blockchain(&self) -> &Blockchain { pub fn get_blockchain(&self) -> &Blockchain {
&self.blockchain &self.blockchain
} }
pub fn add_salt(&mut self, name: String, salt: String) {
&self.settings.salts.insert(name, salt);
}
} }
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Settings { pub struct Settings {
pub chain_id: u32, pub chain_id: u32,
pub version: u32, pub version: u32,
salts: HashMap<String, String> pub key_file: String
} }
impl Settings { impl Settings {
/// TODO parse settings pub fn new<S: Into<String>>(settings: S) -> serde_json::Result<Settings> {
pub fn new<S: Into<String>>(settings: S) -> Settings { serde_json::from_str(&settings.into())
Settings { chain_id: 42, version: 0, salts: HashMap::new() } }
pub fn load(file_name: &str) -> Option<Settings> {
match File::open(file_name) {
Ok(mut file) => {
let mut text = String::new();
file.read_to_string(&mut text);
let loaded = serde_json::from_str(&text);
return if loaded.is_ok() {
Some(loaded.unwrap())
} else {
None
}
},
Err(..) => None
}
} }
} }
+4 -22
View File
@@ -34,7 +34,10 @@
</div><!--column--> </div><!--column-->
<div class="column auto"> <div class="column auto">
<div class="content center" id="main">This screen in now yet implemented</div> <div class="content center" id="main"><h1>Welcome to ALFIS!</h1>
<p>ALFIS stands for Alternative Free Identity System.</p>
<p>It gives you an opportunity to create your own domains and use them in decentralized networks, store security certificates for browsers to trust without any centralized CA.</p>
</div>
<div class="content is-hidden" id="key_load"> <div class="content is-hidden" id="key_load">
<form action="#"> <form action="#">
@@ -56,9 +59,6 @@
<div class="control"> <div class="control">
<button class="button is-link" onclick="loadKey();">Load</button> <button class="button is-link" onclick="loadKey();">Load</button>
</div> </div>
<div class="control">
<button class="button is-link is-light">Cancel</button>
</div>
</div> </div>
</form> </form>
</div> </div>
@@ -84,9 +84,6 @@
<div class="control"> <div class="control">
<button class="button is-link" onclick="createKey();">Create</button> <button class="button is-link" onclick="createKey();">Create</button>
</div> </div>
<div class="control">
<button class="button is-link is-light">Cancel</button>
</div>
</div> </div>
</form> </form>
</div> </div>
@@ -126,9 +123,6 @@
<div class="control"> <div class="control">
<button class="button is-link">Change password</button> <button class="button is-link">Change password</button>
</div> </div>
<div class="control">
<button class="button is-link is-light">Cancel</button>
</div>
</div> </div>
</form> </form>
</div> </div>
@@ -162,9 +156,6 @@
<div class="control"> <div class="control">
<button class="button is-link" onclick="createDomain();">Create domain</button> <button class="button is-link" onclick="createDomain();">Create domain</button>
</div> </div>
<div class="control">
<button class="button is-link is-light">Cancel</button>
</div>
</div> </div>
</form> </form>
</div> </div>
@@ -197,9 +188,6 @@
<div class="control"> <div class="control">
<button class="button is-link" onclick="changeDomain();">Replace records</button> <button class="button is-link" onclick="changeDomain();">Replace records</button>
</div> </div>
<div class="control">
<button class="button is-link is-light">Cancel</button>
</div>
</div> </div>
</form> </form>
</div> </div>
@@ -225,9 +213,6 @@
<div class="control"> <div class="control">
<button class="button is-link" onclick="renewDomain();">Renew domain</button> <button class="button is-link" onclick="renewDomain();">Renew domain</button>
</div> </div>
<div class="control">
<button class="button is-link is-light">Cancel</button>
</div>
</div> </div>
</form> </form>
</div> </div>
@@ -253,9 +238,6 @@
<div class="control"> <div class="control">
<button class="button is-link" onclick="transferDomain();">Transfer domain</button> <button class="button is-link" onclick="transferDomain();">Transfer domain</button>
</div> </div>
<div class="control">
<button class="button is-link is-light">Cancel</button>
</div>
</div> </div>
</form> </form>
</div> </div>
+46 -26
View File
@@ -1,20 +1,25 @@
extern crate crypto; extern crate crypto;
extern crate serde; extern crate serde;
extern crate serde_json;
use crypto::ed25519::{keypair, signature, verify}; use crypto::ed25519::{keypair, signature, verify};
use rand::{thread_rng, Rng}; use rand::{thread_rng, Rng};
use std::fs;
use std::fmt; use std::fmt;
use std::fs;
use std::fs::File;
use std::io::{Read, 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};
// For deserialization // For deserialization
use serde::de::{Error as DeError, Visitor}; use serde::de::{Error as DeError, Visitor};
use serde::export::Formatter; use serde::export::Formatter;
use crate::hash_is_good;
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Keystore { pub struct Keystore {
private_key: Key, private_key: Bytes,
public_key: Key, public_key: Bytes,
#[serde(skip)] #[serde(skip)]
seed: Vec<u8> seed: Vec<u8>
} }
@@ -25,12 +30,12 @@ impl Keystore {
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);
Keystore {private_key: Key::from_bytes(&private), public_key: Key::from_bytes(&public), seed: Vec::from(&buf[..])} Keystore {private_key: Bytes::from_bytes(&private), public_key: Bytes::from_bytes(&public), seed: Vec::from(&buf[..])}
} }
pub fn from_bytes(seed: &[u8]) -> Self { pub fn from_bytes(seed: &[u8]) -> Self {
let (private, public) = keypair(&seed); let (private, public) = keypair(&seed);
Keystore {private_key: Key::from_bytes(&private), public_key: Key::from_bytes(&public), seed: Vec::from(seed)} Keystore {private_key: Bytes::from_bytes(&private), public_key: Bytes::from_bytes(&public), seed: Vec::from(seed)}
} }
pub fn from_file(filename: &str, _password: &str) -> Option<Self> { pub fn from_file(filename: &str, _password: &str) -> Option<Self> {
@@ -44,11 +49,22 @@ impl Keystore {
} }
} }
pub fn get_public(&self) -> Key { //TODO Implement error conditions
pub fn save(&self, filename: &str, password: &str) {
match File::create(Path::new(filename)) {
Ok(mut f) => {
//TODO implement key encryption
f.write_all(&self.seed);
}
Err(_) => { println!("Error saving key file!"); }
}
}
pub fn get_public(&self) -> Bytes {
self.public_key.clone() self.public_key.clone()
} }
pub fn get_private(&self) -> Key { pub fn get_private(&self) -> Bytes {
self.private_key.clone() self.private_key.clone()
} }
@@ -59,20 +75,24 @@ impl Keystore {
pub fn check(&self, message: &[u8], public_key: &[u8], signature: &[u8]) -> bool { pub fn check(&self, message: &[u8], public_key: &[u8], signature: &[u8]) -> bool {
verify(message, public_key, signature) verify(message, public_key, signature)
} }
pub fn hash_is_good(&self, difficulty: usize) -> bool {
hash_is_good(self.public_key.as_bytes(), difficulty)
}
} }
#[derive(Clone)] #[derive(Clone)]
pub struct Key { pub struct Bytes {
data: Vec<u8> data: Vec<u8>
} }
impl Key { impl Bytes {
pub fn new(data: Vec<u8>) -> Self { pub fn new(data: Vec<u8>) -> Self {
Key { data } Bytes { data }
} }
pub fn from_bytes(data: &[u8]) -> Self { pub fn from_bytes(data: &[u8]) -> Self {
Key { data: Vec::from(data) } Bytes { data: Vec::from(data) }
} }
pub fn length(&self) -> usize { pub fn length(&self) -> usize {
@@ -101,21 +121,21 @@ impl Key {
} }
pub fn zero32() -> Self { pub fn zero32() -> Self {
Key { data: [0u8; 32].to_vec() } Bytes { data: [0u8; 32].to_vec() }
} }
pub fn zero64() -> Self { pub fn zero64() -> Self {
Key { data: [0u8; 64].to_vec() } Bytes { data: [0u8; 64].to_vec() }
} }
} }
impl Default for Key { impl Default for Bytes {
fn default() -> Key { fn default() -> Bytes {
Key { data: Vec::new() } Bytes { data: Vec::new() }
} }
} }
impl PartialEq for Key { impl PartialEq for Bytes {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
crate::utils::same_hash(&self.data, &other.data) crate::utils::same_hash(&self.data, &other.data)
} }
@@ -125,23 +145,23 @@ impl PartialEq for Key {
} }
} }
impl fmt::Debug for Key { impl fmt::Debug for Bytes {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str(&crate::utils::to_hex(&self.data)) fmt.write_str(&crate::utils::to_hex(&self.data))
} }
} }
impl Serialize for Key { impl Serialize for Bytes {
fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error> where fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error> where
S: Serializer { S: Serializer {
serializer.serialize_str(&crate::utils::to_hex(&self.data)) serializer.serialize_str(&crate::utils::to_hex(&self.data))
} }
} }
struct KeyVisitor; struct BytesVisitor;
impl<'de> Visitor<'de> for KeyVisitor { impl<'de> Visitor<'de> for BytesVisitor {
type Value = Key; type Value = Bytes;
fn expecting(&self, formatter: &mut Formatter) -> Result<(), Error> { fn expecting(&self, formatter: &mut Formatter) -> Result<(), Error> {
formatter.write_str("32 or 64 bytes") formatter.write_str("32 or 64 bytes")
@@ -149,7 +169,7 @@ impl<'de> Visitor<'de> for KeyVisitor {
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> where E: DeError, { fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> where E: DeError, {
if value.len() == 64 || value.len() == 128 { if value.len() == 64 || value.len() == 128 {
Ok(Key::new(crate::from_hex(value).unwrap())) Ok(Bytes::new(crate::from_hex(value).unwrap()))
} else { } else {
Err(E::custom("Key must be 32 or 64 bytes!")) Err(E::custom("Key must be 32 or 64 bytes!"))
} }
@@ -157,15 +177,15 @@ impl<'de> Visitor<'de> for KeyVisitor {
fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E> where E: DeError, { fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E> where E: DeError, {
if value.len() == 32 || value.len() == 64 { if value.len() == 32 || value.len() == 64 {
Ok(Key::from_bytes(value)) Ok(Bytes::from_bytes(value))
} else { } else {
Err(E::custom("Key must be 32 or 64 bytes!")) Err(E::custom("Key must be 32 or 64 bytes!"))
} }
} }
} }
impl<'dd> Deserialize<'dd> for Key { impl<'dd> Deserialize<'dd> for Bytes {
fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'dd>>::Error> where D: Deserializer<'dd> { fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'dd>>::Error> where D: Deserializer<'dd> {
deserializer.deserialize_str(KeyVisitor) deserializer.deserialize_str(BytesVisitor)
} }
} }
+1 -2
View File
@@ -3,13 +3,12 @@ pub use crate::block::Block;
mod blockchain; mod blockchain;
pub use crate::blockchain::Blockchain; pub use crate::blockchain::Blockchain;
pub mod transaction; pub mod transaction;
pub use crate::transaction::Action;
pub use crate::transaction::Transaction; pub use crate::transaction::Transaction;
pub mod utils; pub mod utils;
pub use crate::utils::*; pub use crate::utils::*;
pub mod keys; pub mod keys;
pub use crate::keys::Keystore; pub use crate::keys::Keystore;
pub use crate::keys::Key; pub use crate::keys::Bytes;
pub mod miner; pub mod miner;
pub mod context; pub mod context;
pub use crate::context::Context; pub use crate::context::Context;
+56 -60
View File
@@ -1,27 +1,32 @@
#![windows_subsystem = "windows"] #![windows_subsystem = "windows"]
extern crate web_view; extern crate web_view;
use alfis::{Blockchain, Block, Action, Transaction, Keystore, Key, Settings, Context}; use alfis::{Blockchain, Block, Transaction, Keystore, Bytes, Settings, Context};
use alfis::miner::Miner; use alfis::miner::Miner;
use alfis::utils::random_string;
use web_view::*; use web_view::*;
use std::thread; use std::thread;
use rand::{Rng, RngCore};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
extern crate serde; extern crate serde;
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::atomic::{AtomicBool, Ordering};
extern crate serde_json; extern crate serde_json;
const ONE_YEAR: u16 = 365; const ONE_YEAR: u16 = 365;
const GENESIS_ZONE: &str = "ygg"; const GENESIS_ZONE: &str = "ygg";
const GENESIS_ZONE_DIFFICULTY: u16 = 20; const GENESIS_ZONE_DIFFICULTY: u16 = 20;
const SALT_LENGTH: usize = 20; const KEYSTORE_DIFFICULTY: usize = 24;
const SETTINGS_FILENAME: &str = "alfis.cfg";
fn main() { fn main() {
println!("ALFIS 0.1.0"); println!("ALFIS 0.1.0");
let settings = Settings::new(""); let settings = Settings::load(SETTINGS_FILENAME).expect("Error loading settings");
let keystore: Keystore = Keystore::from_file("default.key", "").unwrap(); let keystore: Keystore = match Keystore::from_file(&settings.key_file, "") {
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_id, settings.version); let blockchain: Blockchain = Blockchain::new(settings.chain_id, settings.version);
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)));
@@ -79,17 +84,14 @@ fn run_interface(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>) {
} }
}, },
CreateKey { name, pass } => { CreateKey { name, pass } => {
let mut c = context.lock().unwrap(); create_key(context.clone(), &name, &pass);
c.set_keystore(Keystore::new());
} }
CreateDomain { name, records, tags } => { CreateDomain { name, records, tags } => {
let salt = random_string(SALT_LENGTH);
let keystore = { let keystore = {
let mut guard = context.lock().unwrap(); let mut guard = context.lock().unwrap();
guard.add_salt(name.clone(), salt.clone());
guard.get_keystore() guard.get_keystore()
}; };
create_domain(miner.clone(), name, salt, &keystore); create_domain(miner.clone(), name, records, &keystore);
} }
ChangeDomain { name, records, tags } => { ChangeDomain { name, records, tags } => {
let keystore = { context.lock().unwrap().get_keystore() }; let keystore = { context.lock().unwrap().get_keystore() };
@@ -106,77 +108,71 @@ fn run_interface(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>) {
} }
fn create_genesis<S: Into<String>>(miner: Arc<Mutex<Miner>>, name: S, keystore: &Keystore, difficulty: u16) { fn create_genesis<S: Into<String>>(miner: Arc<Mutex<Miner>>, name: S, keystore: &Keystore, difficulty: u16) {
// Creating transaction let mut transaction = Transaction::from_str(name.into(), "zone".to_owned(), difficulty.to_string(), keystore.get_public().clone());
// TODO Do we need to add here an owners key?
let action = Action::genesis(name.into(), Key::zero32(), difficulty);
let mut transaction = Transaction::new(action, keystore.get_public().clone());
// Signing it with private key from Signature // Signing it with private key from Signature
let sign_hash = keystore.sign(&transaction.get_bytes()); let sign_hash = keystore.sign(&transaction.get_bytes());
transaction.set_signature(Key::from_bytes(&sign_hash)); transaction.set_signature(Bytes::from_bytes(&sign_hash));
let mut miner_guard = miner.lock().unwrap(); let mut miner_guard = miner.lock().unwrap();
miner_guard.add_transaction(transaction); miner_guard.add_transaction(transaction);
} }
fn create_domain<S: Into<String>>(miner: Arc<Mutex<Miner>>, name: S, salt: S, keystore: &Keystore) { fn create_domain<S: Into<String>>(miner: Arc<Mutex<Miner>>, name: S, data: S, keystore: &Keystore) {
let name = name.into();
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 = { transaction_new_domain(keystore, name.into(), salt.into()) }; let mut 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);
} }
fn create_zone<S: Into<String>>(miner: Arc<Mutex<Miner>>, name: S, salt: S, keystore: &Keystore) { fn create_transaction<S: Into<String>>(keystore: &Keystore, name: S, method: S, data: S) -> Transaction {
//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 mut transaction = { transaction_new_domain(keystore, name.into(), salt.into()) };
let mut miner_guard = miner.lock().unwrap();
miner_guard.add_transaction(transaction);
}
fn transaction_claim_name<S: Into<String>>(keystore: &Keystore, name: S, salt: S) -> Transaction {
// Creating transaction // Creating transaction
// TODO Do not use owner for now, make a field in UI and use it if filled // TODO Do not use owner for now, make a field in UI and use it if filled
let action = Action::new_domain(name.into(), salt.into(), Key::zero32()); let mut transaction = Transaction::from_str(name.into(), method.into(), data.into(), keystore.get_public().clone());
let mut transaction = Transaction::new(action, keystore.get_public().clone());
// Signing it with private key from Signature // Signing it with private key from Signature
let sign_hash = keystore.sign(&transaction.get_bytes()); let sign_hash = keystore.sign(&transaction.get_bytes());
transaction.set_signature(Key::from_bytes(&sign_hash)); transaction.set_signature(Bytes::from_bytes(&sign_hash));
transaction transaction
} }
fn transaction_new_domain<S: Into<String>>(keystore: &Keystore, name: S, salt: S) -> Transaction { fn create_key(context: Arc<Mutex<Context>>, filename: &str, password: &str) {
let name_string = name.into(); let mut mining = Arc::new(AtomicBool::new(true));
let salt_string = salt.into(); for _ in 0..num_cpus::get() {
println!("Generating domain {} with salt: {}", name_string, salt_string); let context = context.clone();
// Creating transaction let filename= filename.to_owned();
// TODO Do not use owner for now, make a field in UI and use it if filled let password= password.to_owned();
let action = Action::new_domain(name_string, salt_string, Key::zero32()); let mining = mining.clone();
let mut transaction = Transaction::new(action, keystore.get_public().clone()); thread::spawn(move || {
// Signing it with private key from Signature match generate_key(KEYSTORE_DIFFICULTY, mining.clone()) {
let sign_hash = keystore.sign(&transaction.get_bytes()); None => { println!("Keystore mining finished"); }
transaction.set_signature(Key::from_bytes(&sign_hash)); Some(keystore) => {
transaction let mut c = context.lock().unwrap();
mining.store(false,Ordering::Relaxed);
keystore.save(&filename, &password);
c.set_keystore(keystore);
}
}
});
}
} }
/*fn transaction_claim_zone<S: Into<String>>(keystore: &Keystore, hash: S, difficulty: u16) -> Transaction { fn generate_key(difficulty: usize, mining: Arc<AtomicBool>) -> Option<Keystore> {
// Creating transaction let mut rng = rand::thread_rng();
let action = Action::new_zone(hash.into(), salt.into(), &keystore, difficulty); let mut buf = [0u8; 64];
let mut transaction = Transaction::new(action, keystore.get_public().clone()); loop {
// Signing it with private key from Signature rng.fill_bytes(&mut buf);
let sign_hash = keystore.sign(&transaction.get_bytes()); let keystore = Keystore::from_bytes(&buf);
transaction.set_signature(Key::from_bytes(&sign_hash)); if keystore.hash_is_good(difficulty) {
transaction println!("Generated keypair: {:?}", &keystore);
}*/ return Some(keystore);
}
/*fn transaction_new_zone<S: Into<String>>(keystore: &Keystore, name: S, salt: S, records: Vec<String>, tags: Vec<String>, days: u16) -> Transaction { if !mining.load(Ordering::Relaxed) {
// Creating transaction return None;
let action = Action::fill_domain(name.into(), salt.into(), &keystore, records, tags, days); }
let mut transaction = Transaction::new(action, keystore.get_public().clone()); }
// Signing it with private key from Signature None
let sign_hash = keystore.sign(&transaction.get_bytes()); }
transaction.set_signature(Key::from_bytes(&sign_hash));
transaction
}*/
#[derive(Deserialize)] #[derive(Deserialize)]
#[serde(tag = "cmd", rename_all = "camelCase")] #[serde(tag = "cmd", rename_all = "camelCase")]
+4 -13
View File
@@ -1,10 +1,8 @@
use crate::{Transaction, Block, Keystore, Key, Context}; use crate::{Transaction, Block, Keystore, Bytes, Context, hash_is_good};
use std::sync::{Mutex, Arc, Condvar}; use std::sync::{Mutex, Arc, Condvar};
use crypto::digest::Digest; use crypto::digest::Digest;
use std::sync::atomic::{AtomicBool, Ordering, AtomicU32}; use std::sync::atomic::{AtomicBool, Ordering, AtomicU32};
use chrono::Utc; use chrono::Utc;
use num_bigint::BigUint;
use num_traits::One;
use crypto::sha2::Sha256; use crypto::sha2::Sha256;
use std::thread; use std::thread;
use std::time::Duration; use std::time::Duration;
@@ -97,7 +95,7 @@ impl Miner {
// Signing it with private key from Keystore // Signing it with private key from Keystore
let c = context.lock().unwrap(); let c = context.lock().unwrap();
let sign_hash = c.keystore.sign(&transaction.get_bytes()); let sign_hash = c.keystore.sign(&transaction.get_bytes());
transaction.set_signature(Key::from_bytes(&sign_hash)); transaction.set_signature(Bytes::from_bytes(&sign_hash));
} }
// Get last block for mining // Get last block for mining
@@ -106,7 +104,7 @@ impl Miner {
None => { None => {
println!("Mining genesis block"); println!("Mining genesis block");
// Creating a block with that signed transaction // Creating a block with that signed transaction
Block::new(0, Utc::now().timestamp(), chain_id, version, Key::zero32(), Some(transaction.clone())) Block::new(0, Utc::now().timestamp(), chain_id, version, Bytes::zero32(), Some(transaction.clone()))
}, },
Some(block) => { Some(block) => {
last_block_time = block.timestamp; last_block_time = block.timestamp;
@@ -179,7 +177,7 @@ fn find_hash(digest: &mut dyn Digest, mut block: Block, prev_block_time: i64, ru
digest.input(serde_json::to_string(&block).unwrap().as_bytes()); digest.input(serde_json::to_string(&block).unwrap().as_bytes());
digest.result(&mut buf); digest.result(&mut buf);
if hash_is_good(&buf, block.difficulty) { if hash_is_good(&buf, block.difficulty) {
block.hash = Key::from_bytes(&buf); block.hash = Bytes::from_bytes(&buf);
return Some(block); return Some(block);
} }
} }
@@ -193,11 +191,4 @@ fn get_time_difficulty(prev_time: i64, now: i64) -> usize {
} else { } else {
0 0
} }
}
fn hash_is_good(hash: &[u8], difficulty: usize) -> bool {
let target = BigUint::one() << ((hash.len() << 3) - difficulty);
let hash_int = BigUint::from_bytes_be(&hash);
return hash_int < target;
} }
+22 -131
View File
@@ -6,145 +6,32 @@ extern crate serde_json;
use serde::{Serialize, Deserialize, Serializer}; use serde::{Serialize, Deserialize, Serializer};
use serde::ser::SerializeStruct; use serde::ser::SerializeStruct;
use std::fmt; use std::fmt;
use crate::transaction::Action::Genesis;
use crypto::sha2::Sha256; use crypto::sha2::Sha256;
use crypto::digest::Digest; use crypto::digest::Digest;
#[derive(Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "type")]
pub enum Action {
NewDomain { hash: String, #[serde(default, skip_serializing_if = "Key::is_zero")] owner: Key },
FillDomain { name: String, salt: String, owner: Key, #[serde(default, skip_serializing_if = "Vec::is_empty")] records: Vec<String>, #[serde(default, skip_serializing_if = "Vec::is_empty")] tags: Vec<String>, days: u16 },
ChangeDomain { name: String, records: Vec<String>, tags: Vec<String>, #[serde(default, skip_serializing_if = "Key::is_zero")] owner: Key },
RenewDomain { name: String, days: u16 },
NewZone { hash: String, #[serde(default, skip_serializing_if = "Key::is_zero")] owner: Key, difficulty: u16 },
ChangeZone { name: String, salt: String, #[serde(default, skip_serializing_if = "Key::is_zero")] owner: Key, difficulty: u16 },
Genesis { name: String, #[serde(default, skip_serializing_if = "Key::is_zero")] owner: Key, difficulty: u16 },
}
impl Action {
pub fn new_domain<S: Into<String>>(name: S, salt: S, owner: Key) -> Self {
let hash = format!("{} {}", salt.into(), name.into());
// TODO Do not use owner for now, make a field in UI and use it if filled
Action::NewDomain { hash: Action::get_hash(&hash), owner }
}
pub fn fill_domain<S: Into<String>>(name: S, salt: S, owner: Key, records: Vec<String>, tags: Vec<String>, days: u16) -> Self {
Action::FillDomain { name: name.into(), salt: salt.into(), owner, records, tags, days }
}
// TODO change new_owner to Key
pub fn change_domain<S: Into<String>>(name: S, records: Vec<String>, tags: Vec<String>, new_owner: [u8; 32]) -> Self {
Action::ChangeDomain { name: name.into(), records, tags, owner: Key::from_bytes(&new_owner) }
}
pub fn renew_domain<S: Into<String>>(name: S, days: u16) -> Self {
Action::RenewDomain { name: name.into(), days }
}
pub fn new_zone<S: Into<String>>(name: S, salt: S, owner: Key, difficulty: u16) -> Self {
let hash = format!("{} {}", salt.into(), name.into());
Action::NewZone { hash, owner, difficulty }
}
// TODO change new_owner to Key
pub fn change_zone<S: Into<String>>(name: S, salt: S, new_owner: [u8; 32], difficulty: u16) -> Self {
Action::ChangeZone { name: name.into(), salt: salt.into(), owner: Key::from_bytes(&new_owner), difficulty }
}
pub fn genesis<S: Into<String>>(name: S, owner: Key, difficulty: u16) -> Self {
Genesis { name: name.into(), owner, difficulty }
}
pub fn get_bytes(&self) -> Vec<u8> {
// Let it panic if something is not okay
serde_json::to_vec(&self).unwrap()
}
pub fn from_bytes(bytes: Vec<u8>) -> Self {
// Let it panic (for now) if something is not okay
serde_json::from_slice(bytes.as_slice()).unwrap()
}
fn get_hash(data: &str) -> String {
let mut digest = Sha256::new();
digest.input(data.as_bytes());
digest.result_str()
}
}
impl fmt::Debug for Action {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match self {
Action::NewDomain { hash, owner } => {
fmt.debug_struct("NewDomain")
.field("hash", hash)
.field("owner", owner)
.finish()
}
Action::FillDomain { name, salt, owner, records, tags, days } => {
fmt.debug_struct("FillDomain")
.field("name", name)
.field("salt", salt)
.field("owner", &owner)
.field("records", records)
.field("tags", tags)
.field("days", days)
.finish()
}
Action::ChangeDomain { name, records, tags, owner } => {
fmt.debug_struct("ChangeDomain")
.field("name", name)
.field("records", records)
.field("tags", tags)
.field("owner", &owner)
.finish()
}
Action::RenewDomain { name, days } => {
fmt.debug_struct("RenewDomain")
.field("name", name)
.field("days", days)
.finish()
}
Action::NewZone { hash, owner, difficulty } => {
fmt.debug_struct("NewZone")
.field("hash", hash)
.field("owner", &owner)
.field("difficulty", difficulty)
.finish()
}
Action::ChangeZone { name, salt, owner, difficulty } => {
fmt.debug_struct("ChangeZone")
.field("name", name)
.field("salt", salt)
.field("owner", &owner)
.field("difficulty", difficulty)
.finish()
}
Action::Genesis { name, owner, difficulty } => {
fmt.debug_struct("Genesis")
.field("name", name)
.field("owner", &owner)
.field("difficulty", difficulty)
.finish()
}
}
}
}
#[derive(Clone, Deserialize, PartialEq)] #[derive(Clone, Deserialize, PartialEq)]
pub struct Transaction { pub struct Transaction {
pub action: Action, pub identity: Bytes,
pub pub_key: Key, pub method: String,
pub signature: Key, pub data: String,
pub pub_key: Bytes,
pub signature: Bytes,
} }
impl Transaction { impl Transaction {
pub fn new(action: Action, pub_key: Key) -> Self { pub fn from_str(identity: String, method: String, data: String, pub_key: Bytes) -> Self {
Transaction { action, pub_key, signature: Key::zero64() } let mut buf: [u8; 32] = [0; 32];
let mut digest = Sha256::new();
digest.input_str(&identity);
digest.result(&mut buf);
return Self::new(Bytes::from_bytes(&buf), method, data, pub_key);
} }
pub fn set_signature(&mut self, hash: 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 set_signature(&mut self, hash: Bytes) {
self.signature = hash; self.signature = hash;
} }
@@ -157,7 +44,9 @@ impl Transaction {
impl fmt::Debug for Transaction { impl fmt::Debug for Transaction {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Transaction") fmt.debug_struct("Transaction")
.field("action", &self.action) .field("identity", &self.identity)
.field("method", &self.method)
.field("data", &self.data)
.field("pub", &&self.pub_key) .field("pub", &&self.pub_key)
.field("sign", &&self.signature) .field("sign", &&self.signature)
.finish() .finish()
@@ -168,7 +57,9 @@ impl Serialize for Transaction {
fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error> where fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error> where
S: Serializer { S: Serializer {
let mut structure = serializer.serialize_struct("Transaction", 3).unwrap(); let mut structure = serializer.serialize_struct("Transaction", 3).unwrap();
structure.serialize_field("action", &self.action); structure.serialize_field("identity", &self.identity);
structure.serialize_field("method", &self.method);
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()
+10 -1
View File
@@ -1,5 +1,7 @@
use std::num; use std::num;
use rand::Rng; use rand::Rng;
use num_bigint::BigUint;
use num_traits::One;
/// Convert bytes array to HEX format /// Convert bytes array to HEX format
pub fn to_hex(buf: &[u8]) -> String { pub fn to_hex(buf: &[u8]) -> String {
@@ -33,12 +35,19 @@ pub fn same_hash(left: &[u8], right: &[u8]) -> bool {
true true
} }
pub fn hash_is_good(hash: &[u8], difficulty: usize) -> bool {
let target = BigUint::one() << ((hash.len() << 3) - difficulty);
let hash_int = BigUint::from_bytes_be(&hash);
return hash_int < target;
}
/// Generates random string of given length /// Generates random string of given length
pub fn random_string(length: usize) -> String { pub fn random_string(length: usize) -> String {
let chars: Vec<char> = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!?".chars().collect(); let chars: Vec<char> = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!?".chars().collect();
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
let mut result = String::with_capacity(length); let mut result = String::with_capacity(length);
for x in 0..length { for _ in 0..length {
let position: usize = rng.gen::<usize>() % chars.len(); let position: usize = rng.gen::<usize>() % chars.len();
let c: char = *chars.get(position).unwrap(); let c: char = *chars.get(position).unwrap();
result.push(c); result.push(c);