From bb3ecf879568cbb556b9f8ce786023e41a262a6d Mon Sep 17 00:00:00 2001
From: ZettaScript <contact@zettascript.org>
Date: Tue, 26 Mar 2019 18:41:31 +0100
Subject: [PATCH] [feat] blockchain: check rules BR_G99->04

---
 .../blockchain/src/dubp/check/mod.rs          | 89 ++++++++++++++++++-
 .../blockchain/blockchain/src/dubp/mod.rs     |  1 +
 lib/modules/blockchain/blockchain/src/lib.rs  |  4 +-
 3 files changed, 91 insertions(+), 3 deletions(-)

diff --git a/lib/modules/blockchain/blockchain/src/dubp/check/mod.rs b/lib/modules/blockchain/blockchain/src/dubp/check/mod.rs
index 0c9959ba..cb3b0bf4 100644
--- a/lib/modules/blockchain/blockchain/src/dubp/check/mod.rs
+++ b/lib/modules/blockchain/blockchain/src/dubp/check/mod.rs
@@ -23,12 +23,36 @@ use dubp_documents::*;
 use dup_crypto::keys::PubKey;
 use durs_blockchain_dal::*;
 use durs_wot::*;
+use std::cmp::Ordering;
 use std::collections::HashMap;
 
-#[derive(Debug, Copy, Clone)]
+#[derive(Fail, Debug, Copy, Clone)]
+pub enum InvalidRuleError {
+    #[fail(display = "BR_G99: different currency")]
+    DifferentCurrency,
+    #[fail(display = "BR_G03: wrong previous issuer")]
+    WrongPreviousIssuer,
+    #[fail(display = "BR_G100: issuer is not a member")]
+    NotMemberIssuer,
+    #[fail(display = "BR_G04: wrong issuers count")]
+    WrongIssuersCount,
+    #[fail(display = "BR_G05: genesis: issuers frame must be 1")]
+    WrongIssuersFrame,
+}
+
+#[derive(Fail, Debug, Copy, Clone)]
 pub enum InvalidBlockError {
+    #[fail(display = "Error: not found previous block")]
     NoPreviousBlock,
+    #[fail(display = "Error: version decrease in new block")]
     VersionDecrease,
+    #[fail(display = "Error at {}", _0)]
+    InvalidRule(InvalidRuleError),
+}
+
+#[inline]
+fn invalid_rule_error(error: InvalidRuleError) -> BlockError {
+    BlockError::InvalidBlock(InvalidBlockError::InvalidRule(error))
 }
 
 pub fn verify_block_validity<W: WebOfTrust>(
@@ -37,6 +61,7 @@ pub fn verify_block_validity<W: WebOfTrust>(
     _certs_db: &BinDB<CertsExpirV10Datas>,
     _wot_index: &HashMap<PubKey, NodeId>,
     _wot_db: &BinDB<W>,
+    identities_db: &BinDB<IdentitiesV10Datas>,
 ) -> Result<(), BlockError> {
     // Rules that do not concern genesis block
     if block.number.0 > 0 {
@@ -56,6 +81,68 @@ pub fn verify_block_validity<W: WebOfTrust>(
         if previous_block.version > block.version {
             return Err(BlockError::InvalidBlock(InvalidBlockError::VersionDecrease));
         }
+
+        // BR_G99 - same currency
+        if previous_block.currency != block.currency {
+            return Err(invalid_rule_error(InvalidRuleError::DifferentCurrency));
+        }
+
+        // BR_G03 - previous issuer
+        if Some(previous_block.issuers[0]) != block.previous_issuer {
+            return Err(invalid_rule_error(InvalidRuleError::WrongPreviousIssuer));
+        }
+
+        // BR_G100 - issuer is member
+        match readers::identity::get_identity(identities_db, &block.issuers[0])?
+            .expect("safe unwrap")
+            .state
+        {
+            entities::identity::DALIdentityState::Member(_) => {}
+            _ => return Err(invalid_rule_error(InvalidRuleError::NotMemberIssuer)),
+        }
+
+        // BR_G04 - issuers count
+        let mut issuers: Vec<PubKey> = vec![];
+        for i in (previous_block.issuers_frame as u32)..=previous_block.number.0 {
+            let issuer = readers::block::get_block_in_local_blockchain(blockchain_db, BlockId(i))?
+                .expect("safe unwrap")
+                .issuers[0];
+            if !issuers.contains(&issuer) {
+                issuers.push(issuer);
+            }
+        }
+        if issuers.len() != block.issuers_count {
+            return Err(invalid_rule_error(InvalidRuleError::WrongIssuersCount));
+        }
+
+        //BR_G05 - issuers frame
+        if block.issuers_frame
+            != previous_block.issuers_frame
+                + match previous_block.issuers_frame_var.cmp(&0) {
+                    Ordering::Less => -1,
+                    Ordering::Greater => 1,
+                    Ordering::Equal => 0,
+                }
+        {
+            return Err(invalid_rule_error(InvalidRuleError::WrongIssuersFrame));
+        }
+    }
+    // Only rules that do concern genesis block
+    else {
+        // BR_G03 - previous issuer
+        if block.previous_issuer != None {
+            return Err(invalid_rule_error(InvalidRuleError::WrongPreviousIssuer));
+        }
+
+        // BR_G04 - issuers count
+        if block.issuers_count != 0 {
+            return Err(invalid_rule_error(InvalidRuleError::WrongIssuersCount));
+        }
+
+        // BR_G05 - issuers count
+        if block.issuers_frame != 1 {
+            return Err(invalid_rule_error(InvalidRuleError::WrongIssuersFrame));
+        }
     }
 
     Ok(())
diff --git a/lib/modules/blockchain/blockchain/src/dubp/mod.rs b/lib/modules/blockchain/blockchain/src/dubp/mod.rs
index 0cb4208c..fc0b823c 100644
--- a/lib/modules/blockchain/blockchain/src/dubp/mod.rs
+++ b/lib/modules/blockchain/blockchain/src/dubp/mod.rs
@@ -98,6 +98,7 @@ pub fn check_and_apply_block(
             &bc.wot_databases.certs_db,
             &bc.wot_index,
             &bc.wot_databases.wot_db,
+            &bc.wot_databases.identities_db,
         )?;
 
         Ok(CheckAndApplyBlockReturn::ValidBlock(apply_valid_block(
diff --git a/lib/modules/blockchain/blockchain/src/lib.rs b/lib/modules/blockchain/blockchain/src/lib.rs
index 81bfe176..657f4825 100644
--- a/lib/modules/blockchain/blockchain/src/lib.rs
+++ b/lib/modules/blockchain/blockchain/src/lib.rs
@@ -28,8 +28,8 @@
     unused_qualifications
 )]
 
-//#[macro_use]
-//extern crate failure;
+#[macro_use]
+extern crate failure;
 #[macro_use]
 extern crate log;
 
-- 
GitLab