use std::slice::{Split, SplitMut, SplitN, SplitNMut, RSplitN, RSplitNMut};
use itertools::Itertools;
use block::Block;
use block_identifier::BlockIdentifier;
use node_block::NodeBlock;
use node_block;
use sodiumoxide::crypto::sign::PublicKey;
#[derive(Default, Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub struct DataChain {
chain: Vec<Block>,
}
impl DataChain {
pub fn validate_ownership(&mut self, my_group: &[PublicKey]) -> bool {
self.mark_blocks_valid();
if let Some(last_link) = self.last_valid_link() {
return (last_link.proof()
.iter()
.filter(|k| my_group.iter().any(|&z| PublicKey(z.0) == k.0))
.count() * 2) > last_link.proof().len();
} else {
false
}
}
pub fn add_node_block(&mut self, block: NodeBlock) -> Option<BlockIdentifier> {
if !block.validate() {
return None;
}
let len; {
len = self.len();
}
{
let mut iter = self.chain.iter_mut().rev().multipeek();
'outer: while let Some(blk) = iter.next() {
if blk.identifier() == block.identifier() {
if len == 1 {
let _ = blk.add_proof(block.proof().clone());
return None;
}
if blk.identifier().is_link() && Self::link_locked(blk) {
blk.valid = true;
continue;
}
while let Some(link) = iter.peek() {
if link.identifier().is_link()
{
if blk.proof().len() >
if Self::link_locked(link) {
link.proof().len()
} else {
0
} {
continue 'outer;
} let _ = blk.add_proof(block.proof().clone());
if Self::validate_block_with_proof(blk, link) {
blk.valid = true;
break;
} else {
return None;
}
}
}
return Some(blk.identifier().clone());
}
}
}
if let Ok(blk) = Block::new(block) {
self.chain.push(blk);
}
None
}
pub fn find(&self, block_identifier: &BlockIdentifier) -> Option<&Block> {
self.chain.iter().find(|x| x.identifier() == block_identifier)
}
pub fn as_slice(&self) -> &[Block] {
self.chain.as_slice()
}
pub fn as_mut_slice(&mut self) -> &[Block] {
self.chain.as_mut_slice()
}
pub fn remove(&mut self, data_id: &BlockIdentifier) {
self.chain.retain(|x| x.identifier() != data_id || x.identifier().is_link());
}
pub fn clear(&mut self) {
self.chain.clear()
}
pub fn contains(&self, block_identifier: &BlockIdentifier) -> bool {
self.chain.iter().find(|x| x.identifier() == block_identifier).is_some()
}
pub fn position(&self, block_identifier: &BlockIdentifier) -> Option<usize> {
self.chain.iter().position(|x| x.identifier() == block_identifier)
}
pub fn insert(&mut self, index: usize, block: Block) {
self.chain.insert(index, block)
}
pub fn split<F>(&self, pred: F) -> Split<Block, F>
where F: FnMut(&Block) -> bool {
self.chain.split(pred)
}
pub fn split_mut<F>(&mut self, pred: F) -> SplitMut<Block, F>
where F: FnMut(&Block) -> bool {
self.chain.split_mut(pred)
}
pub fn splitn<F>(&self, n: usize, pred: F) -> SplitN<Block, F>
where F: FnMut(&Block) -> bool {
self.chain.splitn(n, pred)
}
pub fn splitn_mut<F>(&mut self, n: usize, pred: F) -> SplitNMut<Block, F>
where F: FnMut(&Block) -> bool {
self.chain.splitn_mut(n, pred)
}
pub fn split_off(&mut self, at: usize) -> Vec<Block> {
self.chain.split_off(at)
}
pub fn rsplitn<F>(&self, n: usize, pred: F) -> RSplitN<Block, F>
where F: FnMut(&Block) -> bool {
self.chain.rsplitn(n, pred)
}
pub fn rsplitn_mut<F>(&mut self, n: usize, pred: F) -> RSplitNMut<Block, F>
where F: FnMut(&Block) -> bool {
self.chain.rsplitn_mut(n, pred)
}
fn link_locked(link: &Block) -> bool {
if link.identifier().is_block() {
return false;
}
let keys = link.proof().iter().map(|x| x.0).collect_vec();
node_block::create_link_descriptor(&keys[..]) == link.identifier().hash().0
}
pub fn validate_block(&mut self, block: &mut Block) -> bool {
if let Some(ref mut link) = self.last_valid_link() {
return Self::validate_block_with_proof(block, link);
}
false
}
pub fn prune(&mut self) {
self.mark_blocks_valid();
self.chain.retain(|x| x.valid);
}
pub fn len(&self) -> usize {
self.chain.len()
}
pub fn valid_len(&self) -> usize {
self.blocks_len() + self.links_len()
}
pub fn blocks_len(&self) -> usize {
self.chain.iter().filter(|x| x.identifier().is_block() && x.valid).count()
}
pub fn links_len(&self) -> usize {
self.chain.iter().filter(|x| x.identifier().is_link() && x.valid).count()
}
pub fn is_empty(&self) -> bool {
self.chain.is_empty()
}
fn last_valid_link(&mut self) -> Option<&mut Block> {
self.chain.iter_mut().rev().find((|x| x.identifier().is_link() && x.valid))
}
pub fn get_all_links(&self) -> DataChain {
DataChain {
chain: self.chain
.iter()
.cloned()
.filter(|x| x.identifier().is_link())
.collect_vec(),
}
}
pub fn get_all_valid_links(&mut self) -> DataChain {
self.mark_blocks_valid();
DataChain {
chain: self.chain
.iter()
.cloned()
.filter(|x| x.identifier().is_link() && x.valid)
.collect_vec(),
}
}
pub fn mark_blocks_valid(&mut self) {
if let Some(mut first_link) = self.chain
.iter()
.cloned()
.find(|x| x.identifier().is_link()) {
for block in self.chain.iter_mut() {
block.remove_invalid_signatures();
if Self::validate_block_with_proof(block, &mut first_link) {
block.valid = true;
if block.identifier().is_link() {
first_link = block.clone();
}
} else {
block.valid = false;
}
}
} else {
self.chain.clear();
}
}
fn validate_block_with_proof(block: &Block, proof: &Block) -> bool {
proof.proof()
.iter()
.map(|x| x.0)
.filter(|&y| block.proof().iter().map(|z| z.0).any(|p| p == y))
.count() * 2 > proof.proof().len()
}
}
#[cfg(test)]
mod tests {
use super::*;
use sodiumoxide::crypto;
use sodiumoxide::crypto::hash::sha256;
use itertools::Itertools;
use node_block;
use node_block::NodeBlock;
use block_identifier::BlockIdentifier;
#[test]
fn link_only_chain() {
::sodiumoxide::init();
let keys = (0..10)
.map(|_| crypto::sign::gen_keypair())
.collect_vec();
let pub1 = keys.iter().map(|x| x.0).take(3).collect_vec();
let pub2 = keys.iter().map(|x| x.0).skip(1).take(3).collect_vec();
let pub3 = keys.iter().map(|x| x.0).skip(2).take(3).collect_vec();
assert!(pub1 != pub2);
assert!(pub1 != pub3);
assert!(pub1.len() == 3);
assert!(pub2.len() == 3);
assert!(pub3.len() == 3);
let link_desc1 = node_block::create_link_descriptor(&pub1[..]);
let link_desc2 = node_block::create_link_descriptor(&pub2[..]);
let link_desc3 = node_block::create_link_descriptor(&pub3[..]);
let identifier1 = BlockIdentifier::Link(link_desc1);
let identifier2 = BlockIdentifier::Link(link_desc2);
let identifier3 = BlockIdentifier::Link(link_desc3);
assert!(identifier1 != identifier2);
assert!(identifier1 != identifier3);
assert!(identifier2 != identifier3);
let link1_1 = NodeBlock::new(&keys[0].0, &keys[0].1, identifier1.clone());
let link1_2 = NodeBlock::new(&keys[1].0, &keys[1].1, identifier1.clone());
let link1_3 = NodeBlock::new(&keys[2].0, &keys[2].1, identifier1);
let link2_1 = NodeBlock::new(&keys[1].0, &keys[1].1, identifier2.clone());
let link2_1_again_1 = NodeBlock::new(&keys[1].0, &keys[1].1, identifier2.clone());
let link2_1_again_2 = NodeBlock::new(&keys[1].0, &keys[1].1, identifier2.clone());
let link2_2 = NodeBlock::new(&keys[2].0, &keys[2].1, identifier2.clone());
let link2_3 = NodeBlock::new(&keys[3].0, &keys[3].1, identifier2);
let link3_1 = NodeBlock::new(&keys[2].0, &keys[2].1, identifier3.clone());
let link3_2 = NodeBlock::new(&keys[3].0, &keys[3].1, identifier3.clone());
let link3_3 = NodeBlock::new(&keys[4].0, &keys[4].1, identifier3);
assert!(link1_1.is_ok());
assert!(link1_2.is_ok());
assert!(link1_3.is_ok());
assert!(link2_1.is_ok());
assert!(link2_2.is_ok());
assert!(link2_3.is_ok());
assert!(link3_1.is_ok());
assert!(link3_2.is_ok());
assert!(link3_3.is_ok());
let mut chain = DataChain::default();
assert!(chain.is_empty());
assert!(chain.add_node_block(link1_1.unwrap()).is_none());
assert!(chain.validate_ownership(&pub1)); assert_eq!(chain.len(), 1);
assert!(chain.add_node_block(link1_2.unwrap()).is_none());
assert!(chain.add_node_block(link1_3.unwrap()).is_none());
assert!(chain.validate_ownership(&pub1));
assert!(!chain.validate_ownership(&pub3));
assert_eq!(chain.len(), 1);
assert_eq!(chain.blocks_len(), 0);
assert_eq!(chain.links_len(), 1);
assert!(chain.add_node_block(link2_1.unwrap()).is_none());
assert_eq!(chain.links_len(), 1);
assert_eq!(chain.blocks_len(), 0);
assert_eq!(chain, chain.get_all_links()); let chain_valid_links1 = chain.get_all_valid_links();
assert_eq!(chain.links_len(), 1);
assert_eq!(chain.len(), 2); assert_eq!(chain.valid_len(), 1);
assert!(chain != chain_valid_links1); assert!(chain.add_node_block(link2_1_again_1.unwrap()).is_none()); assert!(chain.validate_ownership(&pub2));
assert_eq!(chain.links_len(), 1);
assert!(chain.add_node_block(link2_1_again_2.unwrap()).is_none());
assert!(chain.add_node_block(link2_2.unwrap()).is_some()); assert_eq!(chain.links_len(), 2);
assert_eq!(chain.len(), 2);
assert!(chain.add_node_block(link2_3.unwrap()).is_some());
assert!(chain.validate_ownership(&pub2));
assert!(chain.add_node_block(link3_1.unwrap()).is_none());
assert!(chain.add_node_block(link3_2.unwrap()).is_some()); assert!(chain.add_node_block(link3_3.unwrap()).is_some());
assert_eq!(chain.links_len(), 3);
assert!(chain.validate_ownership(&pub3));
assert!(!chain.validate_ownership(&pub1));
let chain_links = chain.get_all_links();
assert_eq!(chain, chain_links);
let chain_valid_links = chain.get_all_valid_links();
assert_eq!(chain, chain_valid_links);
assert_eq!(chain.len(), 3);
assert!(!chain.is_empty());
assert_eq!(chain.blocks_len(), 0);
assert_eq!(chain.links_len(), 3);
chain.prune();
assert_eq!(chain.len(), 3);
assert_eq!(chain.blocks_len(), 0);
assert_eq!(chain.links_len(), 3);
}
#[test]
fn single_link_chain() {
::sodiumoxide::init();
let keys = (0..50)
.map(|_| crypto::sign::gen_keypair())
.collect_vec();
let pub1 = keys.iter().map(|x| x.0).take(3).collect_vec();
let pub2 = keys.iter().map(|x| x.0).skip(1).take(3).collect_vec();
let pub3 = keys.iter().map(|x| x.0).skip(2).take(3).collect_vec();
assert!(pub1 != pub2);
assert!(pub1 != pub3);
assert!(pub1.len() == 3);
assert!(pub2.len() == 3);
assert!(pub3.len() == 3);
let link_desc1 = node_block::create_link_descriptor(&pub1[..]);
let identifier1 = BlockIdentifier::Link(link_desc1);
let id_ident = BlockIdentifier::ImmutableData(sha256::hash(b"id1hash"));
let sd1_ident = BlockIdentifier::StructuredData(sha256::hash(b"sd1hash"),
sha256::hash(b"sd1name"));
let sd2_ident = BlockIdentifier::StructuredData(sha256::hash(b"s21hash"),
sha256::hash(b"sd2name"));
assert!(identifier1 != id_ident);
assert!(identifier1 != sd1_ident);
assert!(id_ident != sd1_ident);
assert!(sd1_ident != sd2_ident);
let link1_1 = NodeBlock::new(&keys[0].0, &keys[0].1, identifier1.clone());
let link1_2 = NodeBlock::new(&keys[1].0, &keys[1].1, identifier1.clone());
let link1_3 = NodeBlock::new(&keys[2].0, &keys[2].1, identifier1);
let sd1_1 = NodeBlock::new(&keys[1].0, &keys[1].1, id_ident.clone());
let sd1_1_again_1 = NodeBlock::new(&keys[1].0, &keys[1].1, id_ident.clone());
let sd1_1_again_2 = NodeBlock::new(&keys[1].0, &keys[1].1, id_ident.clone());
let sd1_2 = NodeBlock::new(&keys[2].0, &keys[2].1, id_ident.clone());
let sd1_3 = NodeBlock::new(&keys[3].0, &keys[3].1, id_ident);
let id_1 = NodeBlock::new(&keys[2].0, &keys[2].1, sd1_ident.clone());
let id_2 = NodeBlock::new(&keys[3].0, &keys[3].1, sd1_ident.clone()); let id_3 = NodeBlock::new(&keys[4].0, &keys[4].1, sd1_ident); let mut chain = DataChain::default();
assert!(chain.is_empty());
assert!(chain.add_node_block(link1_1.unwrap()).is_none());
assert!(chain.validate_ownership(&pub1)); assert_eq!(chain.len(), 1);
assert!(chain.add_node_block(link1_2.unwrap()).is_none());
assert!(chain.validate_ownership(&pub1)); assert_eq!(chain.len(), 1);
assert!(chain.add_node_block(link1_3.unwrap()).is_none());
assert!(chain.validate_ownership(&pub1)); assert_eq!(chain.len(), 1);
assert!(chain.validate_ownership(&pub1));
assert!(!chain.validate_ownership(&pub3));
assert_eq!(chain.len(), 1);
assert_eq!(chain.blocks_len(), 0);
assert_eq!(chain.links_len(), 1);
assert!(chain.add_node_block(sd1_1.unwrap()).is_none());
assert_eq!(chain.links_len(), 1);
assert_eq!(chain.len(), 2); assert_eq!(chain.valid_len(), 1);
assert!(chain.add_node_block(sd1_1_again_1.unwrap()).is_none()); assert!(chain.validate_ownership(&pub2));
assert_eq!(chain.links_len(), 1);
assert!(chain.add_node_block(sd1_1_again_2.unwrap()).is_none()); assert!(chain.add_node_block(sd1_2.unwrap()).is_some()); assert!(chain.validate_ownership(&pub2)); assert_eq!(chain.links_len(), 1);
assert_eq!(chain.blocks_len(), 1);
assert_eq!(chain.len(), 2);
assert!(chain.add_node_block(sd1_3.unwrap()).is_some());
assert!(chain.validate_ownership(&pub2));
assert_eq!(chain.links_len(), 1);
assert_eq!(chain.blocks_len(), 1);
assert_eq!(chain.len(), 2);
let id1 = id_1.unwrap();
assert!(chain.add_node_block(id1.clone()).is_none()); assert!(chain.add_node_block(id_3.unwrap()).is_none()); assert!(chain.add_node_block(id_2.unwrap()).is_none());
assert_eq!(chain.links_len(), 1);
assert_eq!(chain.blocks_len(), 1);
assert_eq!(chain.len(), 3);
chain.prune();
assert_eq!(chain.len(), 2);
assert_eq!(chain.valid_len(), 2);
assert!(chain.add_node_block(id1.clone()).is_none());
assert_eq!(chain.len(), 3);
assert_eq!(chain.valid_len(), 2);
chain.remove(id1.identifier());
assert_eq!(chain.len(), 2);
assert!(chain.add_node_block(id1.clone()).is_none());
assert_eq!(chain.len(), 3);
assert_eq!(chain.valid_len(), 2);
}
}