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.

pull/2/head
Revertron 3 years ago
parent 4703ae6f49
commit 70b3a833b9

@ -3,6 +3,7 @@ name = "alfis"
version = "0.1.0"
authors = ["Revertron <rev@revertron.com>"]
edition = "2018"
build = "build.rs"
#![windows_subsystem = "windows"]
# 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"
num_cpus = "1.13.0"
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_json = "1.0.42"
num-bigint = "0.2"
@ -20,7 +21,15 @@ groestl = "0.8.0"
base64 = "0.11.0"
chrono = "0.4.9"
rand = "0.7.2"
eventbus = "0.5.1"
[build-dependencies]
winres = "0.1"
[dev-dependencies]
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."

@ -0,0 +1,5 @@
{
"chain_id": 42,
"version": 0,
"key_file": "default.key"
}

@ -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();
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

@ -11,7 +11,7 @@ use num_bigint::BigUint;
use num_traits::One;
use crypto::sha2::Sha256;
use crypto::digest::Digest;
use crate::keys::Key;
use crate::keys::Bytes;
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
pub struct Block {
@ -24,14 +24,14 @@ pub struct Block {
pub nonce: u64,
#[serde(skip_serializing_if = "Option::is_none")]
pub transaction: Option<Transaction>,
#[serde(default, skip_serializing_if = "Key::is_zero")]
pub prev_block_hash: Key,
#[serde(default, skip_serializing_if = "Key::is_zero")]
pub hash: Key,
#[serde(default, skip_serializing_if = "Bytes::is_zero")]
pub prev_block_hash: Bytes,
#[serde(default, skip_serializing_if = "Bytes::is_zero")]
pub hash: Bytes,
}
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 {
index,
timestamp,
@ -43,41 +43,19 @@ impl Block {
nonce: 0,
transaction,
prev_block_hash,
hash: Key::default(),
hash: Bytes::default(),
}
}
pub fn mine(&mut self) {
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 {
pub fn hash(data: &[u8]) -> Bytes {
let mut buf: [u8; 32] = [0; 32];
let mut digest = Sha256::new();
digest.input(data);
digest.result(&mut buf);
Key::new(buf.to_vec())
Bytes::new(buf.to_vec())
}
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;
}

@ -1,4 +1,4 @@
use crate::{Block, Transaction, Key};
use crate::{Block, Transaction, Bytes};
use chrono::Utc;
pub struct Blockchain {
@ -54,7 +54,7 @@ impl Blockchain {
pub fn check_block_hash(block: &Block) -> bool {
// We need to clear Hash value to rehash it without it for check :(
let mut copy: Block = block.clone();
copy.hash = Key::default();
copy.hash = Bytes::default();
let data = serde_json::to_string(&copy).unwrap();
Block::hash(data.as_bytes()) == block.hash
}

10832
src/bulma.css vendored

File diff suppressed because it is too large Load Diff

@ -1,5 +1,9 @@
use crate::{Keystore, Blockchain};
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(crate) settings: Settings,
@ -38,21 +42,33 @@ impl Context {
pub fn get_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 chain_id: u32,
pub version: u32,
salts: HashMap<String, String>
pub key_file: String
}
impl Settings {
/// TODO parse settings
pub fn new<S: Into<String>>(settings: S) -> Settings {
Settings { chain_id: 42, version: 0, salts: HashMap::new() }
pub fn new<S: Into<String>>(settings: S) -> serde_json::Result<Settings> {
serde_json::from_str(&settings.into())
}
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
}
}
}

@ -34,7 +34,10 @@
</div><!--column-->
<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">
<form action="#">
@ -56,9 +59,6 @@
<div class="control">
<button class="button is-link" onclick="loadKey();">Load</button>
</div>
<div class="control">
<button class="button is-link is-light">Cancel</button>
</div>
</div>
</form>
</div>
@ -84,9 +84,6 @@
<div class="control">
<button class="button is-link" onclick="createKey();">Create</button>
</div>
<div class="control">
<button class="button is-link is-light">Cancel</button>
</div>
</div>
</form>
</div>
@ -126,9 +123,6 @@
<div class="control">
<button class="button is-link">Change password</button>
</div>
<div class="control">
<button class="button is-link is-light">Cancel</button>
</div>
</div>
</form>
</div>
@ -162,9 +156,6 @@
<div class="control">
<button class="button is-link" onclick="createDomain();">Create domain</button>
</div>
<div class="control">
<button class="button is-link is-light">Cancel</button>
</div>
</div>
</form>
</div>
@ -197,9 +188,6 @@
<div class="control">
<button class="button is-link" onclick="changeDomain();">Replace records</button>
</div>
<div class="control">
<button class="button is-link is-light">Cancel</button>
</div>
</div>
</form>
</div>
@ -225,9 +213,6 @@
<div class="control">
<button class="button is-link" onclick="renewDomain();">Renew domain</button>
</div>
<div class="control">
<button class="button is-link is-light">Cancel</button>
</div>
</div>
</form>
</div>
@ -253,9 +238,6 @@
<div class="control">
<button class="button is-link" onclick="transferDomain();">Transfer domain</button>
</div>
<div class="control">
<button class="button is-link is-light">Cancel</button>
</div>
</div>
</form>
</div>

@ -1,20 +1,25 @@
extern crate crypto;
extern crate serde;
extern crate serde_json;
use crypto::ed25519::{keypair, signature, verify};
use rand::{thread_rng, Rng};
use std::fs;
use std::fmt;
use std::fs;
use std::fs::File;
use std::io::{Read, Write};
use std::path::Path;
use serde::export::fmt::Error;
use serde::{Serialize, Deserialize, Serializer, Deserializer};
// For deserialization
use serde::de::{Error as DeError, Visitor};
use serde::export::Formatter;
use crate::hash_is_good;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Keystore {
private_key: Key,
public_key: Key,
private_key: Bytes,
public_key: Bytes,
#[serde(skip)]
seed: Vec<u8>
}
@ -25,12 +30,12 @@ impl Keystore {
let mut rng = thread_rng();
rng.fill(&mut 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 {
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> {
@ -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()
}
pub fn get_private(&self) -> Key {
pub fn get_private(&self) -> Bytes {
self.private_key.clone()
}
@ -59,20 +75,24 @@ impl Keystore {
pub fn check(&self, message: &[u8], public_key: &[u8], signature: &[u8]) -> bool {
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)]
pub struct Key {
pub struct Bytes {
data: Vec<u8>
}
impl Key {
impl Bytes {
pub fn new(data: Vec<u8>) -> Self {
Key { data }
Bytes { data }
}
pub fn from_bytes(data: &[u8]) -> Self {
Key { data: Vec::from(data) }
Bytes { data: Vec::from(data) }
}
pub fn length(&self) -> usize {
@ -101,21 +121,21 @@ impl Key {
}
pub fn zero32() -> Self {
Key { data: [0u8; 32].to_vec() }
Bytes { data: [0u8; 32].to_vec() }
}
pub fn zero64() -> Self {
Key { data: [0u8; 64].to_vec() }
Bytes { data: [0u8; 64].to_vec() }
}
}
impl Default for Key {
fn default() -> Key {
Key { data: Vec::new() }
impl Default for Bytes {
fn default() -> Bytes {
Bytes { data: Vec::new() }
}
}
impl PartialEq for Key {
impl PartialEq for Bytes {
fn eq(&self, other: &Self) -> bool {
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 {
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
S: Serializer {
serializer.serialize_str(&crate::utils::to_hex(&self.data))
}
}
struct KeyVisitor;
struct BytesVisitor;
impl<'de> Visitor<'de> for KeyVisitor {
type Value = Key;
impl<'de> Visitor<'de> for BytesVisitor {
type Value = Bytes;
fn expecting(&self, formatter: &mut Formatter) -> Result<(), Error> {
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, {
if value.len() == 64 || value.len() == 128 {
Ok(Key::new(crate::from_hex(value).unwrap()))
Ok(Bytes::new(crate::from_hex(value).unwrap()))
} else {
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, {
if value.len() == 32 || value.len() == 64 {
Ok(Key::from_bytes(value))
Ok(Bytes::from_bytes(value))
} else {
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> {
deserializer.deserialize_str(KeyVisitor)
deserializer.deserialize_str(BytesVisitor)
}
}

@ -3,13 +3,12 @@ pub use crate::block::Block;
mod blockchain;
pub use crate::blockchain::Blockchain;
pub mod transaction;
pub use crate::transaction::Action;
pub use crate::transaction::Transaction;
pub mod utils;
pub use crate::utils::*;
pub mod keys;
pub use crate::keys::Keystore;
pub use crate::keys::Key;
pub use crate::keys::Bytes;
pub mod miner;
pub mod context;
pub use crate::context::Context;

@ -1,27 +1,32 @@
#![windows_subsystem = "windows"]
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::utils::random_string;
use web_view::*;
use std::thread;
use rand::{Rng, RngCore};
use std::sync::{Arc, Mutex};
extern crate serde;
use serde::{Serialize, Deserialize};
use std::collections::HashMap;
use std::sync::atomic::{AtomicBool, Ordering};
extern crate serde_json;
const ONE_YEAR: u16 = 365;
const GENESIS_ZONE: &str = "ygg";
const GENESIS_ZONE_DIFFICULTY: u16 = 20;
const SALT_LENGTH: usize = 20;
const KEYSTORE_DIFFICULTY: usize = 24;
const SETTINGS_FILENAME: &str = "alfis.cfg";
fn main() {
println!("ALFIS 0.1.0");
let settings = Settings::new("");
let keystore: Keystore = Keystore::from_file("default.key", "").unwrap();
let settings = Settings::load(SETTINGS_FILENAME).expect("Error loading settings");
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 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 } => {
let mut c = context.lock().unwrap();
c.set_keystore(Keystore::new());
create_key(context.clone(), &name, &pass);
}
CreateDomain { name, records, tags } => {
let salt = random_string(SALT_LENGTH);
let keystore = {
let mut guard = context.lock().unwrap();
guard.add_salt(name.clone(), salt.clone());
guard.get_keystore()
};
create_domain(miner.clone(), name, salt, &keystore);
create_domain(miner.clone(), name, records, &keystore);
}
ChangeDomain { name, records, tags } => {
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) {
// Creating transaction
// 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());
let mut transaction = Transaction::from_str(name.into(), "zone".to_owned(), difficulty.to_string(), keystore.get_public().clone());
// Signing it with private key from Signature
let sign_hash = keystore.sign(&transaction.get_bytes());
transaction.set_signature(Key::from_bytes(&sign_hash));
let mut miner_guard = miner.lock().unwrap();
miner_guard.add_transaction(transaction);
}
fn create_domain<S: Into<String>>(miner: Arc<Mutex<Miner>>, name: S, salt: S, keystore: &Keystore) {
//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()) };
transaction.set_signature(Bytes::from_bytes(&sign_hash));
let mut miner_guard = miner.lock().unwrap();
miner_guard.add_transaction(transaction);
}
fn create_zone<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 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();
miner_guard.add_transaction(transaction);
}
fn transaction_claim_name<S: Into<String>>(keystore: &Keystore, name: S, salt: S) -> Transaction {
fn create_transaction<S: Into<String>>(keystore: &Keystore, name: S, method: S, data: S) -> Transaction {
// Creating transaction
// 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::new(action, keystore.get_public().clone());
let mut transaction = Transaction::from_str(name.into(), method.into(), data.into(), keystore.get_public().clone());
// Signing it with private key from Signature
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
}
fn transaction_new_domain<S: Into<String>>(keystore: &Keystore, name: S, salt: S) -> Transaction {
let name_string = name.into();
let salt_string = salt.into();
println!("Generating domain {} with salt: {}", name_string, salt_string);
// Creating transaction
// TODO Do not use owner for now, make a field in UI and use it if filled
let action = Action::new_domain(name_string, salt_string, Key::zero32());
let mut transaction = Transaction::new(action, keystore.get_public().clone());
// Signing it with private key from Signature
let sign_hash = keystore.sign(&transaction.get_bytes());
transaction.set_signature(Key::from_bytes(&sign_hash));
transaction
fn create_key(context: Arc<Mutex<Context>>, filename: &str, password: &str) {
let mut mining = Arc::new(AtomicBool::new(true));
for _ in 0..num_cpus::get() {
let context = context.clone();
let filename= filename.to_owned();
let password= password.to_owned();
let mining = mining.clone();
thread::spawn(move || {
match generate_key(KEYSTORE_DIFFICULTY, mining.clone()) {
None => { println!("Keystore mining finished"); }
Some(keystore) => {
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 {
// Creating transaction
let action = Action::new_zone(hash.into(), salt.into(), &keystore, difficulty);
let mut transaction = Transaction::new(action, keystore.get_public().clone());
// Signing it with private key from Signature
let sign_hash = keystore.sign(&transaction.get_bytes());
transaction.set_signature(Key::from_bytes(&sign_hash));
transaction
}*/
/*fn transaction_new_zone<S: Into<String>>(keystore: &Keystore, name: S, salt: S, records: Vec<String>, tags: Vec<String>, days: u16) -> Transaction {
// Creating transaction
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
let sign_hash = keystore.sign(&transaction.get_bytes());
transaction.set_signature(Key::from_bytes(&sign_hash));
transaction
}*/
fn generate_key(difficulty: usize, mining: Arc<AtomicBool>) -> Option<Keystore> {
let mut rng = rand::thread_rng();
let mut buf = [0u8; 64];
loop {
rng.fill_bytes(&mut buf);
let keystore = Keystore::from_bytes(&buf);
if keystore.hash_is_good(difficulty) {
println!("Generated keypair: {:?}", &keystore);
return Some(keystore);
}
if !mining.load(Ordering::Relaxed) {
return None;
}
}
None
}
#[derive(Deserialize)]
#[serde(tag = "cmd", rename_all = "camelCase")]

@ -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 crypto::digest::Digest;
use std::sync::atomic::{AtomicBool, Ordering, AtomicU32};
use chrono::Utc;
use num_bigint::BigUint;
use num_traits::One;
use crypto::sha2::Sha256;
use std::thread;
use std::time::Duration;
@ -97,7 +95,7 @@ impl Miner {
// Signing it with private key from Keystore
let c = context.lock().unwrap();
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
@ -106,7 +104,7 @@ impl Miner {
None => {
println!("Mining genesis block");
// 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) => {
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.result(&mut buf);
if hash_is_good(&buf, block.difficulty) {
block.hash = Key::from_bytes(&buf);
block.hash = Bytes::from_bytes(&buf);
return Some(block);
}
}
@ -193,11 +191,4 @@ fn get_time_difficulty(prev_time: i64, now: i64) -> usize {
} else {
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;
}

@ -6,145 +6,32 @@ extern crate serde_json;
use serde::{Serialize, Deserialize, Serializer};
use serde::ser::SerializeStruct;
use std::fmt;
use crate::transaction::Action::Genesis;
use crypto::sha2::Sha256;
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)]
pub struct Transaction {
pub action: Action,
pub pub_key: Key,
pub signature: Key,
pub identity: Bytes,
pub method: String,
pub data: String,
pub pub_key: Bytes,
pub signature: Bytes,
}
impl Transaction {
pub fn new(action: Action, pub_key: Key) -> Self {
Transaction { action, pub_key, signature: Key::zero64() }
pub fn from_str(identity: String, method: String, data: String, pub_key: Bytes) -> Self {
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 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: Key) {
pub fn set_signature(&mut self, hash: Bytes) {
self.signature = hash;
}
@ -157,7 +44,9 @@ impl Transaction {
impl fmt::Debug for Transaction {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
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("sign", &&self.signature)
.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
S: Serializer {
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("signature", &self.signature);
structure.end()

@ -1,5 +1,7 @@
use std::num;
use rand::Rng;
use num_bigint::BigUint;
use num_traits::One;
/// Convert bytes array to HEX format
pub fn to_hex(buf: &[u8]) -> String {
@ -33,12 +35,19 @@ pub fn same_hash(left: &[u8], right: &[u8]) -> bool {
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
pub fn random_string(length: usize) -> String {
let chars: Vec<char> = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!?".chars().collect();
let mut rng = rand::thread_rng();
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 c: char = *chars.get(position).unwrap();
result.push(c);

Loading…
Cancel
Save