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"
|
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."
|
||||||
@@ -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 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
@@ -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(©).unwrap();
|
let data = serde_json::to_string(©).unwrap();
|
||||||
Block::hash(data.as_bytes()) == block.hash
|
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 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user