...
 
Commits (4)
......@@ -23,40 +23,224 @@ 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_genesis_block_validity(block: &BlockDocument) -> Result<(), BlockError> {
// 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(())
}
pub fn verify_block_validity<W: WebOfTrust>(
block: &BlockDocument,
blockchain_db: &BinDB<LocalBlockchainV10Datas>,
identities_db: &BinDB<IdentitiesV10Datas>,
_certs_db: &BinDB<CertsExpirV10Datas>,
_wot_index: &HashMap<PubKey, NodeId>,
_wot_db: &BinDB<W>,
) -> Result<(), BlockError> {
// Rules that do not concern genesis block
if block.number.0 > 0 {
// Get previous block
let previous_block_opt = readers::block::get_block_in_local_blockchain(
blockchain_db,
BlockNumber(block.number.0 - 1),
)?;
// Get previous block
let previous_block_opt = readers::block::get_block_in_local_blockchain(
blockchain_db,
BlockNumber(block.number.0 - 1),
)?;
// Previous block must exist
if previous_block_opt.is_none() {
return Err(BlockError::InvalidBlock(InvalidBlockError::NoPreviousBlock));
}
let previous_block = previous_block_opt.unwrap_or_else(|| panic!(dbg!("dev error")));
// Block version must not decrease
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));
}
// Previous block must exist
if previous_block_opt.is_none() {
return Err(BlockError::InvalidBlock(InvalidBlockError::NoPreviousBlock));
}
let previous_block = previous_block_opt.expect("safe unwrap");
// 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
if let entities::identity::DALIdentityState::Member(_) =
readers::identity::get_identity(identities_db, &block.issuers[0])?
.unwrap_or_else(|| panic!(dbg!("dev error")))
.state
{
} else {
return Err(invalid_rule_error(InvalidRuleError::NotMemberIssuer));
}
// BR_G04 - issuers count
let issuers_frame = readers::block::get_current_frame(
&entities::block::DALBlock {
block: block.clone(),
expire_certs: None,
},
blockchain_db,
)?;
if issuers_frame.len() != block.issuers_count {
return Err(invalid_rule_error(InvalidRuleError::WrongIssuersCount));
}
// Block version must not decrease
if previous_block.version > block.version {
return Err(BlockError::InvalidBlock(InvalidBlockError::VersionDecrease));
}
//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));
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use dubp_documents_tests_tools::mocks::*;
use dup_crypto_tests_tools::mocks::*;
use durs_blockchain_dal::entities::block::DALBlock;
use durs_blockchain_dal::entities::identity::*;
#[test]
fn test_verify_blocks() -> Result<(), BlockError> {
let blocks_dbs = BlocksV10DBs::open(None);
let wot_dbs = WotsV10DBs::open(None);
let wot_index: HashMap<PubKey, NodeId> = HashMap::new();
let idty_a = identity::gen_mock_idty(pubkey('A'), BlockNumber(0));
let pubkey_a = idty_a.issuers()[0];
let idty_b = identity::gen_mock_idty(pubkey('B'), BlockNumber(0));
let pubkey_b = idty_b.issuers()[0];
let mut blocks = gen_empty_timed_blocks(2, 300);
// Valid block 0
blocks[0].issuers_frame = 1;
blocks[0].issuers.push(pubkey_a);
blocks[0].identities.push(idty_a.clone());
blocks[0].identities.push(idty_b.clone());
verify_genesis_block_validity(&blocks[0])?;
blocks_dbs
.blockchain_db
.write(|db| {
db.insert(
blocks[0].number,
DALBlock {
block: blocks[0].clone(),
expire_certs: None,
},
);
})
.expect("Fail write to blockchain db");
wot_dbs
.identities_db
.write(|db| {
db.insert(
pubkey_a,
DALIdentity {
hash: String::new(),
state: DALIdentityState::Member(vec![]),
joined_on: blocks[0].blockstamp(),
expired_on: None,
revoked_on: None,
idty_doc: idty_a,
wot_id: NodeId(0),
ms_created_block_id: blocks[0].number,
ms_chainable_on: vec![0],
cert_chainable_on: vec![0],
},
);
db.insert(
pubkey_b,
DALIdentity {
hash: String::new(),
state: DALIdentityState::Member(vec![]),
joined_on: blocks[0].blockstamp(),
expired_on: None,
revoked_on: None,
idty_doc: idty_b,
wot_id: NodeId(1),
ms_created_block_id: blocks[0].number,
ms_chainable_on: vec![0],
cert_chainable_on: vec![0],
},
);
})
.expect("Fail write to idty db");
// Valid block 1
blocks[1].issuers_count = 1;
blocks[1].issuers_frame = 1;
blocks[1].issuers_frame_var = 5;
blocks[1].issuers.push(pubkey_b);
blocks[1].previous_issuer = Some(pubkey_a);
verify_block_validity(
&blocks[1],
&blocks_dbs.blockchain_db,
&wot_dbs.identities_db,
&wot_dbs.certs_db,
&wot_index,
&wot_dbs.wot_db,
)?;
Ok(())
}
}
......@@ -92,13 +92,18 @@ pub fn check_and_apply_block(
)?;
// Verify block validity (check all protocol rule, very long !)
verify_block_validity(
&block_doc,
&bc.blocks_databases.blockchain_db,
&bc.wot_databases.certs_db,
&bc.wot_index,
&bc.wot_databases.wot_db,
)?;
if block_doc.number.0 == 0 {
verify_genesis_block_validity(&block_doc)?;
} else {
verify_block_validity(
&block_doc,
&bc.blocks_databases.blockchain_db,
&bc.wot_databases.identities_db,
&bc.wot_databases.certs_db,
&bc.wot_index,
&bc.wot_databases.wot_db,
)?;
}
Ok(CheckAndApplyBlockReturn::ValidBlock(apply_valid_block(
block_doc,
......
......@@ -28,8 +28,8 @@
unused_qualifications
)]
//#[macro_use]
//extern crate failure;
#[macro_use]
extern crate failure;
#[macro_use]
extern crate log;
......