2 releases
Uses old Rust 2015
0.1.1 | Jun 10, 2016 |
---|---|
0.1.0 | Jun 10, 2016 |
#36 in #verifiable
230KB
714 lines
data_chain
Data blocks that are chained to provide cryptographically verifiable assuredness that they contain network valid data that a secured network has previously accepted. .
[API Documentation] (https://dirvine.github.io/data_chain/master/data_chain/)
[RFC] (https://github.com/dirvine/data_chain/blob/master/docs/0029-data-blocks.md)
lib.rs
:
#data_chain Data blocks can be chained to provide verifiable assuredness that they contain network valid data and not injected.
A chain may look like
`link` - all current group members - cryptographically secured as valid
data - DataIdentifiers interspersed in a chain of links
data - each block signed by a majority of previous link
....
`link` - As churn events occur new links are created
`link` - each link will have a majority
(usually n - 1 actually) members of previous link
The chain, when presented to the current close group (the group identified in last link) can be validated as holding data that has been agreed by the network over time to exist, A chain provides cryptographic proofs of data and group memberships over time.
The link is a group agreement chain component which is created by sorting the closest nodes
to a network node (Address) and sending this hash, signed to that node.
The recipient will then receive these, NodeBlocks
and create the chain link.
This link will allow the agreed members of the group so sign DataBlocks
for the chain
If a majority of the link members sign the data, it is validly in the chain.
On group membership changes, a new link is constructed in the chain and the process repeats.
A chain can split and nodes will maintain several chains, dependent on data overlaps with
the chains links.
The link identifier is the hash of all group members that contains the current node.
Containers of Chain Links only may also be maintained in groups to prove historic memberships of a network. It is not well enough understoof the validity of this action, but it may prove valuable in the event of network restarts. Please also see [github repository][1], and [RFC][3]
Examples
Basic usage:
extern crate sodiumoxide;
extern crate data_chain;
extern crate itertools;
fn main() {
use sodiumoxide::crypto;
use sodiumoxide::crypto::hash::sha256;
use itertools::Itertools;
use data_chain::{NodeBlock, BlockIdentifier, DataChain, create_link_descriptor};
::sodiumoxide::init();
let keys = (0..50)
.map(|_| crypto::sign::gen_keypair())
.collect_vec();
// ########################################################################################
// create groups of keys to resemble close_groups
// ########################################################################################
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 = 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);
// ########################################################################################
// Create NodeBlocks, these are what nodes send to each other
// Here they are all links only. For Put Delete Post
// these would be Identifiers for the data types that includes a hash of the serialised data
// ########################################################################################
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());
// here we need to add 2_1 again as 2_1 will be purged as part of test later on
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()); // fail w/wrong keys
let id_3 = NodeBlock::new(&keys[4].0, &keys[4].1, sd1_ident); // fail w/wrong keys
// #################### Create chain ########################
let mut chain = DataChain::default();
assert!(chain.is_empty());
// ############# start adding link #####################
assert!(chain.add_node_block(link1_1.unwrap()).is_none());
assert!(chain.validate_ownership(&pub1)); // 1 link - all OK
assert_eq!(chain.len(), 1);
assert!(chain.add_node_block(link1_2.unwrap()).is_none());
assert!(chain.validate_ownership(&pub1)); // 1 link - all OK
assert_eq!(chain.len(), 1);
assert!(chain.add_node_block(link1_3.unwrap()).is_none());
assert!(chain.validate_ownership(&pub1)); // 1 link - all OK
assert_eq!(chain.len(), 1);
// ########################################################################################
// pune_and_validate will prune any invalid data, In first link all data is valid if sig OK
// ########################################################################################
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());
// ########################################################################################
// Ading a link block will not increase length of chain links as it's not yet valid
// ########################################################################################
assert_eq!(chain.links_len(), 1);
assert_eq!(chain.len(), 2); // contains an invalid link for now
assert_eq!(chain.valid_len(), 1);
assert!(chain.add_node_block(sd1_1_again_1.unwrap()).is_none()); // re-add 2.1
// ########################################################################################
// The call below will prune 2_1 as it is a new link without majority agreement
// ########################################################################################
assert!(chain.validate_ownership(&pub2));
assert_eq!(chain.links_len(), 1);
assert!(chain.add_node_block(sd1_1_again_2.unwrap()).is_none()); // re-add 2.1
assert!(chain.add_node_block(sd1_2.unwrap()).is_some()); // majority reached here
assert!(chain.validate_ownership(&pub2)); // Ok as now 2 is in majority
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);
// the call below will not add any links
let id1 = id_1.unwrap();
assert!(chain.add_node_block(id1.clone()).is_none()); // only 1st id has valid signature
assert!(chain.add_node_block(id_3.unwrap()).is_none()); // will not get majority
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);
}
Panics
Errors
Safety
Aborts
There are no aborts in this crate.
Undefined Behaviour
None known of. [1]: https://github.com/dirvine/data_chain/tree/master [3]: https://github.com/dirvine/data_chain/blob/master/docs/0029-data-blocks.md
Dependencies
~29MB
~342K SLoC