From 01f37cc238ffbc220b00f041c7c759af5432484a Mon Sep 17 00:00:00 2001 From: Revertron Date: Sat, 18 Apr 2020 21:31:40 +0200 Subject: [PATCH] Made a full refactoring of synchronization primitives between settings, keystore, blockchain and miner. --- Cargo.toml | 4 +- alfis_ie10.reg | Bin 0 -> 642 bytes src/blockchain.rs | 9 +- src/context.rs | 50 ++++++++ src/index.html | 271 +++++++++++++++++++++++++++++++++++++++ src/keys.rs | 10 +- src/lib.rs | 8 +- src/main.rs | 306 ++++++++++++++++++--------------------------- src/miner.rs | 137 ++++++++++++++++++++ src/scripts.js | 62 +++++++++ src/ser.rs | 9 -- src/styles.css | 75 +++++++++++ src/transaction.rs | 45 ++++++- 13 files changed, 775 insertions(+), 211 deletions(-) create mode 100644 alfis_ie10.reg create mode 100644 src/context.rs create mode 100644 src/index.html create mode 100644 src/miner.rs create mode 100644 src/scripts.js delete mode 100644 src/ser.rs create mode 100644 src/styles.css diff --git a/Cargo.toml b/Cargo.toml index 24edee6..a84d8d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "wyrd_ns" +name = "alfis" version = "0.1.0" authors = ["Revertron "] edition = "2018" @@ -10,7 +10,7 @@ edition = "2018" rust-crypto = "^0.2" num_cpus = "1.10.1" byteorder = "1.3.2" -pancurses = "0.16" +web-view = { version = "0.5.4", features = [] } serde = { version = "1.0.102", features = ["derive"] } serde_json = "1.0.42" num-bigint = "0.2" diff --git a/alfis_ie10.reg b/alfis_ie10.reg new file mode 100644 index 0000000000000000000000000000000000000000..4107d88f37ca3f160adb930b52abb09b0d7dda8e GIT binary patch literal 642 zcmdsz-Acny5QM*L!FMQqfFk}Of)`p+EZP*()*wbgF|7njB5fu0<<;+;XYfiwve}tE zGjsOmJEx|hqNQU;kBk-XVmtP1`4UNFYrEFI$CLb4wzhBVFBov*bIehEU%2PNGtZPf zGG)lEwPa!)%8f~73uba7=H%j8L?&v!sokpHvevP1y0Hew#_v9+Iq<PJN26bPEZ?En4RTo9H!X5&cT;tW*7G;+Y8(l@?|VGh>;Q*Lb78nj7 Self { let mut blockchain = Blockchain{chain_id, version, blocks: Vec::new()}; - let mut genesis = Self::genesis(chain_id, version); - genesis.mine(); - blockchain.add_block(genesis); blockchain } @@ -26,6 +23,12 @@ impl Blockchain { Block::new(0, Utc::now().timestamp(), chain_id, version, Key::zero32(), None) } + pub fn make_genesis(&mut self) { + let mut genesis = Self::genesis(self.chain_id, self.version); + genesis.mine(); + self.add_block(genesis); + } + pub fn add_block(&mut self, block: Block) { if self.check_block(&block, None) { println!("Adding block:\n{:?}", &block); diff --git a/src/context.rs b/src/context.rs new file mode 100644 index 0000000..601ca00 --- /dev/null +++ b/src/context.rs @@ -0,0 +1,50 @@ +use crate::{Keystore, Blockchain}; +use std::collections::HashMap; + +pub struct Context { + pub(crate) settings: Settings, + pub(crate) keystore: Keystore, + pub(crate) blockchain: Blockchain, +} + +impl Context { + /// Creating an essential context to work with + pub fn new(settings: Settings, keystore: Keystore, blockchain: Blockchain) -> Context { + Context { settings, keystore, blockchain } + } + + /// Load keystore and return Context + pub fn load_keystore>(mut self, name: S, password: S) -> Context { + let filename = &name.into(); + match Keystore::from_file(filename, &password.into()) { + None => { + println!("Error loading keystore '{}'!", filename); + }, + Some(keystore) => { + self.keystore = keystore; + }, + } + self + } + + pub fn get_keystore(&self) -> Keystore { + self.keystore.clone() + } + + pub fn set_keystore(&mut self, keystore: Keystore) { + self.keystore = keystore; + } +} + +pub struct Settings { + pub chain_id: u32, + pub version: u32, + salts: HashMap +} + +impl Settings { + /// TODO parse settings + pub fn new>(chain_id: u32, version: u32, settings: S) -> Settings { + Settings { chain_id, version, salts: HashMap::new() } + } +} \ No newline at end of file diff --git a/src/index.html b/src/index.html new file mode 100644 index 0000000..a0d643c --- /dev/null +++ b/src/index.html @@ -0,0 +1,271 @@ + + + + + + Wyrd + {styles} + + {scripts} + + +
+
+
+
+ +
+ +
+
This screen in now yet implemented
+ + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + \ No newline at end of file diff --git a/src/keys.rs b/src/keys.rs index 24728e2..b32a4e3 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -12,23 +12,25 @@ use serde::de::{Error as DeError, Visitor}; use serde::export::Formatter; #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Signature { +pub struct Keystore { private_key: Key, public_key: Key, + #[serde(skip)] + seed: Vec } -impl Signature { +impl Keystore { pub fn new() -> Self { let mut buf = [0u8; 64]; let mut rng = thread_rng(); rng.fill(&mut buf); let (private, public) = keypair(&buf); - Signature {private_key: Key::from_bytes(&private), public_key: Key::from_bytes(&public)} + Keystore {private_key: Key::from_bytes(&private), public_key: Key::from_bytes(&public), seed: Vec::from(&buf[..])} } pub fn from_bytes(seed: &[u8]) -> Self { let (private, public) = keypair(&seed); - Signature {private_key: Key::from_bytes(&private), public_key: Key::from_bytes(&public)} + Keystore {private_key: Key::from_bytes(&private), public_key: Key::from_bytes(&public), seed: Vec::from(seed)} } pub fn from_file(filename: &str, _password: &str) -> Option { diff --git a/src/lib.rs b/src/lib.rs index a08d7a7..0a3cd1f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,5 +8,9 @@ pub use crate::transaction::Transaction; pub mod utils; pub use crate::utils::*; pub mod keys; -pub use crate::keys::Signature; -pub use crate::keys::Key; \ No newline at end of file +pub use crate::keys::Keystore; +pub use crate::keys::Key; +pub mod miner; +pub mod context; +pub use crate::context::Context; +pub use crate::context::Settings; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 185761d..44c9c5d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,204 +1,140 @@ #![windows_subsystem = "windows"] -extern crate pancurses; -use pancurses::{initscr, endwin, Input, noecho, resize_term, Window, start_color, init_pair, colorpair::ColorPair, COLOR_PAIR}; +extern crate web_view; +use alfis::{Blockchain, Block, Action, Transaction, Keystore, Key, Settings, Context}; +use web_view::*; +use std::thread; +use std::sync::{Arc, Mutex}; -use wyrd_ns::{Blockchain, Block, Action, Transaction, Signature, Key}; +extern crate serde; +use serde::{Serialize, Deserialize}; +use alfis::miner::Miner; +use std::collections::HashMap; -const COLOR_TEXT: i16 = 0; -const COLOR_TITLE: i16 = 1; -const COLOR_MENU_NORMAL: i16 = 2; -const COLOR_MENU_FOCUSED: i16 = 3; -const COLOR_STATUS: i16 = 4; +extern crate serde_json; fn main() { - println!("Wyrd DNS 0.1.0"); - run_interface(); - //test_blockchain() + println!("ALFIS 0.1.0"); + let settings = Settings::new(42, 0,""); + let keystore: Keystore = Keystore::from_file("default.key", "").unwrap(); + let blockchain: Blockchain = Blockchain::new(settings.chain_id, settings.version); + let context: Arc> = Arc::new(Mutex::new(Context::new(settings, keystore, blockchain))); + + let miner: Arc> = Arc::new(Mutex::new(Miner::new(context.clone()))); + + // TODO check settings and if there is no mention of bootstrap nodes, generate genesis block + /*let chain_for_genesis = blockchain.clone(); + thread::spawn(move || { + let mut block = Blockchain::genesis(42, 0); + // TODO remake genesis to use Miner + block.mine(); + chain_for_genesis.lock().unwrap().add_block(block); + println!("Blockchain with genesis block has been created"); + });*/ + run_interface(context.clone(), miner.clone()); } -fn init_colors() { - start_color(); - let background = pancurses::COLOR_BLACK; - let accent = pancurses::COLOR_CYAN; - let text = pancurses::COLOR_WHITE; +fn run_interface(context: Arc>, miner: Arc>) { + let file_content = include_str!("index.html"); + let styles = inline_style(include_str!("bulma.css")); + let scripts = inline_script(include_str!("scripts.js")); - init_pair(COLOR_TEXT, text, background); - init_pair(COLOR_TITLE, background, accent); - init_pair(COLOR_MENU_NORMAL, text, background); - init_pair(COLOR_MENU_FOCUSED, background, accent); - init_pair(COLOR_STATUS, background, accent); -} - -fn draw_title(win: &Window, title: &str) { - win.color_set(COLOR_TITLE); - win.mvprintw(0, win.get_beg_x(), format!("{:width$}", title, width = win.get_max_x() as usize)); -} - -fn draw_status(win: &Window, title: &str) { - win.color_set(COLOR_TITLE); - win.mvprintw(win.get_max_y() - 1, win.get_beg_x(), format!("{:width$}", title, width = win.get_max_x() as usize)); -} - -#[derive(Debug)] -pub struct MenuItem { - id: usize, - caption: String, - hint: String -} - -impl MenuItem { - pub fn simple>(id: usize, caption: S) -> Self { - MenuItem{ id, caption: caption.into(), hint: String::new() } - } - - pub fn full>(id: usize, caption: S, hint: S) -> Self { - MenuItem{ id, caption: caption.into(), hint: hint.into() } - } - - pub fn separator() -> Self { - MenuItem { id: 0, caption: String::new(), hint: String::new() } - } - - pub fn is_separator(&self) -> bool { - self.caption.is_empty() - } - - pub fn get_id(&self) -> usize { - self.id - } - - pub fn get_caption(&self) -> &str { - &self.caption - } - - pub fn get_hint(&self) -> &str { - &self.hint - } -} - -struct Menu { - x: i32, - y: i32, - items: Vec, - position: usize, - max_width: usize, -} - -impl Menu { - fn new(x: i32, y: i32, items: Vec) -> Self { - let mut max = 0; - for item in items.iter() { - if item.get_caption().len() > max { - max = item.get_caption().len(); - } - } - Menu{ x, y, items, position: 0, max_width: max } - } - - fn up(&mut self) { - if self.position > 0 { - self.position = self.position - 1; - if self.items[self.position].is_separator() { - self.up(); - } - } - } - - fn down(&mut self) { - if self.position < (self.items.len() - 1) { - self.position = self.position + 1; - if self.items[self.position].is_separator() { - self.down(); - } - } - } - - fn position(&self) -> usize { - self.position - } - - fn current(&self) -> &MenuItem { - &self.items[self.position] - } - - fn paint(&self, win: &Window) { - let mut pos = 0; - for item in self.items.iter() { - let color = { if pos == self.position {COLOR_MENU_FOCUSED} else {COLOR_MENU_NORMAL} }; - win.color_set(color); - win.mvprintw(self.y + pos as i32, self.x, format!(" {:width$} ", item.get_caption(), width = self.max_width)); - pos = pos + 1; - } - } -} - -fn run_interface() { - let window = initscr(); - resize_term(24, 80); - init_colors(); - draw_title(&window, " Wyrd 0.1.0"); - window.refresh(); - window.keypad(true); - window.timeout(20); - pancurses::noecho(); - window.keypad(true); - pancurses::curs_set(0); - let mut menu = create_menu(); - - loop { - match window.getch() { - Some(Input::Character(c)) => { - if c == '\n' { - println!("Selected {:?}", menu.current()); - } else { - window.addch(c); + web_view::builder() + .title("ALFIS 0.1.0") + .content(Content::Html(file_content.to_owned().replace("{styles}", &styles).replace("{scripts}", &scripts))) + .size(1024, 720) + .resizable(true) + .debug(true) + .user_data(()) + .invoke_handler(|_web_view, arg| { + use Cmd::*; + println!("Command {}", arg); + match serde_json::from_str(arg).unwrap() { + LoadKey { name, pass } => { + match Keystore::from_file(&name, &pass) { + None => { + println!("Error loading keystore '{}'!", &name); + }, + Some(k) => { + let mut c = context.lock().unwrap(); + c.set_keystore(k); + }, + } + }, + CreateKey { name, pass } => { + let mut c = context.lock().unwrap(); + c.set_keystore(Keystore::new()); } - }, - Some(Input::KeyResize) => { resize_term(0, 0); }, - Some(Input::KeyUp) => { menu.up(); }, - Some(Input::KeyDown) => { menu.down(); }, - Some(Input::KeyEnter) => { println!("Selected {:?}", menu.current()); }, - Some(Input::KeyDC) => break, - Some(input) => { window.addstr(&format!("{:?}", input)); }, - None => () - } - draw_status(&window, menu.current().get_hint()); - menu.paint(&window); - window.refresh(); - } - endwin(); + CreateDomain { name, records, tags } => { + let mut c = context.lock().unwrap(); + create_domain(miner.clone(), name, records, tags, c.get_keystore()); + } + ChangeDomain { name, records, tags } => { + + } + RenewDomain { name, days } => {} + TransferDomain { name, owner } => {} + } + //dbg!(&signature); + Ok(()) + }) + .run() + .unwrap(); } -fn create_menu() -> Menu { - let menu_items = vec![ - MenuItem::full(1, "Key create", "Create keypair to sign domain operations"), - MenuItem::full(2, "Key load", "Load existing keypair"), - MenuItem::separator(), - MenuItem::full(3, "Domain create new", "Create and mine new domain"), - MenuItem::full(4, "Domain change records", "Change DNS records for your domain"), - MenuItem::full(5, "Domain renew", "Renew your domain name, needs additional mining"), - MenuItem::full(6, "Domain transfer", "Transfer your domain to a new owner (new keypair)"), - MenuItem::separator(), - MenuItem::full(7, "Test blockchain", "Do some test blockchain operations with simple mining") - ]; - Menu::new(1, 3, menu_items) +fn create_domain(miner: Arc>, name: String, records: String, tags: String, keystore: Keystore) { + let rec_vector: Vec = records.trim().split("\n").map(|s| s.trim()).map(String::from).collect(); + let tags_vector: Vec = tags.trim().split(",").map(|s| s.trim()).map(String::from).collect(); + let mut transaction = { transaction_new_domain(keystore, name, rec_vector, tags_vector, 365) }; + let mut miner_guard = miner.lock().unwrap(); + miner_guard.add_transaction(transaction); + miner_guard.mine(); +} + +fn transaction_claim_name>(keystore: Keystore, name: S, salt: S) -> Transaction { + // Creating transaction + let action = Action::claim_name(name.into(), salt.into(), &keystore); + 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_domain>(keystore: Keystore, name: S, records: Vec, tags: Vec, days: u16) -> Transaction { + // Creating transaction + let action = Action::new_domain(name.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 +} + +#[derive(Deserialize)] +#[serde(tag = "cmd", rename_all = "camelCase")] +pub enum Cmd { + LoadKey{name: String, pass: String}, + CreateKey{name: String, pass: String}, + CreateDomain{name: String, records: String, tags: String}, + ChangeDomain{name: String, records: String, tags: String}, + RenewDomain{name: String, days: u16}, + TransferDomain{name: String, owner: String}, +} + +fn inline_style(s: &str) -> String { + format!(r#""#, s) +} + +fn inline_script(s: &str) -> String { + format!(r#""#, s) } fn test_blockchain() -> () { let mut blockchain = Blockchain::new(42, 0); println!("Blockchain with genesis block has been created"); - let signature = Signature::from_file("default.key", "").unwrap(); + let keystore = Keystore::from_file("default.key", "").unwrap(); - // Creating transaction - let action = Action::new_domain("test.zz".to_owned(), &signature, vec!["AAAA IN 301:2925::1".to_owned()], vec!["testing".to_owned(), "example".to_owned()], 365); - let mut transaction = Transaction::new(action, signature.get_public().clone()); - - // Signing it with private key from Signature - let sign_hash = signature.sign(&transaction.get_bytes()); - transaction.set_signature(Key::from_bytes(&sign_hash)); - - // Creating a block with that signed transaction - let mut block = blockchain.new_block(transaction); + /*let mut block = create_transaction(&mut blockchain, keystore.clone(), "test.zz", vec!["AAAA IN 301:2925::1".to_owned()], vec!["testing".to_owned(), "example".to_owned()], 365); // Mining the nonce block.mine(); @@ -210,7 +146,7 @@ fn test_blockchain() -> () { println!("Second block added"); let block2: Block = serde_json::from_str(&s).unwrap(); - println!("DeSerialized block:\n{:?}", block2); + println!("DeSerialized block:\n{:?}", block2);*/ // Let's check if the blockchain is valid if blockchain.check() { diff --git a/src/miner.rs b/src/miner.rs new file mode 100644 index 0000000..8e1ec0e --- /dev/null +++ b/src/miner.rs @@ -0,0 +1,137 @@ +use crate::{Transaction, Block, Keystore, Key, Context}; +use std::sync::{Mutex, Arc}; +use crypto::digest::Digest; +use std::sync::atomic::{AtomicBool, Ordering}; +use chrono::Utc; +use num_bigint::BigUint; +use num_traits::One; +use crypto::sha2::Sha256; +use std::thread; + +pub struct Miner { + context: Arc>, + keystore: Keystore, + chain_id: u32, + version: u32, + transactions: Arc>>, + last_block: Option, + running: Arc, +} + +impl Miner { + pub fn new(context: Arc>) -> Self { + let c = context.lock().unwrap(); + Miner { + context: context.clone(), + keystore: c.keystore.clone(), + chain_id: c.settings.chain_id, + version: c.settings.version, + transactions: Arc::new(Mutex::new(Vec::new())), + last_block: c.blockchain.blocks.last().cloned(), + running: Arc::new(AtomicBool::new(false)), + } + } + + pub fn add_transaction(&mut self, transaction: Transaction) { + self.transactions.lock().unwrap().push(transaction); + } + + pub fn stop(&mut self) { + self.running.store(false, Ordering::Relaxed); + } + + pub fn mine(&mut self) { + let transaction = { self.transactions.lock().unwrap().first().cloned() }; + match transaction { + Some(transaction) => { + self.mine_internal(transaction); + }, + None => { + println!("Nothing to mine"); + }, + } + } + + pub fn is_mining(&self) -> bool { + self.running.load(Ordering::Relaxed) + } + + fn mine_internal(&mut self, mut transaction: Transaction) { + let mut last_block_time = 0i64; + let block = { + // Signing it with private key from Keystore + let sign_hash = self.keystore.sign(&transaction.get_bytes()); + transaction.set_signature(Key::from_bytes(&sign_hash)); + + match &self.last_block { + None => { + // Creating a block with that signed transaction + Block::new(0,Utc::now().timestamp(), self.chain_id, self.version, Key::zero32(), Some(transaction)) + }, + Some(block) => { + last_block_time = block.timestamp; + // Creating a block with that signed transaction + Block::new(block.index + 1,Utc::now().timestamp(), self.chain_id, self.version, block.hash.clone(), Some(transaction)) + }, + } + }; + //let blockchain = self.blockchain.clone(); + let transactions = self.transactions.clone(); + let running = self.running.clone(); + running.store(true, Ordering::Relaxed); + let context = self.context.clone(); + thread::spawn(move || { + match find_hash(&mut Sha256::new(), block, last_block_time, running.clone()) { + None => { + println!("Mining stopped"); + }, + Some(block) => { + //blockchain.lock().unwrap().add_block(block); + transactions.lock().unwrap().remove(0); + running.store(false, Ordering::Relaxed); + context.lock().unwrap().blockchain.add_block(block); + }, + } + }); + } +} + +fn find_hash(digest: &mut dyn Digest, mut block: Block, prev_block_time: i64, running: Arc) -> Option { + let mut buf: [u8; 32] = [0; 32]; + block.random = rand::random(); + let start_difficulty = block.difficulty; + for nonce in 0..std::u64::MAX { + if !running.load(Ordering::Relaxed) { + return None; + } + block.timestamp = Utc::now().timestamp(); + block.nonce = nonce; + // TODO uncomment for real run + //block.difficulty = start_difficulty + get_time_difficulty(prev_block_time, block.timestamp); + + digest.reset(); + 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); + return Some(block); + } + } + None +} + +fn get_time_difficulty(prev_time: i64, now: i64) -> usize { + let diff = now - prev_time; + if diff < 900_000 { + (900_000 as usize - diff as usize) / 60_000 + } else { + 0 + } +} + +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; +} \ No newline at end of file diff --git a/src/scripts.js b/src/scripts.js new file mode 100644 index 0000000..0db35af --- /dev/null +++ b/src/scripts.js @@ -0,0 +1,62 @@ +function openTab(element, tabName) { + // Declare all variables + var i, tabContent, tabLinks; + + // Get all elements with class="content" and hide them + tabContent = document.getElementsByClassName("content"); + for (i = 0; i < tabContent.length; i++) { + tabContent[i].className = "context is-hidden"; + } + + // Get all elements with class="tablinks" and remove the class "active" + tabLinks = document.getElementsByClassName("is-active"); + for (i = 0; i < tabLinks.length; i++) { + tabLinks[i].className = ""; + } + + // Show the current tab, and add an "active" class to the button that opened the tab + document.getElementById(tabName).className = "content"; + element.className = "is-active"; +} + +function loadKey() { + key_name = document.getElementById("load_key_name").value; + key_pass = document.getElementById("load_key_password").value; + external.invoke(JSON.stringify({cmd: 'loadKey', name: key_name, pass: key_pass})); +} + +function createKey() { + key_name = document.getElementById("create_key_name").value; + key_pass = document.getElementById("create_key_password").value; + external.invoke(JSON.stringify({cmd: 'createKey', name: key_name, pass: key_pass})); +} + +function createDomain() { + new_domain = document.getElementById("new_domain").value; + new_dom_records = document.getElementById("new_domain_records").value; + new_dom_tags = document.getElementById("new_domain_tags").value; + external.invoke(JSON.stringify({cmd: 'createDomain', name: new_domain, records: new_dom_records, tags: new_dom_tags})); +} + +function changeDomain() { + domain = document.getElementById("change_domain").value; + dom_records = document.getElementById("change_domain_records").value; + dom_tags = document.getElementById("change_domain_records").value; + external.invoke(JSON.stringify({cmd: 'changeDomain', name: domain, records: dom_records, tags: dom_tags})); +} + +function renewDomain() { + domain = document.getElementById("renew_domain").value; + days = document.getElementById("renew_domain_extend_days").value; + external.invoke(JSON.stringify({cmd: 'renewDomain', name: domain, days: days})); +} + +function transferDomain() { + domain = document.getElementById("transfer_domain").value; + new_owner = document.getElementById("transfer_domain_transfer_owner").value; + external.invoke(JSON.stringify({cmd: 'transferDomain', name: domain, owner: new_owner})); +} + +function sendAction(param) { + external.invoke(JSON.stringify(param)); +} \ No newline at end of file diff --git a/src/ser.rs b/src/ser.rs deleted file mode 100644 index df0a72a..0000000 --- a/src/ser.rs +++ /dev/null @@ -1,9 +0,0 @@ - -/// Signal to a serializable object how much of its data should be serialized -#[derive(Copy, Clone, PartialEq, Eq)] -pub enum SerializationMode { - /// Serialize everything sufficiently to fully reconstruct the object - Full, - /// Serialize the data that defines the object - Hash, -} \ No newline at end of file diff --git a/src/styles.css b/src/styles.css new file mode 100644 index 0000000..ffa8faa --- /dev/null +++ b/src/styles.css @@ -0,0 +1,75 @@ +html { + background: #202020; + background-attachment: fixed; +} +html, body { + width: 100%; + height: 100%; + margin: 0; + padding: 0; + background: linear-gradient(0deg, #404040, #090909); + background-attachment: fixed; + overflow: hidden; +} +h1, h2, h3 { color: #dddddd; } +p { color: #dddddd; } +a { color: #dddddd; } + /* Style the tab */ +.tab { + overflow: hidden; + border: 0px; + background: linear-gradient(180deg, #404040, #202020); +} + +/* Style the buttons that are used to open the tab content */ +.tab button { + background: inherit; + color: #dddddd; + float: left; + border: none; + outline: none; + cursor: pointer; + padding: 8px 16px; + transition: 0.3s; +} + +/* Change background color of buttons on hover */ +.tab button:hover { + background: linear-gradient(180deg, #808080, #202020); +} + +/* Create an active/current tablink class */ +.tab button.active { + background: linear-gradient(180deg, #606060, #202020); +} + +/* Style the tab content */ +.tabcontent { + display: none; + padding: 12px 12px; + border: 0px; + border-top: none; + height: 100%; +} + +button { + border: none; + outline: none; + color: #dddddd; + padding: 8px 8px; + background: linear-gradient(180deg, #404040, #202020); +} + +.tabcontent button { + min-width: 200px; +} + +.footer { + position: fixed; + left: 0; + bottom: 0; + width: 100%; + background-color: #404040; + color: #dddddd; + padding: 6px 12px; +} \ No newline at end of file diff --git a/src/transaction.rs b/src/transaction.rs index f6457a3..118d8bb 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -1,4 +1,3 @@ -use crate::transaction::Action::{MoveDomain, RenewDomain, ChangeDomain, NewDomain}; use crate::keys::*; extern crate serde; extern crate serde_json; @@ -10,27 +9,43 @@ use std::fmt; #[derive(Clone, Serialize, Deserialize, PartialEq)] #[serde(tag = "type")] pub enum Action { + ClaimName { hash: String, owner: Key }, NewDomain { name: String, owner: Key, #[serde(default, skip_serializing_if = "Vec::is_empty")] records: Vec, #[serde(default, skip_serializing_if = "Vec::is_empty")] tags: Vec, days: u16 }, ChangeDomain { name: String, records: Vec, tags: Vec }, RenewDomain { name: String, days: u16 }, MoveDomain { name: String, new_owner: Key }, + NewZone { name: String, difficulty: u16}, + ChangeZone { name: String, difficulty: u16}, } impl Action { - pub fn new_domain(name: String, signature: &Signature, records: Vec, tags: Vec, days: u16) -> Self { - NewDomain {name, owner: signature.get_public(), records, tags, days} + pub fn claim_name(name: String, salt: String, signature: &Keystore) -> Self { + let hash = format!("{} {}", salt, name); + Action::ClaimName {hash, owner: signature.get_public()} + } + + pub fn new_domain(name: String, signature: &Keystore, records: Vec, tags: Vec, days: u16) -> Self { + Action::NewDomain {name, owner: signature.get_public(), records, tags, days} } pub fn change_domain(name: String, records: Vec, tags: Vec) -> Self { - ChangeDomain {name, records, tags} + Action::ChangeDomain {name, records, tags} } pub fn renew_domain(name: String, days: u16) -> Self { - RenewDomain {name, days} + Action::RenewDomain {name, days} } pub fn move_domain(name: String, new_owner: [u8; 32]) -> Self { - MoveDomain {name, new_owner: Key::from_bytes(&new_owner)} + Action::MoveDomain {name, new_owner: Key::from_bytes(&new_owner)} + } + + pub fn new_zone(name: String, difficulty: u16) -> Self { + Action::NewZone {name, difficulty} + } + + pub fn change_zone(name: String, difficulty: u16) -> Self { + Action::ChangeZone {name, difficulty} } pub fn get_bytes(&self) -> Vec { @@ -47,6 +62,12 @@ impl Action { impl fmt::Debug for Action { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self { + Action::ClaimName { hash, owner } => { + fmt.debug_struct("ClaimName") + .field("hash", hash) + .field("owner", owner) + .finish() + }, Action::NewDomain { name, owner, records, tags, days } => { fmt.debug_struct("NewDomain") .field("name", name) @@ -75,6 +96,18 @@ impl fmt::Debug for Action { .field("new_owner", new_owner) .finish() }, + Action::NewZone { name, difficulty } => { + fmt.debug_struct("NewZone") + .field("name", name) + .field("difficulty", difficulty) + .finish() + }, + Action::ChangeZone { name, difficulty } => { + fmt.debug_struct("ChangeZone") + .field("name", name) + .field("difficulty", difficulty) + .finish() + } } } }