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:
+11
-2
@@ -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,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 |
+10
-32
@@ -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;
|
||||
}
|
||||
+2
-2
@@ -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(©).unwrap();
|
||||
Block::hash(data.as_bytes()) == block.hash
|
||||
}
|
||||
|
||||
Vendored
+10832
File diff suppressed because it is too large
Load Diff
+24
-8
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-22
@@ -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>
|
||||
|
||||
+46
-26
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -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;
|
||||
|
||||
+56
-60
@@ -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));
|
||||
transaction.set_signature(Bytes::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) {
|
||||
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 create_zone<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()) };
|
||||
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")]
|
||||
|
||||
+4
-13
@@ -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;
|
||||
}
|
||||
+22
-131
@@ -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 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;
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
+10
-1
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user