// Copyright 2017 The Grin Developers // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Plugin wrapper for cuckoo miner, implementing common traits //! with the existing embedded miner. This is all included conditionally //! for compatibility reasons with those who aren't interested in playing //! with cuckoo-miner at present use std::env; use cuckoo; use cuckoo::Error; use MiningWorker; use core::global; use core::core::Proof; use types::MinerConfig; use std::sync::{Mutex}; use cuckoo_miner::{ CuckooMiner, CuckooPluginManager, CuckooMinerConfig, CuckooMinerSolution}; //For now, we're just going to keep a static reference around to the loaded config //And not allow querying the plugin directory twice once a plugin has been selected //This is to keep compatibility with multi-threaded testing, so that spawned //testing threads don't try to load/unload the library while another thread is //using it. lazy_static!{ static ref LOADED_CONFIG: Mutex> = Mutex::new(None); } /// plugin miner pub struct PluginMiner { /// the miner pub miner:Option, last_solution: CuckooMinerSolution, config: CuckooMinerConfig, } impl Default for PluginMiner { fn default() -> PluginMiner { PluginMiner { miner: None, config: CuckooMinerConfig::new(), last_solution: CuckooMinerSolution::new(), } } } impl PluginMiner { /// Init the plugin miner pub fn init(&mut self, miner_config: MinerConfig){ //Get directory of executable let mut exe_path=env::current_exe().unwrap(); exe_path.pop(); let exe_path=exe_path.to_str().unwrap(); //println!("Plugin dir: {}", miner_config.clone().cuckoo_miner_plugin_dir.unwrap()); let plugin_install_path = match miner_config.cuckoo_miner_plugin_dir { Some(s) => s, None => String::from(format!("{}/plugins", exe_path)) }; let plugin_impl_filter = match miner_config.cuckoo_miner_plugin_type { Some(s) => s, None => String::from("simple") }; //First, load and query the plugins in the given directory //These should all be stored in 'plugins' at the moment relative //to the executable path, though they should appear somewhere else //when packaging is more//thought out let mut loaded_config_ref = LOADED_CONFIG.lock().unwrap(); //Load from here instead if let Some(ref c) = *loaded_config_ref { debug!("Not re-loading plugin or directory."); //this will load the associated plugin let result=CuckooMiner::new(c.clone()); self.miner=Some(result.unwrap()); return; } let mut plugin_manager = CuckooPluginManager::new().unwrap(); let result=plugin_manager.load_plugin_dir(plugin_install_path); if let Err(_) = result { error!("Unable to load cuckoo-miner plugin directory, either from configuration or [exe_path]/plugins."); panic!("Unable to load plugin directory... Please check configuration values"); } let sz = global::sizeshift(); //So this is built dynamically based on the plugin implementation //type and the consensus sizeshift let filter = format!("{}_{}", plugin_impl_filter, sz); let caps = plugin_manager.get_available_plugins(&filter).unwrap(); //insert it into the miner configuration being created below let mut config = CuckooMinerConfig::new(); info!("Mining using plugin: {}", caps[0].full_path.clone()); config.plugin_full_path = caps[0].full_path.clone(); if let Some(l) = miner_config.cuckoo_miner_parameter_list { config.parameter_list = l.clone(); } //Store this config now, because we just want one instance //of the plugin lib per invocation now *loaded_config_ref=Some(config.clone()); //this will load the associated plugin let result=CuckooMiner::new(config.clone()); if let Err(e) = result { error!("Error initializing mining plugin: {:?}", e); error!("Accepted values are: {:?}", caps[0].parameters); panic!("Unable to init mining plugin."); } self.config=config.clone(); self.miner=Some(result.unwrap()); } /// Get the miner pub fn get_consumable(&mut self)->CuckooMiner{ //this will load the associated plugin let result=CuckooMiner::new(self.config.clone()); if let Err(e) = result { error!("Error initializing mining plugin: {:?}", e); panic!("Unable to init mining plugin."); } result.unwrap() } } impl MiningWorker for PluginMiner { /// This will initialise a plugin according to what's currently /// included in CONSENSUS::TEST_SIZESHIFT, just using the edgetrim /// version of the miner for now, though this should become /// configurable somehow fn new(_ease: u32, _sizeshift: u32, _proof_size: usize) -> Self { PluginMiner::default() } /// And simply calls the mine function of the loaded plugin /// returning whether a solution was found and the solution itself fn mine(&mut self, header: &[u8]) -> Result { let result = self.miner.as_mut().unwrap().mine(&header, &mut self.last_solution).unwrap(); if result == true { return Ok(Proof::new(self.last_solution.solution_nonces.to_vec())); } Err(Error::NoSolution) } }