diff --git a/Cargo.lock b/Cargo.lock index ce368dbec3eb022ab9e7392fd54e1eaf3bebc74f..11408c7aefb898e2108a200d4c23348c8208c1be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -943,10 +943,12 @@ dependencies = [ "json-pest-parser 0.2.0", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "mockall 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "pbr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rules-engine 0.1.0", "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/lib/modules-lib/bc-db-reader/src/indexes/identities.rs b/lib/modules-lib/bc-db-reader/src/indexes/identities.rs index b1067c13e55be570d50bc95622b68651c6f09b7f..80eeddc859c5286e3afaa93d2c733ed7d7d75745 100644 --- a/lib/modules-lib/bc-db-reader/src/indexes/identities.rs +++ b/lib/modules-lib/bc-db-reader/src/indexes/identities.rs @@ -135,16 +135,8 @@ pub fn get_identities<DB: BcDbInReadTx>( } } -/// Get identity by pubkey in databases -pub fn get_identity_by_pubkey<DB: BcDbInReadTx>( - db: &DB, - pubkey: &PubKey, -) -> Result<Option<DbIdentity>, DbError> { - get_identity_by_pubkey_(db, pubkey) -} - /// Get identity by pubkey -pub fn get_identity_by_pubkey_<DB: BcDbInReadTx>( +pub fn get_identity_by_pubkey<DB: BcDbInReadTx>( db: &DB, pubkey: &PubKey, ) -> Result<Option<DbIdentity>, DbError> { @@ -172,16 +164,19 @@ pub fn get_identity_by_wot_id<DB: BcDbInReadTx>( } } -/// Get uid from pubkey +/// Get identity state from pubkey #[inline] -pub fn get_uid<DB: BcDbInReadTx>(db: &DB, pubkey: &PubKey) -> Result<Option<String>, DbError> { - Ok(get_identity_by_pubkey(db, pubkey)?.map(|db_idty| db_idty.idty_doc.username().to_owned())) +pub fn get_idty_state_by_pubkey<DB: BcDbInReadTx>( + db: &DB, + pubkey: &PubKey, +) -> Result<Option<DbIdentityState>, DbError> { + Ok(get_identity_by_pubkey(db, pubkey)?.map(|db_idty| db_idty.state)) } /// Get uid from pubkey #[inline] -pub fn get_uid_<DB: BcDbInReadTx>(db: &DB, pubkey: &PubKey) -> Result<Option<String>, DbError> { - Ok(get_identity_by_pubkey_(db, pubkey)?.map(|db_idty| db_idty.idty_doc.username().to_owned())) +pub fn get_uid<DB: BcDbInReadTx>(db: &DB, pubkey: &PubKey) -> Result<Option<String>, DbError> { + Ok(get_identity_by_pubkey(db, pubkey)?.map(|db_idty| db_idty.idty_doc.username().to_owned())) } /// Get wot id from uid diff --git a/lib/modules-lib/bc-db-reader/src/traits.rs b/lib/modules-lib/bc-db-reader/src/traits.rs index 544a2776707ad5119b51bf696df23f820be4ef4b..bf4a36e737a19770b4142bfc93c97695cc1f61d3 100644 --- a/lib/modules-lib/bc-db-reader/src/traits.rs +++ b/lib/modules-lib/bc-db-reader/src/traits.rs @@ -17,6 +17,7 @@ // ! Define read only trait use crate::blocks::DbBlock; +use crate::indexes::identities::{DbIdentity, DbIdentityState}; use crate::{BcDbWithReaderStruct, DbReadable, DbReader}; use dubp_common_doc::{BlockNumber, Blockstamp}; use dup_crypto::keys::PubKey; @@ -83,15 +84,20 @@ pub trait BcDbInReadTx: BcDbWithReader { numbers: Vec<BlockNumber>, ) -> Result<Vec<DbBlock>, DbError>; fn get_uid_from_pubkey(&self, pubkey: &PubKey) -> Result<Option<String>, DbError>; + fn get_idty_state_by_pubkey(&self, pubkey: &PubKey) + -> Result<Option<DbIdentityState>, DbError>; + fn get_identity_by_pubkey(&self, pubkey: &PubKey) -> Result<Option<DbIdentity>, DbError>; } impl<T> BcDbInReadTx for T where T: BcDbWithReader + durs_common_tools::traits::NotMock, { + #[inline] fn get_current_blockstamp(&self) -> Result<Option<Blockstamp>, DbError> { crate::current_meta_datas::get_current_blockstamp(self) } + #[inline] fn get_current_block(&self) -> Result<Option<DbBlock>, DbError> { if let Some(current_blockstamp) = crate::current_meta_datas::get_current_blockstamp(self)? { crate::blocks::get_db_block_in_local_blockchain(self, current_blockstamp.id) @@ -99,6 +105,7 @@ where Ok(None) } } + #[inline] fn get_db_block_in_local_blockchain( &self, block_number: BlockNumber, @@ -106,13 +113,26 @@ where crate::blocks::get_db_block_in_local_blockchain(self, block_number) } #[cfg(feature = "client-indexer")] + #[inline] fn get_db_blocks_in_local_blockchain( &self, numbers: Vec<BlockNumber>, ) -> Result<Vec<DbBlock>, DbError> { crate::blocks::get_blocks_in_local_blockchain_by_numbers(self, numbers) } + #[inline] fn get_uid_from_pubkey(&self, pubkey: &PubKey) -> Result<Option<String>, DbError> { - crate::indexes::identities::get_uid_(self, pubkey) + crate::indexes::identities::get_uid(self, pubkey) + } + #[inline] + fn get_idty_state_by_pubkey( + &self, + pubkey: &PubKey, + ) -> Result<Option<DbIdentityState>, DbError> { + crate::indexes::identities::get_idty_state_by_pubkey(self, pubkey) + } + #[inline] + fn get_identity_by_pubkey(&self, pubkey: &PubKey) -> Result<Option<DbIdentity>, DbError> { + crate::indexes::identities::get_identity_by_pubkey(self, pubkey) } } diff --git a/lib/modules/blockchain/blockchain/Cargo.toml b/lib/modules/blockchain/blockchain/Cargo.toml index bf03e517a8cac3cf1beee1e7eaa42eb3b64ece75..278cb2e340d4622557e64dc51f52393e2c51b3b2 100644 --- a/lib/modules/blockchain/blockchain/Cargo.toml +++ b/lib/modules/blockchain/blockchain/Cargo.toml @@ -28,9 +28,11 @@ durs-wot = { path = "../../../dubp/wot" } failure = "0.1.5" json-pest-parser = { path = "../../../tools/json-pest-parser" } log = "0.4.*" +maplit = "1.0.1" num_cpus = "1.10.*" pbr = "1.0.*" rayon = "1.2.0" +rules-engine = { path = "../../../tools/rules-engine" } serde = "1.0.*" serde_json = "1.0.*" threadpool = "1.7.*" @@ -41,7 +43,9 @@ unwrap = "1.2.1" dup-crypto-tests-tools = { path = "../../../tests-tools/crypto-tests-tools" } dubp-user-docs-tests-tools = { path = "../../../tests-tools/user-docs-tests-tools" } dubp-blocks-tests-tools = { path = "../../../tests-tools/blocks-tests-tools" } +durs-bc-db-reader = { path = "../../../modules-lib/bc-db-reader", features = ["mock"] } durs-common-tests-tools = { path = "../../../tests-tools/common-tests-tools" } maplit = "1.0.1" +mockall = "0.5.2" pretty_assertions = "0.5.1" tempfile = "3.1.0" diff --git a/lib/modules/blockchain/blockchain/src/dubp/check.rs b/lib/modules/blockchain/blockchain/src/dubp/check.rs index f9a0c14ecf8137dd699a4196364ef6c6cf859ed7..cca4bd56964368932c633ddf685451b9ac3e9103 100644 --- a/lib/modules/blockchain/blockchain/src/dubp/check.rs +++ b/lib/modules/blockchain/blockchain/src/dubp/check.rs @@ -25,7 +25,7 @@ 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 dubp_common_doc::{BlockNumber, Blockstamp}; use durs_bc_db_reader::BcDbInReadTx; use durs_common_tools::traits::bool_ext::BoolExt; use unwrap::unwrap; @@ -86,21 +86,28 @@ pub fn check_block<DB: BcDbInReadTx>( && 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 { + debug!("check_block: block {} chainable!", block_doc.blockstamp()); + // 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)?; + if block_doc.number() > BlockNumber(0) { + global::verify_global_validity_block( + block_doc, + db, + &bc.wot_index, + &bc.wot_databases.wot_db, + ) + .map_err(CheckBlockError::Global)?; + } + + debug!( + "check_block: block {} is fully valid.!", + block_doc.blockstamp() + ); } Ok(BlockChainability::FullyValidAndChainableBLock) diff --git a/lib/modules/blockchain/blockchain/src/dubp/check/global.rs b/lib/modules/blockchain/blockchain/src/dubp/check/global.rs index a3f1d357023a801a03c2d685eefbb460821c8576..5baceee970b57b33b5c294eb65bae345394d6dcb 100644 --- a/lib/modules/blockchain/blockchain/src/dubp/check/global.rs +++ b/lib/modules/blockchain/blockchain/src/dubp/check/global.rs @@ -15,6 +15,12 @@ //! Sub-module checking if a block complies with all the rules of the (DUBP DUniter Blockchain Protocol). +mod protocol_versions; +mod rules; + +pub use self::rules::InvalidRuleError; + +use self::rules::RuleNotSyncDatas; use dubp_block_doc::block::{BlockDocument, BlockDocumentTrait}; use dubp_common_doc::traits::Document; use dubp_common_doc::BlockNumber; @@ -23,11 +29,13 @@ use durs_bc_db_reader::{BcDbInReadTx, DbError}; use durs_bc_db_writer::BinFreeStructDb; use durs_common_tools::traits::bool_ext::BoolExt; use durs_wot::*; +use rules_engine::{EngineError, ProtocolVersion, RulesEngine}; use std::collections::HashMap; #[derive(Debug)] pub enum GlobalVerifyBlockError { DbError(DbError), + InvalidRule(EngineError<InvalidRuleError>), NoPreviousBlock, VersionDecrease, } @@ -48,25 +56,39 @@ where DB: BcDbInReadTx, W: WebOfTrust, { - // Rules that do not concern genesis block - if block.number().0 > 0 { - // Get previous block - let previous_block_opt = durs_bc_db_reader::blocks::get_block_in_local_blockchain( - db, - BlockNumber(block.number().0 - 1), - )?; + // Get previous block + let previous_block_opt = durs_bc_db_reader::blocks::get_block_in_local_blockchain( + db, + BlockNumber(block.number().0 - 1), + )?; - // Previous block must exist - previous_block_opt - .is_some() - .or_err(GlobalVerifyBlockError::NoPreviousBlock)?; - let previous_block = previous_block_opt.expect("safe unwrap"); + // Previous block must exist + previous_block_opt + .is_some() + .or_err(GlobalVerifyBlockError::NoPreviousBlock)?; + let previous_block = previous_block_opt.expect("safe unwrap"); - // Block version must not decrease - (block.version() >= previous_block.version()) - .or_err(GlobalVerifyBlockError::VersionDecrease)?; - } + // Block version must not decrease + (block.version() >= previous_block.version()) + .or_err(GlobalVerifyBlockError::VersionDecrease)?; + + // Define rules datas + let mut rules_datas = rules::RuleDatas { + block, + previous_block: &previous_block, + }; + let mut rules_not_sync_datas = RuleNotSyncDatas { db }; + + // Apply protocol v10 + let engine = RulesEngine::new(rules::all_rules::get_all_rules()); + engine + .apply_protocol( + protocol_versions::get_blockchain_protocol(), + ProtocolVersion(11), + &mut rules_datas, + &mut rules_not_sync_datas, + ) + .map_err(GlobalVerifyBlockError::InvalidRule)?; - // TODO BR_G100 - issuerIsMember Ok(()) } diff --git a/lib/modules/blockchain/blockchain/src/dubp/check/global/protocol_versions.rs b/lib/modules/blockchain/blockchain/src/dubp/check/global/protocol_versions.rs new file mode 100644 index 0000000000000000000000000000000000000000..87a62b6b3453160d3d0f5bba1f858342e447b781 --- /dev/null +++ b/lib/modules/blockchain/blockchain/src/dubp/check/global/protocol_versions.rs @@ -0,0 +1,27 @@ +// Copyright (C) 2017-2019 The AXIOM TEAM Association. +// +// 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/>. + +//! Sub-module manage blockchain protocol versions. + +mod v11; + +use rules_engine::{Protocol, ProtocolVersion}; + +#[inline] +pub fn get_blockchain_protocol() -> Protocol { + Protocol::new(maplit::btreemap![ + ProtocolVersion(11) => v11::get_protocol_rules() + ]) +} diff --git a/lib/modules/blockchain/blockchain/src/dubp/check/global/protocol_versions/v11.rs b/lib/modules/blockchain/blockchain/src/dubp/check/global/protocol_versions/v11.rs new file mode 100644 index 0000000000000000000000000000000000000000..aae07a8d47a9e0edfbb01be9494a06d74796ca6d --- /dev/null +++ b/lib/modules/blockchain/blockchain/src/dubp/check/global/protocol_versions/v11.rs @@ -0,0 +1,23 @@ +// Copyright (C) 2017-2019 The AXIOM TEAM Association. +// +// 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/>. + +//! List of rules applied for blockchain protocol V11. + +use rules_engine::{ProtocolRules, RulesGroup}; + +#[inline] +pub fn get_protocol_rules() -> ProtocolRules { + vec![RulesGroup::ser(vec![3usize, 100])].into() +} diff --git a/lib/modules/blockchain/blockchain/src/dubp/check/global/rules.rs b/lib/modules/blockchain/blockchain/src/dubp/check/global/rules.rs new file mode 100644 index 0000000000000000000000000000000000000000..5010748ee4da5799a645a2318395fd7f7b196bed --- /dev/null +++ b/lib/modules/blockchain/blockchain/src/dubp/check/global/rules.rs @@ -0,0 +1,66 @@ +// Copyright (C) 2017-2019 The AXIOM TEAM Association. +// +// 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/>. + +//! Sub-module define rules engine + +pub mod all_rules; +mod br_g03; +mod br_g100; + +use dubp_block_doc::BlockDocument; +//use dup_crypto::keys::PubKey; +use durs_bc_db_reader::indexes::identities::DbIdentityState; +use durs_bc_db_reader::{BcDbInReadTx, DbError}; +//use durs_wot::*; +use failure::Fail; +//use std::collections::HashMap; + +#[derive(Debug)] +pub struct RuleDatas<'a> { + pub(crate) block: &'a BlockDocument, + pub(crate) previous_block: &'a BlockDocument, + //db: &'a Db, + //wot_db: &BinFreeStructDb<W>, + //wot_index: HashMap<PubKey, NodeId>, + //current_frame: Option<HashMap<PubKey, usize>>, +} + +pub struct RuleNotSyncDatas<'db, DB: BcDbInReadTx> { + pub(crate) db: &'db DB, +} + +#[derive(Clone, Debug, Eq, Fail, PartialEq)] +pub enum InvalidRuleError { + #[fail(display = "Database error: {:?}", _0)] + DbError(String), + #[fail(display = "BR_G99: different currency")] + _DifferentCurrency, + #[fail(display = "BR_G03: wrong previous issuer")] + WrongPreviousIssuer, + #[fail(display = "BR_G100: issuer is not a member (not exist)")] + IssuerNotExist, + #[fail(display = "BR_G100: issuer is not a member (issuer_state={:?})", _0)] + NotMemberIssuer(DbIdentityState), + #[fail(display = "BR_G04: wrong issuers count")] + _WrongIssuersCount, + #[fail(display = "BR_G05: wrong issuers frame size")] + _WrongIssuersFrame, +} + +impl From<DbError> for InvalidRuleError { + fn from(e: DbError) -> Self { + Self::DbError(format!("{:?}", e)) + } +} diff --git a/lib/modules/blockchain/blockchain/src/dubp/check/global/rules/all_rules.rs b/lib/modules/blockchain/blockchain/src/dubp/check/global/rules/all_rules.rs new file mode 100644 index 0000000000000000000000000000000000000000..c8938f46f28d34b30a70879724600f07b96f0fa4 --- /dev/null +++ b/lib/modules/blockchain/blockchain/src/dubp/check/global/rules/all_rules.rs @@ -0,0 +1,33 @@ +// Copyright (C) 2017-2019 The AXIOM TEAM Association. +// +// 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/>. + +//! Sub-module define all rules of blockchain protocol. + +use super::br_g03; +use super::br_g100; +use super::{RuleDatas, RuleNotSyncDatas}; +use crate::dubp::check::global::rules::InvalidRuleError; +use durs_bc_db_reader::BcDbInReadTx; +use rules_engine::rule::{Rule, RuleNumber}; +use std::collections::BTreeMap; + +#[inline] +pub fn get_all_rules<'d, 'db, DB: BcDbInReadTx>( +) -> BTreeMap<RuleNumber, Rule<RuleDatas<'d>, RuleNotSyncDatas<'db, DB>, InvalidRuleError>> { + maplit::btreemap![ + RuleNumber(3) => br_g03::rule(), + RuleNumber(100) => br_g100::rule(), + ] +} diff --git a/lib/modules/blockchain/blockchain/src/dubp/check/global/rules/br_g03.rs b/lib/modules/blockchain/blockchain/src/dubp/check/global/rules/br_g03.rs new file mode 100644 index 0000000000000000000000000000000000000000..9fbe8af18f0b2cb5974fad494d67dec6aff18b32 --- /dev/null +++ b/lib/modules/blockchain/blockchain/src/dubp/check/global/rules/br_g03.rs @@ -0,0 +1,50 @@ +// Copyright (C) 2017-2019 The AXIOM TEAM Association. +// +// 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/>. + +//! Rule BR_G03 - previousIssuer + +use super::{InvalidRuleError, RuleDatas, RuleNotSyncDatas}; +use dubp_block_doc::BlockDocument; +use durs_bc_db_reader::BcDbInReadTx; +use durs_common_tools::traits::bool_ext::BoolExt; +use rules_engine::rule::{Rule, RuleFn, RuleNumber}; +use rules_engine::ProtocolVersion; +use unwrap::unwrap; + +#[inline] +pub fn rule<'d, 'db, DB: BcDbInReadTx>( +) -> Rule<RuleDatas<'d>, RuleNotSyncDatas<'db, DB>, InvalidRuleError> { + unwrap!(Rule::new( + RuleNumber(3), + maplit::btreemap![ + ProtocolVersion(10) => RuleFn::Ref(v10), + ] + )) +} + +fn v10(rule_datas: &RuleDatas) -> Result<(), InvalidRuleError> { + let RuleDatas { + ref block, + ref previous_block, + .. + } = rule_datas; + let BlockDocument::V10(ref block) = block; + let BlockDocument::V10(ref previous_block) = previous_block; + + (Some(previous_block.issuers[0]) == block.previous_issuer) + .or_err(InvalidRuleError::WrongPreviousIssuer)?; + + Ok(()) +} diff --git a/lib/modules/blockchain/blockchain/src/dubp/check/global/rules/br_g100.rs b/lib/modules/blockchain/blockchain/src/dubp/check/global/rules/br_g100.rs new file mode 100644 index 0000000000000000000000000000000000000000..3cb201dfc9dc1fb0ab8af38b06690dc47938dd4b --- /dev/null +++ b/lib/modules/blockchain/blockchain/src/dubp/check/global/rules/br_g100.rs @@ -0,0 +1,111 @@ +// Copyright (C) 2017-2019 The AXIOM TEAM Association. +// +// 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/>. + +//! Rule BR_G100 - issuerIsMember + +use super::{InvalidRuleError, RuleDatas, RuleNotSyncDatas}; +use dubp_common_doc::traits::Document; +use durs_bc_db_reader::indexes::identities::DbIdentityState; +use durs_bc_db_reader::BcDbInReadTx; +use rules_engine::rule::{Rule, RuleFn, RuleNumber}; +use rules_engine::ProtocolVersion; +use unwrap::unwrap; + +#[inline] +pub fn rule<'d, 'db, DB: BcDbInReadTx>( +) -> Rule<RuleDatas<'d>, RuleNotSyncDatas<'db, DB>, InvalidRuleError> { + unwrap!(Rule::new( + RuleNumber(100), + maplit::btreemap![ + ProtocolVersion(10) => RuleFn::RefMut(v10), + ] + )) +} + +fn v10<DB: BcDbInReadTx>( + datas: &mut RuleDatas, + not_sync_datas: &mut RuleNotSyncDatas<DB>, +) -> Result<(), InvalidRuleError> { + let RuleDatas { ref block, .. } = datas; + let RuleNotSyncDatas { ref db } = not_sync_datas; + + if let Some(idty_state) = db.get_idty_state_by_pubkey(&block.issuers()[0])? { + if let DbIdentityState::Member(_) = idty_state { + Ok(()) + } else { + Err(InvalidRuleError::NotMemberIssuer(idty_state)) + } + } else { + Err(InvalidRuleError::IssuerNotExist) + } +} + +#[cfg(test)] +mod tests { + + use super::*; + use dubp_block_doc::BlockDocument; + use durs_bc_db_reader::MockBcDbInReadTx; + use mockall::predicate::eq; + + #[test] + fn test_br_g100_issuer_not_exist() { + let pubkey = dup_crypto_tests_tools::mocks::pubkey('A'); + let block = BlockDocument::V10(dubp_blocks_tests_tools::mocks::gen_empty_issued_block_v10( + pubkey, + )); + + let mut mock_db = MockBcDbInReadTx::new(); + mock_db + .expect_get_idty_state_by_pubkey() + .times(1) + .with(eq(pubkey)) + .returning(|_| Ok(None)); + + let mut datas = RuleDatas { + block: &block, + previous_block: &block, + }; + let mut not_sync_datas = RuleNotSyncDatas { db: &mock_db }; + + assert_eq!( + Err(InvalidRuleError::IssuerNotExist), + v10(&mut datas, &mut not_sync_datas) + ) + } + + #[test] + fn test_br_g100_issuer_is_member() { + let pubkey = dup_crypto_tests_tools::mocks::pubkey('A'); + let block = BlockDocument::V10(dubp_blocks_tests_tools::mocks::gen_empty_issued_block_v10( + pubkey, + )); + + let mut mock_db = MockBcDbInReadTx::new(); + mock_db + .expect_get_idty_state_by_pubkey() + .times(1) + .with(eq(pubkey)) + .returning(|_| Ok(Some(DbIdentityState::Member(vec![1])))); + + let mut datas = RuleDatas { + block: &block, + previous_block: &block, + }; + let mut not_sync_datas = RuleNotSyncDatas { db: &mock_db }; + + assert_eq!(Ok(()), v10(&mut datas, &mut not_sync_datas)) + } +} diff --git a/lib/modules/blockchain/blockchain/tests/apply_blocks_cautious.rs b/lib/modules/blockchain/blockchain/tests/apply_blocks_cautious.rs new file mode 100644 index 0000000000000000000000000000000000000000..cb2bbbf4e1e80a7258cd2199f9c25e8bc58eea8d --- /dev/null +++ b/lib/modules/blockchain/blockchain/tests/apply_blocks_cautious.rs @@ -0,0 +1,131 @@ +// Copyright (C) 2017-2019 The AXIOM TEAM Association. +// +// 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/>. + +mod common; + +use crate::common::*; +use dubp_block_doc::BlockDocument; +use dubp_currency_params::genesis_block_params::v10::BlockV10Parameters; +use durs_blockchain::BlockchainModule; +use durs_message::events::{BlockchainEvent, DursEvent}; +use durs_message::requests::DursReqContent; +use durs_message::DursMsg; +use durs_module::{ + ModuleEvent, ModuleReqFullId, ModuleReqId, ModuleRole, ModuleStaticName, RouterThreadMessage, +}; +use durs_network::events::NetworkEvent; +use durs_network::requests::OldNetworkRequest; +use pretty_assertions::assert_eq; +use std::sync::mpsc::{channel, Receiver, Sender}; + +#[cfg(unix)] +#[test] +fn test_apply_blocks_cautious() { + // Init test + let tmp_profile_path = common::init(); + + // Router channel + let (router_sender, router_receiver) = channel(); // RouterThreadMessage<DursMsg> + + let genesis_params = BlockV10Parameters::default(); + + let mut bc = init_bc_module( + router_sender, + genesis_params, + tmp_profile_path.as_path(), + true, + ); + + // Create blockchain module channel + let (bc_sender, bc_receiver): (Sender<DursMsg>, Receiver<DursMsg>) = channel(); + + let handle = std::thread::spawn(move || { + bc.start_blockchain(&bc_receiver, None); + }); + + // Receive 11 requests GetBlocks + for i in 0..11 { + let msg = router_receiver + .recv() + .expect("blockchain module disconnected."); + if let RouterThreadMessage::ModuleMessage(durs_msg) = msg { + assert_eq!( + DursMsg::Request { + req_from: BlockchainModule::name(), + req_to: ModuleRole::InterNodesNetwork, + req_id: ModuleReqId(i), + req_content: DursReqContent::OldNetworkRequest(OldNetworkRequest::GetBlocks( + ModuleReqFullId(BlockchainModule::name(), ModuleReqId(i)), + 50, + i * 50 + )), + }, + durs_msg + ); + log::info!("Router receive: {:?}", durs_msg); + } else { + panic!("Expect ModuleMesage, found: {:?}", msg) + } + } + + // Receive first g1-test chunk + let gt_chunk_0 = dubp_blocks_tests_tools::gt::get_gt_chunk(0); + receive_valid_blocks(&bc_sender, &router_receiver, gt_chunk_0); + + // Receive second g1-test chunk + let gt_chunk_1 = dubp_blocks_tests_tools::gt::get_gt_chunk(1); + receive_valid_blocks(&bc_sender, &router_receiver, gt_chunk_1); + + // Receive third g1-test chunk + let gt_chunk_2 = dubp_blocks_tests_tools::gt::get_gt_chunk(2); + receive_valid_blocks(&bc_sender, &router_receiver, gt_chunk_2); + + // Stop and clean + common::stop_and_clean(bc_sender, handle, tmp_profile_path); +} + +fn receive_valid_blocks( + bc_sender: &Sender<DursMsg>, + router_receiver: &Receiver<RouterThreadMessage<DursMsg>>, + blocks: Vec<BlockDocument>, +) { + bc_sender + .send(DursMsg::Event { + event_from: ModuleStaticName("toto"), + event_type: ModuleEvent::NewBlockFromNetwork, + event_content: DursEvent::NetworkEvent(NetworkEvent::ReceiveBlocks(blocks.clone())), + }) + .expect("Fail to send blocks to blockchain module."); + for block in blocks { + let msg = router_receiver + .recv() + .expect("blockchain module disconnected."); + if let RouterThreadMessage::ModuleMessage(durs_msg) = msg { + assert_eq!( + DursMsg::Event { + event_from: ModuleStaticName("blockchain"), + event_type: ModuleEvent::NewValidBlock, + event_content: DursEvent::BlockchainEvent(Box::new( + BlockchainEvent::StackUpValidBlock(Box::new(block)) + )), + }, + durs_msg + ); + //log::debug!("Router receive: {:?}", msg); + } else { + panic!("Expect ModuleMesage, found: {:?}", msg) + } + } +} diff --git a/lib/modules/blockchain/blockchain/tests/common.rs b/lib/modules/blockchain/blockchain/tests/common.rs index 21ed4455372f50f47e1a7bffc3d953b9b914dd0b..35e5549d3b61ab16ab5aaaba1a10db0551532bed 100644 --- a/lib/modules/blockchain/blockchain/tests/common.rs +++ b/lib/modules/blockchain/blockchain/tests/common.rs @@ -55,9 +55,9 @@ pub fn init_bc_module( fake_router_sender: Sender<RouterThreadMessage<DursMsg>>, genesis_block_parameters: BlockV10Parameters, tmp_path: &Path, + cautious_mode: bool, ) -> 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()); diff --git a/lib/modules/blockchain/blockchain/tests/revert_blocks.rs b/lib/modules/blockchain/blockchain/tests/revert_blocks.rs index d966a7b661a275db6533dfb7cadcc4b688bb34ba..734aad9e0413c3f0132043b7a27135420919ccd5 100644 --- a/lib/modules/blockchain/blockchain/tests/revert_blocks.rs +++ b/lib/modules/blockchain/blockchain/tests/revert_blocks.rs @@ -34,7 +34,7 @@ use std::sync::mpsc::{channel, Receiver, Sender}; #[cfg(unix)] #[test] -fn test_revert_block() { +fn test_revert_blocks() { // Init test let tmp_profile_path = common::init(); @@ -43,7 +43,12 @@ fn test_revert_block() { let genesis_params = BlockV10Parameters::default(); - let mut bc = init_bc_module(router_sender, genesis_params, tmp_profile_path.as_path()); + let mut bc = init_bc_module( + router_sender, + genesis_params, + tmp_profile_path.as_path(), + false, + ); // Create blockchain module channel let (bc_sender, bc_receiver): (Sender<DursMsg>, Receiver<DursMsg>) = channel(); diff --git a/lib/tests-tools/blocks-tests-tools/src/mocks.rs b/lib/tests-tools/blocks-tests-tools/src/mocks.rs index ad83d12825b5f1a4bf5ae820596d708caabbff93..c7f281efcef1d02dc0803540b6b7ac3bcf604ced 100644 --- a/lib/tests-tools/blocks-tests-tools/src/mocks.rs +++ b/lib/tests-tools/blocks-tests-tools/src/mocks.rs @@ -100,6 +100,14 @@ pub fn gen_empty_timed_block_v10( block } +/// Generate empty issued block document +/// (usefull for tests that only need issuer field) +pub fn gen_empty_issued_block_v10(issuer: PubKey) -> BlockDocumentV10 { + let mut block = gen_empty_block_v10(BlockNumber(0)); + block.issuers = vec![issuer]; + block +} + fn gen_empty_block_v10(block_number: BlockNumber) -> BlockDocumentV10 { BlockDocumentV10 { version: 10, diff --git a/lib/tools/rules-engine/src/lib.rs b/lib/tools/rules-engine/src/lib.rs index 800711925a897ea2a5577ee33aa3c1d93240cae9..b9d23fc3924b8ccdae1f7cd72f666edfb94756a7 100644 --- a/lib/tools/rules-engine/src/lib.rs +++ b/lib/tools/rules-engine/src/lib.rs @@ -91,6 +91,11 @@ impl RulesGroup { RulesGroup::Ser(vec![RuleNumber(rule_number)]) } #[inline] + /// Create serial set of rules + pub fn ser(rules_numbers: Vec<usize>) -> Self { + RulesGroup::Ser(rules_numbers.into_iter().map(|n| RuleNumber(n)).collect()) + } + #[inline] /// Create parallel set of rules pub fn pr(rules_numbers: Vec<usize>) -> Self { RulesGroup::Par(rules_numbers.into_iter().map(RulesGroup::s1).collect()) @@ -98,14 +103,14 @@ impl RulesGroup { } /// Rules engine -pub struct RulesEngine<D: Debug + Sync, E: Eq + Fail + PartialEq> { +pub struct RulesEngine<D: Sync, DNotSync, E: Eq + Fail + PartialEq> { /// All rules - all_rules: BTreeMap<RuleNumber, Rule<D, E>>, + all_rules: BTreeMap<RuleNumber, Rule<D, DNotSync, E>>, } -impl<D: Debug + Sync, E: Eq + Fail + PartialEq> RulesEngine<D, E> { +impl<D: Sync, DNotSync, E: Eq + Fail + PartialEq> RulesEngine<D, DNotSync, E> { /// Create new rules engine - pub fn new(all_rules: BTreeMap<RuleNumber, Rule<D, E>>) -> Self { + pub fn new(all_rules: BTreeMap<RuleNumber, Rule<D, DNotSync, E>>) -> Self { RulesEngine { all_rules } } @@ -148,9 +153,15 @@ impl<D: Debug + Sync, E: Eq + Fail + PartialEq> RulesEngine<D, E> { protocol_version: ProtocolVersion, rule_number: RuleNumber, rule_datas: &mut D, + rule_datas_not_sync: &mut DNotSync, ) -> Result<(), EngineError<E>> { if let Some(rule) = self.all_rules.get(&rule_number) { - rule.execute_mut(protocol_version, rule_number, rule_datas) + rule.execute_mut( + protocol_version, + rule_number, + rule_datas, + rule_datas_not_sync, + ) } else { Err(EngineError::RuleNotExist { rule_number, @@ -165,6 +176,7 @@ impl<D: Debug + Sync, E: Eq + Fail + PartialEq> RulesEngine<D, E> { protocol: Protocol, protocol_version: ProtocolVersion, rule_datas: &mut D, + rule_datas_not_sync: &mut DNotSync, ) -> Result<(), EngineError<E>> { if let Some(protocol_rules) = protocol.get(protocol_version) { for rules_group in &protocol_rules.0 { @@ -172,7 +184,12 @@ impl<D: Debug + Sync, E: Eq + Fail + PartialEq> RulesEngine<D, E> { RulesGroup::Ser(rules_numbers) => rules_numbers .iter() .map(|rule_number| { - self.apply_rule_mut(protocol_version, *rule_number, rule_datas) + self.apply_rule_mut( + protocol_version, + *rule_number, + rule_datas, + rule_datas_not_sync, + ) }) .collect(), RulesGroup::Par(rules_group) => rules_group @@ -254,12 +271,17 @@ mod tests { i: usize, } + #[derive(Debug)] + struct DatasNotSync { + j: usize, + } + #[derive(Debug, Eq, Fail, PartialEq)] #[fail(display = "")] struct Error {} - fn r2_v1(datas: &mut Datas) -> Result<(), Error> { - if datas.i == 0 { + fn r2_v1(datas: &mut Datas, datas_not_sync: &mut DatasNotSync) -> Result<(), Error> { + if datas.i == 0 && datas_not_sync.j < 2 { datas.i += 1; Ok(()) } else { @@ -275,8 +297,8 @@ mod tests { } } - fn get_test_engine() -> RulesEngine<Datas, Error> { - let all_rules: BTreeMap<RuleNumber, Rule<Datas, Error>> = btreemap![ + fn get_test_engine() -> RulesEngine<Datas, DatasNotSync, Error> { + let all_rules: BTreeMap<RuleNumber, Rule<Datas, DatasNotSync, Error>> = btreemap![ RuleNumber(2) => Rule::new(RuleNumber(2), btreemap![ ProtocolVersion(1) => RuleFn::RefMut(r2_v1), ]).expect("Fail to create rule n°2"), @@ -290,7 +312,7 @@ mod tests { #[test] fn rule_without_impl() { - if let Err(err) = Rule::<Datas, Error>::new(RuleNumber(1), btreemap![]) { + if let Err(err) = Rule::<Datas, DatasNotSync, Error>::new(RuleNumber(1), btreemap![]) { assert_eq!( RuleWithoutImpl { rule_number: RuleNumber(1), @@ -310,12 +332,18 @@ mod tests { let engine = get_test_engine(); let mut datas = Datas { i: 0 }; + let mut datas_not_sync = DatasNotSync { j: 1 }; let protocol_empty: Protocol = Protocol::new(btreemap![ ProtocolVersion(1) => Vec::<usize>::with_capacity(0).into() ]); - engine.apply_protocol(protocol_empty, ProtocolVersion(1), &mut datas) + engine.apply_protocol( + protocol_empty, + ProtocolVersion(1), + &mut datas, + &mut datas_not_sync, + ) } #[test] @@ -323,6 +351,7 @@ mod tests { let engine = get_test_engine(); let mut datas = Datas { i: 0 }; + let mut datas_not_sync = DatasNotSync { j: 1 }; let protocol_empty: Protocol = Protocol::new(btreemap![ ProtocolVersion(1) => Vec::<usize>::with_capacity(0).into() @@ -332,7 +361,12 @@ mod tests { Err(EngineError::ProtocolVersionNotExist { protocol_version: ProtocolVersion(2), }), - engine.apply_protocol(protocol_empty, ProtocolVersion(2), &mut datas) + engine.apply_protocol( + protocol_empty, + ProtocolVersion(2), + &mut datas, + &mut datas_not_sync + ) ) } @@ -341,6 +375,7 @@ mod tests { let engine = get_test_engine(); let mut datas = Datas { i: 0 }; + let mut datas_not_sync = DatasNotSync { j: 1 }; let protocol: Protocol = Protocol::new(btreemap![ ProtocolVersion(1) => vec![1usize].into() @@ -351,10 +386,16 @@ mod tests { rule_number: RuleNumber(1), protocol_version: ProtocolVersion(1) }), - engine.apply_protocol(protocol, ProtocolVersion(1), &mut datas) + engine.apply_protocol( + protocol, + ProtocolVersion(1), + &mut datas, + &mut datas_not_sync + ) ); let mut datas = Datas { i: 0 }; + let mut datas_not_sync = DatasNotSync { j: 1 }; let protocol_par: Protocol = Protocol::new(btreemap![ ProtocolVersion(1) => vec![RulesGroup::pr(vec![1usize])].into() @@ -365,7 +406,12 @@ mod tests { rule_number: RuleNumber(1), protocol_version: ProtocolVersion(1) }), - engine.apply_protocol(protocol_par, ProtocolVersion(1), &mut datas) + engine.apply_protocol( + protocol_par, + ProtocolVersion(1), + &mut datas, + &mut datas_not_sync + ) ); } @@ -374,6 +420,7 @@ mod tests { let engine = get_test_engine(); let mut datas = Datas { i: 1 }; + let mut datas_not_sync = DatasNotSync { j: 1 }; let protocol: Protocol = Protocol::new(btreemap![ ProtocolVersion(1) => vec![2usize].into() @@ -384,7 +431,12 @@ mod tests { rule_number: RuleNumber(2), cause: Error {}, })), - engine.apply_protocol(protocol, ProtocolVersion(1), &mut datas) + engine.apply_protocol( + protocol, + ProtocolVersion(1), + &mut datas, + &mut datas_not_sync + ) ) } @@ -393,6 +445,7 @@ mod tests { let engine = get_test_engine(); let mut datas = Datas { i: 0 }; + let mut datas_not_sync = DatasNotSync { j: 1 }; let protocol: Protocol = Protocol::new(btreemap![ ProtocolVersion(2) => vec![RulesGroup::pr(vec![3usize])].into() @@ -403,7 +456,12 @@ mod tests { rule_number: RuleNumber(3), cause: Error {}, })), - engine.apply_protocol(protocol, ProtocolVersion(2), &mut datas) + engine.apply_protocol( + protocol, + ProtocolVersion(2), + &mut datas, + &mut datas_not_sync + ) ) } @@ -412,6 +470,7 @@ mod tests { let engine = get_test_engine(); let mut datas = Datas { i: 0 }; + let mut datas_not_sync = DatasNotSync { j: 1 }; let protocol: Protocol = Protocol::new(btreemap![ ProtocolVersion(1) => vec![2usize, 3].into() @@ -422,7 +481,12 @@ mod tests { protocol_version: ProtocolVersion(1), rule_number: RuleNumber(3), }), - engine.apply_protocol(protocol, ProtocolVersion(1), &mut datas) + engine.apply_protocol( + protocol, + ProtocolVersion(1), + &mut datas, + &mut datas_not_sync + ) ) } @@ -431,6 +495,7 @@ mod tests { let engine = get_test_engine(); let mut datas = Datas { i: 0 }; + let mut datas_not_sync = DatasNotSync { j: 1 }; let protocol: Protocol = Protocol::new(btreemap![ ProtocolVersion(1) => vec![RulesGroup::pr(vec![3])].into() @@ -441,7 +506,12 @@ mod tests { protocol_version: ProtocolVersion(1), rule_number: RuleNumber(3), }), - engine.apply_protocol(protocol, ProtocolVersion(1), &mut datas) + engine.apply_protocol( + protocol, + ProtocolVersion(1), + &mut datas, + &mut datas_not_sync + ) ) } @@ -450,6 +520,7 @@ mod tests { let engine = get_test_engine(); let mut datas = Datas { i: 1 }; + let mut datas_not_sync = DatasNotSync { j: 1 }; let protocol: Protocol = Protocol::new(btreemap![ ProtocolVersion(2) => vec![RulesGroup::pr(vec![2usize, 3])].into() @@ -460,7 +531,12 @@ mod tests { protocol_version: ProtocolVersion(2), rule_number: RuleNumber(2), }), - engine.apply_protocol(protocol, ProtocolVersion(2), &mut datas) + engine.apply_protocol( + protocol, + ProtocolVersion(2), + &mut datas, + &mut datas_not_sync + ) ) } @@ -469,11 +545,17 @@ mod tests { let engine = get_test_engine(); let mut datas = Datas { i: 0 }; + let mut datas_not_sync = DatasNotSync { j: 1 }; let protocol: Protocol = Protocol::new(btreemap![ ProtocolVersion(2) => vec![2usize, 3].into() ]); - engine.apply_protocol(protocol, ProtocolVersion(2), &mut datas) + engine.apply_protocol( + protocol, + ProtocolVersion(2), + &mut datas, + &mut datas_not_sync, + ) } } diff --git a/lib/tools/rules-engine/src/rule.rs b/lib/tools/rules-engine/src/rule.rs index 62dfd220f3ad79c159a707da72c3de51fe84267f..0a164415cb713f3c36875503e6766dbd96dd8d90 100644 --- a/lib/tools/rules-engine/src/rule.rs +++ b/lib/tools/rules-engine/src/rule.rs @@ -44,12 +44,12 @@ pub struct RuleError<E: Eq + Fail + PartialEq> { pub type RuleFnRef<D, E> = fn(&D) -> Result<(), E>; /// Rule mutable execution function -pub type RuleFnRefMut<D, E> = fn(&mut D) -> Result<(), E>; +pub type RuleFnRefMut<D, DNotSync, E> = fn(&mut D, &mut DNotSync) -> Result<(), E>; /// Rule execution function -pub enum RuleFn<D, E> { +pub enum RuleFn<D, DNotSync, E> { Ref(RuleFnRef<D, E>), - RefMut(RuleFnRefMut<D, E>), + RefMut(RuleFnRefMut<D, DNotSync, E>), } #[derive(Debug, Copy, Clone, Eq, Fail, PartialEq)] @@ -62,16 +62,16 @@ pub struct RuleWithoutImpl { } /// Rule -pub struct Rule<D: Debug, E: Eq + Fail + PartialEq> { +pub struct Rule<D, DNotSync, E: Eq + Fail + PartialEq> { /// Dictionary of the different versions of the rule execution function - rule_versions: BTreeMap<ProtocolVersion, RuleFn<D, E>>, + rule_versions: BTreeMap<ProtocolVersion, RuleFn<D, DNotSync, E>>, } -impl<D: Debug, E: Eq + Fail + PartialEq> Rule<D, E> { +impl<D, DNotSync, E: Eq + Fail + PartialEq> Rule<D, DNotSync, E> { /// Create new rule pub fn new( rule_number: RuleNumber, - rule_versions: BTreeMap<ProtocolVersion, RuleFn<D, E>>, + rule_versions: BTreeMap<ProtocolVersion, RuleFn<D, DNotSync, E>>, ) -> Result<Self, RuleWithoutImpl> { if rule_versions.is_empty() { Err(RuleWithoutImpl { rule_number }) @@ -86,7 +86,7 @@ impl<D: Debug, E: Eq + Fail + PartialEq> Rule<D, E> { rule_number: RuleNumber, rule_datas: &D, ) -> Result<(), EngineError<E>> { - let rule_opt: Option<(&ProtocolVersion, &RuleFn<D, E>)> = + let rule_opt: Option<(&ProtocolVersion, &RuleFn<D, DNotSync, E>)> = self.rule_versions.range(..=protocol_version).last(); if let Some((_, rule_fn)) = rule_opt { match rule_fn { @@ -114,13 +114,14 @@ impl<D: Debug, E: Eq + Fail + PartialEq> Rule<D, E> { protocol_version: ProtocolVersion, rule_number: RuleNumber, rule_datas: &mut D, + rule_datas_not_sync: &mut DNotSync, ) -> Result<(), EngineError<E>> { - let rule_opt: Option<(&ProtocolVersion, &RuleFn<D, E>)> = + let rule_opt: Option<(&ProtocolVersion, &RuleFn<D, DNotSync, E>)> = self.rule_versions.range(..=protocol_version).last(); if let Some((_, rule_fn)) = rule_opt { match rule_fn { RuleFn::Ref(rule_fn_ref) => rule_fn_ref(rule_datas), - RuleFn::RefMut(rule_fn_ref_mut) => rule_fn_ref_mut(rule_datas), + RuleFn::RefMut(rule_fn_ref_mut) => rule_fn_ref_mut(rule_datas, rule_datas_not_sync), } .map_err(|err| { EngineError::RuleError(RuleError {