diff --git a/blockchain/lib.rs b/blockchain/lib.rs index 7e24de3f410a18f245f41d5d71b9e45649b9a61a..8710a5214a4064bf7d46218666a320b285cb2113 100644 --- a/blockchain/lib.rs +++ b/blockchain/lib.rs @@ -37,6 +37,7 @@ extern crate serde; extern crate serde_json; extern crate sqlite; +mod stack_up_block; mod sync; use std::collections::HashMap; @@ -47,6 +48,7 @@ use std::str; use std::sync::mpsc; use std::time::{Duration, SystemTime, UNIX_EPOCH}; +use self::stack_up_block::try_stack_up_completed_block; use duniter_crypto::keys::ed25519; use duniter_dal::block::{DALBlock, WotEvent}; use duniter_dal::constants::MAX_FORKS; @@ -54,9 +56,8 @@ use duniter_dal::dal_event::DALEvent; use duniter_dal::dal_requests::{DALReqBlockchain, DALRequest, DALResBlockchain, DALResponse}; use duniter_dal::identity::DALIdentity; use duniter_dal::parsers::memberships::MembershipParseError; -use duniter_dal::writers::certification::write_certification; +use duniter_dal::writers::requests::DBWriteRequest; use duniter_dal::{DuniterDB, ForkState}; -use duniter_documents::blockchain::v10::documents::membership::MembershipType; use duniter_documents::blockchain::v10::documents::{BlockDocument, V10Document}; use duniter_documents::blockchain::{BlockchainProtocol, Document, VerificationResult}; use duniter_documents::{BlockHash, BlockId, Blockstamp}; @@ -446,25 +447,27 @@ impl BlockchainModule { "stackable_block : block {} chainable !", block_doc.blockstamp() ); - let (success, wot_events) = match block { + let (success, db_requests, wot_events) = match block { &Block::NetworkBlock(network_block) => self.try_stack_up_block( &network_block, wotb_index, wot, SyncVerificationLevel::Cautious(), ), - &Block::LocalBlock(block_doc) => self.try_stack_up_completed_block( - &block_doc, - wotb_index, - wot, - SyncVerificationLevel::Cautious(), - ), + &Block::LocalBlock(block_doc) => { + try_stack_up_completed_block(&block_doc, wotb_index, wot) + } }; debug!( "stackable_block_ : block {} chainable !", block_doc.blockstamp() ); if success { + // Apply db requests + db_requests + .iter() + .map(|req| req.apply(&block_doc.currency, &self.db)) + .collect::<()>(); info!("StackUpValidBlock({})", block_doc.number.0); self.send_event(DALEvent::StackUpValidBlock(Box::new(block_doc.clone()))); return (true, Vec::with_capacity(0), wot_events); @@ -491,11 +494,7 @@ impl BlockchainModule { }, ) { Some(fork) => if forks.len() > fork { - if fork > 0 { - (fork, forks[fork]) - } else { - panic!("fork must be positive !") - } + (fork, forks[fork]) } else { panic!(format!("Error: fork n° {} is indicated as non-existent whereas it exists in database !", fork)); }, @@ -534,9 +533,6 @@ impl BlockchainModule { &network_block_v10.uncompleted_block_doc, fork, isolate, - &network_block_v10.joiners, - &network_block_v10.actives, - &network_block_v10.leavers, &network_block_v10.revoked, &network_block_v10.certifications, ) @@ -563,265 +559,17 @@ impl BlockchainModule { wotb_index: &HashMap<ed25519::PublicKey, NodeId>, wot: &W, verif_level: SyncVerificationLevel, - ) -> (bool, Vec<WotEvent>) { - let block_doc = - match self.complete_network_block(network_block, wotb_index, verif_level.clone()) { - Ok(block_doc) => block_doc, - Err(_) => return (false, Vec::with_capacity(0)), - }; - self.try_stack_up_completed_block::<W>(&block_doc, wotb_index, wot, verif_level) - } - fn complete_network_block( - &self, - network_block: &NetworkBlock, - wotb_index: &HashMap<ed25519::PublicKey, NodeId>, - verif_level: SyncVerificationLevel, - ) -> Result<BlockDocument, CompletedBlockError> { - let db = &self.db; - if let &NetworkBlock::V10(ref network_block_v10) = network_block { - let mut block_doc = network_block_v10.uncompleted_block_doc.clone(); - // Indexing block_identities - let mut block_identities = HashMap::new(); - block_doc - .identities - .iter() - .map(|idty| { - if idty.issuers().is_empty() { - panic!("idty without issuer !") - } - block_identities.insert(idty.issuers()[0], idty.clone()); - }) - .collect::<()>(); - /*for idty in block_doc.clone().identities { - if idty.issuers().is_empty() { - panic!("idty without issuer !") - } - block_identities.insert(idty.issuers()[0], idty); - }*/ - for joiner in duniter_dal::parsers::memberships::parse_memberships_from_json_value( - &self.currency.to_string(), - MembershipType::In(), - &network_block_v10.joiners, - ) { - block_doc.joiners.push(joiner?); - } - for active in duniter_dal::parsers::memberships::parse_memberships_from_json_value( - &self.currency.to_string(), - MembershipType::In(), - &network_block_v10.actives, - ) { - block_doc.actives.push(active?); - } - for leaver in duniter_dal::parsers::memberships::parse_memberships_from_json_value( - &self.currency.to_string(), - MembershipType::Out(), - &network_block_v10.leavers, - ) { - block_doc.leavers.push(leaver?); - } - block_doc.certifications = - duniter_dal::parsers::certifications::parse_certifications_from_json_value( - &self.currency.to_string(), - db, - &wotb_index, - &block_identities, - &network_block_v10.certifications, - ); - block_doc.revoked = duniter_dal::parsers::revoked::parse_revocations_from_json_value( - &self.currency.to_string(), - db, - &wotb_index, - &block_identities, - &network_block_v10.revoked, - ); - // In cautions mode, verify all signatures ! - if verif_level == SyncVerificationLevel::Cautious() { - for idty in block_doc.clone().identities { - if idty.verify_signatures() != VerificationResult::Valid() { - error!( - "Fail to sync block #{} : Idty with invalid singature !", - block_doc.number - ); - panic!("Idty with invalid singature !"); - } - } - } - let inner_hash = block_doc.inner_hash.expect("BlockchainModule : complete_network_block() : fatal error : block.inner_hash = None"); - if block_doc.number.0 > 0 { - block_doc.compute_inner_hash(); - } - let hash = block_doc.hash; - block_doc.compute_hash(); - if block_doc.inner_hash.expect("BlockchainModule : complete_network_block() : fatal error : block.inner_hash = None") == inner_hash { - let nonce = block_doc.nonce; - block_doc.change_nonce(nonce); - if verif_level == SyncVerificationLevel::FastSync() - || block_doc.verify_signatures() == VerificationResult::Valid() - || block_doc.number.0 <= 1 { - if block_doc.hash == hash { - Ok(block_doc) - } else { - warn!("BlockchainModule : Refuse Bloc : invalid hash !"); - Err(CompletedBlockError::InvalidHash()) - } - } else { - warn!("BlockchainModule : Refuse Bloc : invalid signature !"); - Err(CompletedBlockError::InvalidSig()) - } - } else { - warn!("BlockchainModule : Refuse Bloc : invalid inner hash !"); - Err(CompletedBlockError::InvalidInnerHash()) - } - } else { - Err(CompletedBlockError::InvalidVersion()) - } - } - fn try_stack_up_completed_block<W: WebOfTrust + Sync>( - &self, - block: &BlockDocument, - wotb_index: &HashMap<ed25519::PublicKey, NodeId>, - wot: &W, - _verif_level: SyncVerificationLevel, - ) -> (bool, Vec<WotEvent>) { - debug!( - "BlockchainModule : try stack up block {}", - block.blockstamp() - ); - let db = &self.db; - let mut wot_events = Vec::new(); - let mut wot_copy: W = wot.clone(); - let mut wotb_index_copy: HashMap<ed25519::PublicKey, NodeId> = wotb_index.clone(); - let current_blockstamp = block.blockstamp(); - let mut identities = HashMap::with_capacity(block.identities.len()); - for identity in block.identities.clone() { - identities.insert(identity.issuers()[0], identity); - } - for joiner in block.joiners.clone() { - let pubkey = joiner.clone().issuers()[0]; - if let Some(compact_idty) = identities.get(&pubkey) { - // Newcomer - let wotb_id = NodeId(wot_copy.size()); - wot_events.push(WotEvent::AddNode(pubkey, wotb_id)); - wot_copy.add_node(); - wotb_index_copy.insert(pubkey, wotb_id); - let idty = DALIdentity::create_identity( - db, - wotb_id, - compact_idty, - current_blockstamp.clone(), - ); - duniter_dal::writers::identity::write( - &idty, - db, - current_blockstamp.clone(), - block.median_time, - ); - } else { - // Renewer - let wotb_id = wotb_index_copy[&joiner.issuers()[0]]; - wot_events.push(WotEvent::EnableNode(wotb_id)); - wot_copy.set_enabled(wotb_id, true); - let mut idty = - DALIdentity::get_identity(&self.currency.to_string(), db, &wotb_id).unwrap(); - idty.renewal_identity( - db, - &wotb_index_copy, - &block.blockstamp(), - block.median_time, - false, - ); - } - } - for active in block.actives.clone() { - let wotb_id = wotb_index_copy[&active.issuers()[0]]; - wot_events.push(WotEvent::EnableNode(wotb_id)); - wot_copy.set_enabled(wotb_id, true); - let mut idty = - DALIdentity::get_identity(&self.currency.to_string(), db, &wotb_id).unwrap(); - idty.renewal_identity( - db, - &wotb_index_copy, - &block.blockstamp(), - block.median_time, - false, - ); - } - for exclusion in block.excluded.clone() { - let wotb_id = wotb_index_copy[&exclusion]; - wot_events.push(WotEvent::DisableNode(wotb_id)); - wot_copy.set_enabled(wotb_id, false); - DALIdentity::exclude_identity(db, wotb_id, block.blockstamp(), false); - } - for revocation in block.revoked.clone() { - let wotb_id = wotb_index_copy[&revocation.issuers()[0]]; - wot_events.push(WotEvent::DisableNode(wotb_id)); - wot_copy.set_enabled(wotb_id, false); - DALIdentity::revoke_identity(db, wotb_id, &block.blockstamp(), false); - } - for certification in block.certifications.clone() { - let wotb_node_from = wotb_index_copy[&certification.issuers()[0]]; - let wotb_node_to = wotb_index_copy[&certification.target()]; - wot_events.push(WotEvent::AddLink(wotb_node_from, wotb_node_to)); - wot_copy.add_link(wotb_node_from, wotb_node_to); - write_certification( - &certification, - db, - current_blockstamp.clone(), - block.median_time, - ); - } - - /*// Calculate the state of the wot - if !wot_events.is_empty() && verif_level != SyncVerificationLevel::FastSync() { - // Calculate sentries_count - let sentries_count = wot_copy.get_sentries(3).len(); - // Calculate average_density - let average_density = calculate_average_density::<W>(&wot_copy); - let sentry_requirement = - get_sentry_requirement(block.members_count, G1_PARAMS.step_max); - // Calculate distances and connectivities - let (average_distance, distances, average_connectivity, connectivities) = - compute_distances::<W>( - &wot_copy, - sentry_requirement, - G1_PARAMS.step_max, - G1_PARAMS.x_percent, - ); - // Calculate centralities and average_centrality - let centralities = - calculate_distance_stress_centralities::<W>(&wot_copy, G1_PARAMS.step_max); - let average_centrality = - (centralities.iter().sum::<u64>() as f64 / centralities.len() as f64) as usize; - // Register the state of the wot - duniter_dal::register_wot_state( - db, - &WotState { - block_number: block.number.0, - block_hash: block.hash.unwrap().to_string(), - sentries_count, - average_density, - average_distance, - distances, - average_connectivity, - connectivities: connectivities - .iter() - .map(|c| { - if *c > *G1_CONNECTIVITY_MAX { - *G1_CONNECTIVITY_MAX - } else { - *c - } - }) - .collect(), - average_centrality, - centralities, - }, - ); - }*/ - // Write block in bdd - duniter_dal::writers::block::write(db, block, 0, false); - - (true, wot_events) + ) -> (bool, Vec<DBWriteRequest>, Vec<WotEvent>) { + let block_doc = match complete_network_block( + &self.currency.to_string(), + Some(&self.db), + network_block, + verif_level.clone(), + ) { + Ok(block_doc) => block_doc, + Err(_) => return (false, Vec::with_capacity(0), Vec::with_capacity(0)), + }; + try_stack_up_completed_block::<W>(&block_doc, wotb_index, wot) } /// Start blockchain module. pub fn start_blockchain(&mut self, blockchain_receiver: mpsc::Receiver<DuniterMessage>) -> () { @@ -926,7 +674,6 @@ impl BlockchainModule { if let Some(current_block) = DALBlock::get_block( &self.currency.to_string(), &self.db, - &wotb_index, ¤t_blockstamp, ) { debug!("BlockchainModule : send_req_response(CurrentBlock({}))", current_block.block.blockstamp()); @@ -1052,7 +799,6 @@ impl BlockchainModule { let stackable_blocks = duniter_dal::block::DALBlock::get_stackables_blocks( &self.currency.to_string(), &self.db, - &wotb_index, ¤t_blockstamp, ); if stackable_blocks.is_empty() { @@ -1154,3 +900,107 @@ impl BlockchainModule { } } } + +/// Complete Network Block +pub fn complete_network_block( + currency: &str, + db: Option<&DuniterDB>, + network_block: &NetworkBlock, + verif_level: SyncVerificationLevel, +) -> Result<BlockDocument, CompletedBlockError> { + if let &NetworkBlock::V10(ref network_block_v10) = network_block { + let mut block_doc = network_block_v10.uncompleted_block_doc.clone(); + trace!("complete_network_block #{}...", block_doc.number); + if verif_level == SyncVerificationLevel::Cautious() { + // Indexing block_identities + let mut block_identities = HashMap::new(); + block_doc + .identities + .iter() + .map(|idty| { + if idty.issuers().is_empty() { + panic!("idty without issuer !") + } + block_identities.insert(idty.issuers()[0], idty.clone()); + }) + .collect::<()>(); + block_doc.certifications = + duniter_dal::parsers::certifications::parse_certifications_from_json_value( + currency, + db.expect("complete_network_block() : Cautious mode need access to blockchain database !"), + &block_identities, + &network_block_v10.certifications, + ); + trace!("Success to complete certs."); + block_doc.revoked = duniter_dal::parsers::revoked::parse_revocations_from_json_value( + currency, + db.expect( + "complete_network_block() : Cautious mode need access to blockchain database !", + ), + &block_identities, + &network_block_v10.revoked, + ); + } else { + block_doc.certifications = + duniter_dal::parsers::certifications::parse_certifications_into_compact( + &network_block_v10.certifications, + ); + trace!("Success to complete certs."); + block_doc.revoked = duniter_dal::parsers::revoked::parse_revocations_into_compact( + &network_block_v10.revoked, + ); + } + trace!("Success to complete certs & revocations."); + // In cautions mode, verify all signatures ! + if verif_level == SyncVerificationLevel::Cautious() { + for idty in block_doc.clone().identities { + if idty.verify_signatures() != VerificationResult::Valid() { + error!( + "Fail to sync block #{} : Idty with invalid singature !", + block_doc.number + ); + panic!("Idty with invalid singature !"); + } + } + } + let inner_hash = block_doc.inner_hash.expect( + "BlockchainModule : complete_network_block() : fatal error : block.inner_hash = None", + ); + if block_doc.number.0 > 0 { + block_doc.compute_inner_hash(); + } + let hash = block_doc.hash; + block_doc.compute_hash(); + if block_doc.inner_hash.expect( + "BlockchainModule : complete_network_block() : fatal error : block.inner_hash = None", + ) == inner_hash + { + let nonce = block_doc.nonce; + block_doc.change_nonce(nonce); + if verif_level == SyncVerificationLevel::FastSync() + || block_doc.verify_signatures() == VerificationResult::Valid() + || block_doc.number.0 <= 1 + { + if block_doc.hash == hash { + trace!("Succes to complete_network_block #{}", block_doc.number.0); + Ok(block_doc) + } else { + warn!("BlockchainModule : Refuse Bloc : invalid hash !"); + Err(CompletedBlockError::InvalidHash()) + } + } else { + warn!("BlockchainModule : Refuse Bloc : invalid signature !"); + Err(CompletedBlockError::InvalidSig()) + } + } else { + warn!("BlockchainModule : Refuse Bloc : invalid inner hash !"); + debug!( + "BlockInnerFormat={}", + block_doc.generate_compact_inner_text() + ); + Err(CompletedBlockError::InvalidInnerHash()) + } + } else { + Err(CompletedBlockError::InvalidVersion()) + } +} diff --git a/blockchain/stack_up_block.rs b/blockchain/stack_up_block.rs new file mode 100644 index 0000000000000000000000000000000000000000..bcc7b15d316dc45d6afde7600e9d00a4fa84d934 --- /dev/null +++ b/blockchain/stack_up_block.rs @@ -0,0 +1,178 @@ +// Copyright (C) 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/>. + +extern crate duniter_crypto; +extern crate duniter_dal; +extern crate duniter_documents; +extern crate duniter_wotb; + +use duniter_crypto::keys::ed25519; +use duniter_dal::block::{DALBlock, WotEvent}; +use duniter_dal::writers::requests::DBWriteRequest; +use duniter_documents::blockchain::v10::documents::BlockDocument; +use duniter_documents::blockchain::Document; +use duniter_wotb::{NodeId, WebOfTrust}; + +use std::collections::HashMap; + +pub fn try_stack_up_completed_block<W: WebOfTrust + Sync>( + block: &BlockDocument, + wotb_index: &HashMap<ed25519::PublicKey, NodeId>, + wot: &W, +) -> (bool, Vec<DBWriteRequest>, Vec<WotEvent>) { + debug!( + "BlockchainModule : try stack up complete block {}", + block.blockstamp() + ); + let mut db_requests = Vec::new(); + let mut wot_events = Vec::new(); + let mut wot_copy: W = wot.clone(); + let mut wotb_index_copy: HashMap<ed25519::PublicKey, NodeId> = wotb_index.clone(); + let current_blockstamp = block.blockstamp(); + let mut identities = HashMap::with_capacity(block.identities.len()); + for identity in block.identities.clone() { + identities.insert(identity.issuers()[0], identity); + } + for joiner in block.joiners.clone() { + let pubkey = joiner.clone().issuers()[0]; + if let Some(idty_doc) = identities.get(&pubkey) { + // Newcomer + let wotb_id = NodeId(wot_copy.size()); + wot_events.push(WotEvent::AddNode(pubkey, wotb_id)); + wot_copy.add_node(); + wotb_index_copy.insert(pubkey, wotb_id); + db_requests.push(DBWriteRequest::CreateIdentity( + wotb_id, + current_blockstamp.clone(), + block.median_time, + idty_doc.clone(), + )); + } else { + // Renewer + let wotb_id = wotb_index_copy[&joiner.issuers()[0]]; + wot_events.push(WotEvent::EnableNode(wotb_id)); + wot_copy.set_enabled(wotb_id, true); + db_requests.push(DBWriteRequest::RenewalIdentity( + joiner.issuers()[0], + block.blockstamp(), + block.median_time, + )); + } + } + for active in block.actives.clone() { + let pubkey = active.issuers()[0]; + if !identities.contains_key(&pubkey) { + let wotb_id = wotb_index_copy[&pubkey]; + wot_events.push(WotEvent::EnableNode(wotb_id)); + wot_copy.set_enabled(wotb_id, true); + db_requests.push(DBWriteRequest::RenewalIdentity( + pubkey, + block.blockstamp(), + block.median_time, + )); + } + } + for exclusion in block.excluded.clone() { + let wotb_id = wotb_index_copy[&exclusion]; + wot_events.push(WotEvent::DisableNode(wotb_id)); + wot_copy.set_enabled(wotb_id, false); + db_requests.push(DBWriteRequest::ExcludeIdentity( + wotb_id, + block.blockstamp(), + block.median_time, + )); + } + for revocation in block.revoked.clone() { + let compact_revoc = revocation.to_compact_document(); + let wotb_id = wotb_index_copy[&compact_revoc.issuer]; + wot_events.push(WotEvent::DisableNode(wotb_id)); + wot_copy.set_enabled(wotb_id, false); + db_requests.push(DBWriteRequest::RevokeIdentity( + wotb_id, + block.blockstamp(), + block.median_time, + )); + } + for certification in block.certifications.clone() { + trace!("try_stack_up_completed_block: apply cert..."); + let compact_cert = certification.to_compact_document(); + let wotb_node_from = wotb_index_copy[&compact_cert.issuer]; + let wotb_node_to = wotb_index_copy[&compact_cert.target]; + wot_events.push(WotEvent::AddLink(wotb_node_from, wotb_node_to)); + wot_copy.add_link(wotb_node_from, wotb_node_to); + db_requests.push(DBWriteRequest::CreateCert( + block.blockstamp(), + block.median_time, + compact_cert, + )); + trace!("try_stack_up_completed_block: apply cert...success."); + } + + /*// Calculate the state of the wot + if !wot_events.is_empty() && verif_level != SyncVerificationLevel::FastSync() { + // Calculate sentries_count + let sentries_count = wot_copy.get_sentries(3).len(); + // Calculate average_density + let average_density = calculate_average_density::<W>(&wot_copy); + let sentry_requirement = + get_sentry_requirement(block.members_count, G1_PARAMS.step_max); + // Calculate distances and connectivities + let (average_distance, distances, average_connectivity, connectivities) = + compute_distances::<W>( + &wot_copy, + sentry_requirement, + G1_PARAMS.step_max, + G1_PARAMS.x_percent, + ); + // Calculate centralities and average_centrality + let centralities = + calculate_distance_stress_centralities::<W>(&wot_copy, G1_PARAMS.step_max); + let average_centrality = + (centralities.iter().sum::<u64>() as f64 / centralities.len() as f64) as usize; + // Register the state of the wot + duniter_dal::register_wot_state( + db, + &WotState { + block_number: block.number.0, + block_hash: block.hash.unwrap().to_string(), + sentries_count, + average_density, + average_distance, + distances, + average_connectivity, + connectivities: connectivities + .iter() + .map(|c| { + if *c > *G1_CONNECTIVITY_MAX { + *G1_CONNECTIVITY_MAX + } else { + *c + } + }) + .collect(), + average_centrality, + centralities, + }, + ); + }*/ + // Write block in bdd + db_requests.push(DBWriteRequest::WriteBlock(DALBlock { + block: block.clone(), + fork: 0, + isolate: false, + })); + + (true, db_requests, wot_events) +} diff --git a/blockchain/sync.rs b/blockchain/sync.rs index 4646b23ec79e64a9a1dee59b329d595d169dee55..3fc1000d64d2fbd60bafc8d5b36d3d13fc09b724 100644 --- a/blockchain/sync.rs +++ b/blockchain/sync.rs @@ -29,6 +29,8 @@ use self::pbr::ProgressBar; use duniter_crypto::keys::{ed25519, PublicKey, Signature}; use duniter_dal::parsers::identities::parse_compact_identity; use duniter_dal::parsers::transactions::parse_transaction; +//use duniter_dal::writers::requests::DBWriteRequest; +use duniter_documents::blockchain::v10::documents::membership::MembershipType; use duniter_documents::blockchain::v10::documents::BlockDocument; use duniter_documents::{BlockHash, BlockId, Hash}; use duniter_network::{NetworkBlock, NetworkBlockV10}; @@ -51,6 +53,7 @@ pub struct BlockHeader { enum ParserWorkMess { TargetBlockstamp(Blockstamp), NetworkBlock(NetworkBlock), + //DBWriteRequest(DBWriteRequest), End(), } @@ -102,8 +105,8 @@ pub fn sync_ts( info!("Start cautious sync..."); SyncVerificationLevel::Cautious() } else { - println!("Start cautious sync..."); - info!("Start cautious sync..."); + println!("Start fast sync..."); + info!("Start fast sync..."); SyncVerificationLevel::FastSync() }; @@ -244,8 +247,21 @@ pub fn sync_ts( // Apply blocks while let Ok(ParserWorkMess::NetworkBlock(network_block)) = recv_sync_thread.recv() { + // Complete block + let block_doc = match complete_network_block( + &blockchain_module.currency.to_string(), + None, + &network_block, + SyncVerificationLevel::FastSync(), + ) { + Ok(block_doc) => block_doc, + Err(_) => panic!("Receive wrong block, please reset data and resync !"), + }; // Apply block - let (success, new_wot_events) = blockchain_module.try_stack_up_block::<RustyWebOfTrust>( + let (success, db_requests, new_wot_events) = + try_stack_up_completed_block::<RustyWebOfTrust>(&block_doc, &wotb_index, &wot); + + blockchain_module.try_stack_up_block::<RustyWebOfTrust>( &network_block, &wotb_index, &wot, @@ -253,6 +269,13 @@ pub fn sync_ts( ); if success { current_blockstamp = network_block.blockstamp(); + debug!("Apply db requests..."); + // Apply db requests + db_requests + .iter() + .map(|req| req.apply(&conf.currency().to_string(), &blockchain_module.db)) + .collect::<()>(); + debug!("Finish to apply db requests."); // Apply WotEvents if !new_wot_events.is_empty() { for wot_event in new_wot_events { @@ -430,9 +453,21 @@ pub fn parse_ts_block(row: &[sqlite::Value]) -> NetworkBlock { ), dividend: dividend, identities, - joiners: Vec::new(), - actives: Vec::new(), - leavers: Vec::new(), + joiners: duniter_dal::parsers::memberships::parse_memberships( + currency, + MembershipType::In(), + row[21].as_string().expect("Fail to parse joiners"), + ).expect("Fail to parse joiners (2)"), + actives: duniter_dal::parsers::memberships::parse_memberships( + currency, + MembershipType::In(), + row[22].as_string().expect("Fail to parse actives"), + ).expect("Fail to parse actives (2)"), + leavers: duniter_dal::parsers::memberships::parse_memberships( + currency, + MembershipType::In(), + row[23].as_string().expect("Fail to parse leavers"), + ).expect("Fail to parse leavers (2)"), revoked: Vec::new(), excluded: excluded .as_array() @@ -448,15 +483,6 @@ pub fn parse_ts_block(row: &[sqlite::Value]) -> NetworkBlock { transactions, inner_hash_and_nonce_str: String::new(), }; - let joiners: serde_json::Value = serde_json::from_str( - row[21].as_string().expect("Fail to parse joiners"), - ).expect("Fail to parse joiners (2)"); - let actives: serde_json::Value = serde_json::from_str( - row[22].as_string().expect("Fail to parse actives"), - ).expect("Fail to parse actives (2)"); - let leavers: serde_json::Value = serde_json::from_str( - row[23].as_string().expect("Fail to parse leavers"), - ).expect("Fail to parse leavers (2)"); let revoked: serde_json::Value = serde_json::from_str( row[24].as_string().expect("Fail to parse revoked"), ).expect("Fail to parse revoked (2)"); @@ -466,18 +492,6 @@ pub fn parse_ts_block(row: &[sqlite::Value]) -> NetworkBlock { // return NetworkBlock NetworkBlock::V10(Box::new(NetworkBlockV10 { uncompleted_block_doc, - joiners: joiners - .as_array() - .expect("Fail to parse joiners (3)") - .to_vec(), - actives: actives - .as_array() - .expect("Fail to parse actives (3)") - .to_vec(), - leavers: leavers - .as_array() - .expect("Fail to parse leavers (3)") - .to_vec(), revoked: revoked .as_array() .expect("Fail to parse revoked (3)") diff --git a/dal/block.rs b/dal/block.rs index 92d5cefda333ccb34e1662288f3c3530ef86a741..ae29b95d44f867a822ff2dd6adb294a181fbe656 100644 --- a/dal/block.rs +++ b/dal/block.rs @@ -79,8 +79,6 @@ pub struct DALBlock { pub fork: usize, pub isolate: bool, pub block: BlockDocument, - pub median_frame: usize, - pub second_tiercile_frame: usize, } impl DALBlock { @@ -195,7 +193,6 @@ impl DALBlock { pub fn get_stackables_blocks( currency: &str, db: &DuniterDB, - wotb_index: &HashMap<ed25519::PublicKey, NodeId>, current_blockstamp: &Blockstamp, ) -> Vec<DALBlock> { debug!("get_stackables_blocks() after {}", current_blockstamp); @@ -204,12 +201,9 @@ impl DALBlock { let (hashs, previous_hashs) = DALBlock::get_blocks_hashs_all_forks(db, &block_id); for (hash, previous_hash) in hashs.into_iter().zip(previous_hashs) { if previous_hash == current_blockstamp.hash.0 { - if let Some(dal_block) = DALBlock::get_block( - currency, - db, - wotb_index, - &Blockstamp { id: block_id, hash }, - ) { + if let Some(dal_block) = + DALBlock::get_block(currency, db, &Blockstamp { id: block_id, hash }) + { stackables_blocks.push(dal_block); } else { panic!(format!( @@ -237,12 +231,7 @@ impl DALBlock { } stackables_forks } - pub fn get_block( - currency: &str, - db: &DuniterDB, - wotb_index: &HashMap<ed25519::PublicKey, NodeId>, - blockstamp: &Blockstamp, - ) -> Option<DALBlock> { + pub fn get_block(currency: &str, db: &DuniterDB, blockstamp: &Blockstamp) -> Option<DALBlock> { let mut cursor = db .0 .prepare( @@ -410,7 +399,6 @@ impl DALBlock { revoked: parse_revocations( currency, db, - wotb_index, &hashmap_identities, row[25] .as_string() @@ -424,7 +412,6 @@ impl DALBlock { certifications: parse_certifications( currency, db, - wotb_index, &hashmap_identities, row[27] .as_string() @@ -444,8 +431,8 @@ impl DALBlock { nonce ), }, - median_frame: row[13].as_integer().unwrap_or(0) as usize, - second_tiercile_frame: row[14].as_integer().unwrap_or(0) as usize, + //median_frame: row[13].as_integer().unwrap_or(0) as usize, + //second_tiercile_frame: row[14].as_integer().unwrap_or(0) as usize, }) } else { None @@ -499,7 +486,7 @@ impl DALBlock { let mut current_frame_vec: Vec<_> = current_frame.values().cloned().collect(); current_frame_vec.sort_unstable(); - // Calculate median + /*// Calculate median let mut median_index = match self.block.issuers_count % 2 { 1 => (self.block.issuers_count / 2) + 1, _ => self.block.issuers_count / 2, @@ -517,7 +504,7 @@ impl DALBlock { if second_tiercile_index >= self.block.issuers_count { second_tiercile_index = self.block.issuers_count - 1; } - self.second_tiercile_frame = current_frame_vec[second_tiercile_index]; + self.second_tiercile_frame = current_frame_vec[second_tiercile_index];*/ } } } diff --git a/dal/identity.rs b/dal/identity.rs index b65dc0306157f0b8e9f1f715ac9bc387d51932cb..2486c628b3e9ff9ceeeb17fb42b06b52c6fbae7b 100644 --- a/dal/identity.rs +++ b/dal/identity.rs @@ -12,7 +12,6 @@ use std::collections::HashMap; #[derive(Debug, Clone)] pub struct DALIdentity { - pub wotb_id: NodeId, pub hash: String, pub state: isize, pub joined_on: Blockstamp, @@ -78,7 +77,6 @@ impl DALIdentity { pub fn create_identity( db: &DuniterDB, - wotb_id: NodeId, idty_doc: &IdentityDocument, current_blockstamp: Blockstamp, ) -> DALIdentity { @@ -87,7 +85,6 @@ impl DALIdentity { .expect("convert blockstamp to timestamp failure !"); DALIdentity { - wotb_id, hash: "0".to_string(), state: 0, joined_on: current_blockstamp, @@ -131,7 +128,7 @@ impl DALIdentity { pub fn renewal_identity( &mut self, db: &DuniterDB, - wotb_index: &HashMap<ed25519::PublicKey, NodeId>, + pubkey: &ed25519::PublicKey, renewal_blockstamp: &Blockstamp, renawal_timestamp: u64, revert: bool, @@ -142,9 +139,8 @@ impl DALIdentity { DALBlock::get_block( self.idty_doc.currency(), db, - wotb_index, &self.penultimate_renewed_on.clone(), - ).unwrap(), + ).expect("renewal_identity: Fail to get penultimate_renewed_block"), ); penultimate_renewed_block.clone().unwrap().block.median_time + super::constants::G1_PARAMS.ms_validity < renawal_timestamp @@ -160,7 +156,7 @@ impl DALIdentity { }; let mut cursor = db.0 .prepare( - "UPDATE identities SET state=?, last_renewed_on=?, expires_on=?, revokes_on=? WHERE wotb_id=?;", + "UPDATE identities SET state=?, last_renewed_on=?, expires_on=?, revokes_on=? WHERE pubkey=?;", ) .expect("Fail to renewal idty !") .cursor(); @@ -173,7 +169,7 @@ impl DALIdentity { sqlite::Value::Integer( (renawal_timestamp + (super::constants::G1_PARAMS.ms_validity * 2)) as i64, ), - sqlite::Value::Integer(self.wotb_id.0 as i64), + sqlite::Value::String(pubkey.to_string()), ]) .expect("Fail to renewal idty !"); } @@ -187,62 +183,92 @@ impl DALIdentity { .unwrap(); } - pub fn get_identity(currency: &str, db: &DuniterDB, wotb_id: &NodeId) -> Option<DALIdentity> { + pub fn get_identity( + currency: &str, + db: &DuniterDB, + pubkey: &ed25519::PublicKey, + ) -> Option<DALIdentity> { let mut cursor = db .0 .prepare( - "SELECT uid, pubkey, hash, sig, + "SELECT uid, hash, sig, state, created_on, joined_on, penultimate_renewed_on, last_renewed_on, - expires_on, revokes_on, expired_on, revoked_on FROM identities WHERE wotb_id=?;", + expires_on, revokes_on, expired_on, revoked_on FROM identities WHERE pubkey=?;", ) .expect("Fail to get idty !") .cursor(); cursor - .bind(&[sqlite::Value::Integer(wotb_id.0 as i64)]) + .bind(&[sqlite::Value::String(pubkey.to_string())]) .expect("Fail to get idty !"); - if let Some(row) = cursor.next().unwrap() { + if let Some(row) = cursor.next().expect("get_identity: cursor error") { let idty_doc_builder = IdentityDocumentBuilder { currency, - username: row[0].as_string().unwrap(), + username: row[0] + .as_string() + .expect("get_identity: fail to parse username"), blockstamp: &Blockstamp::from_string( - row[5] + row[4] .as_string() .expect("DB Error : idty created_on invalid !"), ).expect("DB Error : idty created_on invalid (2) !"), - issuer: &PublicKey::from_base58(row[1].as_string().unwrap()).unwrap(), + issuer: &pubkey, }; - let idty_sig = Signature::from_base64(row[3].as_string().unwrap()).unwrap(); + let idty_sig = Signature::from_base64( + row[2].as_string().expect("get_identity: fail to parse sig"), + ).expect("get_identity: fail to parse sig (2)"); let idty_doc = idty_doc_builder.build_with_signature(vec![idty_sig]); - let expired_on = match Blockstamp::from_string(row[11].as_string().unwrap()) { + let expired_on = match Blockstamp::from_string( + row[10] + .as_string() + .expect("get_identity: fail to parse expire on"), + ) { Ok(blockstamp) => Some(blockstamp), Err(_) => None, }; - let revoked_on = match Blockstamp::from_string(row[12].as_string().unwrap()) { + let revoked_on = match Blockstamp::from_string( + row[11] + .as_string() + .expect("get_identity: fail to parse revoked on"), + ) { Ok(blockstamp) => Some(blockstamp), Err(_) => None, }; Some(DALIdentity { - wotb_id: wotb_id.clone(), - hash: row[2].as_string().unwrap().to_string(), - state: row[4].as_integer().unwrap() as isize, + hash: row[2] + .as_string() + .expect("get_identity: fail to parse hash") + .to_string(), + state: row[3] + .as_integer() + .expect("get_identity: fail to parse state") as isize, joined_on: Blockstamp::from_string( - row[6] + row[5] .as_string() .expect("DB Error : idty joined_on invalid !"), ).expect("DB Error : idty joined_on invalid !"), penultimate_renewed_on: Blockstamp::from_string( - row[7] + row[6] .as_string() .expect("DB Error : idty penultimate_renewed_on invalid !"), ).expect( "DB Error : idty penultimate_renewed_on invalid (2) !", ), - last_renewed_on: Blockstamp::from_string(row[8].as_string().unwrap()).unwrap(), - expires_on: row[9].as_integer().unwrap() as u64, - revokes_on: row[10].as_integer().unwrap() as u64, + last_renewed_on: Blockstamp::from_string( + row[7] + .as_string() + .expect("get_identity: fail to parse last_renewed_on"), + ).expect("get_identity: fail to parse last_renewed_on (2)"), + expires_on: row[8] + .as_integer() + .expect("get_identity: fail to parse expires_on") + as u64, + revokes_on: row[9] + .as_integer() + .expect("get_identity: fail to parse revokes_on") + as u64, expired_on, revoked_on, idty_doc, diff --git a/dal/lib.rs b/dal/lib.rs index 7b6eb80e0d144737018cc3fd8ba683aa828fed35..7c1541dcc352dbe86ff8262f27ae691df90a9b81 100644 --- a/dal/lib.rs +++ b/dal/lib.rs @@ -44,11 +44,10 @@ pub mod parsers; pub mod tools; pub mod writers; -use duniter_crypto::keys::{ed25519, PublicKey, Signature}; +use duniter_crypto::keys::{PublicKey, Signature}; use duniter_documents::blockchain::v10::documents::BlockDocument; use duniter_documents::{BlockHash, BlockId, Blockstamp, Hash}; use duniter_wotb::NodeId; -use std::collections::HashMap; use std::fmt::Debug; use std::marker; use std::path::PathBuf; @@ -144,7 +143,7 @@ pub fn close_db(db: &DuniterDB) { pub fn get_uid(db: &DuniterDB, wotb_id: NodeId) -> Option<String> { let mut cursor: sqlite::Cursor = db .0 - .prepare("SELECT uid FROM identities WHERE wotb_id=? LIMIT 1;") + .prepare("SELECT uid FROM identities WHERE wotb_id=? AND state=0 LIMIT 1;") .expect("Request SQL get_current_block is wrong !") .cursor(); cursor @@ -217,11 +216,7 @@ pub fn new_get_current_block(db: &DuniterDB) -> Option<BlockDocument> { None } -pub fn get_current_block( - currency: &str, - db: &DuniterDB, - wotb_index: &HashMap<ed25519::PublicKey, NodeId>, -) -> Option<DALBlock> { +pub fn get_current_block(currency: &str, db: &DuniterDB) -> Option<DALBlock> { let mut cursor: sqlite::Cursor = db .0 .prepare("SELECT number, hash FROM blocks WHERE fork=0 ORDER BY median_time DESC LIMIT ?;") @@ -235,7 +230,7 @@ pub fn get_current_block( id: BlockId(row[0].as_integer().unwrap() as u32), hash: BlockHash(Hash::from_hex(row[1].as_string().unwrap()).unwrap()), }; - DALBlock::get_block(currency, db, wotb_index, &blockstamp) + DALBlock::get_block(currency, db, &blockstamp) } else { None } diff --git a/dal/parsers/blocks.rs b/dal/parsers/blocks.rs index e78ce51adb90701374d846cd4b3812839d117e45..780ff728f3cc4057a26ff2123f7f3f85eef6ff0b 100644 --- a/dal/parsers/blocks.rs +++ b/dal/parsers/blocks.rs @@ -8,6 +8,7 @@ use super::excluded::parse_exclusions_from_json_value; use super::identities::parse_compact_identity; use super::transactions::parse_transaction; use duniter_crypto::keys::{PublicKey, Signature}; +use duniter_documents::blockchain::v10::documents::membership::MembershipType; use duniter_documents::blockchain::v10::documents::BlockDocument; use duniter_documents::{BlockHash, BlockId, Hash}; @@ -60,6 +61,42 @@ pub fn parse_json_block(source: &serde_json::Value) -> Option<NetworkBlock> { for raw_idty in source.get("identities")?.as_array()? { identities.push(parse_compact_identity(¤cy, &raw_idty)?); } + let mut joiners = Vec::new(); + for joiner in super::memberships::parse_memberships_from_json_value( + ¤cy, + MembershipType::In(), + &source.get("joiners")?.as_array()?, + ) { + if let Ok(joiner) = joiner { + joiners.push(joiner); + } else { + return None; + } + } + let mut actives = Vec::new(); + for active in super::memberships::parse_memberships_from_json_value( + ¤cy, + MembershipType::In(), + &source.get("actives")?.as_array()?, + ) { + if let Ok(active) = active { + actives.push(active); + } else { + return None; + } + } + let mut leavers = Vec::new(); + for leaver in super::memberships::parse_memberships_from_json_value( + ¤cy, + MembershipType::Out(), + &source.get("leavers")?.as_array()?, + ) { + if let Ok(leaver) = leaver { + leavers.push(leaver); + } else { + return None; + } + } let mut transactions = Vec::new(); for json_tx in source.get("transactions")?.as_array()? { transactions.push(parse_transaction("g1", &json_tx)?); @@ -86,9 +123,9 @@ pub fn parse_json_block(source: &serde_json::Value) -> Option<NetworkBlock> { inner_hash, dividend, identities, - joiners: Vec::with_capacity(0), - actives: Vec::with_capacity(0), - leavers: Vec::with_capacity(0), + joiners, + actives, + leavers, revoked: Vec::with_capacity(0), excluded: parse_exclusions_from_json_value(&source.get("excluded")?.as_array()?), certifications: Vec::with_capacity(0), @@ -101,9 +138,6 @@ pub fn parse_json_block(source: &serde_json::Value) -> Option<NetworkBlock> { }; Some(NetworkBlock::V10(Box::new(NetworkBlockV10 { uncompleted_block_doc: block_doc, - joiners: source.get("joiners")?.as_array()?.clone(), - actives: source.get("actives")?.as_array()?.clone(), - leavers: source.get("leavers")?.as_array()?.clone(), revoked: source.get("revoked")?.as_array()?.clone(), certifications: source.get("certifications")?.as_array()?.clone(), }))) diff --git a/dal/parsers/certifications.rs b/dal/parsers/certifications.rs index ee395afd0df1ee54bc60ac4d8ee2ddb8eea020ab..a62b0a4ad73c69b00f27bff8ee42d97574b61048 100644 --- a/dal/parsers/certifications.rs +++ b/dal/parsers/certifications.rs @@ -6,34 +6,65 @@ use super::super::block::DALBlock; use super::super::identity::DALIdentity; use super::super::DuniterDB; use duniter_crypto::keys::{ed25519, PublicKey, Signature}; -use duniter_documents::blockchain::v10::documents::certification::CertificationDocumentBuilder; -use duniter_documents::blockchain::v10::documents::{CertificationDocument, IdentityDocument}; +use duniter_documents::blockchain::v10::documents::certification::{ + CertificationDocumentBuilder, CompactCertificationDocument, +}; +use duniter_documents::blockchain::v10::documents::{ + CertificationDocument, IdentityDocument, TextDocumentFormat, +}; use duniter_documents::blockchain::{Document, DocumentBuilder}; use duniter_documents::{BlockHash, BlockId, Blockstamp, Hash}; -use duniter_wotb::NodeId; use std::collections::HashMap; +pub fn parse_certifications_into_compact( + json_certs: &Vec<serde_json::Value>, +) -> Vec<TextDocumentFormat<CertificationDocument>> { + let mut certifications: Vec<TextDocumentFormat<CertificationDocument>> = Vec::new(); + for certification in json_certs.iter() { + let certifications_datas: Vec<&str> = certification + .as_str() + .expect("Receive block in wrong format : fail to split cert !") + .split(':') + .collect(); + if certifications_datas.len() == 4 { + certifications.push(TextDocumentFormat::Compact(CompactCertificationDocument { + issuer: PublicKey::from_base58(certifications_datas[0]) + .expect("Receive block in wrong format : fail to parse issuer !"), + target: PublicKey::from_base58(certifications_datas[1]) + .expect("Receive block in wrong format : fail to parse target !"), + block_number: BlockId( + certifications_datas[2] + .parse() + .expect("Receive block in wrong format : fail to parse block number !"), + ), + signature: Signature::from_base64(certifications_datas[3]) + .expect("Receive block in wrong format : fail to parse signature !"), + })); + } + } + certifications +} + pub fn parse_certifications_from_json_value( currency: &str, db: &DuniterDB, - wotb_index: &HashMap<ed25519::PublicKey, NodeId>, block_identities: &HashMap<ed25519::PublicKey, IdentityDocument>, array_certifications: &[serde_json::Value], -) -> Vec<CertificationDocument> { - let mut certifications: Vec<CertificationDocument> = Vec::new(); +) -> Vec<TextDocumentFormat<CertificationDocument>> { + let mut certifications: Vec<TextDocumentFormat<CertificationDocument>> = Vec::new(); for certification in array_certifications.iter() { - let certification_datas: Vec<&str> = certification.as_str().unwrap().split(':').collect(); + let certification_datas: Vec<&str> = certification + .as_str() + .expect("Fail to parse certs : json isn't str !") + .split(':') + .collect(); if certification_datas.len() == 4 { let target = PublicKey::from_base58(certification_datas[1]) .expect("Fail to parse cert target !"); let target_idty_doc: IdentityDocument = match block_identities.get(&target) { Some(idty_doc) => idty_doc.clone(), None => { - let target_wotb_id = wotb_index.get(&target).expect(&format!( - "target identity {} not found in wotb index !", - target.to_string() - )); - let dal_idty = DALIdentity::get_identity(currency, db, target_wotb_id) + let dal_idty = DALIdentity::get_identity(currency, db, &target) .expect("target identity not found in bdd !"); dal_idty.idty_doc } @@ -53,7 +84,7 @@ pub fn parse_certifications_from_json_value( hash: if cert_blockstamp_id == BlockId(0) { BlockHash(Hash::from_hex( "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", - ).unwrap()) + ).expect("Fail to parse cert : invalid genesis hash")) } else { DALBlock::get_block_hash(db, &cert_blockstamp_id).expect(&format!( "Fatal Error : Block {} not found in bdd !", @@ -68,7 +99,9 @@ pub fn parse_certifications_from_json_value( }; let cert_sig = Signature::from_base64(certification_datas[3]).expect("Fail to parse cert sig !"); - certifications.push(cert_builder.build_with_signature(vec![cert_sig])); + certifications.push(TextDocumentFormat::Complete( + cert_builder.build_with_signature(vec![cert_sig]), + )); } } certifications @@ -77,19 +110,20 @@ pub fn parse_certifications_from_json_value( pub fn parse_certifications( currency: &str, db: &DuniterDB, - wotb_index: &HashMap<ed25519::PublicKey, NodeId>, block_identities: &HashMap<ed25519::PublicKey, IdentityDocument>, json_datas: &str, -) -> Option<Vec<CertificationDocument>> { - let raw_certifications: serde_json::Value = serde_json::from_str(json_datas).unwrap(); +) -> Option<Vec<TextDocumentFormat<CertificationDocument>>> { + let raw_certifications: serde_json::Value = + serde_json::from_str(json_datas).expect("Fail to parse certs: str isn't json !"); if raw_certifications.is_array() { Some(parse_certifications_from_json_value( currency, db, - wotb_index, block_identities, - raw_certifications.as_array().unwrap(), + raw_certifications + .as_array() + .expect("Fail to parse certs: json datas must be an array !"), )) } else { None diff --git a/dal/parsers/revoked.rs b/dal/parsers/revoked.rs index dc24d1b2d1df5a3cba065d6b8ea8baec13dedcd5..28f12568284da1ef35e2e2583101000737babde5 100644 --- a/dal/parsers/revoked.rs +++ b/dal/parsers/revoked.rs @@ -1,32 +1,55 @@ extern crate serde_json; use duniter_crypto::keys::{ed25519, PublicKey, Signature}; -use duniter_documents::blockchain::v10::documents::revocation::RevocationDocumentBuilder; -use duniter_documents::blockchain::v10::documents::{IdentityDocument, RevocationDocument}; +use duniter_documents::blockchain::v10::documents::revocation::{ + CompactRevocationDocument, RevocationDocumentBuilder, +}; +use duniter_documents::blockchain::v10::documents::{ + IdentityDocument, RevocationDocument, TextDocumentFormat, +}; use duniter_documents::blockchain::{Document, DocumentBuilder}; -use duniter_wotb::NodeId; use super::super::identity::DALIdentity; use super::super::DuniterDB; use std::collections::HashMap; +pub fn parse_revocations_into_compact( + json_recocations: &Vec<serde_json::Value>, +) -> Vec<TextDocumentFormat<RevocationDocument>> { + let mut revocations: Vec<TextDocumentFormat<RevocationDocument>> = Vec::new(); + for revocation in json_recocations.iter() { + let revocations_datas: Vec<&str> = revocation + .as_str() + .expect("Receive block in wrong format !") + .split(':') + .collect(); + if revocations_datas.len() == 2 { + revocations.push(TextDocumentFormat::Compact(CompactRevocationDocument { + issuer: PublicKey::from_base58(revocations_datas[0]) + .expect("Receive block in wrong format !"), + signature: Signature::from_base64(revocations_datas[1]) + .expect("Receive block in wrong format !"), + })); + } + } + revocations +} + pub fn parse_revocations( currency: &str, db: &DuniterDB, - wotb_index: &HashMap<ed25519::PublicKey, NodeId>, block_identities: &HashMap<ed25519::PublicKey, IdentityDocument>, json_datas: &str, -) -> Option<Vec<RevocationDocument>> { - let raw_certifications: serde_json::Value = serde_json::from_str(json_datas).unwrap(); +) -> Option<Vec<TextDocumentFormat<RevocationDocument>>> { + let raw_revocations: serde_json::Value = serde_json::from_str(json_datas).unwrap(); - if raw_certifications.is_array() { + if raw_revocations.is_array() { Some(parse_revocations_from_json_value( currency, db, - wotb_index, block_identities, - raw_certifications.as_array().unwrap(), + raw_revocations.as_array().unwrap(), )) } else { None @@ -36,11 +59,10 @@ pub fn parse_revocations( pub fn parse_revocations_from_json_value( currency: &str, db: &DuniterDB, - wotb_index: &HashMap<ed25519::PublicKey, NodeId>, block_identities: &HashMap<ed25519::PublicKey, IdentityDocument>, array_revocations: &[serde_json::Value], -) -> Vec<RevocationDocument> { - let mut revocations: Vec<RevocationDocument> = Vec::new(); +) -> Vec<TextDocumentFormat<RevocationDocument>> { + let mut revocations: Vec<TextDocumentFormat<RevocationDocument>> = Vec::new(); for revocation in array_revocations.iter() { let revocations_datas: Vec<&str> = revocation.as_str().unwrap().split(':').collect(); if revocations_datas.len() == 2 { @@ -49,8 +71,7 @@ pub fn parse_revocations_from_json_value( let idty_doc: IdentityDocument = match block_identities.get(&idty_pubkey) { Some(idty_doc) => idty_doc.clone(), None => { - let idty_wotb_id = wotb_index.get(&idty_pubkey).unwrap(); - let dal_idty = DALIdentity::get_identity(currency, db, idty_wotb_id).unwrap(); + let dal_idty = DALIdentity::get_identity(currency, db, &idty_pubkey).unwrap(); dal_idty.idty_doc } }; @@ -62,7 +83,9 @@ pub fn parse_revocations_from_json_value( identity_sig: &idty_doc.signatures()[0], }; let revoc_sig = Signature::from_base64(revocations_datas[1]).unwrap(); - revocations.push(revoc_doc_builder.build_with_signature(vec![revoc_sig])); + revocations.push(TextDocumentFormat::Complete( + revoc_doc_builder.build_with_signature(vec![revoc_sig]), + )); } } revocations diff --git a/dal/writers/block.rs b/dal/writers/block.rs index 906dbdfe6a55b372548f6641753bb0de94548260..aeb4d4d87415c38b6330c57d415032b79f03505b 100644 --- a/dal/writers/block.rs +++ b/dal/writers/block.rs @@ -15,9 +15,6 @@ pub fn write_network_block( block: &BlockDocument, fork: usize, isolate: bool, - joiners: &Vec<serde_json::Value>, - actives: &Vec<serde_json::Value>, - leavers: &Vec<serde_json::Value>, revoked: &Vec<serde_json::Value>, certifications: &Vec<serde_json::Value>, ) { @@ -32,8 +29,8 @@ pub fn write_network_block( block.previous_hash.to_string(), block.inner_hash.unwrap().to_string(), block.dividend.unwrap_or(0), serde_json::to_string(&block.identities).unwrap(), - serde_json::to_string(joiners).unwrap(), serde_json::to_string(actives).unwrap(), - serde_json::to_string(leavers).unwrap(), serde_json::to_string(revoked).unwrap(), + serde_json::to_string(&block.joiners).unwrap(), serde_json::to_string(&block.actives).unwrap(), + serde_json::to_string(&block.leavers).unwrap(), serde_json::to_string(revoked).unwrap(), serde_json::to_string(&block.excluded).unwrap(), serde_json::to_string(certifications).unwrap(), serde_json::to_string(&block.transactions).unwrap() )) diff --git a/dal/writers/certification.rs b/dal/writers/certification.rs index 511c776612dba820ca59d7e7860580cba3b703a2..03ec2db95ec3c77b0a9cdb7fb7acf4148b08342a 100644 --- a/dal/writers/certification.rs +++ b/dal/writers/certification.rs @@ -4,12 +4,11 @@ extern crate sqlite; use super::super::DuniterDB; use duniter_crypto::keys::ed25519; -use duniter_documents::blockchain::v10::documents::CertificationDocument; -use duniter_documents::blockchain::Document; +use duniter_documents::blockchain::v10::documents::certification::CompactCertificationDocument; use duniter_documents::Blockstamp; pub fn write_certification( - cert: &CertificationDocument, + cert: &CompactCertificationDocument, db: &DuniterDB, written_blockstamp: Blockstamp, written_timestamp: u64, @@ -17,11 +16,11 @@ pub fn write_certification( let mut cursor = db .0 .prepare("SELECT median_time FROM blocks WHERE number=? AND fork=0 LIMIT 1;") - .unwrap() + .expect("invalid write_certification sql request") .cursor(); cursor - .bind(&[sqlite::Value::Integer(cert.blockstamp().id.0 as i64)]) + .bind(&[sqlite::Value::Integer(cert.block_number.0 as i64)]) .expect("convert blockstamp to timestamp failure at step 1 !"); let mut created_timestamp: i64 = 0; @@ -29,18 +28,20 @@ pub fn write_certification( .next() .expect("convert blockstamp to timestamp failure at step 2 !") { - created_timestamp = row[0].as_integer().unwrap(); + created_timestamp = row[0] + .as_integer() + .expect("Fail to write cert, impossible to get created_timestamp !"); } db.0 .execute( format!("INSERT INTO certifications (pubkey_from, pubkey_to, created_on, signature, written_on, expires_on, chainable_on) VALUES ('{}', '{}', '{}', '{}', '{}', {}, {});", - cert.issuers()[0], cert.target(), cert.blockstamp().id.0, cert.signatures()[0], + cert.issuer, cert.target, cert.block_number.0, cert.signature, written_blockstamp.to_string(), created_timestamp+super::super::constants::G1_PARAMS.sig_validity, written_timestamp+super::super::constants::G1_PARAMS.sig_period )) - .unwrap(); + .expect("Fail to execute INSERT certification !"); } pub fn remove_certification(from: ed25519::PublicKey, to: ed25519::PublicKey, db: &DuniterDB) { @@ -49,5 +50,5 @@ pub fn remove_certification(from: ed25519::PublicKey, to: ed25519::PublicKey, db "DELETE FROM certifications WHERE pubkey_from={} AND pubkey_to={}", from, to )) - .unwrap(); + .expect("Fail to execute DELETE certification !"); } diff --git a/dal/writers/identity.rs b/dal/writers/identity.rs index c000d945cabfc3edf74f155dad765dad2b925d48..ea106fce344f2489d635bf26b09c49446fc67c4e 100644 --- a/dal/writers/identity.rs +++ b/dal/writers/identity.rs @@ -1,12 +1,15 @@ +extern crate duniter_wotb; extern crate sqlite; use super::super::identity::DALIdentity; use super::super::DuniterDB; use duniter_documents::blockchain::Document; use duniter_documents::Blockstamp; +use duniter_wotb::NodeId; pub fn write( idty: &DALIdentity, + wotb_id: &NodeId, db: &DuniterDB, _written_blockstamp: Blockstamp, _written_timestamp: u64, @@ -22,7 +25,7 @@ pub fn write( db.0 .execute( format!("INSERT INTO identities (wotb_id, uid, pubkey, hash, sig, state, created_on, joined_on, penultimate_renewed_on, last_renewed_on, expires_on, revokes_on, expired_on, revoked_on) VALUES ({}, '{}', '{}', '{}', '{}', {}, '{}', '{}', '{}', '{}', {}, {}, '{}', '{}');", - idty.wotb_id.0, idty.idty_doc.username(), idty.idty_doc.issuers()[0], idty.hash, + (*wotb_id).0, idty.idty_doc.username(), idty.idty_doc.issuers()[0], idty.hash, idty.idty_doc.signatures()[0], idty.state, idty.idty_doc.blockstamp().to_string(), idty.joined_on.to_string(), diff --git a/dal/writers/mod.rs b/dal/writers/mod.rs index 41219969b14c6d6fc9368ea0e3eb77513d41ebd6..aba7f80035e06d003fbf4387999ea70411845262 100644 --- a/dal/writers/mod.rs +++ b/dal/writers/mod.rs @@ -1,3 +1,4 @@ pub mod block; pub mod certification; pub mod identity; +pub mod requests; diff --git a/dal/writers/requests.rs b/dal/writers/requests.rs new file mode 100644 index 0000000000000000000000000000000000000000..c48b36a3e385cd6cc6929fb42bcb248c235ce492 --- /dev/null +++ b/dal/writers/requests.rs @@ -0,0 +1,83 @@ +extern crate duniter_crypto; +extern crate duniter_documents; +extern crate duniter_wotb; +extern crate serde; +extern crate serde_json; +extern crate sqlite; + +use self::duniter_crypto::keys::ed25519; +use self::duniter_documents::blockchain::v10::documents::certification::CompactCertificationDocument; +use self::duniter_documents::blockchain::v10::documents::identity::IdentityDocument; +use self::duniter_documents::Blockstamp; +use self::duniter_wotb::NodeId; +use super::super::block::DALBlock; +use super::super::identity::DALIdentity; +use super::super::DuniterDB; + +#[derive(Debug)] +/// Contain a pending write request for blockchain database +pub enum DBWriteRequest { + /// Newcomer + CreateIdentity(NodeId, Blockstamp, u64, IdentityDocument), + /// Active + RenewalIdentity(ed25519::PublicKey, Blockstamp, u64), + /// Excluded + ExcludeIdentity(NodeId, Blockstamp, u64), + /// Revoked + RevokeIdentity(NodeId, Blockstamp, u64), + /// Certification + CreateCert(Blockstamp, u64, CompactCertificationDocument), + /// Certification expiry + CertExpiry(NodeId, NodeId, Blockstamp, u64), + /// Write block + WriteBlock(DALBlock), + /// Revert block + RevertBlock(DALBlock), +} + +impl DBWriteRequest { + pub fn apply(&self, currency: &str, db: &DuniterDB) { + match *self { + DBWriteRequest::CreateIdentity( + ref wotb_id, + ref blockstamp, + ref median_time, + ref idty_doc, + ) => { + trace!("DBWriteRequest::CreateIdentity..."); + let idty = DALIdentity::create_identity(db, idty_doc, blockstamp.clone()); + super::identity::write(&idty, wotb_id, db, blockstamp.clone(), *median_time); + trace!("DBWriteRequest::CreateIdentity...finish."); + } + DBWriteRequest::RenewalIdentity(ref pubkey, ref blockstamp, ref median_time) => { + trace!("DBWriteRequest::RenewalIdentity..."); + let mut idty = DALIdentity::get_identity(currency, db, pubkey) + .expect("Fatal error : impossible ton renewal an identidy that don't exist !"); + idty.renewal_identity(db, pubkey, blockstamp, *median_time, false); + trace!("DBWriteRequest::RenewalIdentity..."); + } + DBWriteRequest::ExcludeIdentity(ref wotb_id, ref blockstamp, ref _median_time) => { + DALIdentity::exclude_identity(db, *wotb_id, *blockstamp, false); + } + DBWriteRequest::RevokeIdentity(ref wotb_id, ref blockstamp, ref _median_time) => { + DALIdentity::revoke_identity(db, *wotb_id, blockstamp, false); + } + DBWriteRequest::CreateCert(ref blockstamp, ref median_time, ref compact_cert) => { + trace!("DBWriteRequest::CreateCert..."); + super::certification::write_certification( + compact_cert, + db, + blockstamp.clone(), + *median_time, + ); + trace!("DBWriteRequest::CreateCert...finish"); + } + DBWriteRequest::WriteBlock(ref dal_block) => { + trace!("DBWriteRequest::WriteBlock..."); + super::block::write(db, &dal_block.block, dal_block.fork, dal_block.isolate); + trace!("DBWriteRequest::WriteBlock...finish"); + } + _ => {} + } + } +} diff --git a/documents/blockchain/v10/documents/block.rs b/documents/blockchain/v10/documents/block.rs index 0305af99761abe685cafcc3d3c8d1f2c839398b5..1b51c4689331f4b1bbf849d348a3ef7428577222 100644 --- a/documents/blockchain/v10/documents/block.rs +++ b/documents/blockchain/v10/documents/block.rs @@ -24,7 +24,7 @@ use blockchain::v10::documents::identity::IdentityDocument; use blockchain::v10::documents::membership::MembershipDocument; use blockchain::v10::documents::revocation::RevocationDocument; use blockchain::v10::documents::transaction::TransactionDocument; -use blockchain::v10::documents::{TextDocument, V10Document}; +use blockchain::v10::documents::*; use blockchain::{BlockchainProtocol, Document, IntoSpecializedDocument}; use {BlockHash, BlockId, Blockstamp, Hash}; @@ -130,11 +130,11 @@ pub struct BlockDocument { /// Leavers pub leavers: Vec<MembershipDocument>, /// Revokeds - pub revoked: Vec<RevocationDocument>, + pub revoked: Vec<TextDocumentFormat<RevocationDocument>>, /// Excludeds pub excluded: Vec<ed25519::PublicKey>, /// Certifications - pub certifications: Vec<CertificationDocument>, + pub certifications: Vec<TextDocumentFormat<CertificationDocument>>, /// Transactions pub transactions: Vec<TransactionDocument>, /// Part to sign @@ -146,9 +146,6 @@ impl BlockDocument { pub fn compute_inner_hash(&mut self) { let mut sha256 = Sha256::new(); let inner_text = self.generate_compact_inner_text(); - /*if self.number.0 == 46473 { - println!("#46473 raw_format=\"{}\"", inner_text); - }*/ sha256.input_str(&inner_text); self.inner_hash = Some(Hash::from_hex(&sha256.result_str()).unwrap()); } @@ -176,7 +173,8 @@ impl BlockDocument { )); self.hash = Some(BlockHash(Hash::from_hex(&sha256.result_str()).unwrap())); } - fn generate_compact_inner_text(&self) -> String { + /// Generate compact inner text (for compute inner_hash) + pub fn generate_compact_inner_text(&self) -> String { let mut identities_str = String::from(""); for identity in self.identities.clone() { identities_str.push_str("\n"); @@ -205,7 +203,7 @@ impl BlockDocument { let mut revokeds_str = String::from(""); for revocation in self.revoked.clone() { revokeds_str.push_str("\n"); - revokeds_str.push_str(&revocation.generate_compact_text()); + revokeds_str.push_str(&revocation.as_compact_text()); } let mut excludeds_str = String::from(""); for exclusion in self.excluded.clone() { @@ -215,7 +213,7 @@ impl BlockDocument { let mut certifications_str = String::from(""); for certification in self.certifications.clone() { certifications_str.push_str("\n"); - certifications_str.push_str(&certification.generate_compact_text()); + certifications_str.push_str(&certification.as_compact_text()); } let mut transactions_str = String::from(""); for transaction in self.transactions.clone() { @@ -313,12 +311,8 @@ impl Document for BlockDocument { } } -impl TextDocument for BlockDocument { - fn as_text(&self) -> &str { - panic!(); - } - - fn generate_compact_text(&self) -> String { +impl CompactTextDocument for BlockDocument { + fn as_compact_text(&self) -> String { let compact_inner_text = self.generate_compact_inner_text(); format!( "{}InnerHash: {}\nNonce: ", @@ -328,6 +322,18 @@ impl TextDocument for BlockDocument { } } +impl TextDocument for BlockDocument { + type CompactTextDocument_ = BlockDocument; + + fn as_text(&self) -> &str { + panic!(); + } + + fn to_compact_document(&self) -> Self::CompactTextDocument_ { + self.clone() + } +} + impl IntoSpecializedDocument<BlockchainProtocol> for BlockDocument { fn into_specialized(self) -> BlockchainProtocol { BlockchainProtocol::V10(Box::new(V10Document::Block(Box::new(self)))) @@ -506,7 +512,7 @@ a9PHPuSfw7jW8FRQHXFsGi/bnLjbtDnTYvEVgUC9u0WlR7GVofa+Xb+l5iy6NwuEXiwvueAkf08wPVY8 leavers: Vec::new(), revoked: Vec::new(), excluded: Vec::new(), - certifications: vec![cert1], + certifications: vec![TextDocumentFormat::Complete(cert1)], transactions: vec![tx1, tx2], inner_hash_and_nonce_str: String::new(), }; diff --git a/documents/blockchain/v10/documents/certification.rs b/documents/blockchain/v10/documents/certification.rs index b3e8857ccbe90c902b1e7d8bc307cb61e780aec3..842591838c7eb796bb28cfc5a76bd2e816fffffc 100644 --- a/documents/blockchain/v10/documents/certification.rs +++ b/documents/blockchain/v10/documents/certification.rs @@ -21,11 +21,9 @@ use self::serde::ser::{Serialize, Serializer}; use duniter_crypto::keys::{ed25519, PublicKey, Signature}; use regex::Regex; -use blockchain::v10::documents::{ - StandardTextDocumentParser, TextDocument, TextDocumentBuilder, V10Document, - V10DocumentParsingError, -}; +use blockchain::v10::documents::*; use blockchain::{BlockchainProtocol, Document, DocumentBuilder, IntoSpecializedDocument}; +use BlockId; use Blockstamp; lazy_static! { @@ -34,6 +32,31 @@ lazy_static! { ).unwrap(); } +#[derive(Debug, Copy, Clone)] +/// Wrap an Compact Revocation document (in block content) +pub struct CompactCertificationDocument { + /// Issuer + pub issuer: ed25519::PublicKey, + /// Target + pub target: ed25519::PublicKey, + /// Blockstamp + pub block_number: BlockId, + /// Signature + pub signature: ed25519::Signature, +} + +impl CompactTextDocument for CompactCertificationDocument { + fn as_compact_text(&self) -> String { + format!( + "{issuer}:{target}:{block_number}:{signature}", + issuer = self.issuer, + target = self.target, + block_number = self.block_number.0, + signature = self.signature, + ) + } +} + /// Wrap an Certification document. /// /// Must be created by parsing a text document or using a builder. @@ -109,27 +132,28 @@ impl Document for CertificationDocument { } impl TextDocument for CertificationDocument { + type CompactTextDocument_ = CompactCertificationDocument; + fn as_text(&self) -> &str { &self.text } - fn generate_compact_text(&self) -> String { - format!( - "{issuer}:{target}:{block_number}:{signature}", - issuer = self.issuers[0], - target = self.target, - block_number = self.blockstamp.id.0, - signature = self.signatures[0], - ) + fn to_compact_document(&self) -> Self::CompactTextDocument_ { + CompactCertificationDocument { + issuer: self.issuers[0], + target: self.target, + block_number: self.blockstamp().id, + signature: self.signatures()[0], + } } } -impl Serialize for CertificationDocument { +impl Serialize for TextDocumentFormat<CertificationDocument> { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, { - serializer.serialize_str(&self.generate_compact_text()) + serializer.serialize_str(&self.as_compact_text()) } } diff --git a/documents/blockchain/v10/documents/identity.rs b/documents/blockchain/v10/documents/identity.rs index 6e986565b04dc04222ff93ed31b3509b7fb4b7be..40bd02bb3c7dc5c1c7d52938028b8f25e14998e0 100644 --- a/documents/blockchain/v10/documents/identity.rs +++ b/documents/blockchain/v10/documents/identity.rs @@ -21,10 +21,7 @@ use self::serde::ser::{Serialize, Serializer}; use duniter_crypto::keys::{ed25519, PublicKey}; use regex::Regex; -use blockchain::v10::documents::{ - StandardTextDocumentParser, TextDocument, TextDocumentBuilder, V10Document, - V10DocumentParsingError, -}; +use blockchain::v10::documents::*; use blockchain::{BlockchainProtocol, Document, DocumentBuilder, IntoSpecializedDocument}; use Blockstamp; @@ -93,12 +90,8 @@ impl Document for IdentityDocument { } } -impl TextDocument for IdentityDocument { - fn as_text(&self) -> &str { - &self.text - } - - fn generate_compact_text(&self) -> String { +impl CompactTextDocument for IdentityDocument { + fn as_compact_text(&self) -> String { format!( "{issuer}:{signature}:{blockstamp}:{username}", issuer = self.issuers[0], @@ -109,6 +102,18 @@ impl TextDocument for IdentityDocument { } } +impl TextDocument for IdentityDocument { + type CompactTextDocument_ = IdentityDocument; + + fn as_text(&self) -> &str { + &self.text + } + + fn to_compact_document(&self) -> Self::CompactTextDocument_ { + self.clone() + } +} + impl Serialize for IdentityDocument { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where diff --git a/documents/blockchain/v10/documents/membership.rs b/documents/blockchain/v10/documents/membership.rs index 0cc53d51b5521471a4aa2719963e94a18704dbdf..2e313601e9f938d431ba33800582234a9ab15382 100644 --- a/documents/blockchain/v10/documents/membership.rs +++ b/documents/blockchain/v10/documents/membership.rs @@ -21,10 +21,7 @@ use self::serde::ser::{Serialize, Serializer}; use duniter_crypto::keys::{ed25519, PublicKey}; use regex::Regex; -use blockchain::v10::documents::{ - StandardTextDocumentParser, TextDocument, TextDocumentBuilder, V10Document, - V10DocumentParsingError, -}; +use blockchain::v10::documents::*; use blockchain::{BlockchainProtocol, Document, DocumentBuilder, IntoSpecializedDocument}; use Blockstamp; @@ -114,12 +111,8 @@ impl Document for MembershipDocument { } } -impl TextDocument for MembershipDocument { - fn as_text(&self) -> &str { - &self.text - } - - fn generate_compact_text(&self) -> String { +impl CompactTextDocument for MembershipDocument { + fn as_compact_text(&self) -> String { format!( "{issuer}:{signature}:{blockstamp}:{idty_blockstamp}:{username}", issuer = self.issuers[0], @@ -131,6 +124,18 @@ impl TextDocument for MembershipDocument { } } +impl TextDocument for MembershipDocument { + type CompactTextDocument_ = MembershipDocument; + + fn as_text(&self) -> &str { + &self.text + } + + fn to_compact_document(&self) -> Self::CompactTextDocument_ { + self.clone() + } +} + impl Serialize for MembershipDocument { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where diff --git a/documents/blockchain/v10/documents/mod.rs b/documents/blockchain/v10/documents/mod.rs index 3557543aabb1be765eb61f36933a895a55c5eba1..495190dd55e0d22a5e671b0c16f1cc8e6e0f2405 100644 --- a/documents/blockchain/v10/documents/mod.rs +++ b/documents/blockchain/v10/documents/mod.rs @@ -42,6 +42,8 @@ pub use blockchain::v10::documents::transaction::{ TransactionDocument, TransactionDocumentBuilder, TransactionDocumentParser, }; +use std::marker::Sized; + // Use of lazy_static so the regex is only compiled at first use. lazy_static! { static ref DOCUMENT_REGEX: Regex = Regex::new( @@ -54,6 +56,25 @@ lazy_static! { static ref SIGNATURES_REGEX: Regex = Regex::new("[[:alnum:]+/=]+\n?").unwrap(); } +#[derive(Debug, Clone)] +/// Contains a document in full or compact format +pub enum TextDocumentFormat<D: TextDocument> { + /// Complete format (Allows to check the validity of the signature) + Complete(D), + /// Format present in the blocks (does not always allow to verify the signature) + Compact(D::CompactTextDocument_), +} + +impl<D: TextDocument> TextDocumentFormat<D> { + /// To compact document + pub fn to_compact_document(&self) -> D::CompactTextDocument_ { + match *self { + TextDocumentFormat::Complete(ref doc) => doc.to_compact_document(), + TextDocumentFormat::Compact(ref compact_doc) => (*compact_doc).clone(), + } + } +} + /// List of wrapped document types. /// /// > TODO Add wrapped types in enum variants. @@ -78,8 +99,30 @@ pub enum V10Document { Revocation(Box<RevocationDocument>), } +/// Trait for a compact V10 document. +pub trait CompactTextDocument: Sized + Clone { + /// Generate document compact text. + /// the compact format is the one used in the blocks. + /// + /// - Don't contains leading signatures + /// - Contains line breaks on all line. + fn as_compact_text(&self) -> String; +} + +impl<D: TextDocument> CompactTextDocument for TextDocumentFormat<D> { + fn as_compact_text(&self) -> String { + match *self { + TextDocumentFormat::Complete(ref doc) => doc.generate_compact_text(), + TextDocumentFormat::Compact(ref doc) => doc.as_compact_text(), + } + } +} + /// Trait for a V10 document. pub trait TextDocument: Document<PublicKey = ed25519::PublicKey, CurrencyType = str> { + /// Type of associated compact document. + type CompactTextDocument_: CompactTextDocument; + /// Return document as text. fn as_text(&self) -> &str; @@ -100,12 +143,19 @@ pub trait TextDocument: Document<PublicKey = ed25519::PublicKey, CurrencyType = text } + /// Generate compact document. + /// the compact format is the one used in the blocks. + /// - Don't contains leading signatures + fn to_compact_document(&self) -> Self::CompactTextDocument_; + /// Generate document compact text. /// the compact format is the one used in the blocks. /// /// - Don't contains leading signatures /// - Contains line breaks on all line. - fn generate_compact_text(&self) -> String; + fn generate_compact_text(&self) -> String { + self.to_compact_document().as_compact_text() + } } /// Trait for a V10 document builder. diff --git a/documents/blockchain/v10/documents/revocation.rs b/documents/blockchain/v10/documents/revocation.rs index b954ae13b2ead8be53710732e66daadf3ae3eb26..d40d97046fe03fb391ae42598985aa8c143ffcde 100644 --- a/documents/blockchain/v10/documents/revocation.rs +++ b/documents/blockchain/v10/documents/revocation.rs @@ -21,10 +21,7 @@ use self::serde::ser::{Serialize, Serializer}; use duniter_crypto::keys::{ed25519, PublicKey, Signature}; use regex::Regex; -use blockchain::v10::documents::{ - StandardTextDocumentParser, TextDocument, TextDocumentBuilder, V10Document, - V10DocumentParsingError, -}; +use blockchain::v10::documents::*; use blockchain::{BlockchainProtocol, Document, DocumentBuilder, IntoSpecializedDocument}; use Blockstamp; @@ -37,6 +34,25 @@ lazy_static! { ).unwrap(); } +#[derive(Debug, Copy, Clone)] +/// Wrap an Compact Revocation document (in block content) +pub struct CompactRevocationDocument { + /// Issuer + pub issuer: ed25519::PublicKey, + /// Signature + pub signature: ed25519::Signature, +} + +impl CompactTextDocument for CompactRevocationDocument { + fn as_compact_text(&self) -> String { + format!( + "{issuer}:{signature}", + issuer = self.issuer, + signature = self.signature, + ) + } +} + /// Wrap an Revocation document. /// /// Must be created by parsing a text document or using a builder. @@ -98,25 +114,26 @@ impl Document for RevocationDocument { } impl TextDocument for RevocationDocument { + type CompactTextDocument_ = CompactRevocationDocument; + fn as_text(&self) -> &str { &self.text } - fn generate_compact_text(&self) -> String { - format!( - "{issuer}:{signature}", - issuer = self.issuers[0], - signature = self.signatures[0], - ) + fn to_compact_document(&self) -> Self::CompactTextDocument_ { + CompactRevocationDocument { + issuer: self.issuers[0], + signature: self.signatures[0], + } } } -impl Serialize for RevocationDocument { +impl Serialize for TextDocumentFormat<RevocationDocument> { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, { - serializer.serialize_str(&self.generate_compact_text()) + serializer.serialize_str(&self.as_compact_text()) } } diff --git a/documents/blockchain/v10/documents/transaction.rs b/documents/blockchain/v10/documents/transaction.rs index efcf04a7e1252862277bde9898b73b450bf415ee..992640c8a6ce937f77e9e703803fa1791f6a8835 100644 --- a/documents/blockchain/v10/documents/transaction.rs +++ b/documents/blockchain/v10/documents/transaction.rs @@ -25,10 +25,7 @@ use regex::RegexBuilder; use self::serde::ser::{Serialize, Serializer}; -use blockchain::v10::documents::{ - StandardTextDocumentParser, TextDocument, TextDocumentBuilder, V10Document, - V10DocumentParsingError, -}; +use blockchain::v10::documents::*; use blockchain::{BlockchainProtocol, Document, DocumentBuilder, IntoSpecializedDocument}; use Blockstamp; @@ -442,12 +439,8 @@ impl Document for TransactionDocument { } } -impl TextDocument for TransactionDocument { - fn as_text(&self) -> &str { - &self.text - } - - fn generate_compact_text(&self) -> String { +impl CompactTextDocument for TransactionDocument { + fn as_compact_text(&self) -> String { let mut issuers_str = String::from(""); for issuer in self.issuers.clone() { issuers_str.push_str("\n"); @@ -499,12 +492,24 @@ impl TextDocument for TransactionDocument { } } +impl TextDocument for TransactionDocument { + type CompactTextDocument_ = TransactionDocument; + + fn as_text(&self) -> &str { + &self.text + } + + fn to_compact_document(&self) -> Self::CompactTextDocument_ { + self.clone() + } +} + impl Serialize for TransactionDocument { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, { - let compact_text = self.generate_compact_text(); + let compact_text = self.to_compact_document().generate_compact_text(); serializer.serialize_str(&compact_text.replace("\n", "$")) } } diff --git a/network/lib.rs b/network/lib.rs index d02928b921cb78a28098fc8fe8860c6ecccafb1f..d6b42720d63d0ef75665aa551e0fe19e3c13d7b8 100644 --- a/network/lib.rs +++ b/network/lib.rs @@ -109,12 +109,6 @@ pub trait NetworkConf: Debug + Copy + Clone + PartialEq {} pub struct NetworkBlockV10 { /// Uncompleted block document pub uncompleted_block_doc: BlockDocument, - /// Joiners - pub joiners: Vec<serde_json::Value>, - /// actives - pub actives: Vec<serde_json::Value>, - /// leavers - pub leavers: Vec<serde_json::Value>, /// revoked pub revoked: Vec<serde_json::Value>, /// certifications diff --git a/ws2p/lib.rs b/ws2p/lib.rs index aef80ddd09595acb261441f5296c91cb3ddbf2df..835e3c0db4aa647f2b0a732e85b3fe5e4042bbbc 100644 --- a/ws2p/lib.rs +++ b/ws2p/lib.rs @@ -1063,22 +1063,28 @@ impl WS2PModuleDatas { pub fn connect_to_know_endpoints(&mut self) -> () { let mut count_established_connections = 0; let mut reachable_endpoints = Vec::new(); + let mut unreachable_endpoints = Vec::new(); for (_ws2p_full_id, (ep, state)) in self.ws2p_endpoints.clone() { match state { WS2PConnectionState::Established => count_established_connections += 1, WS2PConnectionState::NeverTry | WS2PConnectionState::Close | WS2PConnectionState::Denial => reachable_endpoints.push(ep), - _ => {} + _ => unreachable_endpoints.push(ep), } } let mut free_outcoming_rooms = self.conf.clone().unwrap().outcoming_quota - count_established_connections; - for ep in reachable_endpoints { - if free_outcoming_rooms > 0 { - free_outcoming_rooms -= 1; - self.connect_to_without_checking_quotas(ep); - } + while free_outcoming_rooms > 0 { + let ep = if !reachable_endpoints.is_empty() { + reachable_endpoints.pop().unwrap() + } else if !unreachable_endpoints.is_empty() { + unreachable_endpoints.pop().unwrap() + } else { + break; + }; + self.connect_to_without_checking_quotas(ep); + free_outcoming_rooms -= 1; } } pub fn connect_to(&mut self, endpoint: NetworkEndpoint) -> () {