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

[ref] durs-bc: refactor dubp:check & treat cautious_mode

parent 0974c435
Branches
No related tags found
1 merge request!234Elois/bc
Showing
with 200 additions and 115 deletions
......@@ -319,24 +319,34 @@ impl DursCore<DuRsConf> {
// Get profile path
let profile_path = self.soft_meta_datas.profile_path;
// Define sync_opts
let sync_opts_opt = if let Some(ServerMode::Sync(sync_opts)) = self.server_command {
Some(sync_opts)
} else {
None
};
// Define cautious mode
let cautious_mode = if let Some(ref sync_opts) = sync_opts_opt {
sync_opts.cautious_mode
} else {
true
};
// Instantiate blockchain module and load is conf
let mut blockchain_module = BlockchainModule::load_blockchain_conf(
bc_db,
router_sender.clone(),
profile_path,
RequiredKeysContent::MemberKeyPair(None),
cautious_mode,
);
info!("Success to load Blockchain module.");
// Start blockchain module in thread
let thread_builder = thread::Builder::new().name(BlockchainModule::name().0.into());
let sync_opts = if let Some(ServerMode::Sync(opts)) = self.server_command {
Some(opts)
} else {
None
};
let blockchain_thread_handler = thread_builder
.spawn(move || blockchain_module.start_blockchain(&blockchain_receiver, sync_opts))
.spawn(move || blockchain_module.start_blockchain(&blockchain_receiver, sync_opts_opt))
.expect("Fatal error: fail to spawn module main thread !");
// Wait until all modules threads are finished
......
......@@ -18,15 +18,13 @@
pub mod apply;
pub mod check;
use crate::dubp::apply::{apply_valid_block, ApplyValidBlockError, ValidBlockApplyReqs};
use crate::dubp::check::global::verify_global_validity_block;
use crate::dubp::check::local::verify_local_validity_block;
use crate::dubp::check::InvalidBlockError;
use crate::dubp::apply::{ApplyValidBlockError, WriteBlockQueries};
use crate::dubp::check::CheckBlockError;
use crate::BlockchainModule;
use dubp_block_doc::block::BlockDocumentTrait;
use dubp_block_doc::BlockDocument;
use dubp_common_doc::traits::Document;
use dubp_common_doc::{BlockNumber, Blockstamp};
use dubp_common_doc::BlockNumber;
use durs_bc_db_reader::blocks::DbBlock;
use durs_bc_db_reader::DbError;
use durs_bc_db_writer::{BcDbRwWithWriter, Db, DbWriter};
......@@ -34,7 +32,7 @@ use unwrap::unwrap;
#[derive(Debug, Clone)]
pub enum CheckAndApplyBlockReturn {
ValidMainBlock(ValidBlockApplyReqs),
ValidMainBlock(WriteBlockQueries),
ForkBlock,
OrphanBlock,
}
......@@ -45,7 +43,7 @@ pub enum BlockError {
ApplyValidBlockError(ApplyValidBlockError),
BlockOrOutForkWindow,
DbError(DbError),
InvalidBlock(InvalidBlockError),
InvalidBlock(CheckBlockError),
}
impl From<ApplyValidBlockError> for BlockError {
......@@ -60,8 +58,8 @@ impl From<DbError> for BlockError {
}
}
impl From<InvalidBlockError> for BlockError {
fn from(e: InvalidBlockError) -> Self {
impl From<CheckBlockError> for BlockError {
fn from(e: CheckBlockError) -> Self {
Self::InvalidBlock(e)
}
}
......@@ -72,54 +70,29 @@ pub fn check_and_apply_block(
w: &mut DbWriter,
block_doc: BlockDocument,
) -> Result<CheckAndApplyBlockReturn, BlockError> {
// Get BlockDocument && check if already have block
let already_have_block = durs_bc_db_reader::blocks::already_have_block(
&BcDbRwWithWriter { db, w },
block_doc.blockstamp(),
block_doc.previous_hash(),
)?;
// Verify proof of work
// The case where the block has none hash is captured by verify_block_hashs below
if let Some(hash) = block_doc.hash() {
self::check::pow::verify_hash_pattern(hash.0, block_doc.pow_min())
.map_err(InvalidBlockError::Pow)?;
match check::check_block(bc, &BcDbRwWithWriter { db, w }, &block_doc)? {
check::BlockChainability::FullyValidAndChainableBLock => {
treat_chainable_block(bc, db, w, block_doc)
}
check::BlockChainability::LocalValidAndUnchainableBlock => {
treat_unchainable_block(bc, db, w, block_doc)
}
}
}
// Verify block hashs
crate::dubp::check::hashs::verify_block_hashs(&block_doc).map_err(InvalidBlockError::Hashs)?;
// Check block chainability
if (block_doc.number().0 == 0 && bc.current_blockstamp == Blockstamp::default())
|| (block_doc.number().0 == bc.current_blockstamp.id.0 + 1
&& unwrap!(block_doc.previous_hash()).to_string()
== bc.current_blockstamp.hash.0.to_string())
{
debug!(
"check_and_apply_block: block {} chainable!",
block_doc.blockstamp()
);
// Local verification
verify_local_validity_block(&block_doc, bc.currency_params)
.map_err(InvalidBlockError::Local)?;
fn treat_chainable_block(
bc: &mut BlockchainModule,
db: &Db,
w: &mut DbWriter,
block_doc: BlockDocument,
) -> Result<CheckAndApplyBlockReturn, BlockError> {
// Detect expire_certs
let blocks_expiring = Vec::with_capacity(0);
let blocks_expiring = Vec::with_capacity(0); // TODO
let expire_certs = durs_bc_db_reader::indexes::certs::find_expire_certs(
&BcDbRwWithWriter { db, w },
blocks_expiring,
)?;
// Verify block validity (check all protocol rule, very long !)
verify_global_validity_block(
&block_doc,
&BcDbRwWithWriter { db, w },
&bc.wot_index,
&bc.wot_databases.wot_db,
)
.map_err(InvalidBlockError::Global)?;
// If we're in block genesis, get the currency parameters
if block_doc.number() == BlockNumber(0) {
// Open currency_params_db
......@@ -133,17 +106,27 @@ pub fn check_and_apply_block(
);
}
Ok(CheckAndApplyBlockReturn::ValidMainBlock(apply_valid_block(
let write_block_queries: WriteBlockQueries = crate::dubp::apply::apply_valid_block(
db,
w,
block_doc,
&mut bc.wot_index,
&bc.wot_databases.wot_db,
&expire_certs,
)?))
} else if already_have_block {
Err(BlockError::AlreadyHaveBlock)
} else if block_doc.number().0 >= bc.current_blockstamp.id.0
)?;
Ok(CheckAndApplyBlockReturn::ValidMainBlock(
write_block_queries,
))
}
fn treat_unchainable_block(
bc: &mut BlockchainModule,
db: &Db,
w: &mut DbWriter,
block_doc: BlockDocument,
) -> Result<CheckAndApplyBlockReturn, BlockError> {
if block_doc.number().0 >= bc.current_blockstamp.id.0
|| (bc.current_blockstamp.id.0 - block_doc.number().0)
< unwrap!(bc.currency_params).fork_window_size as u32
{
......
......@@ -32,7 +32,7 @@ use std::collections::{HashMap, HashSet};
#[derive(Debug, Clone)]
/// Stores all queries to apply in database to "apply" the block
pub struct ValidBlockApplyReqs(
pub struct WriteBlockQueries(
pub BlocksDBsWriteQuery,
pub Vec<WotsDBsWriteQuery>,
pub Vec<CurrencyDBsWriteQuery>,
......@@ -54,7 +54,7 @@ pub fn apply_valid_block<W: WebOfTrust>(
wot_index: &mut HashMap<PubKey, WotId>,
wot_db: &BinFreeStructDb<W>,
expire_certs: &HashMap<(WotId, WotId), BlockNumber>,
) -> Result<ValidBlockApplyReqs, ApplyValidBlockError> {
) -> Result<WriteBlockQueries, ApplyValidBlockError> {
match block {
BlockDocument::V10(block_v10) => {
apply_valid_block_v10(db, w, block_v10, wot_index, wot_db, expire_certs)
......@@ -69,7 +69,7 @@ pub fn apply_valid_block_v10<W: WebOfTrust>(
wot_index: &mut HashMap<PubKey, WotId>,
wot_db: &BinFreeStructDb<W>,
expire_certs: &HashMap<(WotId, WotId), BlockNumber>,
) -> Result<ValidBlockApplyReqs, ApplyValidBlockError> {
) -> Result<WriteBlockQueries, ApplyValidBlockError> {
trace!("apply_valid_block({})", block.blockstamp(),);
let mut wot_dbs_requests = Vec::new();
let mut currency_dbs_requests = Vec::new();
......@@ -287,7 +287,7 @@ pub fn apply_valid_block_v10<W: WebOfTrust>(
expire_certs: Some(expire_certs.clone()),
};
// Return DBs requests
Ok(ValidBlockApplyReqs(
Ok(WriteBlockQueries(
BlocksDBsWriteQuery::WriteBlock(block_db),
wot_dbs_requests,
currency_dbs_requests,
......
......@@ -20,10 +20,98 @@ pub mod hashs;
pub mod local;
pub mod pow;
use crate::dubp::BlockError;
use crate::BlockchainModule;
use dubp_block_doc::block::BlockDocumentTrait;
use dubp_block_doc::BlockDocument;
use dubp_common_doc::traits::Document;
use dubp_common_doc::Blockstamp;
use durs_bc_db_reader::BcDbInReadTx;
use durs_common_tools::traits::bool_ext::BoolExt;
use unwrap::unwrap;
#[derive(Debug)]
pub enum InvalidBlockError {
pub enum CheckBlockError {
Global(global::GlobalVerifyBlockError),
Hashs(dubp_block_doc::block::VerifyBlockHashError),
Local(local::LocalVerifyBlockError),
Pow(pow::BlockPoWError),
Pow(pow::InvalidHashPattern),
}
#[derive(Debug)]
pub enum BlockChainability {
FullyValidAndChainableBLock,
LocalValidAndUnchainableBlock,
}
/// Check block validity
pub fn check_block<DB: BcDbInReadTx>(
bc: &mut BlockchainModule,
db: &DB,
block_doc: &BlockDocument,
) -> Result<BlockChainability, BlockError> {
let already_have_block;
if bc.cautious_mode {
// Check if we already have the block
// VERY IMPORTANT: there are cases where it's legitimate to check a block that we already have.
// For example, in case of rollback or application of orphan blocks that have become stackable.
// The fact of having already received the block is a cause of rejection only if the block is not chainable.
already_have_block = durs_bc_db_reader::blocks::already_have_block(
db,
block_doc.blockstamp(),
block_doc.previous_hash(),
)
.map_err(BlockError::DbError)?;
if already_have_block.not() {
// Verify proof of work
// The case where the block has none hash is captured by check_block_hashes below
if let Some(hash) = block_doc.hash() {
pow::verify_hash_pattern(hash.0, block_doc.pow_min())
.map_err(CheckBlockError::Pow)?;
}
// Check block hashes.
crate::dubp::check::hashs::check_block_hashes(block_doc)
.map_err(CheckBlockError::Hashs)?;
}
} else {
// If we're not in cautious mode, we still need to check the block hashes.
crate::dubp::check::hashs::check_block_hashes(block_doc).map_err(CheckBlockError::Hashs)?;
already_have_block = false;
};
// Check block chainability
if (block_doc.number().0 == 0 && bc.current_blockstamp == Blockstamp::default())
|| (block_doc.number().0 == bc.current_blockstamp.id.0 + 1
&& unwrap!(block_doc.previous_hash()).to_string()
== bc.current_blockstamp.hash.0.to_string())
{
debug!("check_block: block {} chainable!", block_doc.blockstamp());
if bc.cautious_mode {
// Local verification
local::verify_local_validity_block(block_doc, bc.currency_params)
.map_err(CheckBlockError::Local)?;
// Verify block validity (check all protocol rule, very long !)
global::verify_global_validity_block(
block_doc,
db,
&bc.wot_index,
&bc.wot_databases.wot_db,
)
.map_err(CheckBlockError::Global)?;
}
Ok(BlockChainability::FullyValidAndChainableBLock)
} else {
// Check that we don't already have the block
already_have_block
.not()
.or_err(BlockError::AlreadyHaveBlock)?;
// TODO check estimate pow_min
Ok(BlockChainability::LocalValidAndUnchainableBlock)
}
}
......@@ -67,5 +67,6 @@ where
.or_err(GlobalVerifyBlockError::VersionDecrease)?;
}
// TODO BR_G100 - issuerIsMember
Ok(())
}
......@@ -18,7 +18,7 @@
use dubp_block_doc::block::{BlockDocument, BlockDocumentTrait, VerifyBlockHashError};
/// Verify block hashs
pub fn verify_block_hashs(block_doc: &BlockDocument) -> Result<(), VerifyBlockHashError> {
pub fn check_block_hashes(block_doc: &BlockDocument) -> Result<(), VerifyBlockHashError> {
trace!("complete_block #{}...", block_doc.number());
match block_doc.verify_inner_hash() {
......
......@@ -29,7 +29,6 @@ use dubp_common_doc::errors::DocumentSigsErr;
use dubp_common_doc::traits::Document;
use dubp_common_doc::BlockNumber;
use dubp_currency_params::CurrencyParameters;
use durs_common_tools::fatal_error;
#[derive(Debug, PartialEq)]
/// Local verification of a block error
......@@ -59,6 +58,8 @@ pub enum LocalVerifyBlockError {
TooManyIssuers,
/// Transaction Document Error
TransactionDocumentError(TransactionDocumentError),
/// Receive not genesis block wityhout blockchain
RecvNotGenesisWithoutBlockchain,
}
impl From<LocalVerifyGenesisBlockError> for LocalVerifyBlockError {
......@@ -91,7 +92,7 @@ pub fn verify_local_validity_block(
// Check the local rules specific to non-genesis blocks
self::not_genesis::local_validation_not_genesis_block(block, currency_parameters)?;
} else {
fatal_error!("We must have currency parameters when we check a non-genesis block.");
return Err(LocalVerifyBlockError::RecvNotGenesisWithoutBlockchain);
}
match block {
......
......@@ -20,19 +20,14 @@ use durs_common_tools::traits::bool_ext::BoolExt;
static ZERO_STRING: &str = "0";
/// Proof of Work error
#[derive(Debug, PartialEq)]
pub enum BlockPoWError {
/// Invalid pow_min
_InvalidPoWMin,
/// Invalid PoW pattern
InvalidHashPattern {
#[derive(Debug, PartialEq)]
pub struct InvalidHashPattern {
expected_pattern: String,
actual_hash: String,
},
}
pub fn verify_hash_pattern(hash: Hash, diffi: usize) -> Result<(), BlockPoWError> {
pub fn verify_hash_pattern(hash: Hash, diffi: usize) -> Result<(), InvalidHashPattern> {
let hash_string = hash.to_hex();
let nb_zeros = diffi / 16;
let expected_pattern_last_hex_digit = 16 - (diffi % 16);
......@@ -54,7 +49,7 @@ pub fn verify_hash_pattern(hash: Hash, diffi: usize) -> Result<(), BlockPoWError
.expect("Hash type guarantees a valid hexadecimal string.");
// remainder must be less than or equal to expected_end_pattern
(actual_pattern_last_hex_digit <= expected_pattern_last_hex_digit).or_err(
BlockPoWError::InvalidHashPattern {
InvalidHashPattern {
expected_pattern: expected_pattern.clone(),
actual_hash: hash_string.clone(),
},
......@@ -65,7 +60,7 @@ pub fn verify_hash_pattern(hash: Hash, diffi: usize) -> Result<(), BlockPoWError
};
hash_string
.starts_with(&repeated_zero_string)
.or_err(BlockPoWError::InvalidHashPattern {
.or_err(InvalidHashPattern {
expected_pattern,
actual_hash: hash_string,
})?;
......@@ -97,7 +92,7 @@ mod tests {
)
);
assert_eq!(
Err(BlockPoWError::InvalidHashPattern {
Err(InvalidHashPattern {
expected_pattern: "0000[0-a]*".to_owned(),
actual_hash: "0000B3619ACBF80298F074D8339175901425BC97EF528ED02EBD73CD4CA5C559"
.to_owned(),
......@@ -109,7 +104,7 @@ mod tests {
)
);
assert_eq!(
Err(BlockPoWError::InvalidHashPattern {
Err(InvalidHashPattern {
expected_pattern: "0000[0-a]*".to_owned(),
actual_hash: "000313619ACBF80298F074D8339175901425BC97EF528ED02EBD73CD4CA5C559"
.to_owned(),
......@@ -121,7 +116,7 @@ mod tests {
)
);
assert_eq!(
Err(BlockPoWError::InvalidHashPattern {
Err(InvalidHashPattern {
expected_pattern: "00000".to_owned(),
actual_hash: "000313619ACBF80298F074D8339175901425BC97EF528ED02EBD73CD4CA5C559"
.to_owned(),
......@@ -133,7 +128,7 @@ mod tests {
)
);
assert_eq!(
Err(BlockPoWError::InvalidHashPattern {
Err(InvalidHashPattern {
expected_pattern: "0000".to_owned(),
actual_hash: "000313619ACBF80298F074D8339175901425BC97EF528ED02EBD73CD4CA5C559"
.to_owned(),
......
......@@ -50,7 +50,7 @@ pub fn receive_blocks(bc: &mut BlockchainModule, blocks: Vec<BlockDocument>) {
db.write(|mut w| {
match check_and_apply_block(bc, &db, &mut w, block) {
Ok(check_block_return) => match check_block_return {
CheckAndApplyBlockReturn::ValidMainBlock(ValidBlockApplyReqs(
CheckAndApplyBlockReturn::ValidMainBlock(WriteBlockQueries(
bc_db_query,
wot_dbs_queries,
tx_dbs_queries,
......
......@@ -92,7 +92,7 @@ pub fn apply_rollback(bc: &mut BlockchainModule, new_bc_branch: Vec<Blockstamp>)
new_branch_blocks.push(dal_block.clone());
match check_and_apply_block(bc, &db, &mut w, dal_block.block) {
Ok(check_and_apply_block_return) => match check_and_apply_block_return {
CheckAndApplyBlockReturn::ValidMainBlock(ValidBlockApplyReqs(
CheckAndApplyBlockReturn::ValidMainBlock(WriteBlockQueries(
bc_db_query,
wot_dbs_queries,
tx_dbs_queries,
......
......@@ -45,7 +45,7 @@ pub fn apply_stackable_blocks(bc: &mut BlockchainModule) {
let db = bc.take_db();
let db_write_result = db.write(|mut w| {
match check_and_apply_block(bc, &db, &mut w, stackable_block.block) {
Ok(CheckAndApplyBlockReturn::ValidMainBlock(ValidBlockApplyReqs(
Ok(CheckAndApplyBlockReturn::ValidMainBlock(WriteBlockQueries(
bc_db_query,
wot_dbs_queries,
tx_dbs_queries,
......
......@@ -50,7 +50,7 @@ use std::time::{Duration, SystemTime, UNIX_EPOCH};
use crate::constants::*;
use crate::dbex::DbExQuery;
use crate::dubp::apply::ValidBlockApplyReqs;
use crate::dubp::apply::WriteBlockQueries;
use crate::dubp::*;
use crate::fork::*;
use dubp_block_doc::BlockDocument;
......@@ -88,6 +88,8 @@ pub static DISTANCE_CALCULATOR: &RustyDistanceCalculator = &RustyDistanceCalcula
/// Blockchain Module
pub struct BlockchainModule {
/// Cautious mode
pub cautious_mode: bool,
/// Router sender
pub router_sender: Sender<RouterThreadMessage<DursMsg>>,
///Path to the user datas profile
......@@ -173,6 +175,7 @@ pub enum SyncVerificationLevel {
impl BlockchainModule {
/// Instantiate blockchain module
pub fn new(
cautious_mode: bool,
router_sender: Sender<RouterThreadMessage<DursMsg>>,
profile_path: PathBuf,
currency_name: Option<CurrencyName>,
......@@ -193,6 +196,7 @@ impl BlockchainModule {
db.r(|db_r| durs_bc_db_reader::indexes::identities::get_wot_index(db_r))?;
Ok(BlockchainModule {
cautious_mode,
router_sender,
profile_path,
currency: currency_name,
......@@ -220,6 +224,7 @@ impl BlockchainModule {
router_sender: Sender<RouterThreadMessage<DursMsg>>,
profile_path: PathBuf,
_keys: RequiredKeysContent,
cautious_mode: bool,
) -> BlockchainModule {
// Get db path
let dbs_path = durs_conf::get_blockchain_db_path(profile_path.clone());
......@@ -240,8 +245,8 @@ impl BlockchainModule {
};
// Instanciate BlockchainModule
// TODO ESZ
BlockchainModule::new(
cautious_mode,
router_sender,
profile_path,
currency_name,
......
......@@ -19,7 +19,7 @@ pub mod wot_worker;
use crate::dubp;
use crate::dubp::apply::apply_valid_block;
use crate::dubp::apply::{ApplyValidBlockError, ValidBlockApplyReqs};
use crate::dubp::apply::{ApplyValidBlockError, WriteBlockQueries};
use crate::sync::SyncJobsMess;
use crate::Db;
use dubp_block_doc::block::{BlockDocument, BlockDocumentTrait};
......@@ -76,7 +76,7 @@ impl BlockApplicator {
// Verify block hashs
let verif_block_hashs_begin = SystemTime::now();
if self.verif_inner_hash {
dubp::check::hashs::verify_block_hashs(&block_doc)
dubp::check::hashs::check_block_hashes(&block_doc)
.expect("Receive wrong block, please reset data and resync !");
}
self.all_verif_block_hashs_duration += SystemTime::now()
......@@ -131,7 +131,7 @@ impl BlockApplicator {
} else {
fatal_error!("Dev error: BlockApplicator must have DB.")
}
if let Ok(ValidBlockApplyReqs(block_req, wot_db_reqs, currency_db_reqs)) =
if let Ok(WriteBlockQueries(block_req, wot_db_reqs, currency_db_reqs)) =
apply_valid_block_result
{
self.all_apply_valid_block_duration += SystemTime::now()
......
......@@ -57,12 +57,14 @@ pub fn init_bc_module(
tmp_path: &Path,
) -> BlockchainModule {
let currency_name = CurrencyName(TEST_CURRENCY.to_owned());
let cautious_mode = false;
//let profile_path = tmp_profile_path.to_owned();
//let dbs_path = durs_conf::get_blockchain_db_path(profile_path.clone());
let db = durs_bc_db_writer::open_db(tmp_path).expect("Fail to open blockchain DB.");
BlockchainModule::new(
cautious_mode,
fake_router_sender,
tmp_path.to_owned(),
Some(currency_name.clone()),
......
......@@ -22,7 +22,7 @@ pub trait BoolExt {
/// Transform any type to result<T, E>
fn as_result<T, E>(self, ok: T, err: E) -> Result<T, E>;
/// Reverse bool
fn not(self) -> bool;
fn not(&self) -> bool;
}
impl BoolExt for bool {
......@@ -43,7 +43,7 @@ impl BoolExt for bool {
}
}
#[inline]
fn not(self) -> bool {
fn not(&self) -> bool {
!self
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment