diff --git a/.gitignore b/.gitignore index 8c8bf6105435293d0922b5799496d52498c19169..9a6d17c53aae3a67b43470a53bc3f56dee1bcac6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ test.bin +test2.bin native/target native/index.node native/artifacts.json diff --git a/lib/index.js b/lib/index.js index 3ca5b135db6d1d3c3ac9804619276b3d3d089642..8a5c9696dc68f126423ef120d85ea6f36f564ef3 100644 --- a/lib/index.js +++ b/lib/index.js @@ -7,36 +7,66 @@ const binding = require(binding_path); module.exports = { newFileInstance: (filePath, sigStock) => { - const instance = Object.create(WotB) + const instance = Object.create(UnsafeWoTB) if (process.platform == 'win32') { let bufferedPath = new Buffer(filePath,'ascii'); - instance.init(binding.new_file_instance_win_32(bufferedPath, bufferedPath.length, sigStock)) + instance.init(binding.new_unsafe_file_instance(bufferedPath, bufferedPath.length, sigStock)) } else { - instance.init(binding.new_file_instance(filePath, sigStock)); + instance.init(binding.new_unsafe_file_instance(filePath, sigStock)); } instance.setFilePath(filePath) return instance }, newEmptyFileInstance: (filePath, sigStock) => { - const instance = Object.create(WotB) - const id = binding.new_memory_instance(sigStock); + const instance = Object.create(UnsafeWoTB) + const id = binding.new_unsafe_memory_instance(sigStock); instance.init(id) instance.setFilePath(filePath) return instance }, newMemoryInstance: (sigStock) => { - const instance = Object.create(WotB) - const id = binding.new_memory_instance(sigStock); + const instance = Object.create(UnsafeWoTB) + const id = binding.new_unsafe_memory_instance(sigStock); instance.init(id) return instance }, - + newSafeFileInstance: (filePath, sigStock) => { + var instance = Object.create(SafeWoTB) + instance.setFilePath(filePath) + instance.setMaxCert(sigStock) + let instance_content = binding.new_safe_file_instance(filePath, sigStock); + instance.nodes = instance_content.nodes; + instance.issued_count = instance_content.issued_count; + instance.sources = instance_content.sources; + return instance + }, + + newEmptySafeFileInstance: (filePath, sigStock) => { + var instance = Object.create(SafeWoTB) + instance.setFilePath(filePath) + instance.setMaxCert(sigStock) + let instance_content = binding.new_safe_empty_instance(); + instance.nodes = instance_content.nodes; + instance.issued_count = instance_content.issued_count; + instance.sources = instance_content.sources; + return instance + }, + + newSafeMemoryInstance: (sigStock) => { + var instance = Object.create(SafeWoTB) + instance.setFilePath("") + instance.setMaxCert(sigStock) + instance.nodes = new Array() + instance.issued_count = new Array() + instance.sources = new Array() + return instance + }, }; -const WotB = { +const UnsafeWoTB = { instanceID: -1, filePath: "", @@ -54,98 +84,78 @@ const WotB = { }, write: function() { - return binding.write_instance_in_file(this.instanceID, this.filePath); + return binding.write_unsafe_instance_in_file(this.instanceID, this.filePath); }, memCopy: function() { - const copy = Object.create(WotB) - copy.instanceID = binding.mem_copy(this.instanceID); + const copy = Object.create(UnsafeWoTB) + copy.instanceID = binding.unsafe_mem_copy(this.instanceID); return copy; }, getMaxCert: function() { - return binding.get_max_links(this.instanceID); + return binding.unsafe_get_max_links(this.instanceID); }, getWoTSize: function() { - return binding.get_wot_size(this.instanceID); + return binding.unsafe_get_wot_size(this.instanceID); }, isEnabled: function(nodeId) { - return binding.is_enabled(this.instanceID, nodeId); + return binding.unsafe_is_enabled(this.instanceID, nodeId); }, getEnabled: function() { - return binding.get_enabled(this.instanceID); + return binding.unsafe_get_enabled(this.instanceID); }, getDisabled: function() { - return binding.get_disabled(this.instanceID); + return binding.unsafe_get_disabled(this.instanceID); }, getSentries: function(sentry_requirement) { - return binding.get_sentries(this.instanceID, sentry_requirement); + return binding.unsafe_get_sentries(this.instanceID, sentry_requirement); }, getNonSentries: function(sentry_requirement) { - return binding.get_non_sentries(this.instanceID, sentry_requirement); + return binding.unsafe_get_non_sentries(this.instanceID, sentry_requirement); }, existsLink: function(source, target) { - return binding.exist_link(this.instanceID, source, target); + return binding.unsafe_exist_link(this.instanceID, source, target); }, setMaxCert: function(maxCert) { - return binding.set_max_links(this.instanceID, maxCert); + return binding.unsafe_set_max_links(this.instanceID, maxCert); }, addNode: function() { - var result = binding.add_node(this.instanceID); - if (this.filePath.length > 0) { - this.write(); - } - return result; + return binding.unsafe_add_node(this.instanceID); }, removeNode: function() { - var result = binding.rem_node(this.instanceID); - if (this.filePath.length > 0) { - this.write(); - } - return result; + return binding.unsafe_rem_node(this.instanceID); }, setEnabled: function(is_enabled, nodeId) { - var result = binding.set_enabled(this.instanceID, is_enabled, nodeId); - if (this.filePath.length > 0) { - this.write(); - } - return result; + return binding.unsafe_set_enabled(this.instanceID, is_enabled, nodeId); }, addLink: function(source, target) { - var result = binding.add_link(this.instanceID, source, target); - if (this.filePath.length > 0) { - this.write(); - } - return result; + return binding.unsafe_add_link(this.instanceID, source, target); }, removeLink: function(source, target) { - var result = binding.rem_link(this.instanceID, source, target); - if (this.filePath.length > 0) { - this.write(); - } - return result; + return binding.unsafe_rem_link(this.instanceID, source, target); }, isOutdistanced: function(node, sentry_requirement, step_max, x_percent) { - var distance_result = binding.compute_distance(this.instanceID, node, sentry_requirement, step_max, x_percent); + var distance_result = binding.unsafe_compute_distance(this.instanceID, node, sentry_requirement, step_max, x_percent); return distance_result.outdistanced; }, detailedDistance: function(node, sentry_requirement, step_max, x_percent) { - var distance_result = binding.compute_distance(this.instanceID, node, sentry_requirement, step_max, x_percent); + var distance_result = binding.unsafe_compute_distance(this.instanceID, node, sentry_requirement, step_max, x_percent); return { nbReached: distance_result.reached, nbSuccess: distance_result.success, @@ -155,23 +165,193 @@ const WotB = { }, detailedDistanceV2: function(node, sentry_requirement, step_max, x_percent) { - return binding.compute_distance(this.instanceID, node, sentry_requirement, step_max, x_percent); + return binding.unsafe_compute_distance(this.instanceID, node, sentry_requirement, step_max, x_percent); }, getPaths: function(from, to, step_max) { - return binding.find_paths(this.instanceID, from, to, step_max); + return binding.unsafe_find_paths(this.instanceID, from, to, step_max); }, clear: function() { - return binding.remove_wot(this.instanceID); + return binding.unsafe_remove_wot(this.instanceID); }, resetWoT: function() { - var sigStock = binding.getMaxCert(this.instanceID); - binding.remove_wot(this.instanceID); - this.instanceID = binding.new_memory_instance(sigStock); - if (filePath.length > 0) { - this.write(); - } + var sigStock = binding.unsafe_get_max_links(this.instanceID); + binding.unsafe_remove_wot(this.instanceID); + this.instanceID = binding.new_unsafe_memory_instance(sigStock); } -} \ No newline at end of file +} + +const SafeWoTB = { + filePath: "", + maxCerts: 0, + nodes: [], + issued_count: [], + sources: [], + + /** + * Eventually has a file path if it is a file instance. + * @param filePath + */ + setFilePath: function(filePath) { + this.filePath = filePath + }, + + write: function() { + return binding.write_safe_file_instance(this.filePath, this.maxCerts, this.nodes, this.sources); + }, + + unsafeMemCopy: function() { + const unsafe_copy = Object.create(UnsafeWoTB) + unsafe_copy.instanceID = binding.unsafe_mem_copy_from_safe(this.maxCerts, this.nodes, this.sources); + return unsafe_copy; + }, + + memCopy: function() { + var instance = Object.create(SafeWoTB) + instance.setFilePath("") + instance.setMaxCert(this.maxCerts) + let instance_content = binding.safe_mem_copy(this.maxCerts, this.nodes, this.sources); + instance.nodes = instance_content.nodes; + instance.issued_count = instance_content.issued_count; + instance.sources = instance_content.sources; + return instance + }, + + getMaxCert: function() { + return this.maxCerts; + }, + + getWoTSize: function() { + return this.nodes.length; + }, + + isEnabled: function(nodeId) { + return this.nodes[nodeId]; + }, + + getEnabled: function() { + let enabled = new Array(); + let i=0; + this.nodes.forEach(function(node) { + if (node) { + enabled.push(i); + } + i++; + }); + return enabled; + }, + + getDisabled: function() { + let disabled = new Array(); + let i=0; + this.nodes.forEach(function(node) { + if (!node) { + disabled.push(i); + } + i++; + }); + return disabled; + }, + + getSentries: function(sentry_requirement) { + let sentries = new Array(); + let issued_count = this.issued_count; + let sources = this.sources; + let i=0; + this.nodes.forEach(function(enabled) { + if (enabled && sources[i] != undefined && sources[i].length >= sentry_requirement && issued_count[i] >= sentry_requirement) { + sentries.push(i); + } + i++; + }); + return sentries; + }, + + getNonSentries: function(sentry_requirement) { + let nonSentries = new Array(); + let issued_count = this.issued_count; + let sources = this.sources; + let i=0; + this.nodes.forEach(function(enabled) { + if (enabled && (sources[i] == undefined || sources[i].length < sentry_requirement || issued_count[i] < sentry_requirement)) { + nonSentries.push(i); + } + i++; + }); + return nonSentries; + }, + + existsLink: function(source, target) { + return this.sources[target] != undefined && this.sources[target].indexOf(source) >= 0; + }, + + setMaxCert: function(maxCert) { + this.maxCerts = maxCert; + }, + + addNode: function() { + this.nodes.push(true); + let node_id = this.nodes.length - 1; + this.issued_count[node_id] = 0; + return node_id + }, + + removeNode: function() { + this.nodes.pop(); + return this.nodes.length - 1; + }, + + setEnabled: function(is_enabled, nodeId) { + this.nodes[nodeId] = is_enabled; + return is_enabled; + }, + + addLink: function(source, target) { + if (this.sources[target] == undefined) { + this.sources[target] = new Array(); + } + this.sources[target].push(source); + this.issued_count[source]++; + return this.sources[target].length + }, + + removeLink: function(source, target) { + if (this.sources[target] != undefined) { + let index = this.sources[target].indexOf(source); + if (index > -1) { + this.sources[target].splice(index, 1); + } + this.issued_count[source]--; + } + return this.sources[target].length + }, + + isOutdistanced: function(node, sentry_requirement, step_max, x_percent) { + var distance_result = binding.safe_compute_distance(this.maxCerts, this.nodes, this.sources, node, sentry_requirement, step_max, x_percent); + return distance_result.outdistanced; + }, + + detailedDistance: function(node, sentry_requirement, step_max, x_percent) { + var distance_result = binding.safe_compute_distance(this.maxCerts, this.nodes, this.sources, node, sentry_requirement, step_max, x_percent); + return { + nbReached: distance_result.reached, + nbSuccess: distance_result.success, + nbSentries: distance_result.sentries, + isOutdistanced: distance_result.outdistanced + }; + }, + + detailedDistanceV2: function(node, sentry_requirement, step_max, x_percent) { + return binding.safe_compute_distance(this.maxCerts, this.nodes, this.sources, node, sentry_requirement, step_max, x_percent); + }, + + allDetailedDistanceV2: function(sentry_requirement, step_max, x_percent) { + return binding.safe_compute_distance_all_members(this.maxCerts, this.nodes, this.sources, sentry_requirement, step_max, x_percent); + }, + + getPaths: function(from, to, step_max) { + return binding.safe_find_paths(this.maxCerts, this.nodes, this.sources, from, to, step_max); + }, +} diff --git a/native/src/lib.rs b/native/src/lib.rs index c5caa3cc303fb793791aca43aac9de0f30639b6b..80b5f7497a5f21349c66a561c88f715cdbbe3cb1 100644 --- a/native/src/lib.rs +++ b/native/src/lib.rs @@ -2,345 +2,322 @@ extern crate neon; extern crate duniter_wotb; -extern crate num_cpus; +pub mod unsafe_; + +use self::unsafe_::*; use duniter_wotb::data::rusty::RustyWebOfTrust; -use duniter_wotb::data::{HasLinkResult, NewLinkResult, NodeId, RemLinkResult, WebOfTrust}; +use duniter_wotb::data::{NodeId, WebOfTrust}; +use duniter_wotb::operations::centrality::{CentralitiesCalculator, + UlrikBrandesCentralityCalculator}; use duniter_wotb::operations::distance::{DistanceCalculator, RustyDistanceCalculator, WotDistance, WotDistanceParameters}; use duniter_wotb::operations::file::{BinaryFileFormater, FileFormater}; use duniter_wotb::operations::path::{PathFinder, RustyPathFinder}; -use neon::js::{JsArray, JsBoolean, JsInteger, JsNumber, JsObject, JsString, Object}; +use neon::js::{JsArray, JsBoolean, JsInteger, JsNumber, JsObject, JsString, JsValue, Object}; +use neon::scope::Scope; use neon::vm::{Call, JsResult}; -use std::collections::HashMap; use std::ops::{Deref, DerefMut}; -static mut WOT_INSTANCES: Option<HashMap<usize, Box<RustyWebOfTrust>>> = None; +static CENTRALITY_CALCULATOR: UlrikBrandesCentralityCalculator = + UlrikBrandesCentralityCalculator {}; static DISTANCE_CALCULATOR: RustyDistanceCalculator = RustyDistanceCalculator {}; static FILE_FORMATER: BinaryFileFormater = BinaryFileFormater {}; static PATH_FINDER: RustyPathFinder = RustyPathFinder {}; -fn get_wots() -> &'static mut HashMap<usize, Box<RustyWebOfTrust>> { - unsafe { - match WOT_INSTANCES { - Some(ref mut x) => &mut *x, - None => { - WOT_INSTANCES = Some(HashMap::new()); - match WOT_INSTANCES { - Some(ref mut x) => &mut *x, - None => panic!(), - } - } - } - } -} - -fn new_wot(max_links: usize) -> usize { - let wots = get_wots(); - let mut instance_id = 0; - while wots.contains_key(&instance_id) { - instance_id += 1; - } - wots.insert(instance_id, Box::new(RustyWebOfTrust::new(max_links))); - instance_id -} - -fn get_wot<'a>(instance_id: usize) -> &'a RustyWebOfTrust { - let wots = get_wots(); - let wot = wots.get(&instance_id); - match wot { - Some(wot) => wot.deref(), - None => panic!("This instance don't exist !"), - } -} - -fn get_mut_wot<'a>(instance_id: usize) -> &'a mut RustyWebOfTrust { - let wots = get_wots(); - let wot = wots.get_mut(&instance_id); - match wot { - Some(wot) => wot.deref_mut(), - None => panic!("This instance don't exist !"), - } -} - -fn hello(call: Call) -> JsResult<JsString> { +fn safe_mem_copy(call: Call) -> JsResult<JsObject> { let scope = call.scope; - let args = call.arguments; - let mut str_ = String::from("hello node"); - //let x = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); - if let Some(arg) = args.get(scope, 0) { - let x = try!(arg.check::<JsInteger>()).value(); - str_.push_str(&format!(" {}", x)); - } - Ok(JsString::new(scope, &str_).unwrap()) -} - -fn threading_hint(call: Call) -> JsResult<JsNumber> { - Ok(JsNumber::new(call.scope, num_cpus::get() as f64)) -} - -fn new_file_instance(call: Call) -> JsResult<JsInteger> { - let scope = call.scope; - let file_path = try!(try!(call.arguments.require(scope, 0)).check::<JsString>()).value(); - let max_links = try!(try!(call.arguments.require(scope, 1)).check::<JsInteger>()).value(); - let (wot, _blockstamp) = FILE_FORMATER - .from_file(&file_path, max_links as usize) - .unwrap(); - let wots = get_wots(); - let mut instance_id = 0; - while wots.contains_key(&instance_id) { - instance_id += 1; + let max_links = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); + let mut wot = RustyWebOfTrust::new(max_links as usize); + let arg_nodes = call.arguments.require(scope, 1); + let arg_sources = call.arguments.require(scope, 2); + let _bool = try!(fill_rust_wot(scope, arg_nodes, arg_sources, &mut wot)); + let mut js_nodes_array = JsArray::new(scope, wot.size() as u32); + let mut js_sources_array = JsArray::new(scope, wot.size() as u32); + let mut rs_issued_counts = vec![0; wot.size()]; + for i in 0..wot.size() { + let _bool = try!(JsArray::set( + *js_nodes_array.deref_mut(), + i as u32, + JsBoolean::new(scope, wot.is_enabled(NodeId(i as usize)).unwrap()), + )); + let sources = wot.get_links_source(NodeId(i as usize)).unwrap(); + let mut js_sources = JsArray::new(scope, sources.len() as u32); + let mut j: u32 = 0; + for source in sources { + rs_issued_counts[source.0] += 1; + let _bool = try!(JsArray::set( + *js_sources.deref_mut(), + j, + JsInteger::new(scope, source.0 as i32), + )); + j += 1; + } + let _bool = try!(JsArray::set( + *js_sources_array.deref_mut(), + i as u32, + js_sources, + )); } - wots.insert(instance_id, Box::new(wot)); - Ok(JsInteger::new(scope, instance_id as i32)) -} - -fn write_instance_in_file(call: Call) -> JsResult<JsBoolean> { - let scope = call.scope; - let instance_id = - try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value() as usize; - let file_path = try!(try!(call.arguments.require(scope, 1)).check::<JsString>()).value(); - let wot = get_wot(instance_id as usize); - let header: Vec<u8> = Vec::with_capacity(0); - match FILE_FORMATER.to_file(wot, &header, &file_path) { - Ok(_) => Ok(JsBoolean::new(scope, true)), - Err(e) => panic!("Fatal error : fail to write wot in file : {:?}", e), + let mut js_issued_count_array = JsArray::new(scope, wot.size() as u32); + let mut i: u32 = 0; + for issued_count in rs_issued_counts { + let _bool = try!(JsArray::set( + *js_issued_count_array.deref_mut(), + i, + JsInteger::new(scope, issued_count as i32), + )); + i += 1; } + let mut js_wot = JsObject::new(scope); + let _bool = try!(JsObject::set(*js_wot.deref_mut(), "nodes", js_nodes_array,)); + let _bool = try!(JsObject::set(*js_wot.deref_mut(), "issued_count", js_issued_count_array,)); + let _bool = try!(JsObject::set(*js_wot.deref_mut(), "sources", js_sources_array,)); + Ok(js_wot) } -fn new_memory_instance(call: Call) -> JsResult<JsInteger> { +fn unsafe_mem_copy_from_safe(call: Call) -> JsResult<JsInteger> { let scope = call.scope; let max_links = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); - let _instance_id = new_wot(max_links as usize); - Ok(JsInteger::new(scope, _instance_id as i32)) -} - -fn mem_copy(call: Call) -> JsResult<JsInteger> { - let scope = call.scope; - let instance_id = - try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value() as usize; - let wots = get_wots(); - let wot_copy = wots.get(&instance_id) - .expect("This instance don't exist !") - .deref() - .clone(); + let mut wot = RustyWebOfTrust::new(max_links as usize); + let arg_nodes = call.arguments.require(scope, 1); + let arg_sources = call.arguments.require(scope, 2); + let _bool = try!(fill_rust_wot(scope, arg_nodes, arg_sources, &mut wot)); + let wots = unsafe_::get_wots(); let mut new_instance_id = 0; while wots.contains_key(&new_instance_id) { new_instance_id += 1; } - wots.insert(new_instance_id, Box::new(wot_copy)); + wots.insert(new_instance_id, Box::new(wot)); Ok(JsInteger::new(scope, new_instance_id as i32)) } -fn get_max_links(call: Call) -> JsResult<JsInteger> { - let scope = call.scope; - let instance_id = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); - let mut _max_links = 0; - _max_links = get_wot(instance_id as usize).get_max_link(); - Ok(JsInteger::new(scope, _max_links as i32)) -} - -fn get_wot_size(call: Call) -> JsResult<JsInteger> { - let scope = call.scope; - let instance_id = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); - let mut _size = 0; - _size = get_wot(instance_id as usize).size(); - Ok(JsInteger::new(scope, _size as i32)) -} - -fn is_enabled(call: Call) -> JsResult<JsBoolean> { +fn new_safe_file_instance(call: Call) -> JsResult<JsObject> { let scope = call.scope; - let instance_id = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); - let node_id = try!(try!(call.arguments.require(scope, 1)).check::<JsInteger>()).value(); - if get_wot(instance_id as usize) - .is_enabled(NodeId(node_id as usize)) - .unwrap() - { - Ok(JsBoolean::new(scope, true)) - } else { - Ok(JsBoolean::new(scope, false)) - } -} - -fn get_enabled(call: Call) -> JsResult<JsArray> { - let scope = call.scope; - let instance_id = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); - let enabled = get_mut_wot(instance_id as usize).get_enabled(); - let mut js_array = JsArray::new(scope, enabled.len() as u32); - let mut index: u32 = 0; - for node_id in enabled { + let file_path = try!(try!(call.arguments.require(scope, 0)).check::<JsString>()).value(); + let max_links = try!(try!(call.arguments.require(scope, 1)).check::<JsInteger>()).value(); + let (wot, _blockstamp): (RustyWebOfTrust, Vec<u8>) = FILE_FORMATER + .from_file(&file_path, max_links as usize) + .unwrap(); + let mut js_nodes_array = JsArray::new(scope, wot.size() as u32); + let mut js_sources_array = JsArray::new(scope, wot.size() as u32); + let mut rs_issued_counts = vec![0; wot.size()]; + for i in 0..wot.size() { let _bool = try!(JsArray::set( - *js_array.deref_mut(), - index, - JsInteger::new(scope, node_id.0 as i32), + *js_nodes_array.deref_mut(), + i as u32, + JsBoolean::new(scope, wot.is_enabled(NodeId(i as usize)).unwrap()), )); - index += 1; - } - Ok(js_array) -} - -fn get_disabled(call: Call) -> JsResult<JsArray> { - let scope = call.scope; - let instance_id = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); - let disabled = get_mut_wot(instance_id as usize).get_disabled(); - let js_array = JsArray::new(scope, disabled.len() as u32); - let mut index: u32 = 0; - for node_id in disabled { + let sources = wot.get_links_source(NodeId(i as usize)).unwrap(); + let mut js_sources = JsArray::new(scope, sources.len() as u32); + let mut j: u32 = 0; + for source in sources { + rs_issued_counts[source.0] += 1; + let _bool = try!(JsArray::set( + *js_sources.deref_mut(), + j, + JsInteger::new(scope, source.0 as i32), + )); + j += 1; + } let _bool = try!(JsArray::set( - *js_array.deref(), - index, - JsInteger::new(scope, node_id.0 as i32), + *js_sources_array.deref_mut(), + i as u32, + js_sources, )); - index += 1; } - Ok(js_array) -} - -fn get_sentries(call: Call) -> JsResult<JsArray> { - let scope = call.scope; - let instance_id = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); - let sentry_requirement = - try!(try!(call.arguments.require(scope, 1)).check::<JsInteger>()).value(); - let sentries = get_mut_wot(instance_id as usize).get_sentries(sentry_requirement as usize); - let js_array = JsArray::new(scope, sentries.len() as u32); - let mut index: u32 = 0; - for node_id in sentries { + let mut js_issued_count_array = JsArray::new(scope, wot.size() as u32); + let mut i: u32 = 0; + for issued_count in rs_issued_counts { let _bool = try!(JsArray::set( - *js_array.deref(), - index, - JsInteger::new(scope, node_id.0 as i32), + *js_issued_count_array.deref_mut(), + i, + JsInteger::new(scope, issued_count as i32), )); - index += 1; + i += 1; } - Ok(js_array) + let mut js_wot = JsObject::new(scope); + let _bool = try!(JsObject::set(*js_wot.deref_mut(), "nodes", js_nodes_array,)); + let _bool = try!(JsObject::set(*js_wot.deref_mut(), "issued_count", js_issued_count_array,)); + let _bool = try!(JsObject::set(*js_wot.deref_mut(), "sources", js_sources_array,)); + Ok(js_wot) } -fn get_non_sentries(call: Call) -> JsResult<JsArray> { +fn new_safe_empty_instance(call: Call) -> JsResult<JsObject> { let scope = call.scope; - let instance_id = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); - let sentry_requirement = - try!(try!(call.arguments.require(scope, 1)).check::<JsInteger>()).value(); - let non_sentries = - get_mut_wot(instance_id as usize).get_non_sentries(sentry_requirement as usize); - let js_array = JsArray::new(scope, non_sentries.len() as u32); - let mut index: u32 = 0; - for node_id in non_sentries { - let _bool = try!(JsArray::set( - *js_array.deref(), - index, - JsInteger::new(scope, node_id.0 as i32), - )); - index += 1; - } - Ok(js_array) + let mut js_wot = JsObject::new(scope); + let js_nodes_array = JsArray::new(scope, 0 as u32); + let js_issued_count_array = JsArray::new(scope, 0 as u32); + let js_sources_array = JsArray::new(scope, 0 as u32); + let _bool = try!(JsObject::set(*js_wot.deref_mut(), "nodes", js_nodes_array,)); + let _bool = try!(JsObject::set(*js_wot.deref_mut(), "issued_count", js_issued_count_array,)); + let _bool = try!(JsObject::set(*js_wot.deref_mut(), "sources", js_sources_array,)); + Ok(js_wot) } -fn exist_link(call: Call) -> JsResult<JsBoolean> { - let scope = call.scope; - let instance_id = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); - let source = try!(try!(call.arguments.require(scope, 1)).check::<JsInteger>()).value(); - let target = try!(try!(call.arguments.require(scope, 2)).check::<JsInteger>()).value(); - let result = - get_wot(instance_id as usize).has_link(NodeId(source as usize), NodeId(target as usize)); - if let HasLinkResult::Link(has_link) = result { - Ok(JsBoolean::new(scope, has_link)) - } else { - panic!("Fatal Error : {:?}", result) +fn fill_rust_wot<'a, 'b, S: Scope<'a>>( + scope: &mut S, + arg_nodes: JsResult<'b, JsValue>, + arg_sources: JsResult<'b, JsValue>, + wot: &mut RustyWebOfTrust, +) -> JsResult<'a, JsBoolean> { + let js_nodes_array = try!(try!(arg_nodes).check::<JsArray>()); + let js_sources_array = try!(try!(arg_sources).check::<JsArray>()); + let js_nodes_array = try!(js_nodes_array.to_vec(scope)); + let mut i = 0; + for js_node in js_nodes_array { + wot.add_node(); + if !try!(js_node.check::<JsBoolean>()).value() { + wot.set_enabled(NodeId(i), false); + } + i += 1; + } + let js_sources_array = try!(js_sources_array.to_vec(scope)); + let mut i = 0; + for js_sources in js_sources_array { + let js_sources = try!(try!(js_sources.check::<JsArray>()).to_vec(scope)); + for js_source in js_sources { + wot.add_link( + NodeId(try!(js_source.check::<JsInteger>()).value() as usize), + NodeId(i), + ); + } + i += 1; } + Ok(JsBoolean::new(scope, true)) } -fn set_max_links(call: Call) -> JsResult<JsBoolean> { +fn write_safe_file_instance(call: Call) -> JsResult<JsBoolean> { let scope = call.scope; - let instance_id = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); + let file_path = try!(try!(call.arguments.require(scope, 0)).check::<JsString>()).value(); let max_links = try!(try!(call.arguments.require(scope, 1)).check::<JsInteger>()).value(); - let _result = get_mut_wot(instance_id as usize).set_max_link(max_links as usize); - Ok(JsBoolean::new(scope, true)) -} + let mut wot = RustyWebOfTrust::new(max_links as usize); + let arg_nodes = call.arguments.require(scope, 2); + let arg_sources = call.arguments.require(scope, 3); + let _bool = try!(fill_rust_wot(scope, arg_nodes, arg_sources, &mut wot,)); -fn add_node(call: Call) -> JsResult<JsInteger> { - let scope = call.scope; - let instance_id = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); - let _node_id = get_mut_wot(instance_id as usize).add_node(); - Ok(JsInteger::new(scope, _node_id.0 as i32)) + let mut js_object = JsObject::new(scope); + let header: Vec<u8> = Vec::with_capacity(0); + match FILE_FORMATER.to_file(&wot, &header, &file_path) { + Ok(_) => { + try!(JsObject::set( + *js_object.deref_mut(), + "res", + JsBoolean::new(scope, true), + )); + } + Err(e) => { + panic!("Fatal error : fail to write wot in file : {:?}", e); + } + }; + Ok(JsBoolean::new(scope, true)) } -fn rem_node(call: Call) -> JsResult<JsInteger> { +fn safe_compute_distance(call: Call) -> JsResult<JsObject> { let scope = call.scope; - let instance_id = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); - if let Some(node_id) = get_mut_wot(instance_id as usize).rem_node() { - Ok(JsInteger::new(scope, node_id.0 as i32)) - } else { - panic!("Fatal error : wotb : you try to remove a node to empty wot !") - } + let max_links = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); + let arg_nodes = call.arguments.require(scope, 1); + let arg_sources = call.arguments.require(scope, 2); + let mut wot = RustyWebOfTrust::new(max_links as usize); + let _bool = try!(fill_rust_wot(scope, arg_nodes, arg_sources, &mut wot)); + let node_id = try!(try!(call.arguments.require(scope, 3)).check::<JsInteger>()).value(); + let sentry_requirement = + try!(try!(call.arguments.require(scope, 4)).check::<JsInteger>()).value() as u32; + let step_max = try!(try!(call.arguments.require(scope, 5)).check::<JsInteger>()).value() as u32; + let x_percent = try!(try!(call.arguments.require(scope, 6)).check::<JsNumber>()).value() as f64; + let distance_params = WotDistanceParameters { + node: NodeId(node_id as usize), + sentry_requirement, + step_max, + x_percent, + }; + Ok(try!(build_distance_response( + scope, + &DISTANCE_CALCULATOR + .compute_distance(&wot, distance_params) + .unwrap(), + ))) } -fn set_enabled(call: Call) -> JsResult<JsBoolean> { +fn safe_compute_distance_all_members(call: Call) -> JsResult<JsArray> { let scope = call.scope; - let instance_id = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); - let is_enabled = try!(try!(call.arguments.require(scope, 1)).check::<JsBoolean>()).value(); - let node_id = try!(try!(call.arguments.require(scope, 2)).check::<JsInteger>()).value(); - if let Some(enabled) = - get_mut_wot(instance_id as usize).set_enabled(NodeId(node_id as usize), is_enabled) - { - Ok(JsBoolean::new(scope, enabled)) - } else { - panic!("Fatal error : wotb : node id don't exist !") + let max_links = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); + let arg_nodes = call.arguments.require(scope, 1); + let arg_sources = call.arguments.require(scope, 2); + let mut wot = RustyWebOfTrust::new(max_links as usize); + let _bool = try!(fill_rust_wot(scope, arg_nodes, arg_sources, &mut wot)); + let sentry_requirement = + try!(try!(call.arguments.require(scope, 3)).check::<JsInteger>()).value() as u32; + let step_max = try!(try!(call.arguments.require(scope, 4)).check::<JsInteger>()).value() as u32; + let x_percent = try!(try!(call.arguments.require(scope, 5)).check::<JsNumber>()).value() as f64; + let enabled_nodes = wot.get_enabled(); + let mut js_array = JsArray::new(scope, enabled_nodes.len() as u32); + let mut i: u32 = 0; + for node in enabled_nodes { + let distance_params = WotDistanceParameters { + node, + sentry_requirement, + step_max, + x_percent, + }; + try!(JsArray::set( + *js_array.deref_mut(), + i, + try!(build_distance_response( + scope, + &DISTANCE_CALCULATOR + .compute_distance(&wot, distance_params) + .unwrap(), + )) + )); + i += 1; } + Ok(js_array) } -fn add_link(call: Call) -> JsResult<JsInteger> { +fn safe_find_paths(call: Call) -> JsResult<JsArray> { let scope = call.scope; - let instance_id = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); - let source = try!(try!(call.arguments.require(scope, 1)).check::<JsInteger>()).value(); - let target = try!(try!(call.arguments.require(scope, 2)).check::<JsInteger>()).value(); - let result = get_mut_wot(instance_id as usize) - .add_link(NodeId(source as usize), NodeId(target as usize)); - if let NewLinkResult::Ok(links_count) = result { - Ok(JsInteger::new(scope, links_count as i32)) - } else { - panic!("Fatal error wotb : {:?}", result) - } + let max_links = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); + let arg_nodes = call.arguments.require(scope, 1); + let arg_sources = call.arguments.require(scope, 2); + let mut wot = RustyWebOfTrust::new(max_links as usize); + let _bool = try!(fill_rust_wot(scope, arg_nodes, arg_sources, &mut wot)); + let from = try!(try!(call.arguments.require(scope, 3)).check::<JsInteger>()).value() as usize; + let to = try!(try!(call.arguments.require(scope, 4)).check::<JsInteger>()).value() as usize; + let step_max = try!(try!(call.arguments.require(scope, 5)).check::<JsInteger>()).value() as u32; + Ok(try!(build_paths_response( + scope, + &PATH_FINDER.find_paths(&wot, NodeId(from), NodeId(to), step_max), + ))) } -fn rem_link(call: Call) -> JsResult<JsInteger> { +fn safe_compute_centralities(call: Call) -> JsResult<JsArray> { let scope = call.scope; - let instance_id = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); - let source = try!(try!(call.arguments.require(scope, 1)).check::<JsInteger>()).value(); - let target = try!(try!(call.arguments.require(scope, 2)).check::<JsInteger>()).value(); - let result = get_mut_wot(instance_id as usize) - .rem_link(NodeId(source as usize), NodeId(target as usize)); - if let RemLinkResult::Removed(links_count) = result { - Ok(JsInteger::new(scope, links_count as i32)) - } else { - panic!("Fatal Error : {:?}", result) - } + let max_links = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); + let arg_nodes = call.arguments.require(scope, 1); + let arg_sources = call.arguments.require(scope, 2); + let mut wot = RustyWebOfTrust::new(max_links as usize); + let _bool = try!(fill_rust_wot(scope, arg_nodes, arg_sources, &mut wot)); + let _step_max = + try!(try!(call.arguments.require(scope, 3)).check::<JsInteger>()).value() as u32; + Ok(try!(build_centralities_response( + scope, + &CENTRALITY_CALCULATOR.stress_centralities(&wot), + ))) } -fn compute_distance(call: Call) -> JsResult<JsObject> { - let scope = call.scope; - let instance_id = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); - let node_id = try!(try!(call.arguments.require(scope, 1)).check::<JsInteger>()).value(); - let sentry_requirement = - try!(try!(call.arguments.require(scope, 2)).check::<JsInteger>()).value() as u32; - let step_max = try!(try!(call.arguments.require(scope, 3)).check::<JsInteger>()).value() as u32; - let x_percent = try!(try!(call.arguments.require(scope, 4)).check::<JsNumber>()).value() as f64; - let distance_params = WotDistanceParameters { - node: NodeId(node_id as usize), - sentry_requirement, - step_max, - x_percent, - }; - let wot = get_wot(instance_id as usize); - let WotDistance { +fn build_distance_response<'a, S: Scope<'a>>( + scope: &mut S, + wot_distance: &WotDistance, +) -> JsResult<'a, JsObject> { + let &WotDistance { sentries, success, success_at_border, reached, reached_at_border, outdistanced, - } = DISTANCE_CALCULATOR - .compute_distance(wot, distance_params) - .unwrap(); + } = wot_distance; let js_object = JsObject::new(scope); let _bool = try!(JsObject::set( *js_object.deref(), @@ -375,15 +352,10 @@ fn compute_distance(call: Call) -> JsResult<JsObject> { Ok(js_object) } -fn find_paths(call: Call) -> JsResult<JsArray> { - let scope = call.scope; - let instance_id = - try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value() as usize; - let from = try!(try!(call.arguments.require(scope, 1)).check::<JsInteger>()).value() as u32; - let to = try!(try!(call.arguments.require(scope, 2)).check::<JsInteger>()).value() as u32; - let step_max = try!(try!(call.arguments.require(scope, 3)).check::<JsInteger>()).value() as u32; - let wot = get_wot(instance_id as usize); - let paths = PATH_FINDER.find_paths(wot, NodeId(from as usize), NodeId(to as usize), step_max); +fn build_paths_response<'a, S: Scope<'a>>( + scope: &mut S, + paths: &Vec<Vec<NodeId>>, +) -> JsResult<'a, JsArray> { let mut i: u32 = 0; let js_paths = JsArray::new(scope, paths.len() as u32); for path in paths { @@ -403,42 +375,59 @@ fn find_paths(call: Call) -> JsResult<JsArray> { Ok(js_paths) } -fn remove_wot(call: Call) -> JsResult<JsBoolean> { - let scope = call.scope; - let instance_id = - try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value() as usize; - let wots = get_wots(); - if wots.len() > instance_id { - wots.remove(&instance_id).unwrap(); - Ok(JsBoolean::new(scope, true)) - } else { - Ok(JsBoolean::new(scope, false)) +fn build_centralities_response<'a, S: Scope<'a>>( + scope: &mut S, + centralities: &Vec<u64>, +) -> JsResult<'a, JsArray> { + let mut i: u32 = 0; + let js_centralities = JsArray::new(scope, centralities.len() as u32); + for centrality in centralities { + let _bool = try!(JsArray::set( + *js_centralities.deref(), + i, + JsInteger::new(scope, *centrality as i32), + )); + i += 1; } + Ok(js_centralities) } register_module!(m, { - m.export("hello", hello)?; - m.export("threadingHint", threading_hint)?; - m.export("new_file_instance", new_file_instance)?; - m.export("write_instance_in_file", write_instance_in_file)?; - m.export("new_memory_instance", new_memory_instance)?; - m.export("mem_copy", mem_copy)?; - m.export("get_max_links", get_max_links)?; - m.export("get_wot_size", get_wot_size)?; - m.export("is_enabled", is_enabled)?; - m.export("get_enabled", get_enabled)?; - m.export("get_disabled", get_disabled)?; - m.export("get_sentries", get_sentries)?; - m.export("get_non_sentries", get_non_sentries)?; - m.export("exist_link", exist_link)?; - m.export("set_max_links", set_max_links)?; - m.export("add_node", add_node)?; - m.export("rem_node", rem_node)?; - m.export("set_enabled", set_enabled)?; - m.export("add_link", add_link)?; - m.export("rem_link", rem_link)?; - m.export("compute_distance", compute_distance)?; - m.export("find_paths", find_paths)?; - m.export("remove_wot", remove_wot)?; + m.export("safe_mem_copy", safe_mem_copy)?; + m.export("unsafe_mem_copy_from_safe", unsafe_mem_copy_from_safe)?; + m.export("new_safe_file_instance", new_safe_file_instance)?; + m.export("new_safe_empty_instance", new_safe_empty_instance)?; + m.export("write_safe_file_instance", write_safe_file_instance)?; + m.export("safe_compute_distance", safe_compute_distance)?; + m.export( + "safe_compute_distance_all_members", + safe_compute_distance_all_members, + )?; + m.export("safe_find_paths", safe_find_paths)?; + m.export("safe_compute_centralities", safe_compute_centralities)?; + m.export("new_unsafe_file_instance", new_unsafe_file_instance)?; + m.export( + "write_unsafe_instance_in_file", + write_unsafe_instance_in_file, + )?; + m.export("new_unsafe_memory_instance", new_unsafe_memory_instance)?; + m.export("unsafe_mem_copy", unsafe_mem_copy)?; + m.export("unsafe_get_max_links", unsafe_get_max_links)?; + m.export("unsafe_get_wot_size", unsafe_get_wot_size)?; + m.export("unsafe_is_enabled", unsafe_is_enabled)?; + m.export("unsafe_get_enabled", unsafe_get_enabled)?; + m.export("unsafe_get_disabled", unsafe_get_disabled)?; + m.export("unsafe_get_sentries", unsafe_get_sentries)?; + m.export("unsafe_get_non_sentries", unsafe_get_non_sentries)?; + m.export("unsafe_exist_link", unsafe_exist_link)?; + m.export("unsafe_set_max_links", unsafe_set_max_links)?; + m.export("unsafe_add_node", unsafe_add_node)?; + m.export("unsafe_rem_node", unsafe_rem_node)?; + m.export("unsafe_set_enabled", unsafe_set_enabled)?; + m.export("unsafe_add_link", unsafe_add_link)?; + m.export("unsafe_rem_link", unsafe_rem_link)?; + m.export("unsafe_compute_distance", unsafe_compute_distance)?; + m.export("unsafe_find_paths", unsafe_find_paths)?; + m.export("unsafe_remove_wot", unsafe_remove_wot)?; Ok(()) }); diff --git a/native/src/unsafe_.rs b/native/src/unsafe_.rs new file mode 100644 index 0000000000000000000000000000000000000000..e396e24fb8fcb98642c79ba6f6c0771f0e54df91 --- /dev/null +++ b/native/src/unsafe_.rs @@ -0,0 +1,363 @@ +extern crate duniter_wotb; +extern crate neon; + +use super::{build_distance_response, build_paths_response, DISTANCE_CALCULATOR, FILE_FORMATER, + PATH_FINDER}; +use duniter_wotb::data::rusty::RustyWebOfTrust; +use duniter_wotb::data::{HasLinkResult, NewLinkResult, NodeId, RemLinkResult, WebOfTrust}; +use duniter_wotb::operations::distance::{DistanceCalculator, WotDistanceParameters}; +use duniter_wotb::operations::file::FileFormater; +use duniter_wotb::operations::path::PathFinder; +use neon::js::{JsArray, JsBoolean, JsInteger, JsNumber, JsObject, JsString, Object}; +use neon::vm::{Call, JsResult}; +use std::collections::HashMap; +use std::ops::{Deref, DerefMut}; + +static mut WOT_INSTANCES: Option<HashMap<usize, Box<RustyWebOfTrust>>> = None; + +pub fn get_wots() -> &'static mut HashMap<usize, Box<RustyWebOfTrust>> { + unsafe { + match WOT_INSTANCES { + Some(ref mut x) => &mut *x, + None => { + WOT_INSTANCES = Some(HashMap::new()); + match WOT_INSTANCES { + Some(ref mut x) => &mut *x, + None => panic!(), + } + } + } + } +} + +fn new_wot(max_links: usize) -> usize { + let wots = get_wots(); + let mut instance_id = 0; + while wots.contains_key(&instance_id) { + instance_id += 1; + } + wots.insert(instance_id, Box::new(RustyWebOfTrust::new(max_links))); + instance_id +} + +fn get_wot<'a>(instance_id: usize) -> &'a RustyWebOfTrust { + let wots = get_wots(); + let wot = wots.get(&instance_id); + match wot { + Some(wot) => wot.deref(), + None => panic!("This instance don't exist !"), + } +} + +fn get_mut_wot<'a>(instance_id: usize) -> &'a mut RustyWebOfTrust { + let wots = get_wots(); + let wot = wots.get_mut(&instance_id); + match wot { + Some(wot) => wot.deref_mut(), + None => panic!("This instance don't exist !"), + } +} + +pub fn new_unsafe_file_instance(call: Call) -> JsResult<JsInteger> { + let scope = call.scope; + let file_path = try!(try!(call.arguments.require(scope, 0)).check::<JsString>()).value(); + let max_links = try!(try!(call.arguments.require(scope, 1)).check::<JsInteger>()).value(); + let (wot, _blockstamp): (RustyWebOfTrust, Vec<u8>) = FILE_FORMATER + .from_file(&file_path, max_links as usize) + .unwrap(); + let wots = get_wots(); + let mut instance_id = 0; + while wots.contains_key(&instance_id) { + instance_id += 1; + } + wots.insert(instance_id, Box::new(wot)); + Ok(JsInteger::new(scope, instance_id as i32)) +} + +pub fn write_unsafe_instance_in_file(call: Call) -> JsResult<JsBoolean> { + let scope = call.scope; + let instance_id = + try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value() as usize; + let file_path = try!(try!(call.arguments.require(scope, 1)).check::<JsString>()).value(); + let wot = get_wot(instance_id as usize); + let header: Vec<u8> = Vec::with_capacity(0); + match FILE_FORMATER.to_file(wot, &header, &file_path) { + Ok(_) => Ok(JsBoolean::new(scope, true)), + Err(e) => panic!("Fatal error : fail to write wot in file : {:?}", e), + } +} + +pub fn new_unsafe_memory_instance(call: Call) -> JsResult<JsInteger> { + let scope = call.scope; + let max_links = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); + let _instance_id = new_wot(max_links as usize); + Ok(JsInteger::new(scope, _instance_id as i32)) +} + +pub fn unsafe_mem_copy(call: Call) -> JsResult<JsInteger> { + let scope = call.scope; + let instance_id = + try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value() as usize; + let wots = get_wots(); + let wot_copy = wots.get(&instance_id) + .expect("This instance don't exist !") + .deref() + .clone(); + let mut new_instance_id = 0; + while wots.contains_key(&new_instance_id) { + new_instance_id += 1; + } + wots.insert(new_instance_id, Box::new(wot_copy)); + Ok(JsInteger::new(scope, new_instance_id as i32)) +} + +pub fn unsafe_get_max_links(call: Call) -> JsResult<JsInteger> { + let scope = call.scope; + let instance_id = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); + let mut _max_links = 0; + _max_links = get_wot(instance_id as usize).get_max_link(); + Ok(JsInteger::new(scope, _max_links as i32)) +} + +pub fn unsafe_get_wot_size(call: Call) -> JsResult<JsInteger> { + let scope = call.scope; + let instance_id = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); + let mut _size = 0; + _size = get_wot(instance_id as usize).size(); + Ok(JsInteger::new(scope, _size as i32)) +} + +pub fn unsafe_is_enabled(call: Call) -> JsResult<JsBoolean> { + let scope = call.scope; + let instance_id = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); + let node_id = try!(try!(call.arguments.require(scope, 1)).check::<JsInteger>()).value(); + if get_wot(instance_id as usize) + .is_enabled(NodeId(node_id as usize)) + .unwrap() + { + Ok(JsBoolean::new(scope, true)) + } else { + Ok(JsBoolean::new(scope, false)) + } +} + +pub fn unsafe_get_enabled(call: Call) -> JsResult<JsArray> { + let scope = call.scope; + let instance_id = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); + let enabled = get_mut_wot(instance_id as usize).get_enabled(); + let mut js_array = JsArray::new(scope, enabled.len() as u32); + let mut index: u32 = 0; + for node_id in enabled { + let _bool = try!(JsArray::set( + *js_array.deref_mut(), + index, + JsInteger::new(scope, node_id.0 as i32), + )); + index += 1; + } + Ok(js_array) +} + +pub fn unsafe_get_disabled(call: Call) -> JsResult<JsArray> { + let scope = call.scope; + let instance_id = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); + let disabled = get_mut_wot(instance_id as usize).get_disabled(); + let js_array = JsArray::new(scope, disabled.len() as u32); + let mut index: u32 = 0; + for node_id in disabled { + let _bool = try!(JsArray::set( + *js_array.deref(), + index, + JsInteger::new(scope, node_id.0 as i32), + )); + index += 1; + } + Ok(js_array) +} + +pub fn unsafe_get_sentries(call: Call) -> JsResult<JsArray> { + let scope = call.scope; + let instance_id = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); + let sentry_requirement = + try!(try!(call.arguments.require(scope, 1)).check::<JsInteger>()).value(); + let sentries = get_mut_wot(instance_id as usize).get_sentries(sentry_requirement as usize); + let js_array = JsArray::new(scope, sentries.len() as u32); + let mut index: u32 = 0; + for node_id in sentries { + let _bool = try!(JsArray::set( + *js_array.deref(), + index, + JsInteger::new(scope, node_id.0 as i32), + )); + index += 1; + } + Ok(js_array) +} + +pub fn unsafe_get_non_sentries(call: Call) -> JsResult<JsArray> { + let scope = call.scope; + let instance_id = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); + let sentry_requirement = + try!(try!(call.arguments.require(scope, 1)).check::<JsInteger>()).value(); + let non_sentries = + get_mut_wot(instance_id as usize).get_non_sentries(sentry_requirement as usize); + let js_array = JsArray::new(scope, non_sentries.len() as u32); + let mut index: u32 = 0; + for node_id in non_sentries { + let _bool = try!(JsArray::set( + *js_array.deref(), + index, + JsInteger::new(scope, node_id.0 as i32), + )); + index += 1; + } + Ok(js_array) +} + +pub fn unsafe_exist_link(call: Call) -> JsResult<JsBoolean> { + let scope = call.scope; + let instance_id = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); + let source = try!(try!(call.arguments.require(scope, 1)).check::<JsInteger>()).value(); + let target = try!(try!(call.arguments.require(scope, 2)).check::<JsInteger>()).value(); + let result = + get_wot(instance_id as usize).has_link(NodeId(source as usize), NodeId(target as usize)); + if let HasLinkResult::Link(has_link) = result { + Ok(JsBoolean::new(scope, has_link)) + } else { + panic!("Fatal Error : {:?}", result) + } +} + +pub fn unsafe_set_max_links(call: Call) -> JsResult<JsBoolean> { + let scope = call.scope; + let instance_id = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); + let max_links = try!(try!(call.arguments.require(scope, 1)).check::<JsInteger>()).value(); + let _result = get_mut_wot(instance_id as usize).set_max_link(max_links as usize); + Ok(JsBoolean::new(scope, true)) +} + +pub fn unsafe_add_node(call: Call) -> JsResult<JsInteger> { + let scope = call.scope; + let instance_id = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); + let _node_id = get_mut_wot(instance_id as usize).add_node(); + Ok(JsInteger::new(scope, _node_id.0 as i32)) +} + +pub fn unsafe_rem_node(call: Call) -> JsResult<JsInteger> { + let scope = call.scope; + let instance_id = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); + if let Some(node_id) = get_mut_wot(instance_id as usize).rem_node() { + Ok(JsInteger::new(scope, node_id.0 as i32)) + } else { + panic!("Fatal error : wotb : you try to remove a node to empty wot !") + } +} + +pub fn unsafe_set_enabled(call: Call) -> JsResult<JsBoolean> { + let scope = call.scope; + let instance_id = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); + let is_enabled = try!(try!(call.arguments.require(scope, 1)).check::<JsBoolean>()).value(); + let node_id = try!(try!(call.arguments.require(scope, 2)).check::<JsInteger>()).value(); + if let Some(enabled) = + get_mut_wot(instance_id as usize).set_enabled(NodeId(node_id as usize), is_enabled) + { + Ok(JsBoolean::new(scope, enabled)) + } else { + panic!("Fatal error : wotb : node id don't exist !") + } +} + +pub fn unsafe_add_link(call: Call) -> JsResult<JsInteger> { + let scope = call.scope; + let instance_id = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); + let source = try!(try!(call.arguments.require(scope, 1)).check::<JsInteger>()).value(); + let target = try!(try!(call.arguments.require(scope, 2)).check::<JsInteger>()).value(); + let result = get_mut_wot(instance_id as usize) + .add_link(NodeId(source as usize), NodeId(target as usize)); + if let NewLinkResult::Ok(links_count) = result { + Ok(JsInteger::new(scope, links_count as i32)) + } else { + panic!("Fatal error wotb : {:?}", result) + } +} + +pub fn unsafe_rem_link(call: Call) -> JsResult<JsInteger> { + let scope = call.scope; + let instance_id = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); + let source = try!(try!(call.arguments.require(scope, 1)).check::<JsInteger>()).value(); + let target = try!(try!(call.arguments.require(scope, 2)).check::<JsInteger>()).value(); + let result = get_mut_wot(instance_id as usize) + .rem_link(NodeId(source as usize), NodeId(target as usize)); + if let RemLinkResult::Removed(links_count) = result { + Ok(JsInteger::new(scope, links_count as i32)) + } else { + panic!("Fatal Error : {:?}", result) + } +} + +pub fn unsafe_compute_distance(call: Call) -> JsResult<JsObject> { + let scope = call.scope; + let instance_id = try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value(); + let node_id = try!(try!(call.arguments.require(scope, 1)).check::<JsInteger>()).value(); + let sentry_requirement = + try!(try!(call.arguments.require(scope, 2)).check::<JsInteger>()).value() as u32; + let step_max = try!(try!(call.arguments.require(scope, 3)).check::<JsInteger>()).value() as u32; + let x_percent = try!(try!(call.arguments.require(scope, 4)).check::<JsNumber>()).value() as f64; + let distance_params = WotDistanceParameters { + node: NodeId(node_id as usize), + sentry_requirement, + step_max, + x_percent, + }; + let wot = get_wot(instance_id as usize); + build_distance_response( + scope, + &DISTANCE_CALCULATOR + .compute_distance(wot, distance_params) + .unwrap(), + ) +} + +pub fn unsafe_find_paths(call: Call) -> JsResult<JsArray> { + let scope = call.scope; + let instance_id = + try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value() as usize; + let from = try!(try!(call.arguments.require(scope, 1)).check::<JsInteger>()).value() as u32; + let to = try!(try!(call.arguments.require(scope, 2)).check::<JsInteger>()).value() as u32; + let step_max = try!(try!(call.arguments.require(scope, 3)).check::<JsInteger>()).value() as u32; + let wot = get_wot(instance_id as usize); + Ok(try!(build_paths_response( + scope, + &PATH_FINDER.find_paths(wot, NodeId(from as usize), NodeId(to as usize), step_max) + ))) + /*let mut i: u32 = 0; + let js_paths = JsArray::new(scope, paths.len() as u32); + for path in paths { + let mut j: u32 = 0; + let js_path = JsArray::new(scope, path.len() as u32); + for node_id in path { + let _bool = try!(JsArray::set( + *js_path.deref(), + j, + JsInteger::new(scope, node_id.0 as i32), + )); + j += 1; + } + let _bool = try!(JsArray::set(*js_paths.deref(), i, js_path,)); + i += 1; + } + Ok(js_paths)*/ +} + +pub fn unsafe_remove_wot(call: Call) -> JsResult<JsBoolean> { + let scope = call.scope; + let instance_id = + try!(try!(call.arguments.require(scope, 0)).check::<JsInteger>()).value() as usize; + let wots = get_wots(); + if wots.len() > instance_id { + wots.remove(&instance_id).unwrap(); + Ok(JsBoolean::new(scope, true)) + } else { + Ok(JsBoolean::new(scope, false)) + } +} diff --git a/tests/tests_safe_wots.js b/tests/tests_safe_wots.js new file mode 100644 index 0000000000000000000000000000000000000000..15555f9b814fbc0eb5c28962374fef4ab1c6bed7 --- /dev/null +++ b/tests/tests_safe_wots.js @@ -0,0 +1,465 @@ +"use strict"; + +const addon = require('./../lib/index'); +var assert = require('assert'); +var fs = require('fs'); +var path = require('path'); +var should = require('should'); + +const UNSAFE_INSTANCES = false; +const SAFE_INSTANCES = true; +const EMPTY_FILE = path.join(__dirname, 'wotb.bin'); +const FILE = path.join(__dirname, 'g1_genesis.bin'); +const X_PERCENT = 1.0; +const _100_PERCENT = 1.0; +const MAX_DISTANCE_1 = 1; +const MAX_DISTANCE_2 = 2; +const MAX_DISTANCE_3 = 3; +const MAX_DISTANCE_4 = 4; +const MAX_DISTANCE_5 = 5; +const FROM_1_LINK_SENTRIES = 1; +const FROM_2_LINKS_SENTRIES = 2; +const FROM_3_LINKS_SENTRIES = 3; +const __OUTDISTANCED__ = true; +const __OK__ = false; + +testsSafe() + +function testsSafe() { + function newInstance(launchSafeTests) { + return () => { + let wot = addon.newSafeMemoryInstance(3); + launchSafeTests(wot); + } + } + + describe("wotb-rs binding tests", () => { + + describe('Basic operations', newInstance((wot) => { + + it('should have 3 max links', function() { + assert.equal(wot.getMaxCert(), 3) + }); + + it('should have an initial size of 0', function() { + should.equal(wot.getWoTSize(), 0); + }); + + it('should give number 0 if we add a node', function() { + // Add a node + should.equal(wot.addNode(), 0); + should.equal(wot.getWoTSize(), 1); + should.equal(wot.isEnabled(0), true); + var enabled = wot.getEnabled(); + should.equal(enabled.length, 1); + should.equal(enabled[0], 0); + should.equal(wot.getDisabled().length, 0); + // Add another + should.equal(wot.addNode(), 1); + should.equal(wot.getWoTSize(), 2); + var enabled2 = wot.getEnabled(); + should.equal(enabled2.length, 2); + should.equal(enabled2[1], 1); + should.equal(wot.getDisabled().length, 0); + // Add 10 nodes + for (let i = 0; i < 10; i++) { + should.equal(wot.addNode(), i + 2); + } + should.equal(wot.getWoTSize(), 2 + 10); + should.equal(wot.getEnabled().length, 2 + 10); + }); + + it('should add certs only in the boundaries of maxCert', () => { + wot.addLink(0, 1); + wot.addLink(0, 2); + wot.addLink(0, 3); + //wot.addLink(0, 4); + should.equal(wot.getMaxCert(), 3); + should.equal(wot.existsLink(0, 1), true); + should.equal(wot.existsLink(0, 2), true); + should.equal(wot.existsLink(0, 3), true); + should.equal(wot.existsLink(0, 4), false); + wot.setMaxCert(4); + should.equal(wot.getMaxCert(), 4); + should.equal(wot.existsLink(0, 4), false); + wot.addLink(0, 4); + should.equal(wot.existsLink(0, 4), true); + wot.removeLink(0,1); + wot.removeLink(0,2); + wot.removeLink(0,3); + wot.removeLink(0,4); + }); + + it('should not throw if testing existsLink() with inbounds link', function() { + should.equal(wot.existsLink(4, 6), false); + }); + + it('first 4 nodes should be enabled', function() { + should.equal(wot.isEnabled(0), true); + should.equal(wot.isEnabled(1), true); + should.equal(wot.isEnabled(2), true); + should.equal(wot.isEnabled(3), true); + }); + + it('last node should be enabled', function() { + should.equal(wot.isEnabled(11), true); + }); + + it('should be able to disable some nodes', function() { + should.equal(wot.setEnabled(false, 0), false); + should.equal(wot.setEnabled(false, 1), false); + should.equal(wot.setEnabled(false, 2), false); + should.equal(wot.getDisabled().length, 3); + should.equal(wot.setEnabled(true, 1), true); + }); + + it('nodes 0 and 2 should be disabled', function() { + should.equal(wot.isEnabled(0), false); + should.equal(wot.isEnabled(1), true); + should.equal(wot.isEnabled(2), false); + should.equal(wot.isEnabled(3), true); + // Set enabled again + should.equal(wot.setEnabled(true, 0), true); + should.equal(wot.setEnabled(true, 1), true); + should.equal(wot.setEnabled(true, 2), true); + should.equal(wot.setEnabled(true, 1), true); + should.equal(wot.getDisabled().length, 0); + }); + + it('should not exist a link from 2 to 0', function() { + should.equal(wot.existsLink(2, 0), false); + }); + + it('should be able to add some links', function() { + should.equal(wot.addLink(2, 0), 1); + should.equal(wot.addLink(4, 0), 2); + //should.equal(wot.addLink(4, 0), 2); + should.equal(wot.addLink(5, 0), 3); + }); + + it('should exist new links', function() { + /** + * WoT is: + * + * 2 --> 0 + * 4 --> 0 + * 5 --> 0 + */ + should.equal(wot.existsLink(2, 0), true); + should.equal(wot.existsLink(4, 0), true); + should.equal(wot.existsLink(5, 0), true); + should.equal(wot.existsLink(2, 1), false); + }); + + it('should be able to remove some links', function() { + should.equal(wot.removeLink(4, 0), 2); + /** + * WoT is now: + * + * 2 --> 0 + * 5 --> 0 + */ + }); + + it('should exist less links', function() { + should.equal(wot.existsLink(2, 0), true); + should.equal(wot.existsLink(4, 0), false); + should.equal(wot.existsLink(5, 0), true); + should.equal(wot.existsLink(2, 1), false); + }); + + it('should successfully use distance rule', function() { + should.equal(wot.isOutdistanced(0, FROM_1_LINK_SENTRIES, MAX_DISTANCE_1, X_PERCENT), __OK__); // No because 2,4,5 have certified him + should.equal(wot.isOutdistanced(0, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_1, X_PERCENT), __OK__); // No because only member 2 has 2 certs, and has certified him + should.equal(wot.isOutdistanced(0, FROM_3_LINKS_SENTRIES, MAX_DISTANCE_1, X_PERCENT), __OK__); // No because no member has issued 3 certifications + // We add links from member 3 + should.equal(wot.addLink(3, 1), 1); + should.equal(wot.addLink(3, 2), 1); + /** + * WoT is now: + * + * 2 --> 0 + * 5 --> 0 + * 3 --> 1 + * 3 --> 2 + */ + should.equal(wot.getWoTSize(), 12); + should.equal(wot.getSentries(FROM_1_LINK_SENTRIES).length, 1); + should.equal(wot.getSentries(FROM_1_LINK_SENTRIES)[0], 2); + should.equal(wot.getSentries(FROM_2_LINKS_SENTRIES).length, 0); + should.equal(wot.getSentries(FROM_3_LINKS_SENTRIES).length, 0); + should.equal(wot.getNonSentries(FROM_1_LINK_SENTRIES).length, 11); // 12 - 1 = 11 + should.equal(wot.getNonSentries(FROM_2_LINKS_SENTRIES).length, 12); // 12 - 0 = 12 + should.equal(wot.getNonSentries(FROM_3_LINKS_SENTRIES).length, 12); // 12 - 0 = 12 + should.equal(wot.isOutdistanced(0, FROM_1_LINK_SENTRIES, MAX_DISTANCE_1, X_PERCENT), __OK__); // OK: 2 --> 0 + should.equal(wot.isOutdistanced(0, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_1, X_PERCENT), __OK__); // OK: 2 --> 0 + should.equal(wot.isOutdistanced(0, FROM_3_LINKS_SENTRIES, MAX_DISTANCE_1, X_PERCENT), __OK__); // OK: no sentry with 3 links issued + should.equal(wot.isOutdistanced(0, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_2, X_PERCENT), __OK__); // OK: 2 --> 0 + + wot.addLink(1, 3); + wot.addLink(2, 3); + + should.equal(wot.getWoTSize(), 12); + should.equal(wot.getSentries(FROM_1_LINK_SENTRIES).length, 3); + should.equal(wot.getSentries(FROM_1_LINK_SENTRIES)[0], 1); + should.equal(wot.getSentries(FROM_1_LINK_SENTRIES)[1], 2); + should.equal(wot.getSentries(FROM_1_LINK_SENTRIES)[2], 3); + should.equal(wot.getSentries(FROM_2_LINKS_SENTRIES).length, 1); + should.equal(wot.getSentries(FROM_2_LINKS_SENTRIES)[0], 3); + should.equal(wot.getSentries(FROM_3_LINKS_SENTRIES).length, 0); + should.equal(wot.getNonSentries(FROM_1_LINK_SENTRIES).length, 9); // 12 - 3 = 9 + should.equal(wot.getNonSentries(FROM_2_LINKS_SENTRIES).length, 11); // 12 - 1 = 11 + should.equal(wot.getNonSentries(FROM_3_LINKS_SENTRIES).length, 12); // 12 - 0 = 12 + should.equal(wot.getPaths(3, 0, MAX_DISTANCE_1).length, 0); // KO + should.equal(wot.getPaths(3, 0, MAX_DISTANCE_2).length, 1); // It exists 3 --> 2 --> 0 + should.equal(wot.getPaths(3, 0, MAX_DISTANCE_2)[0].length, 3); // It exists 3 --> 2 --> 0 + should.equal(wot.isOutdistanced(0, FROM_1_LINK_SENTRIES, MAX_DISTANCE_1, X_PERCENT), __OUTDISTANCED__); // KO: No path 3 --> 0 + should.equal(wot.isOutdistanced(0, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_1, X_PERCENT), __OUTDISTANCED__); // KO: No path 3 --> 0 + should.equal(wot.isOutdistanced(0, FROM_3_LINKS_SENTRIES, MAX_DISTANCE_1, X_PERCENT), __OK__); // OK: no sentry with 3 links issued + should.equal(wot.isOutdistanced(0, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_2, X_PERCENT), __OK__); // OK: 3 --> 2 --> 0 + }); + + it('should have 12 nodes', function() { + should.equal(wot.getWoTSize(), 12); + }); + + it('delete top node', function() { + should.equal(wot.removeNode(), 10); + }); + + it('should have 11 nodes', function() { + should.equal(wot.getWoTSize(), 11); + }); + + it('should work with member 3 disabled', function() { + // With member 3 disabled (non-member) + should.equal(wot.setEnabled(false, 3), false); + let disabled_nodes = wot.getDisabled(); + should.equal(disabled_nodes.length, 1); + should.equal(disabled_nodes[0], 3); + should.equal(wot.isOutdistanced(0, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_1, X_PERCENT), __OK__); // OK: No path 3 --> 0, but is disabled + }); + + it('should be able to make a mem copy', function() { + const copy = wot.memCopy(); + should.equal(copy.setEnabled(false, 3), false); + should.equal(wot.getDisabled().length, 1); + should.equal(copy.isOutdistanced(0, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_1, X_PERCENT), __OK__); // OK: No path 3 --> 0, but is disabled + }); + })); + + + + describe('tests open written wot file', newInstance((wot) => { + before(() => { + wot = addon.newSafeFileInstance("test.bin", 3); + }); + + it('should have a wot size of 12', function() { + should.equal(wot.getWoTSize(), 12); + }); + + describe('testing around 2 with d = 1', () => { + + /** + * Sentries of 1 link (X are not sentries): + * + * X --> 1 --> 2 --> 4 --> 5 <==> 6 --> X + * ^ + * || + * ##==> 3 <-- 8 <-- 9 <========## + * | || + * `> 10 <==> 11 <===## + */ + // => It can be seen 1..6, 8..11 = 10 sentries + // => MINUS the sentry #2 (which is tested and is not to be included) + // => 9 sentries TESTED against member#2 + + it('should have 10 sentries', function() { + should.equal(wot.getSentries(FROM_1_LINK_SENTRIES).length, 10); + }); + + it('distance k = 1', function() { + should.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_1, _100_PERCENT), __OUTDISTANCED__); + should.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_1, 0.5), __OUTDISTANCED__); + // 20% of the sentries: OK + // => 20% x 9 = 2 sentries to reach + // => we have 1 --> 2 + // => we have 3 --> 2 + // => OK (1,3) + should.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_1, 0.2), __OK__); + // Who can pass 20% can pass 10% + should.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_1, 0.1), __OK__); + // Can pass 23% (1,98 => 2 sentries) + should.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_1, 0.22), __OK__); + // But cannot pass 23% (2,07 => 3 sentries) + should.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_1, 0.23), __OUTDISTANCED__); + }); + + it('distance k = 2', function() { + should.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_2, _100_PERCENT), __OUTDISTANCED__); + should.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_2, 0.5), __OUTDISTANCED__); + // 33% of the sentries: OK + // => 33% x 9 = 3 sentries to reach + // With k = 2 we have the following paths: + // 1 --> 2 + // 8 --> 3 --> 2 + // => OK (1,8,3) + should.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_2, 0.33), __OK__); + should.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_2, 0.3), __OK__); + should.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_2, 0.2), __OK__); + should.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_2, 0.1), __OK__); + // But cannot pass 34% (3,06 => 4 sentries) + should.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_2, 0.34), __OUTDISTANCED__); + }); + + it('distance k = 5', function() { + should.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_5, _100_PERCENT), __OUTDISTANCED__); + // 66% of the sentries: OK + // => 66% x 9 = 6 sentries to reach + // With k = 5 we have the following paths: + // 1 --> 2 + // 10 --> 11 --> 9 --> 8 --> 3 --> 2 + // => OK (1,10,11,9,8,3) + should.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_5, 0.66), __OK__); + should.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_5, 0.3), __OK__); + should.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_5, 0.2), __OK__); + should.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_5, 0.1), __OK__); + // But cannot pass 67% (6,03 => 7 sentries) + should.equal(wot.isOutdistanced(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_5, 0.67), __OUTDISTANCED__); + assert.deepEqual(wot.detailedDistance(2, FROM_1_LINK_SENTRIES, MAX_DISTANCE_5, 0.67), { + nbReached: 7, // +1 compared to reached sentries, because of member `0` + nbSuccess: 6, + nbSentries: 9, + isOutdistanced: true + }); + }); + }); + + describe('testing around 2 with d = 2', () => { + /** + * Sentries of 2 links (X are not sentries): + * + * X --> X --> 2 --> X --> X <==> X --> X + * ^ + * || + * ##==> X <-- X <-- X <========## + * | || + * `> X <==> 11 <===## + */ + // => It can be seen 2,6,8,9,11 = 5 sentries + // => MINUS the sentry #2 (which is tested and is not to be included) + // => 4 sentries + + it('should have 2 sentries', function() { + should.equal(wot.getSentries(FROM_2_LINKS_SENTRIES).length, 2); + }); + + it('distance k = 1', function() { + should.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_1, _100_PERCENT), __OUTDISTANCED__); + // With k = 1 we have no paths + // => ALWAYS KO + should.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_1, 0.99), __OUTDISTANCED__); + should.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_1, 0.5), __OUTDISTANCED__); + should.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_1, 0.01), __OUTDISTANCED__); + }); + + it('distance k = 2', function() { + // Always distanced with k = 2 + should.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_2, _100_PERCENT), __OUTDISTANCED__); + should.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_2, 0.25), __OUTDISTANCED__); + should.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_2, 0.24), __OUTDISTANCED__); + should.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_2, 0.251), __OUTDISTANCED__); + }); + + it('distance k = 3', function() { + // Always distanced with k = 2 + should.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_3, _100_PERCENT), __OUTDISTANCED__); + should.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_3, 0.50), __OUTDISTANCED__); + should.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_3, 0.49), __OUTDISTANCED__); + should.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_3, 0.51), __OUTDISTANCED__); + }); + + it('distance k = 4', function() { + // Only 1 sentry at distance 4: always OK + should.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_4, _100_PERCENT), __OK__); + should.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_4, 0.75), __OK__); + should.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_4, 0.01), __OK__); + should.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_4, 0.99), __OK__); + }); + + it('distance k = 5', function() { + // Only 1 sentry at distance 4: always OK + should.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_5, _100_PERCENT), __OK__); + should.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_5, 0.75), __OK__); + should.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_5, 0.01), __OK__); + should.equal(wot.isOutdistanced(2, FROM_2_LINKS_SENTRIES, MAX_DISTANCE_5, 0.99), __OK__); + }); + }); + + describe('testing around 2 with d = 3', () => { + /** + * Sentries of 3 links (X are not sentries): + * + * X --> X --> 2 --> X --> X <==> X --> X + * ^ + * || + * ##==> X <-- X <-- X <========## + * | || + * `> X <==> X <===## + */ + // => It can be seen 2 = 1 sentries + // => MINUS the sentry #2 (which is tested and is not to be included) + // => 0 sentries + // => ALWAYS OK, no sentries to constraint + + it('distance k = 1', function() { + should.equal(wot.isOutdistanced(2, FROM_3_LINKS_SENTRIES, MAX_DISTANCE_1, _100_PERCENT), __OK__); + should.equal(wot.isOutdistanced(2, FROM_3_LINKS_SENTRIES, MAX_DISTANCE_1, 0.01), __OK__); + }); + + it('distance k = 2', function() { + should.equal(wot.isOutdistanced(2, FROM_3_LINKS_SENTRIES, MAX_DISTANCE_2, _100_PERCENT), __OK__); + should.equal(wot.isOutdistanced(2, FROM_3_LINKS_SENTRIES, MAX_DISTANCE_2, 0.01), __OK__); + }); + + it('distance k = 5', function() { + should.equal(wot.isOutdistanced(2, FROM_3_LINKS_SENTRIES, MAX_DISTANCE_5, _100_PERCENT), __OK__); + should.equal(wot.isOutdistanced(2, FROM_3_LINKS_SENTRIES, MAX_DISTANCE_5, 0.01), __OK__); + }); + }); + + it('should add node, write and read new wot with 13 nodes', function() { + wot.addNode(); + wot.setFilePath("test2.bin"); + assert.equal(wot.write(), true) + wot = addon.newSafeFileInstance("test2.bin", 3); + should.equal(wot.getWoTSize(), 13); + }); + })); + + describe('tests g1 genesis wot', newInstance((wot) => { + + before(() => { + wot = addon.newSafeFileInstance(FILE, 100); + }); + + it('should have 100 max links', function() { + assert.equal(wot.getMaxCert(), 100) + }); + + it('should have a wot size of 59', function() { + should.equal(wot.getWoTSize(), 59); + }); + + it('should have only enabled members', function() { + should.equal(wot.getEnabled().length, 59); + should.equal(wot.getDisabled().length, 0); + }); + + it('should have 48 sentries', function() { + should.equal(wot.getSentries(FROM_3_LINKS_SENTRIES).length, 48); + }); + })); + }); +} \ No newline at end of file diff --git a/tests/test.js b/tests/tests_unsafe_wot.js similarity index 97% rename from tests/test.js rename to tests/tests_unsafe_wot.js index d905fbd8015209beac193bcfe9b2bd782c268cd3..e0fa1adbd98e8e487b0e0a01ba3d54e4764a1fb3 100644 --- a/tests/test.js +++ b/tests/tests_unsafe_wot.js @@ -21,13 +21,13 @@ const FROM_3_LINKS_SENTRIES = 3; const __OUTDISTANCED__ = true; const __OK__ = false; -testSuite(); +testSuite() function testSuite() { - function newInstance(launchTests) { + function newInstance(launchUnsafeTests) { return () => { let wot = addon.newMemoryInstance(3); - launchTests(wot); + launchUnsafeTests(wot); } } @@ -58,9 +58,9 @@ function testSuite() { // Add another should.equal(wot.addNode(), 1); should.equal(wot.getWoTSize(), 2); - var enabled = wot.getEnabled(); - should.equal(enabled.length, 2); - should.equal(enabled[1], 1); + var enabled2 = wot.getEnabled(); + should.equal(enabled2.length, 2); + should.equal(enabled2[1], 1); should.equal(wot.getDisabled().length, 0); // Add 10 nodes for (let i = 0; i < 10; i++) { @@ -251,7 +251,7 @@ function testSuite() { it('should drop this instance and create new instance with id zero', function() { wot.clear(); - var wot2 = addon.newMemoryInstance(100); + let wot2 = addon.newMemoryInstance(3); should.equal(wot2.instanceID, 0); wot2.clear() }); @@ -259,9 +259,8 @@ function testSuite() { describe('Building a larger WoT', newInstance((wot) => { - before(() => { - /** - * We build WoT: + it('should build a larget WoT', function() { + /* We build WoT: * * 0 --> 1 --> 2 --> 4 --> 5 <==> 6 --> 7 * ^ @@ -281,7 +280,6 @@ function testSuite() { should.equal(wot.addLink(4, 5), 1); should.equal(wot.addLink(5, 6), 1); should.equal(wot.addLink(6, 7), 1); - should.equal(wot.addLink(6, 5), 2); // 2n level should.equal(wot.addLink(2, 3), 1); should.equal(wot.addLink(3, 2), 2); @@ -298,7 +296,7 @@ function testSuite() { return Promise.resolve(); }); - it('should have an initial size of 0', function() { + it('should have an initial size of 12', function() { should.equal(wot.getWoTSize(), 12); }); @@ -496,9 +494,10 @@ function testSuite() { it('should add node, write and read new wot with 13 nodes', function() { wot.addNode(); + wot.setFilePath("test2.bin"); assert.equal(wot.write(), true) wot.clear(); - wot = addon.newFileInstance("test.bin", 3); + wot = addon.newFileInstance("test2.bin", 3); should.equal(wot.getWoTSize(), 13); });