Skip to content
Snippets Groups Projects
Commit 4c5c8554 authored by Éloïs's avatar Éloïs
Browse files

[fix] #69 + migrate wot i/o file to rustbreak

parent f52ebeaa
Branches
Tags
1 merge request!64Resolve "[wotb] Data Legacy wot not compile with bincode 1.0.0"
......@@ -84,15 +84,6 @@ dependencies = [
"safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bincode"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bincode"
version = "1.0.0"
......@@ -409,7 +400,7 @@ dependencies = [
name = "duniter-wotb"
version = "0.8.0-a0.6"
dependencies = [
"bincode 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
"bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)",
......@@ -1443,7 +1434,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30e93c03064e7590d0466209155251b90c22e37fab1daf2771582598b5827557"
"checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9"
"checksum base64 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9263aa6a38da271eec5c91a83ce1e800f093c8535788d403d626d8d5c3f8f007"
"checksum bincode 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9a6301db0b49fb63551bc15b5ae348147101cdf323242b93ec7546d5002ff1af"
"checksum bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bda13183df33055cbb84b847becce220d392df502ebe7a4a78d7021771ed94d0"
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
"checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789"
......
......@@ -17,14 +17,16 @@ use duniter_crypto::keys::*;
use duniter_dal::block::DALBlock;
use duniter_dal::sources::SourceAmount;
use duniter_dal::writers::requests::*;
use duniter_dal::ForkId;
use duniter_dal::{BinDB, ForkId};
use duniter_documents::blockchain::v10::documents::transaction::{TxAmount, TxBase};
use duniter_documents::blockchain::v10::documents::BlockDocument;
use duniter_documents::blockchain::Document;
use duniter_documents::BlockId;
use duniter_wotb::data::NewLinkResult;
use duniter_wotb::{NodeId, WebOfTrust};
use rustbreak::backend::Backend;
use std::collections::HashMap;
use std::fmt::Debug;
#[derive(Debug)]
/// Stores all queries to apply in database to "apply" the block
......@@ -41,10 +43,10 @@ pub enum ApplyValidBlockError {
RevokeUnknowNodeId(),
}
pub fn apply_valid_block<W: WebOfTrust + Sync>(
pub fn apply_valid_block<W: WebOfTrust, B: Backend + Debug>(
block: &BlockDocument,
wot_index: &mut HashMap<PubKey, NodeId>,
wot: &mut W,
wot_db: &BinDB<W, B>,
expire_certs: &HashMap<(NodeId, NodeId), BlockId>,
old_fork_id: Option<ForkId>,
) -> Result<ValidBlockApplyReqs, ApplyValidBlockError> {
......@@ -63,8 +65,16 @@ pub fn apply_valid_block<W: WebOfTrust + Sync>(
let pubkey = joiner.clone().issuers()[0];
if let Some(idty_doc) = identities.get(&pubkey) {
// Newcomer
let wotb_id = NodeId(wot.size());
wot.add_node();
let wotb_id = NodeId(
wot_db
.read(|db| db.size())
.expect("Fatal error : fail to read WotDB !"),
);
wot_db
.write(|db| {
db.add_node();
})
.expect("Fail to write in WotDB");
wot_index.insert(pubkey, wotb_id);
wot_dbs_requests.push(WotsDBsWriteQuery::CreateIdentity(
wotb_id,
......@@ -76,7 +86,11 @@ pub fn apply_valid_block<W: WebOfTrust + Sync>(
} else {
// Renewer
let wotb_id = wot_index[&joiner.issuers()[0]];
wot.set_enabled(wotb_id, true);
wot_db
.write(|db| {
db.set_enabled(wotb_id, true);
})
.expect("Fail to write in WotDB");
wot_dbs_requests.push(WotsDBsWriteQuery::RenewalIdentity(
joiner.issuers()[0],
wotb_id,
......@@ -89,7 +103,11 @@ pub fn apply_valid_block<W: WebOfTrust + Sync>(
let pubkey = active.issuers()[0];
if !identities.contains_key(&pubkey) {
let wotb_id = wot_index[&pubkey];
wot.set_enabled(wotb_id, true);
wot_db
.write(|db| {
db.set_enabled(wotb_id, true);
})
.expect("Fail to write in WotDB");
wot_dbs_requests.push(WotsDBsWriteQuery::RenewalIdentity(
pubkey,
wotb_id,
......@@ -104,7 +122,11 @@ pub fn apply_valid_block<W: WebOfTrust + Sync>(
} else {
return Err(ApplyValidBlockError::ExcludeUnknowNodeId());
};
wot.set_enabled(*wot_id, false);
wot_db
.write(|db| {
db.set_enabled(*wot_id, false);
})
.expect("Fail to write in WotDB");
wot_dbs_requests.push(WotsDBsWriteQuery::ExcludeIdentity(
exclusion,
block.blockstamp(),
......@@ -117,7 +139,11 @@ pub fn apply_valid_block<W: WebOfTrust + Sync>(
} else {
return Err(ApplyValidBlockError::RevokeUnknowNodeId());
};
wot.set_enabled(*wot_id, false);
wot_db
.write(|db| {
db.set_enabled(*wot_id, false);
})
.expect("Fail to write in WotDB");
wot_dbs_requests.push(WotsDBsWriteQuery::RevokeIdentity(
compact_revoc.issuer,
block.blockstamp(),
......@@ -128,7 +154,9 @@ pub fn apply_valid_block<W: WebOfTrust + Sync>(
let compact_cert = certification.to_compact_document();
let wotb_node_from = wot_index[&compact_cert.issuer];
let wotb_node_to = wot_index[&compact_cert.target];
let result = wot.add_link(wotb_node_from, wotb_node_to);
wot_db
.write(|db| {
let result = db.add_link(wotb_node_from, wotb_node_to);
match result {
NewLinkResult::Ok(_) => {}
_ => panic!(
......@@ -136,6 +164,8 @@ pub fn apply_valid_block<W: WebOfTrust + Sync>(
wotb_node_from.0, wotb_node_to.0, result
),
}
})
.expect("Fail to read WotDB");
wot_dbs_requests.push(WotsDBsWriteQuery::CreateCert(
compact_cert.issuer,
wotb_node_from,
......@@ -154,7 +184,9 @@ pub fn apply_valid_block<W: WebOfTrust + Sync>(
}
if let Some(du_amount) = block.dividend {
if du_amount > 0 {
let members_wot_ids = wot.get_enabled();
let members_wot_ids = wot_db
.read(|db| db.get_enabled())
.expect("Fail to read WotDB");
let mut members_pubkeys = Vec::new();
for (pubkey, wotb_id) in wot_index {
if members_wot_ids.contains(wotb_id) {
......
......@@ -22,6 +22,8 @@ use duniter_dal::*;
use duniter_documents::blockchain::Document;
use duniter_documents::{BlockHash, BlockId, Blockstamp, PreviousBlockstamp};
use duniter_network::NetworkBlock;
use rustbreak::backend::Backend;
use std::fmt::Debug;
use *;
#[derive(Debug, Copy, Clone)]
......@@ -53,13 +55,13 @@ impl From<ApplyValidBlockError> for BlockError {
}
}
pub fn check_and_apply_block<W: WebOfTrust + Sync>(
pub fn check_and_apply_block<W: WebOfTrust, B: Backend + Debug>(
blocks_databases: &BlocksV10DBs,
certs_db: &BinFileDB<CertsExpirV10Datas>,
block: &Block,
current_blockstamp: &Blockstamp,
wotb_index: &mut HashMap<PubKey, NodeId>,
wot: &mut W,
wot_db: &BinDB<W, B>,
forks_states: &[ForkStatus],
) -> Result<ValidBlockApplyReqs, BlockError> {
let (block_doc, already_have_block) = match *block {
......@@ -102,7 +104,7 @@ pub fn check_and_apply_block<W: WebOfTrust + Sync>(
return Ok(apply_valid_block(
&block_doc,
wotb_index,
wot,
wot_db,
&expire_certs,
old_fork_id,
)?);
......
......@@ -16,7 +16,6 @@
use duniter_crypto::keys::*;
use duniter_dal::identity::DALIdentity;
use duniter_documents::blockchain::v10::documents::transaction::*;
use duniter_documents::Blockstamp;
use duniter_module::DuniterConf;
use duniter_wotb::data::rusty::RustyWebOfTrust;
use std::time::*;
......@@ -135,18 +134,17 @@ pub fn dbex_wot(conf: &DuniterConf, query: &DBExWotQuery) {
let wot_reverse_index: HashMap<NodeId, &PubKey> =
wot_index.iter().map(|(p, id)| (*id, p)).collect();
// Get wot path
let wot_path = duniter_conf::get_wot_path(conf.profile().clone().to_string(), &conf.currency());
// Open wot file
let (wot, wot_blockstamp): (RustyWebOfTrust, Blockstamp) =
open_wot_file(&WOT_FILE_FORMATER, &wot_path, *INFINITE_SIG_STOCK);
// Open wot db
let wot_db = open_wot_db::<RustyWebOfTrust>(&db_path).expect("Fail to open WotDB !");
// Print wot blockstamp
println!("Wot : Current blockstamp = {}.", wot_blockstamp);
//println!("Wot : Current blockstamp = {}.", wot_blockstamp);
// Print members count
let members_count = wot.get_enabled().len();
let members_count = wot_db
.read(|db| db.get_enabled())
.expect("Fail to read WotDB")
.len();
println!(" Members count = {}.", members_count);
match *query {
......@@ -162,8 +160,9 @@ pub fn dbex_wot(conf: &DuniterConf, query: &DBExWotQuery) {
wot_id.0,
pubkey.to_string()
);
let sources = wot
.get_links_source(wot_id)
let sources = wot_db
.read(|db| db.get_links_source(wot_id))
.expect("Fail to read WotDB")
.expect("Fail to get links source !");
println!("Certifiers : {}", sources.len());
for (i, source) in sources.iter().enumerate() {
......
......@@ -47,6 +47,7 @@ mod ts_parsers;
use std::collections::HashMap;
use std::env;
use std::fmt::Debug;
use std::ops::Deref;
use std::path::PathBuf;
use std::str;
......@@ -73,9 +74,8 @@ use duniter_network::{
NetworkBlock, NetworkDocument, NetworkEvent, NetworkRequest, NetworkResponse, NodeFullId,
};
use duniter_wotb::data::rusty::RustyWebOfTrust;
use duniter_wotb::operations::file::BinaryFileFormater;
use duniter_wotb::{NodeId, WebOfTrust};
use rustbreak::backend::FileBackend;
use rustbreak::backend::{Backend, FileBackend};
/// The blocks are requested by packet groups. This constant sets the block packet size.
pub static CHUNK_SIZE: &'static u32 = &50;
......@@ -83,8 +83,6 @@ pub static CHUNK_SIZE: &'static u32 = &50;
pub static INFINITE_SIG_STOCK: &'static usize = &4_000_000_000;
/// The blocks are requested by packet groups. This constant sets the number of packets per group.
pub static MAX_BLOCKS_REQUEST: &'static u32 = &500;
/// There can be several implementations of the wot file backup, this constant fixes the implementation used by the blockchain module.
pub static WOT_FILE_FORMATER: BinaryFileFormater = BinaryFileFormater {};
/// Blockchain Module
#[derive(Debug)]
......@@ -300,12 +298,12 @@ impl BlockchainModule {
}
}
}
fn receive_network_documents<W: WebOfTrust + Sync>(
fn receive_network_documents<W: WebOfTrust, B: Backend + Debug>(
&mut self,
network_documents: &[NetworkDocument],
current_blockstamp: &Blockstamp,
wotb_index: &mut HashMap<PubKey, NodeId>,
wot: &mut W,
wot_db: &BinDB<W, B>,
) -> Blockstamp {
let mut blockchain_documents = Vec::new();
let mut current_blockstamp = *current_blockstamp;
......@@ -321,7 +319,7 @@ impl BlockchainModule {
&Block::NetworkBlock(network_block),
&current_blockstamp,
wotb_index,
wot,
wot_db,
&self.forks_states,
) {
Ok(ValidBlockApplyReqs(block_req, wot_dbs_reqs, currency_dbs_reqs)) => {
......@@ -440,12 +438,12 @@ impl BlockchainModule {
}
}
}
fn receive_blocks<W: WebOfTrust + Sync>(
fn receive_blocks<W: WebOfTrust, B: Backend + Debug>(
&mut self,
blocks_in_box: &[Box<NetworkBlock>],
current_blockstamp: &Blockstamp,
wotb_index: &mut HashMap<PubKey, NodeId>,
wot: &mut W,
wot: &BinDB<W, B>,
) -> Blockstamp {
debug!("BlockchainModule : receive_blocks()");
let blocks: Vec<&NetworkBlock> = blocks_in_box.into_iter().map(|b| b.deref()).collect();
......@@ -455,7 +453,7 @@ impl BlockchainModule {
let mut save_currency_dbs = false;
for block in blocks {
if let Ok(ValidBlockApplyReqs(bc_db_query, wot_dbs_queries, tx_dbs_queries)) =
check_and_apply_block::<W>(
check_and_apply_block::<W, B>(
&self.blocks_databases,
&self.wot_databases.certs_db,
&Block::NetworkBlock(block),
......@@ -513,8 +511,9 @@ impl BlockchainModule {
pub fn start_blockchain(&mut self, blockchain_receiver: &mpsc::Receiver<DuniterMessage>) -> () {
info!("BlockchainModule::start_blockchain()");
// Get wot path
let wot_path = duniter_conf::get_wot_path(self.conf_profile.clone(), &self.currency);
// Get dbs path
let dbs_path =
duniter_conf::get_blockchain_db_path(self.conf_profile.as_str(), &self.currency);
// Get wotb index
let mut wotb_index: HashMap<PubKey, NodeId> =
......@@ -522,11 +521,7 @@ impl BlockchainModule {
.expect("Fatal eror : get_wotb_index : Fail to read blockchain databases");
// Open wot file
let (mut wot, mut _wot_blockstamp) = open_wot_file::<RustyWebOfTrust, BinaryFileFormater>(
&WOT_FILE_FORMATER,
&wot_path,
self.currency_params.sig_stock,
);
let wot_db = open_wot_db::<RustyWebOfTrust>(&dbs_path).expect("Fail to open WotDB !");
// Get current block
let mut current_blockstamp = duniter_dal::block::get_current_blockstamp(
......@@ -640,7 +635,7 @@ impl BlockchainModule {
network_docs,
&current_blockstamp,
&mut wotb_index,
&mut wot,
&wot_db,
);
current_blockstamp = new_current_blockstamp;
}
......@@ -667,7 +662,7 @@ impl BlockchainModule {
blocks,
&current_blockstamp,
&mut wotb_index,
&mut wot,
&wot_db,
);
if current_blockstamp != new_current_blockstamp {
current_blockstamp = new_current_blockstamp;
......@@ -728,7 +723,7 @@ impl BlockchainModule {
&Block::LocalBlock(&stackable_block.block),
&current_blockstamp,
&mut wotb_index,
&mut wot,
&wot_db,
&self.forks_states,
) {
// Apply db requests
......
......@@ -26,8 +26,7 @@ use duniter_dal::writers::requests::*;
use duniter_dal::ForkId;
use duniter_documents::{BlockHash, BlockId, Hash};
use duniter_network::NetworkBlock;
use duniter_wotb::operations::file::FileFormater;
use duniter_wotb::{NodeId, WebOfTrust};
use duniter_wotb::NodeId;
use rustbreak::{deser::Bincode, MemoryDatabase};
use std::collections::{HashMap, VecDeque};
use std::fs;
......@@ -80,34 +79,10 @@ pub fn sync_ts(
let mut current_blockstamp = *current_blockstamp;
// Get wot path
let wot_path = duniter_conf::get_wot_path(profile.clone().to_string(), currency);
// Open wot file
let (mut wot, mut _wot_blockstamp): (RustyWebOfTrust, Blockstamp) =
if wot_path.as_path().exists() {
match WOT_FILE_FORMATER.from_file(
wot_path
.as_path()
.to_str()
.expect("Fail to convert path to str"),
*INFINITE_SIG_STOCK,
) {
Ok((wot, binary_blockstamp)) => match str::from_utf8(&binary_blockstamp) {
Ok(str_blockstamp) => (
wot,
Blockstamp::from_string(str_blockstamp)
.expect("Fail to deserialize wot blockcstamp"),
),
Err(e) => panic!("Invalid UTF-8 sequence: {}", e),
},
Err(e) => panic!("Fatal Error : fail te read wot file : {:?}", e),
}
} else {
(
RustyWebOfTrust::new(*INFINITE_SIG_STOCK),
Blockstamp::default(),
)
};
let db_path = duniter_conf::get_blockchain_db_path(&profile, &currency);
// Open wot db
let wot_db = open_wot_db::<RustyWebOfTrust>(&db_path).expect("Fail to open WotDB !");
// Get verification level
let _verif_level = if cautious {
......@@ -496,7 +471,6 @@ pub fn sync_ts(
block_doc.currency.clone(),
block_doc.parameters.unwrap(),
));
wot.set_max_link(currency_params.sig_stock);
get_currency_params = true;
} else {
panic!("The genesis block are None parameters !");
......@@ -522,10 +496,10 @@ pub fn sync_ts(
// Apply block
let apply_valid_block_begin = SystemTime::now();
if let Ok(ValidBlockApplyReqs(block_req, wot_db_reqs, currency_db_reqs)) =
apply_valid_block::<RustyWebOfTrust>(
apply_valid_block::<RustyWebOfTrust, FileBackend>(
&block_doc,
&mut wotb_index,
&mut wot,
&wot_db,
&expire_certs,
None,
) {
......@@ -609,13 +583,7 @@ pub fn sync_ts(
info!("Sync : send End signal to tx job.");
// Save wot file
WOT_FILE_FORMATER
.to_file(
&wot,
current_blockstamp.to_string().as_bytes(),
wot_path.as_path().to_str().unwrap(),
)
.expect("Fatal Error: Fail to write wotb in file !");
wot_db.save().expect("Fail to save wotb db");
let main_job_duration =
SystemTime::now().duration_since(main_job_begin).unwrap() - all_wait_duration;
......
......@@ -52,7 +52,6 @@ pub mod writers;
use duniter_crypto::keys::*;
use duniter_documents::blockchain::v10::documents::transaction::*;
use duniter_documents::{BlockHash, BlockId, Blockstamp, Hash, PreviousBlockstamp};
use duniter_wotb::operations::file::FileFormater;
use duniter_wotb::{NodeId, WebOfTrust};
use rustbreak::backend::{Backend, FileBackend, MemoryBackend};
use rustbreak::error::{RustbreakError, RustbreakErrorKind};
......@@ -326,12 +325,13 @@ pub fn open_db<D: Serialize + DeserializeOwned + Debug + Default + Clone + Send>
}
}
/// Open wot file (cf. duniter-wot crate)
pub fn open_wot_file<W: WebOfTrust, WF: FileFormater>(
file_formater: &WF,
wot_path: &PathBuf,
sig_stock: usize,
) -> (W, Blockstamp) {
/// Open wot db (cf. duniter-wot crate)
pub fn open_wot_db<W: WebOfTrust>(dbs_folder_path: &PathBuf) -> Result<BinFileDB<W>, DALError> {
open_db::<W>(dbs_folder_path, "wot.db")
}
// Open wot file (cf. duniter-wot crate)
/*pub fn open_wot_file<W: WebOfTrust>(wot_path: &PathBuf, sig_stock: usize) -> (W, Blockstamp) {
if wot_path.as_path().exists() {
match file_formater.from_file(
wot_path
......@@ -353,4 +353,4 @@ pub fn open_wot_file<W: WebOfTrust, WF: FileFormater>(
} else {
(W::new(sig_stock), Blockstamp::default())
}
}
}*/
......@@ -14,7 +14,7 @@ path = "lib.rs"
[dependencies]
serde = "1.0.57"
serde_derive = "1.0.57"
bincode = "0.9.2"
bincode = "1.0.0"
byteorder = "1.2.3"
rayon = "1.0.1"
......
// Copyright (C) 2017-2018 The Duniter Project Developers.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! Provide a legacy implementation of `WebOfTrust` storage and calculations.
//! Its mostly translated directly from the original C++ code.
use std::collections::hash_set::Iter;
use std::collections::HashSet;
use std::fs::File;
use std::io::prelude::*;
use bincode::{deserialize, serialize, Infinite};
use super::{HasLinkResult, NewLinkResult, RemLinkResult};
use NodeId;
use WebOfTrust;
#[derive(Debug, Clone, Serialize, Deserialize)]
struct Node {
id: NodeId,
/// Is the node enabled ?
pub enabled: bool,
certs: HashSet<NodeId>,
issued_count: usize,
}
impl Node {
/// Create a new node.
pub fn new(id: usize) -> Node {
Node {
id: NodeId(id),
enabled: true,
certs: HashSet::new(),
issued_count: 0,
}
}
/// Getter of node id.
pub fn id(&self) -> NodeId {
self.id
}
/// Add a certification from this node to the given node.
///
/// Certification will fail if this node already used all its certs.
pub fn link_to(&mut self, to: &mut Node, max_certs: usize) -> NewLinkResult {
if self.issued_count >= max_certs {
NewLinkResult::AllCertificationsUsed(to.certs.len())
} else if to.certs.contains(&self.id()) {
NewLinkResult::AlreadyCertified(to.certs.len())
} else {
to.certs.insert(self.id());
self.issued_count += 1;
NewLinkResult::Ok(to.certs.len())
}
}
/// Remove a certification (if it exist) from this node to the given node.
pub fn unlink_to(&mut self, to: &mut Node) -> RemLinkResult {
if to.certs.contains(&self.id()) {
to.certs.remove(&self.id());
self.issued_count -= 1;
RemLinkResult::Removed(to.certs.len())
} else {
RemLinkResult::UnknownCert(to.certs.len())
}
}
/// Tells if this node has a link from the given node.
pub fn has_link_from(&self, from: &Node) -> bool {
self.certs.contains(&from.id())
}
/// Tells if this node has a link to the given node.
pub fn has_link_to(&self, to: &Node) -> bool {
to.has_link_from(self)
}
/// Give an iterator of node certs.
pub fn links_iter(&self) -> Iter<NodeId> {
self.certs.iter()
}
/// Getter of the issued count.
pub fn issued_count(&self) -> usize {
self.issued_count
}
}
/// Store a Web of Trust.
///
/// Allow to create/remove nodes and links between them.
///
/// It provides methods to find sentries nodes, find all paths
/// between 2 nodes and to compute distances in the web.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LegacyWebOfTrust {
nodes: Vec<Node>,
/// Maxiumum amout of certifications a node can provide.
///
/// It can be changed afterward, and will be accounted for every future calculations.
///
/// In practice it should not change after initialization.
pub max_cert: usize,
}
impl LegacyWebOfTrust {
/// Read `WoT` from file.
pub fn legacy_from_file(path: &str) -> Option<LegacyWebOfTrust> {
let mut file = match File::open(path) {
Ok(file) => file,
Err(_) => return None,
};
let mut content: Vec<u8> = vec![];
if file.read_to_end(&mut content).is_err() {
return None;
}
match deserialize::<LegacyWebOfTrust>(&content[..]) {
Ok(wot) => Some(wot),
Err(_) => None,
}
}
/// Write `WoT` to file.
pub fn legacy_to_file(&self, path: &str) -> bool {
let encoded: Vec<u8> = serialize(self, Infinite).unwrap();
match File::create(path) {
Ok(mut buffer) => buffer.write_all(&encoded).is_ok(),
Err(_) => false,
}
}
}
impl WebOfTrust for LegacyWebOfTrust {
fn new(max_cert: usize) -> LegacyWebOfTrust {
LegacyWebOfTrust {
nodes: vec![],
max_cert,
}
}
fn get_max_link(&self) -> usize {
self.max_cert
}
fn set_max_link(&mut self, max_link: usize) {
self.max_cert = max_link;
}
fn add_node(&mut self) -> NodeId {
let node_id = self.nodes.len();
self.nodes.push(Node::new(node_id));
NodeId(node_id)
}
fn rem_node(&mut self) -> Option<NodeId> {
self.nodes.pop();
if !self.nodes.is_empty() {
Some(NodeId(self.nodes.iter().len() - 1))
} else {
None
}
}
fn size(&self) -> usize {
self.nodes.iter().count()
}
fn is_enabled(&self, node: NodeId) -> Option<bool> {
if node.0 >= self.size() {
None
} else {
Some(self.nodes[node.0].enabled)
}
}
fn set_enabled(&mut self, node: NodeId, state: bool) -> Option<bool> {
if node.0 >= self.size() {
None
} else {
self.nodes[node.0].enabled = state;
Some(state)
}
}
fn get_enabled(&self) -> Vec<NodeId> {
self.nodes
.iter()
.filter(|x| x.enabled)
.map(|x| x.id())
.collect()
}
fn get_disabled(&self) -> Vec<NodeId> {
self.nodes
.iter()
.filter(|x| !x.enabled)
.map(|x| x.id())
.collect()
}
fn add_link(&mut self, from: NodeId, to: NodeId) -> NewLinkResult {
if from.0 == to.0 {
NewLinkResult::SelfLinkingForbidden()
} else if from.0 >= self.size() {
NewLinkResult::UnknownSource()
} else if to.0 >= self.size() {
NewLinkResult::UnknownTarget()
} else if from.0 < to.0 {
// split `nodes` in two part to allow borrowing 2 nodes at the same time
let (start, end) = self.nodes.split_at_mut(to.0);
start[from.0].link_to(&mut end[0], self.max_cert)
} else {
// split `nodes` in two part to allow borrowing 2 nodes at the same time
let (start, end) = self.nodes.split_at_mut(from.0);
end[0].link_to(&mut start[to.0], self.max_cert)
}
}
fn rem_link(&mut self, from: NodeId, to: NodeId) -> RemLinkResult {
if from.0 >= self.size() {
RemLinkResult::UnknownSource()
} else if to.0 >= self.size() {
RemLinkResult::UnknownTarget()
} else if from.0 < to.0 {
// split `nodes` in two part to allow borrowing 2 nodes at the same time
let (start, end) = self.nodes.split_at_mut(to.0);
start[from.0].unlink_to(&mut end[0])
} else {
// split `nodes` in two part to allow borrowing 2 nodes at the same time
let (start, end) = self.nodes.split_at_mut(from.0);
end[0].unlink_to(&mut start[to.0])
}
}
fn has_link(&self, from: NodeId, to: NodeId) -> HasLinkResult {
if from.0 >= self.size() {
HasLinkResult::UnknownSource()
} else if to.0 >= self.size() {
HasLinkResult::UnknownTarget()
} else {
HasLinkResult::Link(self.nodes[from.0].has_link_to(&self.nodes[to.0]))
}
}
fn is_sentry(&self, node: NodeId, sentry_requirement: usize) -> Option<bool> {
if node.0 >= self.size() {
return None;
}
let node = &self.nodes[node.0];
Some(
node.enabled
&& node.issued_count() >= sentry_requirement
&& node.links_iter().count() >= sentry_requirement,
)
}
fn get_sentries(&self, sentry_requirement: usize) -> Vec<NodeId> {
self.nodes
.iter()
.filter(|x| {
x.enabled
&& x.issued_count() >= sentry_requirement
&& x.links_iter().count() >= sentry_requirement
})
.map(|x| x.id())
.collect()
}
fn get_non_sentries(&self, sentry_requirement: usize) -> Vec<NodeId> {
self.nodes
.iter()
.filter(|x| {
x.enabled
&& (x.issued_count < sentry_requirement
|| x.links_iter().count() < sentry_requirement)
})
.map(|x| x.id())
.collect()
}
fn get_links_source(&self, target: NodeId) -> Option<Vec<NodeId>> {
if target.0 >= self.size() {
None
} else {
Some(self.nodes[target.0].certs.iter().cloned().collect())
}
}
fn issued_count(&self, id: NodeId) -> Option<usize> {
if id.0 >= self.size() {
None
} else {
Some(self.nodes[id.0].issued_count)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use tests::generic_wot_test;
#[test]
fn node_tests() {
// Correct node id
assert_eq!(Node::new(1).id().0, 1);
// Create 2 nodes
let mut node1 = Node::new(1);
let mut node2 = Node::new(2);
// Default value
assert_eq!(node1.issued_count(), 0);
assert_eq!(node2.links_iter().count(), 0);
assert!(!node1.has_link_to(&node2));
assert!(!node2.has_link_to(&node2));
assert!(!node1.has_link_from(&node1));
assert!(!node2.has_link_from(&node1));
// New link 1 -> 2
match node1.link_to(&mut node2, 10) {
NewLinkResult::Ok(1) => (),
_ => panic!(),
};
assert_eq!(node1.issued_count(), 1);
assert_eq!(node2.links_iter().count(), 1);
assert!(node1.has_link_to(&node2));
assert!(!node2.has_link_to(&node2));
assert!(!node1.has_link_from(&node1));
assert!(node2.has_link_from(&node1));
// Existing link 1 -> 2
match node1.link_to(&mut node2, 10) {
NewLinkResult::AlreadyCertified(1) => (),
_ => panic!(),
};
assert_eq!(node1.issued_count(), 1);
assert_eq!(node2.links_iter().count(), 1);
assert!(node1.has_link_to(&node2));
assert!(!node2.has_link_to(&node2));
assert!(!node1.has_link_from(&node1));
assert!(node2.has_link_from(&node1));
// Max certification count
let mut node3 = Node::new(3);
match node1.link_to(&mut node3, 1) {
NewLinkResult::AllCertificationsUsed(0) => (),
_ => panic!(),
};
assert_eq!(node1.issued_count(), 1);
assert_eq!(node2.links_iter().count(), 1);
assert_eq!(node3.links_iter().count(), 0);
assert!(node1.has_link_to(&node2));
assert!(!node2.has_link_to(&node2));
assert!(!node1.has_link_from(&node1));
assert!(node2.has_link_from(&node1));
}
#[test]
fn wot_tests() {
generic_wot_test::<LegacyWebOfTrust>();
}
}
......@@ -17,9 +17,12 @@
//! `LegacyWebOfTrust` is almost a translation of the legacy C++ coden while
//! `RustyWebOfTrust` is a brand new implementation with a more "rusty" style.
pub mod legacy;
pub mod rusty;
use serde::de::DeserializeOwned;
use serde::Serialize;
use std::fmt::Debug;
/// Wrapper for a node id.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct NodeId(pub usize);
......@@ -70,7 +73,7 @@ pub enum HasLinkResult {
/// Trait for a Web Of Trust.
/// Allow to provide other implementations of the `WoT` logic instead of the legacy C++
/// translated one.
pub trait WebOfTrust: Clone + Sync {
pub trait WebOfTrust: Clone + Debug + Default + DeserializeOwned + Send + Serialize + Sync {
/// Create a new Web of Trust with the maximum of links a node can issue.
fn new(max_links: usize) -> Self;
......
......@@ -22,7 +22,7 @@ use NodeId;
use WebOfTrust;
/// A node in the `WoT` graph.
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
struct Node {
/// Is this node enabled ?
enabled: bool,
......@@ -44,7 +44,7 @@ impl Node {
}
/// A more idiomatic implementation of a Web of Trust.
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct RustyWebOfTrust {
/// List of nodes in the WoT.
nodes: Vec<Node>,
......@@ -52,6 +52,15 @@ pub struct RustyWebOfTrust {
max_links: usize,
}
impl Default for RustyWebOfTrust {
fn default() -> RustyWebOfTrust {
RustyWebOfTrust {
nodes: Vec::new(),
max_links: 4_000_000_000,
}
}
}
impl WebOfTrust for RustyWebOfTrust {
fn new(max_links: usize) -> RustyWebOfTrust {
RustyWebOfTrust {
......
......@@ -116,6 +116,14 @@ impl FileFormater for BinaryFileFormater {
// Read up to nodes_states_size bytes (nodes_states)
let file_pointing_to_links =
file_pointing_to_nodes_states.split_off(nodes_states_size as usize);
let count_total_bytes_read = file_pointing_to_links.len()
+ nodes_states_size as usize
+ 4
+ blockstamp_size as usize
+ 4;
if count_total_bytes_read != file_size as usize {
panic!("not read all wot file !");
}
// Apply nodes state
let mut count_remaining_nodes = nodes_count;
for byte in file_pointing_to_nodes_states {
......@@ -159,6 +167,9 @@ impl FileFormater for BinaryFileFormater {
count_bytes += 1;
}
}
if count_bytes % 3 != 0 {
panic!("not read all wot file !");
}
Ok((wot, file_pointing_to_blockstamp))
}
......@@ -182,7 +193,7 @@ impl FileFormater for BinaryFileFormater {
let mut bytes: Vec<u8> = Vec::with_capacity(4);
bytes.write_u32::<BigEndian>(nodes_count).unwrap();
buffer.append(&mut bytes);
// Write enable state by groups of 8 (count links at the same time)
// Write enable state by groups of 8
let mut enable_states: u8 = 0;
let mut factor: u8 = 128;
for n in 0..nodes_count {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment