Reworked handling appropriate (mined) keys absence. Now that info handled in UI as well. It won't allow users without keys to mine domains or zones.

This commit is contained in:
Revertron
2021-03-23 18:55:11 +01:00
parent 046c06beeb
commit f5949e6ec0
11 changed files with 184 additions and 97 deletions
+2 -2
View File
@@ -1,8 +1,8 @@
# Settings # Settings
origin = "00000102C2F9BFD2803284D93327F089D60FC72A06F19AF2384567F2646B8348" origin = "00000102C2F9BFD2803284D93327F089D60FC72A06F19AF2384567F2646B8348"
key_file = "default.key" key_file = "default1.key"
listen = "[::]:4244" listen = "[::]:4244"
public = false public = true
# Bootstrap nodes # Bootstrap nodes
#peers = ["test-ip4.alfis.name:4244", "test-ip6.alfis.name:4244"] #peers = ["test-ip4.alfis.name:4244", "test-ip6.alfis.name:4244"]
+5 -5
View File
@@ -6,7 +6,7 @@ use log::{trace, debug, info, warn, error};
pub struct Context { pub struct Context {
pub app_version: String, pub app_version: String,
pub settings: Settings, pub settings: Settings,
pub keystore: Keystore, pub keystore: Option<Keystore>,
pub chain: Chain, pub chain: Chain,
pub x_zones: ExternalZones, pub x_zones: ExternalZones,
pub bus: Bus<Event>, pub bus: Bus<Event>,
@@ -14,7 +14,7 @@ pub struct Context {
impl Context { impl Context {
/// Creating an essential context to work with /// Creating an essential context to work with
pub fn new(app_version: String, settings: Settings, keystore: Keystore, chain: Chain) -> Context { pub fn new(app_version: String, settings: Settings, keystore: Option<Keystore>, chain: Chain) -> Context {
Context { app_version, settings, keystore, chain, x_zones: ExternalZones::new(), bus: Bus::new() } Context { app_version, settings, keystore, chain, x_zones: ExternalZones::new(), bus: Bus::new() }
} }
@@ -26,17 +26,17 @@ impl Context {
warn!("Error loading keystore '{}'!", filename); warn!("Error loading keystore '{}'!", filename);
}, },
Some(keystore) => { Some(keystore) => {
self.keystore = keystore; self.keystore = Some(keystore);
}, },
} }
self self
} }
pub fn get_keystore(&self) -> Keystore { pub fn get_keystore(&self) -> Option<Keystore> {
self.keystore.clone() self.keystore.clone()
} }
pub fn set_keystore(&mut self, keystore: Keystore) { pub fn set_keystore(&mut self, keystore: Option<Keystore>) {
self.keystore = keystore; self.keystore = keystore;
} }
+14 -2
View File
@@ -244,8 +244,14 @@ impl DnsServer for DnsUdpServer {
let mut req_buffer = BytePacketBuffer::new(); let mut req_buffer = BytePacketBuffer::new();
let (_, src) = match socket.recv_from(&mut req_buffer.buf) { let (_, src) = match socket.recv_from(&mut req_buffer.buf) {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(err) => {
debug!("Failed to read from UDP socket: {:?}", e); if let Some(code) = err.raw_os_error() {
if code == 10004 {
debug!("UDP service loop has finished");
break;
}
}
debug!("Failed to read from UDP socket: {:?}", err);
continue; continue;
} }
}; };
@@ -347,6 +353,12 @@ impl DnsServer for DnsTcpServer {
let stream = match wrap_stream { let stream = match wrap_stream {
Ok(stream) => stream, Ok(stream) => stream,
Err(err) => { Err(err) => {
if let Some(code) = err.raw_os_error() {
if code == 10004 {
debug!("TCP service loop has finished");
break;
}
}
warn!("Failed to accept TCP connection: {:?}", err); warn!("Failed to accept TCP connection: {:?}", err);
continue; continue;
} }
+3 -2
View File
@@ -1,4 +1,4 @@
use crate::Bytes; use crate::{Bytes, Keystore};
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug)]
pub enum Event { pub enum Event {
@@ -12,7 +12,8 @@ pub enum Event {
NewBlockReceived, NewBlockReceived,
BlockchainChanged { index: u64 }, BlockchainChanged { index: u64 },
ActionStopMining, ActionStopMining,
ActionMineLocker { index: u64, hash: Bytes }, ActionMineLocker { index: u64, hash: Bytes, keystore: Box<Keystore> },
ActionQuit,
NetworkStatus { nodes: usize, blocks: u64 }, NetworkStatus { nodes: usize, blocks: u64 },
Syncing { have: u64, height: u64 }, Syncing { have: u64, height: u64 },
SyncFinished, SyncFinished,
+7 -1
View File
@@ -128,6 +128,12 @@ impl Clone for Keystore {
} }
} }
impl PartialEq for Keystore {
fn eq(&self, other: &Self) -> bool {
self.keypair.to_bytes().eq(&other.keypair.to_bytes())
}
}
/// Checks if some public key is "strong" enough to mine domains /// Checks if some public key is "strong" enough to mine domains
/// TODO Optimize by caching Blakeout somewhere /// TODO Optimize by caching Blakeout somewhere
pub fn check_public_key_strength(key: &Bytes, strength: usize) -> bool { pub fn check_public_key_strength(key: &Bytes, strength: usize) -> bool {
@@ -155,7 +161,7 @@ pub fn create_key(context: Arc<Mutex<Context>>) {
let hash = keystore.get_hash().to_string(); let hash = keystore.get_hash().to_string();
info!("Key mined successfully: {:?}, hash: {}", &keystore.get_public(), &hash); info!("Key mined successfully: {:?}, hash: {}", &keystore.get_public(), &hash);
context.bus.post(Event::KeyCreated { path: keystore.get_path().to_owned(), public: keystore.get_public().to_string(), hash }); context.bus.post(Event::KeyCreated { path: keystore.get_path().to_owned(), public: keystore.get_public().to_string(), hash });
context.set_keystore(keystore); context.set_keystore(Some(keystore));
} }
} }
let miners = miners_count.fetch_sub(1, atomic::Ordering::SeqCst) - 1; let miners = miners_count.fetch_sub(1, atomic::Ordering::SeqCst) - 1;
+8 -11
View File
@@ -80,13 +80,7 @@ fn main() {
let settings = Settings::load(&config_name); let settings = Settings::load(&config_name);
info!(target: LOG_TARGET_MAIN, "Loaded settings: {:?}", &settings); info!(target: LOG_TARGET_MAIN, "Loaded settings: {:?}", &settings);
let keystore: Keystore = match Keystore::from_file(&settings.key_file, "") { let keystore = Keystore::from_file(&settings.key_file, "");
None => {
warn!(target: LOG_TARGET_MAIN, "Generated temporary keystore. Please, generate full-privileged keys.");
Keystore::new()
}
Some(keystore) => { keystore }
};
let chain: Chain = Chain::new(&settings); let chain: Chain = Chain::new(&settings);
if opt_matches.opt_present("l") { if opt_matches.opt_present("l") {
for i in 1..(chain.height() + 1) { for i in 1..(chain.height() + 1) {
@@ -102,7 +96,8 @@ fn main() {
Some(block) => { trace!(target: LOG_TARGET_MAIN, "Loaded DB with origin {:?}", &block.hash); } Some(block) => { trace!(target: LOG_TARGET_MAIN, "Loaded DB with origin {:?}", &block.hash); }
} }
let settings_copy = settings.clone(); let settings_copy = settings.clone();
let context: Arc<Mutex<Context>> = Arc::new(Mutex::new(Context::new(env!("CARGO_PKG_VERSION").to_owned(), settings, keystore, chain))); let context = Context::new(env!("CARGO_PKG_VERSION").to_owned(), settings, keystore, chain);
let context: Arc<Mutex<Context>> = Arc::new(Mutex::new(context));
dns_utils::start_dns_server(&context, &settings_copy); dns_utils::start_dns_server(&context, &settings_copy);
let mut miner_obj = Miner::new(Arc::clone(&context)); let mut miner_obj = Miner::new(Arc::clone(&context));
@@ -136,9 +131,11 @@ fn create_genesis_if_needed(context: &Arc<Mutex<Context>>, miner: &Arc<Mutex<Min
let last_block = context.get_chain().last_block(); let last_block = context.get_chain().last_block();
let origin = context.settings.origin.clone(); let origin = context.settings.origin.clone();
if origin.eq("") && last_block.is_none() { if origin.eq("") && last_block.is_none() {
// If blockchain is empty, we are going to mine a Genesis block if let Some(keystore) = &context.keystore {
let block = Block::new(None, context.get_keystore().get_public(), Bytes::default(), BLOCK_DIFFICULTY); // If blockchain is empty, we are going to mine a Genesis block
miner.lock().unwrap().add_block(block); let block = Block::new(None, context.get_keystore().unwrap().get_public(), Bytes::default(), BLOCK_DIFFICULTY);
miner.lock().unwrap().add_block(block, keystore.clone());
}
} }
} }
+29 -22
View File
@@ -8,17 +8,18 @@ use chrono::Utc;
use log::{debug, error, info, trace, warn}; use log::{debug, error, info, trace, warn};
use num_cpus; use num_cpus;
use crate::{Block, Bytes, Context}; use crate::{Block, Bytes, Context, Keystore};
use crate::commons::{CHAIN_VERSION, LOCKER_DIFFICULTY, KEYSTORE_DIFFICULTY}; use crate::commons::{CHAIN_VERSION, LOCKER_DIFFICULTY, KEYSTORE_DIFFICULTY};
use crate::blockchain::enums::BlockQuality; use crate::blockchain::enums::BlockQuality;
use crate::blockchain::hash_utils::*; use crate::blockchain::hash_utils::*;
use crate::keys::check_public_key_strength; use crate::keys::check_public_key_strength;
use crate::event::Event; use crate::event::Event;
use blakeout::Blakeout; use blakeout::Blakeout;
use std::ops::Deref;
pub struct Miner { pub struct Miner {
context: Arc<Mutex<Context>>, context: Arc<Mutex<Context>>,
blocks: Arc<Mutex<Vec<Block>>>, jobs: Arc<Mutex<Vec<MineJob>>>,
running: Arc<AtomicBool>, running: Arc<AtomicBool>,
mining: Arc<AtomicBool>, mining: Arc<AtomicBool>,
cond_var: Arc<Condvar> cond_var: Arc<Condvar>
@@ -28,15 +29,15 @@ impl Miner {
pub fn new(context: Arc<Mutex<Context>>) -> Self { pub fn new(context: Arc<Mutex<Context>>) -> Self {
Miner { Miner {
context, context,
blocks: Arc::new(Mutex::new(Vec::new())), jobs: Arc::new(Mutex::new(Vec::new())),
running: Arc::new(AtomicBool::new(false)), running: Arc::new(AtomicBool::new(false)),
mining: Arc::new(AtomicBool::new(false)), mining: Arc::new(AtomicBool::new(false)),
cond_var: Arc::new(Condvar::new()) cond_var: Arc::new(Condvar::new())
} }
} }
pub fn add_block(&mut self, block: Block) { pub fn add_block(&mut self, block: Block, keystore: Keystore) {
self.blocks.lock().unwrap().push(block); self.jobs.lock().unwrap().push(MineJob { block, keystore });
self.cond_var.notify_one(); self.cond_var.notify_one();
} }
@@ -48,7 +49,7 @@ impl Miner {
pub fn start_mining_thread(&mut self) { pub fn start_mining_thread(&mut self) {
let context = Arc::clone(&self.context); let context = Arc::clone(&self.context);
let blocks = self.blocks.clone(); let blocks = self.jobs.clone();
let running = self.running.clone(); let running = self.running.clone();
let mining = self.mining.clone(); let mining = self.mining.clone();
let cond_var = self.cond_var.clone(); let cond_var = self.cond_var.clone();
@@ -73,7 +74,7 @@ impl Miner {
} }
}); });
let mining = self.mining.clone(); let mining = self.mining.clone();
let blocks = self.blocks.clone(); let blocks = self.jobs.clone();
let cond_var = self.cond_var.clone(); let cond_var = self.cond_var.clone();
self.context.lock().unwrap().bus.register(move |_uuid, e| { self.context.lock().unwrap().bus.register(move |_uuid, e| {
match e { match e {
@@ -82,11 +83,11 @@ impl Miner {
Event::ActionStopMining => { Event::ActionStopMining => {
mining.store(false, Ordering::SeqCst); mining.store(false, Ordering::SeqCst);
} }
Event::ActionMineLocker { index, hash } => { Event::ActionMineLocker { index, hash, keystore } => {
if !mining.load(Ordering::SeqCst) { if !mining.load(Ordering::SeqCst) {
let mut block = Block::new(None, Bytes::default(), hash, LOCKER_DIFFICULTY); let mut block = Block::new(None, Bytes::default(), hash, LOCKER_DIFFICULTY);
block.index = index; block.index = index;
blocks.lock().unwrap().push(block); blocks.lock().unwrap().push(MineJob { block, keystore: keystore.deref().clone() });
cond_var.notify_all(); cond_var.notify_all();
info!("Added a locker block to mine"); info!("Added a locker block to mine");
} }
@@ -101,16 +102,16 @@ impl Miner {
self.running.load(Ordering::Relaxed) self.running.load(Ordering::Relaxed)
} }
fn mine_internal(context: Arc<Mutex<Context>>, mut block: Block, mining: Arc<AtomicBool>) { fn mine_internal(context: Arc<Mutex<Context>>, mut job: MineJob, mining: Arc<AtomicBool>) {
// Clear signature and hash just in case // Clear signature and hash just in case
block.signature = Bytes::default(); job.block.signature = Bytes::default();
block.hash = Bytes::default(); job.block.hash = Bytes::default();
block.version = CHAIN_VERSION; job.block.version = CHAIN_VERSION;
// If this block needs to be a locker // If this block needs to be a locker
if block.index > 0 && !block.prev_block_hash.is_empty() { if job.block.index > 0 && !job.block.prev_block_hash.is_empty() {
info!("Mining locker block"); info!("Mining locker block");
block.pub_key = context.lock().unwrap().keystore.get_public(); job.block.pub_key = job.keystore.get_public();
if !check_public_key_strength(&block.pub_key, KEYSTORE_DIFFICULTY) { if !check_public_key_strength(&job.block.pub_key, KEYSTORE_DIFFICULTY) {
warn!("Can not mine block with weak public key!"); warn!("Can not mine block with weak public key!");
context.lock().unwrap().bus.post(Event::MinerStopped); context.lock().unwrap().bus.post(Event::MinerStopped);
mining.store(false, Ordering::SeqCst); mining.store(false, Ordering::SeqCst);
@@ -121,7 +122,7 @@ impl Miner {
Some(last_block) => { Some(last_block) => {
info!("Last block found"); info!("Last block found");
// If we were doing something else and got new block before we could mine this block // If we were doing something else and got new block before we could mine this block
if last_block.index > block.index || last_block.hash != block.prev_block_hash { if last_block.index > job.block.index || last_block.hash != job.block.prev_block_hash {
warn!("We missed block to lock"); warn!("We missed block to lock");
context.lock().unwrap().bus.post(Event::MinerStopped); context.lock().unwrap().bus.post(Event::MinerStopped);
mining.store(false, Ordering::SeqCst); mining.store(false, Ordering::SeqCst);
@@ -130,8 +131,8 @@ impl Miner {
} }
} }
} else { } else {
block.index = context.lock().unwrap().chain.height() + 1; job.block.index = context.lock().unwrap().chain.height() + 1;
block.prev_block_hash = match context.lock().unwrap().chain.last_block() { job.block.prev_block_hash = match context.lock().unwrap().chain.last_block() {
None => { Bytes::default() } None => { Bytes::default() }
Some(block) => { block.hash } Some(block) => { block.hash }
}; };
@@ -144,12 +145,12 @@ impl Miner {
debug!("Starting {} threads for mining", cpus); debug!("Starting {} threads for mining", cpus);
for _cpu in 0..cpus { for _cpu in 0..cpus {
let context = Arc::clone(&context); let context = Arc::clone(&context);
let block = block.clone(); let job = job.clone();
let mining = Arc::clone(&mining); let mining = Arc::clone(&mining);
let live_threads = Arc::clone(&live_threads); let live_threads = Arc::clone(&live_threads);
thread::spawn(move || { thread::spawn(move || {
live_threads.fetch_add(1, Ordering::SeqCst); live_threads.fetch_add(1, Ordering::SeqCst);
match find_hash(Arc::clone(&context), block, Arc::clone(&mining)) { match find_hash(Arc::clone(&context), job.block, Arc::clone(&mining)) {
None => { None => {
debug!("Mining was cancelled"); debug!("Mining was cancelled");
let count = live_threads.fetch_sub(1, Ordering::SeqCst); let count = live_threads.fetch_sub(1, Ordering::SeqCst);
@@ -162,7 +163,7 @@ impl Miner {
Some(mut block) => { Some(mut block) => {
let index = block.index; let index = block.index;
let mut context = context.lock().unwrap(); let mut context = context.lock().unwrap();
block.signature = Bytes::from_bytes(&context.keystore.sign(&block.as_bytes())); block.signature = Bytes::from_bytes(&job.keystore.sign(&block.as_bytes()));
if context.chain.check_new_block(&block) != BlockQuality::Good { if context.chain.check_new_block(&block) != BlockQuality::Good {
warn!("Error adding mined block!"); warn!("Error adding mined block!");
if index == 0 { if index == 0 {
@@ -184,6 +185,12 @@ impl Miner {
} }
} }
#[derive(Clone)]
pub struct MineJob {
block: Block,
keystore: Keystore
}
fn find_hash(context: Arc<Mutex<Context>>, mut block: Block, running: Arc<AtomicBool>) -> Option<Block> { fn find_hash(context: Arc<Mutex<Context>>, mut block: Block, running: Arc<AtomicBool>) -> Option<Block> {
let difficulty = block.difficulty as usize; let difficulty = block.difficulty as usize;
let full = block.transaction.is_some(); let full = block.transaction.is_some();
+35 -10
View File
@@ -18,6 +18,7 @@ use std::collections::HashSet;
use crate::{Context, Block, p2p::Message, p2p::State, p2p::Peer, p2p::Peers, Bytes}; use crate::{Context, Block, p2p::Message, p2p::State, p2p::Peer, p2p::Peers, Bytes};
use crate::blockchain::enums::BlockQuality; use crate::blockchain::enums::BlockQuality;
use crate::commons::CHAIN_VERSION; use crate::commons::CHAIN_VERSION;
use std::sync::atomic::{AtomicBool, Ordering};
const SERVER: Token = Token(0); const SERVER: Token = Token(0);
const POLL_TIMEOUT: Option<Duration> = Some(Duration::from_millis(3000)); const POLL_TIMEOUT: Option<Duration> = Some(Duration::from_millis(3000));
@@ -40,6 +41,9 @@ impl Network {
(c.settings.listen.clone(), c.settings.peers.clone()) (c.settings.listen.clone(), c.settings.peers.clone())
}; };
let running = Arc::new(AtomicBool::new(true));
subscribe_to_bus(&mut self.context, Arc::clone(&running));
// Starting server socket // Starting server socket
let addr = listen_addr.parse().expect("Error parsing listen address"); let addr = listen_addr.parse().expect("Error parsing listen address");
let mut server = TcpListener::bind(addr).expect("Can't bind to address"); let mut server = TcpListener::bind(addr).expect("Can't bind to address");
@@ -62,6 +66,9 @@ impl Network {
loop { loop {
// Poll Mio for events, blocking until we get an event. // Poll Mio for events, blocking until we get an event.
poll.poll(&mut events, POLL_TIMEOUT).expect("Error polling sockets"); poll.poll(&mut events, POLL_TIMEOUT).expect("Error polling sockets");
if !running.load(Ordering::SeqCst) {
break;
}
// Process each event. // Process each event.
for event in events.iter() { for event in events.iter() {
@@ -125,11 +132,26 @@ impl Network {
peers.send_pings(poll.registry(), height, hash); peers.send_pings(poll.registry(), height, hash);
peers.connect_new_peers(poll.registry(), &mut unique_token); peers.connect_new_peers(poll.registry(), &mut unique_token);
} }
info!("Network loop finished");
}); });
Ok(()) Ok(())
} }
} }
fn subscribe_to_bus(context: &mut Arc<Mutex<Context>>, running: Arc<AtomicBool>) {
use crate::event::Event;
context.lock().unwrap().bus.register(move |_uuid, e| {
match e {
Event::ActionQuit => {
running.store(false, Ordering::SeqCst);
return false;
}
_ => {}
}
true
});
}
fn handle_connection_event(context: Arc<Mutex<Context>>, peers: &mut Peers, registry: &Registry, event: &Event) -> bool { fn handle_connection_event(context: Arc<Mutex<Context>>, peers: &mut Peers, registry: &Registry, event: &Event) -> bool {
if event.is_error() || (event.is_read_closed() && event.is_write_closed()) { if event.is_error() || (event.is_read_closed() && event.is_write_closed()) {
return false; return false;
@@ -415,16 +437,19 @@ fn handle_message(context: Arc<Mutex<Context>>, message: Message, peers: &mut Pe
fn mine_locker_block(context: Arc<Mutex<Context>>) { fn mine_locker_block(context: Arc<Mutex<Context>>) {
let mut context = context.lock().unwrap(); let mut context = context.lock().unwrap();
if let Some(block) = context.chain.last_block() { if let Some(block) = context.chain.last_block() {
if block.index < context.chain.max_height() { if let Some(keystore) = &context.keystore {
info!("No locker mining while syncing"); if block.index < context.chain.max_height() {
return; info!("No locker mining while syncing");
} return;
let lockers: HashSet<Bytes> = context.chain.get_block_lockers(&block).into_iter().collect(); }
if lockers.contains(&context.keystore.get_public()) { let lockers: HashSet<Bytes> = context.chain.get_block_lockers(&block).into_iter().collect();
info!("We have an honor to mine locker block!"); if lockers.contains(&keystore.get_public()) {
context.bus.post(crate::event::Event::ActionMineLocker { index: block.index + 1, hash: block.hash }); info!("We have an honor to mine locker block!");
} else if !lockers.is_empty() { let keystore = Box::new(keystore.clone());
info!("Locker block must be mined by other nodes"); context.bus.post(crate::event::Event::ActionMineLocker { index: block.index + 1, hash: block.hash, keystore });
} else if !lockers.is_empty() {
info!("Locker block must be mined by other nodes");
}
} }
} }
} }
+54 -29
View File
@@ -61,12 +61,13 @@ pub fn run_interface(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>) {
.build() .build()
.expect("Error building GUI"); .expect("Error building GUI");
run_interface_loop(&mut interface); let mut context = Arc::clone(&context);
run_interface_loop(&mut context, &mut interface);
interface.exit(); interface.exit();
} }
/// Indefinitely loops through WebView steps /// Indefinitely loops through WebView steps
fn run_interface_loop(interface: &mut WebView<()>) { fn run_interface_loop(context: &mut Arc<Mutex<Context>>, interface: &mut WebView<()>) {
// We use this ugly loop to lower CPU usage a lot. // We use this ugly loop to lower CPU usage a lot.
// If we use .run() or only .step() in a loop without sleeps it will try // If we use .run() or only .step() in a loop without sleeps it will try
// to support 60FPS and uses more CPU than it should. // to support 60FPS and uses more CPU than it should.
@@ -76,6 +77,8 @@ fn run_interface_loop(interface: &mut WebView<()>) {
match interface.step() { match interface.step() {
None => { None => {
info!("Interface closed, exiting"); info!("Interface closed, exiting");
context.lock().unwrap().bus.post(Event::ActionQuit);
thread::sleep(Duration::from_millis(100));
break; break;
} }
Some(result) => { Some(result) => {
@@ -101,8 +104,10 @@ fn action_check_zone(context: &Arc<Mutex<Context>>, web_view: &mut WebView<()>,
web_view.eval("zoneAvailable(false)").expect("Error evaluating!"); web_view.eval("zoneAvailable(false)").expect("Error evaluating!");
} else { } else {
let c = context.lock().unwrap(); let c = context.lock().unwrap();
let available = c.get_chain().is_domain_available(&name, &c.get_keystore()); if let Some(keystore) = c.get_keystore() {
web_view.eval(&format!("zoneAvailable({})", available)).expect("Error evaluating!"); let available = c.get_chain().is_domain_available(&name, &keystore);
web_view.eval(&format!("zoneAvailable({})", available)).expect("Error evaluating!");
}
} }
} }
@@ -114,24 +119,31 @@ fn action_check_record(web_view: &mut WebView<()>, data: String) {
} }
fn action_check_domain(context: &Arc<Mutex<Context>>, web_view: &mut WebView<()>, name: String) { fn action_check_domain(context: &Arc<Mutex<Context>>, web_view: &mut WebView<()>, name: String) {
let name = name.to_lowercase();
let c = context.lock().unwrap(); let c = context.lock().unwrap();
let available = c.get_chain().is_domain_available(&name, &c.get_keystore()); if let Some(keystore) = c.get_keystore() {
web_view.eval(&format!("domainAvailable({})", available)).expect("Error evaluating!"); let name = name.to_lowercase();
let available = c.get_chain().is_domain_available(&name, &keystore);
web_view.eval(&format!("domainAvailable({})", available)).expect("Error evaluating!");
}
} }
fn action_save_key(context: &Arc<Mutex<Context>>) { fn action_save_key(context: &Arc<Mutex<Context>>) {
if context.lock().unwrap().get_keystore().is_none() {
return;
}
let result = tfd::save_file_dialog_with_filter("Save keys file", "", &["*.key"], "Key files (*.key)"); let result = tfd::save_file_dialog_with_filter("Save keys file", "", &["*.key"], "Key files (*.key)");
match result { match result {
None => {} None => {}
Some(new_path) => { Some(new_path) => {
let mut context = context.lock().unwrap(); let mut context = context.lock().unwrap();
let path = new_path.clone(); let path = new_path.clone();
let public = context.keystore.get_public().to_string(); if let Some(mut keystore) = context.get_keystore() {
let hash = context.keystore.get_hash().to_string(); let public = keystore.get_public().to_string();
context.keystore.save(&new_path, ""); let hash = keystore.get_hash().to_string();
info!("Key file saved to {}", &path); keystore.save(&new_path, "");
context.bus.post(Event::KeySaved { path, public, hash }); info!("Key file saved to {}", &path);
context.bus.post(Event::KeySaved { path, public, hash });
}
} }
} }
} }
@@ -152,7 +164,7 @@ fn action_load_key(context: &Arc<Mutex<Context>>, _web_view: &mut WebView<()>) {
let public = keystore.get_public().to_string(); let public = keystore.get_public().to_string();
let hash = keystore.get_hash().to_string(); let hash = keystore.get_hash().to_string();
c.bus.post(Event::KeyLoaded { path, public, hash }); c.bus.post(Event::KeyLoaded { path, public, hash });
c.set_keystore(keystore); c.set_keystore(Some(keystore));
} }
} }
} }
@@ -213,23 +225,32 @@ fn action_loaded(context: &Arc<Mutex<Context>>, web_view: &mut WebView<()>) {
}; };
if !eval.is_empty() { if !eval.is_empty() {
//debug!("Evaluating {}", &eval);
handle.dispatch(move |web_view| { handle.dispatch(move |web_view| {
web_view.eval(&eval.replace("\\", "\\\\")) web_view.eval(&eval.replace("\\", "\\\\"))
}).expect("Error dispatching!"); }).expect("Error dispatching!");
} }
true true
}); });
let eval = format!("keystoreChanged('{}', '{}', '{}');", c.keystore.get_path(), &c.keystore.get_public().to_string(), &c.keystore.get_hash().to_string()); if let Some(keystore) = c.get_keystore() {
debug!("Evaluating {}", &eval); let eval = format!("keystoreChanged('{}', '{}', '{}');",
web_view.eval(&eval.replace("\\", "\\\\")).expect("Error evaluating!"); keystore.get_path(),
&keystore.get_public().to_string(),
&keystore.get_hash().to_string());
//debug!("Evaluating {}", &eval);
web_view.eval(&eval.replace("\\", "\\\\")).expect("Error evaluating!");
}
} }
fn action_create_domain(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>, web_view: &mut WebView<()>, name: String, records: &String) { fn action_create_domain(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>, web_view: &mut WebView<()>, name: String, records: &String) {
debug!("Creating domain with records: {}", records); debug!("Creating domain with records: {}", records);
let c = Arc::clone(&context); let c = Arc::clone(&context);
let context = context.lock().unwrap(); let context = context.lock().unwrap();
let pub_key = context.keystore.get_public(); if context.get_keystore().is_none() {
show_warning(web_view, "You don't have keys loaded!\nLoad or mine the keys and try again.");
return;
}
let keystore = context.get_keystore().unwrap();
let pub_key = keystore.get_public();
match context.chain.can_mine_domain(&name, &records, &pub_key) { match context.chain.can_mine_domain(&name, &records, &pub_key) {
MineResult::Fine => { MineResult::Fine => {
let zone = get_domain_zone(&name); let zone = get_domain_zone(&name);
@@ -237,7 +258,6 @@ fn action_create_domain(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>,
if let Ok(records) = serde_json::from_str::<Vec<DnsRecord>>(&records) { if let Ok(records) = serde_json::from_str::<Vec<DnsRecord>>(&records) {
let data = DomainData::new(zone.clone(), records); let data = DomainData::new(zone.clone(), records);
let data = serde_json::to_string(&data).unwrap(); let data = serde_json::to_string(&data).unwrap();
let keystore = context.keystore.clone();
std::mem::drop(context); std::mem::drop(context);
create_domain(c, miner, &name, &data, difficulty, &keystore); create_domain(c, miner, &name, &data, difficulty, &keystore);
let _ = web_view.eval("domainMiningStarted()"); let _ = web_view.eval("domainMiningStarted()");
@@ -271,18 +291,23 @@ fn action_create_zone(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>, we
let context = context.lock().unwrap(); let context = context.lock().unwrap();
(context.get_keystore(), context.chain.get_domain_transaction(&name)) (context.get_keystore(), context.chain.get_domain_transaction(&name))
}; };
match transaction { if let Some(keystore) = keystore {
None => { match transaction {
create_domain(Arc::clone(&context), miner.clone(), &name, &data, ZONE_DIFFICULTY, &keystore); None => {
}
Some(transaction) => {
if transaction.pub_key == keystore.get_public() {
create_domain(Arc::clone(&context), miner.clone(), &name, &data, ZONE_DIFFICULTY, &keystore); create_domain(Arc::clone(&context), miner.clone(), &name, &data, ZONE_DIFFICULTY, &keystore);
} else { }
warn!("Tried to mine not owned domain!"); Some(transaction) => {
show_warning(web_view, "You cannot change domain that you don't own!"); if transaction.pub_key == keystore.get_public() {
create_domain(Arc::clone(&context), miner.clone(), &name, &data, ZONE_DIFFICULTY, &keystore);
} else {
warn!("Tried to mine not owned domain!");
show_warning(web_view, "You cannot change domain that you don't own!");
}
} }
} }
} else {
warn!("Can not mine without keys!");
show_warning(web_view, "You don't have keys loaded!\nLoad or mine the keys and try again.");
} }
} }
@@ -303,7 +328,7 @@ fn create_domain(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>, name: &
//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 transaction = Transaction::from_str(name, "dns".to_owned(), data.to_owned(), keystore.get_public().clone()); let transaction = Transaction::from_str(name, "dns".to_owned(), data.to_owned(), keystore.get_public().clone());
let block = Block::new(Some(transaction), keystore.get_public(), Bytes::default(), difficulty); let block = Block::new(Some(transaction), keystore.get_public(), Bytes::default(), difficulty);
miner.lock().unwrap().add_block(block); miner.lock().unwrap().add_block(block, keystore.clone());
} }
#[derive(Deserialize)] #[derive(Deserialize)]
+13 -13
View File
@@ -154,7 +154,7 @@
<div class="content is-hidden" id="key_load"> <div class="content is-hidden" id="key_load">
<div class="field"> <div class="field">
<label class="label">Key path</label> <label class="label">Key path</label>
<p id="key_file_name">Key not saved</p> <p id="key_file_name">Not loaded</p>
</div> </div>
<div class="field"> <div class="field">
@@ -169,16 +169,16 @@
<br> <br>
<div class="field is-grouped"> <div class="field is-grouped">
<div class="control">
<button class="button is-success" onclick="loadKey();">Load key</button>
</div>
<div class="control"> <div class="control">
<button class="button is-warning" onclick="createKey();">Mine new key</button> <button class="button is-warning" onclick="createKey();">Mine new key</button>
</div> </div>
<div class="control"> <div class="control">
<button class="button is-primary" onclick="saveKey();">Save key</button> <button class="button is-light" onclick="loadKey();">Load key</button>
</div>
<div class="control">
<button id="save_key" class="button is-light" onclick="saveKey();" disabled>Save key</button>
</div> </div>
</div> </div>
</div> </div>
@@ -190,7 +190,7 @@
<div class="field"> <div class="field">
<label class="label">Domain name</label> <label class="label">Domain name</label>
<div class="control"> <div class="control">
<input class="input" type="text" placeholder="example.ygg" id="new_domain" oninput="onDomainChange(this)"> <input class="input" type="text" placeholder="example.ygg" id="new_domain" oninput="onDomainChange(this)" disabled>
</div> </div>
</div> </div>
</div> </div>
@@ -198,7 +198,7 @@
<div class="field"> <div class="field">
<label class="label">Domain tags (will be used for search)</label> <label class="label">Domain tags (will be used for search)</label>
<div class="control"> <div class="control">
<input class="input" type="text" placeholder="blog, community, friendship" id="new_domain_tags"> <input class="input" type="text" placeholder="blog, community, friendship" id="new_domain_tags" disabled>
</div> </div>
</div> </div>
</div> </div>
@@ -210,10 +210,10 @@
<div class="field is-grouped"> <div class="field is-grouped">
<div class="control"> <div class="control">
<button class="button is-success" id="add_record_button" onclick="showNewRecordDialog();">Add record</button> <button id="new_domain_button" class="button is-warning" onclick="createDomain();" disabled>Mine domain</button>
</div> </div>
<div class="control"> <div class="control">
<button class="button is-link" id="new_domain_button" onclick="createDomain();" disabled>Mine domain</button> <button id="add_record_button" class="button is-light" onclick="showNewRecordDialog();" disabled>Add record</button>
</div> </div>
</div> </div>
</div> </div>
@@ -225,7 +225,7 @@
<div class="field"> <div class="field">
<label class="label">Zone name</label> <label class="label">Zone name</label>
<div class="control"> <div class="control">
<input class="input" type="text" placeholder="ygg" id="new_zone" oninput="onZoneChange()"> <input class="input" type="text" placeholder="ygg" id="new_zone" oninput="onZoneChange()" disabled>
</div> </div>
</div> </div>
</div> </div>
@@ -233,7 +233,7 @@
<div class="field"> <div class="field">
<label class="label">Difficulty (for all domains in zone)</label> <label class="label">Difficulty (for all domains in zone)</label>
<div class="control"> <div class="control">
<input class="input" type="number" placeholder="20" id="new_zone_difficulty" oninput="onZoneChange()"> <input class="input" type="number" placeholder="20" id="new_zone_difficulty" oninput="onZoneChange()" disabled>
</div> </div>
</div> </div>
</div> </div>
@@ -241,7 +241,7 @@
<div class="field is-grouped"> <div class="field is-grouped">
<div class="control"> <div class="control">
<button class="button is-link" id="new_zone_button" onclick="createZone();" disabled>Mine zone</button> <button class="button is-warning" id="new_zone_button" onclick="createZone();" disabled>Mine zone</button>
</div> </div>
</div> </div>
</div> </div>
+14
View File
@@ -189,12 +189,15 @@ function onDomainChange(element) {
function domainAvailable(available) { function domainAvailable(available) {
input = document.getElementById("new_domain"); input = document.getElementById("new_domain");
button = document.getElementById("new_domain_button"); button = document.getElementById("new_domain_button");
button2 = document.getElementById("add_record_button");
if (available) { if (available) {
input.className = "input"; input.className = "input";
button.disabled = false button.disabled = false
button2.disabled = false
} else { } else {
input.className = "input is-danger"; input.className = "input is-danger";
button.disabled = true button.disabled = true
button2.disabled = true
} }
} }
@@ -309,4 +312,15 @@ function keystoreChanged(path, pub_key, hash) {
key_public_key.innerHTML = pub_key; key_public_key.innerHTML = pub_key;
var key_public_hash = document.getElementById("key_public_hash"); var key_public_hash = document.getElementById("key_public_hash");
key_public_hash.innerHTML = hash; key_public_hash.innerHTML = hash;
var save_key = document.getElementById("save_key");
save_key.disabled = false;
var new_domain = document.getElementById("new_domain");
new_domain.disabled = false;
var new_domain_tags = document.getElementById("new_domain_tags");
new_domain_tags.disabled = false;
var new_zone = document.getElementById("new_zone");
new_zone.disabled = false;
var new_zone_difficulty = document.getElementById("new_zone_difficulty");
new_zone_difficulty.disabled = false;
} }