mod metadata;
mod seq_crdt;
use crate::{Error, PublicKey, Result};
use crdts::lseq::ident::Identifier;
pub use metadata::{
Action, Address, Entries, Entry, Index, Kind, Perm, Permissions, Policy, PrivatePermissions,
PrivatePolicy, PublicPermissions, PublicPolicy, User,
};
use seq_crdt::{CrdtDataOperation, CrdtPolicyOperation, Op, SequenceCrdt};
use serde::{Deserialize, Serialize};
use std::{
collections::BTreeMap,
fmt::{self, Debug, Formatter},
hash::Hash,
};
use xor_name::XorName;
type ActorType = String;
pub type DataWriteOp<T> = CrdtDataOperation<ActorType, T>;
pub type PolicyWriteOp<T> = CrdtPolicyOperation<ActorType, T>;
pub type PublicSeqData = SequenceCrdt<ActorType, PublicPolicy>;
pub type PrivateSeqData = SequenceCrdt<ActorType, PrivatePolicy>;
impl Debug for PublicSeqData {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
write!(formatter, "PubSequence {:?}", self.address().name())
}
}
impl Debug for PrivateSeqData {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
write!(formatter, "PrivSequence {:?}", self.address().name())
}
}
macro_rules! check_perm {
($policy: ident, $requester: ident, $action: ident) => {
match $policy {
None => {
if $action == Action::Admin {
Ok(())
} else {
Err(Error::AccessDenied($requester))
}
}
Some(policy) => policy.is_action_allowed($requester, $action),
}
};
}
#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Serialize, Deserialize, Debug)]
enum SeqData {
Public(PublicSeqData),
Private(PrivateSeqData),
}
#[derive(Clone, Eq, PartialEq, PartialOrd, Hash, Serialize, Deserialize, Debug)]
pub struct Data {
operations_pk: PublicKey,
data: SeqData,
}
impl Data {
pub fn new_public(operations_pk: PublicKey, actor: ActorType, name: XorName, tag: u64) -> Self {
Self {
operations_pk,
data: SeqData::Public(PublicSeqData::new(actor, Address::Public { name, tag })),
}
}
pub fn new_private(
operations_pk: PublicKey,
actor: ActorType,
name: XorName,
tag: u64,
) -> Self {
Self {
operations_pk,
data: SeqData::Private(PrivateSeqData::new(actor, Address::Private { name, tag })),
}
}
pub fn address(&self) -> &Address {
match &self.data {
SeqData::Public(data) => data.address(),
SeqData::Private(data) => data.address(),
}
}
pub fn kind(&self) -> Kind {
self.address().kind()
}
pub fn name(&self) -> &XorName {
self.address().name()
}
pub fn tag(&self) -> u64 {
self.address().tag()
}
pub fn is_pub(&self) -> bool {
self.kind().is_pub()
}
pub fn is_private(&self) -> bool {
self.kind().is_private()
}
pub fn len(&self, requester: Option<PublicKey>) -> Result<u64> {
self.check_permission(Action::Read, requester, None)?;
Ok(match &self.data {
SeqData::Public(data) => data.len(),
SeqData::Private(data) => data.len(),
})
}
pub fn is_empty(&self, requester: Option<PublicKey>) -> Result<bool> {
self.check_permission(Action::Read, requester, None)?;
Ok(self.len(None)? == 0)
}
pub fn policy_version(&self, requester: Option<PublicKey>) -> Result<Option<u64>> {
self.check_permission(Action::Read, requester, None)?;
Ok(match &self.data {
SeqData::Public(data) => data.policy_index(),
SeqData::Private(data) => data.policy_index(),
})
}
pub fn in_range(
&self,
start: Index,
end: Index,
requester: Option<PublicKey>,
) -> Result<Option<Entries>> {
self.check_permission(Action::Read, requester, None)?;
Ok(match &self.data {
SeqData::Public(data) => data.in_range(start, end),
SeqData::Private(data) => data.in_range(start, end),
})
}
pub fn get(&self, index: Index, requester: Option<PublicKey>) -> Result<Option<&Vec<u8>>> {
self.check_permission(Action::Read, requester, None)?;
Ok(match &self.data {
SeqData::Public(data) => data.get(index),
SeqData::Private(data) => data.get(index),
})
}
pub fn last_entry(&self, requester: Option<PublicKey>) -> Result<Option<&Entry>> {
self.check_permission(Action::Read, requester, None)?;
Ok(match &self.data {
SeqData::Public(data) => data.last_entry(),
SeqData::Private(data) => data.last_entry(),
})
}
pub fn create_unsigned_append_op(&mut self, entry: Entry) -> Result<DataWriteOp<Entry>> {
self.check_permission(Action::Append, None, None)?;
match &mut self.data {
SeqData::Public(data) => data.create_append_op(entry, self.operations_pk),
SeqData::Private(data) => data.create_append_op(entry, self.operations_pk),
}
}
pub fn apply_data_op(&mut self, op: DataWriteOp<Entry>) -> Result<()> {
self.check_permission(Action::Append, Some(op.source), Some(&op.ctx))?;
match &mut self.data {
SeqData::Public(data) => data.apply_data_op(op),
SeqData::Private(data) => data.apply_data_op(op),
}
}
pub fn create_unsigned_public_policy_op(
&mut self,
owner: PublicKey,
permissions: BTreeMap<User, PublicPermissions>,
) -> Result<PolicyWriteOp<PublicPolicy>> {
self.check_permission(Action::Admin, None, None)?;
match &mut self.data {
SeqData::Public(data) => {
data.create_policy_op(PublicPolicy { owner, permissions }, self.operations_pk)
}
SeqData::Private(_) => Err(Error::InvalidOperation),
}
}
pub fn create_unsigned_private_policy_op(
&mut self,
owner: PublicKey,
permissions: BTreeMap<PublicKey, PrivatePermissions>,
) -> Result<PolicyWriteOp<PrivatePolicy>> {
self.check_permission(Action::Admin, None, None)?;
match &mut self.data {
SeqData::Private(data) => {
data.create_policy_op(PrivatePolicy { owner, permissions }, self.operations_pk)
}
SeqData::Public(_) => Err(Error::InvalidOperation),
}
}
pub fn apply_public_policy_op(&mut self, op: PolicyWriteOp<PublicPolicy>) -> Result<()> {
match op.ctx {
Some((ref policy_id, _)) => {
self.check_permission(Action::Admin, Some(op.source), Some(policy_id))?
}
None => self.check_permission(Action::Admin, Some(op.source), None)?,
}
match (&mut self.data, &op.crdt_op) {
(SeqData::Public(data), Op::Insert { .. }) => data.apply_policy_op(op),
_ => Err(Error::InvalidOperation),
}
}
pub fn apply_private_policy_op(&mut self, op: PolicyWriteOp<PrivatePolicy>) -> Result<()> {
match op.ctx {
Some((ref policy_id, _)) => {
self.check_permission(Action::Admin, Some(op.source), Some(policy_id))?
}
None => self.check_permission(Action::Admin, Some(op.source), None)?,
}
match &mut self.data {
SeqData::Private(data) => data.apply_policy_op(op),
_ => Err(Error::InvalidOperation),
}
}
pub fn permissions(&self, user: User, requester: Option<PublicKey>) -> Result<Permissions> {
let version = self.policy_version(None)?.ok_or(Error::PolicyNotSet)?;
self.permissions_at(user, version, requester)
}
pub fn permissions_at(
&self,
user: User,
version: impl Into<Index>,
requester: Option<PublicKey>,
) -> Result<Permissions> {
self.check_permission(Action::Read, requester, None)?;
let user_perm = match &self.data {
SeqData::Public(data) => data
.policy_at(version)
.ok_or(Error::NoSuchEntry)?
.permissions(user)
.ok_or(Error::NoSuchEntry)?,
SeqData::Private(data) => data
.policy_at(version)
.ok_or(Error::NoSuchEntry)?
.permissions(user)
.ok_or(Error::NoSuchEntry)?,
};
Ok(user_perm)
}
pub fn public_policy(&self) -> Result<&PublicPolicy> {
let version = self.policy_version(None)?.ok_or(Error::PolicyNotSet)?;
self.public_policy_at(version)
}
pub fn public_policy_at(&self, version: impl Into<Index>) -> Result<&PublicPolicy> {
let perms = match &self.data {
SeqData::Public(data) => data.policy_at(version),
SeqData::Private(_) => return Err(Error::InvalidOperation),
};
perms.ok_or(Error::NoSuchEntry)
}
pub fn private_policy(&self, requester: Option<PublicKey>) -> Result<&PrivatePolicy> {
let version = self.policy_version(None)?.ok_or(Error::PolicyNotSet)?;
self.private_policy_at(version, requester)
}
pub fn private_policy_at(
&self,
version: impl Into<Index>,
requester: Option<PublicKey>,
) -> Result<&PrivatePolicy> {
self.check_permission(Action::Read, requester, None)?;
let perms = match &self.data {
SeqData::Private(data) => data.policy_at(version),
SeqData::Public(_) => return Err(Error::InvalidOperation),
};
perms.ok_or(Error::NoSuchEntry)
}
pub fn check_permission(
&self,
action: Action,
requester: Option<PublicKey>,
policy_id: Option<&Identifier<ActorType>>,
) -> Result<()> {
macro_rules! get_policy {
($policy_id: ident, $data: ident) => {
match $policy_id {
Some(id) => match $data.policy_by_id(id) {
Some(policy) => Ok(Some(policy)),
None => Err(Error::OpNotCausallyReady),
},
None => Ok($data.policy()),
}
};
}
match (requester, &self.data) {
(Some(requester), SeqData::Public(data)) => {
let policy = get_policy!(policy_id, data)?;
check_perm!(policy, requester, action)
}
(Some(requester), SeqData::Private(data)) => {
let policy = get_policy!(policy_id, data)?;
check_perm!(policy, requester, action)
}
(None, SeqData::Public(data)) => {
let policy = get_policy!(policy_id, data)?;
let requester = self.operations_pk;
check_perm!(policy, requester, action)
}
(None, SeqData::Private(data)) => {
let policy = get_policy!(policy_id, data)?;
let requester = self.operations_pk;
check_perm!(policy, requester, action)
}
}
}
pub fn owner(&self) -> PublicKey {
self.operations_pk
}
}
#[cfg(test)]
mod tests {
use crate::{
utils, Error, Keypair, PublicKey, Result, Sequence, SequenceAddress, SequenceDataWriteOp,
SequenceEntry, SequenceIndex, SequenceKind, SequencePermissions, SequencePolicyWriteOp,
SequencePrivatePermissions, SequencePrivatePolicy, SequencePublicPermissions,
SequencePublicPolicy, SequenceUser,
};
use anyhow::anyhow;
use proptest::prelude::*;
use rand::rngs::OsRng;
use rand::seq::SliceRandom;
use std::collections::BTreeMap;
use std::sync::Arc;
use xor_name::XorName;
pub fn sign_sequence_data_op(
mut op: SequenceDataWriteOp<SequenceEntry>,
keypair: &Keypair,
) -> Result<SequenceDataWriteOp<SequenceEntry>> {
let bytes = utils::serialise(&op.crdt_op)?;
let signature = keypair.sign(&bytes);
op.signature = Some(signature);
Ok(op)
}
pub fn sign_sequence_public_policy_op(
mut op: SequencePolicyWriteOp<SequencePublicPolicy>,
keypair: &Keypair,
) -> Result<SequencePolicyWriteOp<SequencePublicPolicy>> {
let bytes = utils::serialise(&op.crdt_op)?;
let signature = keypair.sign(&bytes);
op.signature = Some(signature);
Ok(op)
}
pub fn sign_sequence_private_policy_op(
mut op: SequencePolicyWriteOp<SequencePrivatePolicy>,
keypair: &Keypair,
) -> Result<SequencePolicyWriteOp<SequencePrivatePolicy>> {
let bytes = utils::serialise(&op.crdt_op).map_err(|err| {
Error::Serialisation(format!(
"Could not serialise CRDT policy write operation to generate signature: {}",
err
))
})?;
let signature = keypair.sign(&bytes);
op.signature = Some(signature);
Ok(op)
}
#[test]
fn sequence_create_public() {
let op_source_pk_keypair = Keypair::new_ed25519(&mut OsRng);
let actor = op_source_pk_keypair.public_key();
let sequence_name = XorName::random();
let sequence_tag = 43_000;
let sequence =
Sequence::new_public(actor, "actor".to_string(), sequence_name, sequence_tag);
assert_eq!(sequence.kind(), SequenceKind::Public);
assert_eq!(*sequence.name(), sequence_name);
assert_eq!(sequence.tag(), sequence_tag);
assert!(sequence.is_pub());
assert!(!sequence.is_private());
let sequence_address =
SequenceAddress::from_kind(SequenceKind::Public, sequence_name, sequence_tag);
assert_eq!(*sequence.address(), sequence_address);
}
#[test]
fn sequence_create_private() {
let op_source_pk_keypair = Keypair::new_ed25519(&mut OsRng);
let actor = op_source_pk_keypair.public_key();
let sequence_name = XorName::random();
let sequence_tag = 43_000;
let sequence =
Sequence::new_private(actor, "actor".to_string(), sequence_name, sequence_tag);
assert_eq!(sequence.kind(), SequenceKind::Private);
assert_eq!(*sequence.name(), sequence_name);
assert_eq!(sequence.tag(), sequence_tag);
assert!(!sequence.is_pub());
assert!(sequence.is_private());
let sequence_address =
SequenceAddress::from_kind(SequenceKind::Private, sequence_name, sequence_tag);
assert_eq!(*sequence.address(), sequence_address);
}
#[test]
fn sequence_append_entry_and_apply() -> Result<()> {
let op_source_pk_keypair = Keypair::new_ed25519(&mut OsRng);
let actor = op_source_pk_keypair.public_key();
let sequence_name = XorName::random();
let sequence_tag = 43_000;
let mut replica1 =
Sequence::new_public(actor, "actor".to_string(), sequence_name, sequence_tag);
let mut replica2 =
Sequence::new_public(actor, "actor".to_string(), sequence_name, sequence_tag);
let mut perms1 = BTreeMap::default();
let user_perms1 = SequencePublicPermissions::new(true, false);
let _ = perms1.insert(SequenceUser::Anyone, user_perms1);
let policy_op = replica1.create_unsigned_public_policy_op(actor, perms1)?;
let signed_op = sign_sequence_public_policy_op(policy_op, &op_source_pk_keypair)?;
replica1.apply_public_policy_op(signed_op.clone())?;
replica2.apply_public_policy_op(signed_op)?;
let entry1 = b"value0".to_vec();
let entry2 = b"value1".to_vec();
let op1 = sign_sequence_data_op(
replica1.create_unsigned_append_op(entry1.clone())?,
&op_source_pk_keypair,
)?;
replica1.apply_data_op(op1.clone())?;
let op2 = sign_sequence_data_op(
replica1.create_unsigned_append_op(entry2.clone())?,
&op_source_pk_keypair,
)?;
replica1.apply_data_op(op2.clone())?;
replica2.apply_data_op(op2)?;
replica2.apply_data_op(op1)?;
assert_eq!(replica1.len(None)?, 2);
assert_eq!(replica2.len(None)?, 2);
let index_0 = SequenceIndex::FromStart(0);
let first_entry = replica1.get(index_0, None)?;
assert_eq!(first_entry, Some(&entry1));
assert_eq!(first_entry, replica2.get(index_0, None)?);
let index_1 = SequenceIndex::FromStart(1);
let second_entry = replica1.get(index_1, None)?;
assert_eq!(second_entry, Some(&entry2));
assert_eq!(second_entry, replica2.get(index_1, None)?);
let last_entry = replica1.last_entry(None)?;
assert_eq!(last_entry, Some(&entry2));
assert_eq!(last_entry, replica2.last_entry(None)?);
Ok(())
}
#[test]
fn sequence_get_in_range() -> anyhow::Result<()> {
let op_source_pk_keypair = Keypair::new_ed25519(&mut OsRng);
let actor = op_source_pk_keypair.public_key();
let sequence_name = XorName::random();
let sequence_tag = 43_000;
let mut replica1 =
Sequence::new_public(actor, "actor".to_string(), sequence_name, sequence_tag);
let mut perms1 = BTreeMap::default();
let user_perms1 = SequencePublicPermissions::new(true, false);
let _ = perms1.insert(SequenceUser::Anyone, user_perms1);
let policy_op = replica1.create_unsigned_public_policy_op(actor, perms1)?;
let signed_op = sign_sequence_public_policy_op(policy_op, &op_source_pk_keypair)?;
replica1.apply_public_policy_op(signed_op)?;
let entry1 = b"value0".to_vec();
let entry2 = b"value1".to_vec();
let entry3 = b"value2".to_vec();
let op1 = sign_sequence_data_op(
replica1.create_unsigned_append_op(entry1.clone())?,
&op_source_pk_keypair,
)?;
replica1.apply_data_op(op1)?;
let op2 = sign_sequence_data_op(
replica1.create_unsigned_append_op(entry2.clone())?,
&op_source_pk_keypair,
)?;
replica1.apply_data_op(op2)?;
let op3 = sign_sequence_data_op(
replica1.create_unsigned_append_op(entry3.clone())?,
&op_source_pk_keypair,
)?;
replica1.apply_data_op(op3)?;
assert_eq!(replica1.len(None)?, 3);
let index_0 = SequenceIndex::FromStart(0);
let index_1 = SequenceIndex::FromStart(1);
let index_2 = SequenceIndex::FromStart(2);
let end_index = SequenceIndex::FromEnd(0);
let first_entry = replica1.in_range(index_0, index_1, None)?;
assert_eq!(first_entry, Some(vec![entry1.clone()]));
let all_entries = replica1.in_range(index_0, end_index, None)?;
assert_eq!(
all_entries,
Some(vec![entry1, entry2.clone(), entry3.clone()])
);
let last_entry = replica1.in_range(index_2, end_index, None)?;
assert_eq!(last_entry, Some(vec![entry3]));
let second_entry = replica1.in_range(index_1, SequenceIndex::FromEnd(1), None)?;
assert_eq!(second_entry, Some(vec![entry2]));
let index_3 = SequenceIndex::FromStart(3);
match replica1.in_range(index_3, index_3, None) {
Ok(None) => Ok(()),
Ok(Some(entries)) => Err(anyhow!(
"Unexpectedly fetched entries from Sequence: {:?}",
entries
)),
Err(err) => Err(anyhow!(
"Unexpected error thrown when trying to fetch from Sequence with out of bound start index: {:?}",
err
)),
}
}
#[test]
fn sequence_public_create_policy_op_and_apply() -> anyhow::Result<()> {
let op_source_pk_keypair = Keypair::new_ed25519(&mut OsRng);
let actor = op_source_pk_keypair.public_key();
let sequence_name = XorName::random();
let sequence_tag = 43_000;
let mut replica1 =
Sequence::new_public(actor, "actor".to_string(), sequence_name, sequence_tag);
let mut replica2 =
Sequence::new_public(actor, "actor".to_string(), sequence_name, sequence_tag);
let mut perms1 = BTreeMap::default();
let user_perms1 = SequencePublicPermissions::new(true, false);
let _ = perms1.insert(SequenceUser::Anyone, user_perms1);
let mut perms2 = BTreeMap::default();
let user_perms2 = SequencePublicPermissions::new(false, true);
let _ = perms2.insert(SequenceUser::Key(actor), user_perms2);
let op1 = sign_sequence_public_policy_op(
replica1.create_unsigned_public_policy_op(actor, perms1.clone())?,
&op_source_pk_keypair,
)?;
replica1.apply_public_policy_op(op1.clone())?;
let op2 = sign_sequence_public_policy_op(
replica1.create_unsigned_public_policy_op(actor, perms2.clone())?,
&op_source_pk_keypair,
)?;
replica1.apply_public_policy_op(op2.clone())?;
check_not_causally_ready_failure(replica2.apply_public_policy_op(op2.clone()))?;
replica2.apply_public_policy_op(op1)?;
replica2.apply_public_policy_op(op2)?;
assert_eq!(replica1.policy_version(None)?, Some(1));
assert_eq!(replica2.policy_version(None)?, Some(1));
let index_0 = SequenceIndex::FromStart(0);
let first_entry = replica1.public_policy_at(index_0)?;
assert_eq!(first_entry.permissions, perms1);
assert_eq!(first_entry.owner, actor);
assert_eq!(first_entry, replica2.public_policy_at(index_0)?);
assert_eq!(
SequencePermissions::Public(user_perms1),
replica1.permissions_at(SequenceUser::Anyone, index_0, None)?
);
let index_1 = SequenceIndex::FromStart(1);
let second_entry = replica1.public_policy_at(index_1)?;
assert_eq!(second_entry.permissions, perms2);
assert_eq!(second_entry.owner, actor);
assert_eq!(second_entry, replica2.public_policy_at(index_1)?);
assert_eq!(
SequencePermissions::Public(user_perms2),
replica1.permissions_at(SequenceUser::Key(actor), index_1, None)?
);
Ok(())
}
#[test]
fn sequence_private_create_policy_op_and_apply() -> anyhow::Result<()> {
let op_source_pk_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk = op_source_pk_keypair.public_key();
let op_source_pk2_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk2 = op_source_pk2_keypair.public_key();
let sequence_name = XorName::random();
let sequence_tag = 43_000;
let mut replica1 = Sequence::new_private(
op_source_pk,
"some_identifying_str".to_string(),
sequence_name,
sequence_tag,
);
let mut replica2 = Sequence::new_private(
op_source_pk2,
"some_identifying_str2".to_string(),
sequence_name,
sequence_tag,
);
let mut perms1 = BTreeMap::default();
let user_perms1 = SequencePrivatePermissions::new(true, false, true);
let _ = perms1.insert(op_source_pk, user_perms1);
let mut perms2 = BTreeMap::default();
let user_perms2 = SequencePrivatePermissions::new(true, true, false);
let _ = perms2.insert(op_source_pk2, user_perms2);
let op1 = sign_sequence_private_policy_op(
replica1.create_unsigned_private_policy_op(op_source_pk2, perms1.clone())?,
&op_source_pk_keypair,
)?;
replica1.apply_private_policy_op(op1.clone())?;
let op2 = sign_sequence_private_policy_op(
replica1.create_unsigned_private_policy_op(op_source_pk, perms2.clone())?,
&op_source_pk_keypair,
)?;
replica1.apply_private_policy_op(op2.clone())?;
check_not_causally_ready_failure(replica2.apply_private_policy_op(op2.clone()))?;
replica2.apply_private_policy_op(op1)?;
replica2.apply_private_policy_op(op2)?;
assert_eq!(replica1.policy_version(None)?, Some(1));
assert_eq!(replica2.policy_version(None)?, Some(1));
let index_0 = SequenceIndex::FromStart(0);
let first_entry = replica1.private_policy_at(index_0, None)?;
assert_eq!(first_entry.permissions, perms1);
assert_eq!(first_entry.owner, op_source_pk2);
assert_eq!(first_entry, replica2.private_policy_at(index_0, None)?);
assert_eq!(
SequencePermissions::Private(user_perms1),
replica1.permissions_at(SequenceUser::Key(op_source_pk), index_0, None)?
);
let index_1 = SequenceIndex::FromStart(1);
let second_entry = replica1.private_policy_at(index_1, None)?;
assert_eq!(second_entry.permissions, perms2);
assert_eq!(second_entry.owner, op_source_pk);
assert_eq!(second_entry, replica2.private_policy_at(index_1, None)?);
assert_eq!(
SequencePermissions::Private(user_perms2),
replica1.permissions_at(SequenceUser::Key(op_source_pk2), index_1, None)?
);
Ok(())
}
#[test]
fn sequence_public_create_policy_op_and_append_fails_when_no_perms_for_actor(
) -> anyhow::Result<()> {
let op_source_pk_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk = op_source_pk_keypair.public_key();
let op_source_pk2_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk2 = op_source_pk2_keypair.public_key();
let sequence_name = XorName::random();
let sequence_tag = 43_000;
let mut replica1 = Sequence::new_public(
op_source_pk,
"some_identifying_str".to_string(),
sequence_name,
sequence_tag,
);
let mut replica2 = Sequence::new_public(
op_source_pk2,
"some_identifying_str2".to_string(),
sequence_name,
sequence_tag,
);
let mut perms1 = BTreeMap::default();
let user_perms1 = SequencePublicPermissions::new(true, false);
let _ = perms1.insert(SequenceUser::Key(op_source_pk), user_perms1);
let mut perms2 = BTreeMap::default();
let user_perms2 = SequencePublicPermissions::new(false, false);
let _ = perms2.insert(SequenceUser::Key(op_source_pk2), user_perms2);
let op1 = sign_sequence_public_policy_op(
replica1.create_unsigned_public_policy_op(op_source_pk, perms1)?,
&op_source_pk_keypair,
)?;
replica1.apply_public_policy_op(op1.clone())?;
let op2 = sign_sequence_public_policy_op(
replica1.create_unsigned_public_policy_op(op_source_pk, perms2)?,
&op_source_pk_keypair,
)?;
replica1.apply_public_policy_op(op2.clone())?;
replica2.apply_public_policy_op(op1)?;
replica2.apply_public_policy_op(op2)?;
assert_eq!(replica1.policy_version(None)?, Some(1));
assert_eq!(replica2.policy_version(None)?, Some(1));
let item1 = b"item1";
let item2 = b"item2";
let append_op1 = sign_sequence_data_op(
replica1.create_unsigned_append_op(item1.to_vec())?,
&op_source_pk_keypair,
)?;
replica1.apply_data_op(append_op1.clone())?;
replica2.apply_data_op(append_op1)?;
check_op_not_allowed_failure(replica2.create_unsigned_append_op(item2.to_vec()))?;
assert_eq!(replica1.len(None)?, replica2.len(None)?);
Ok(())
}
#[test]
fn sequence_public_create_policy_op_and_append_succeeds_when_perms_updated_for_actor(
) -> anyhow::Result<()> {
let op_source_pk_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk = op_source_pk_keypair.public_key();
let op_source_pk2_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk2 = op_source_pk2_keypair.public_key();
let sequence_name = XorName::random();
let sequence_tag = 43_000;
let mut replica1 = Sequence::new_public(
op_source_pk,
"some_identifying_str".to_string(),
sequence_name,
sequence_tag,
);
let mut replica2 = Sequence::new_public(
op_source_pk2,
"some_identifying_str2".to_string(),
sequence_name,
sequence_tag,
);
let mut perms1 = BTreeMap::default();
let user_perms1 = SequencePublicPermissions::new(true, false);
let _ = perms1.insert(SequenceUser::Key(op_source_pk), user_perms1);
let mut perms2 = BTreeMap::default();
let user_perms2 = SequencePublicPermissions::new(false, false);
let _ = perms2.insert(SequenceUser::Key(op_source_pk2), user_perms2);
let op1 = sign_sequence_public_policy_op(
replica1.create_unsigned_public_policy_op(op_source_pk, perms1)?,
&op_source_pk_keypair,
)?;
replica1.apply_public_policy_op(op1.clone())?;
let op2 = sign_sequence_public_policy_op(
replica1.create_unsigned_public_policy_op(op_source_pk, perms2)?,
&op_source_pk_keypair,
)?;
replica1.apply_public_policy_op(op2.clone())?;
replica2.apply_public_policy_op(op1)?;
replica2.apply_public_policy_op(op2)?;
assert_eq!(replica1.policy_version(None)?, Some(1));
assert_eq!(replica2.policy_version(None)?, Some(1));
let item1 = b"item1";
let item2 = b"item2";
let append_op1 = sign_sequence_data_op(
replica1.create_unsigned_append_op(item1.to_vec())?,
&op_source_pk_keypair,
)?;
replica1.apply_data_op(append_op1.clone())?;
replica2.apply_data_op(append_op1)?;
check_op_not_allowed_failure(replica2.create_unsigned_append_op(item2.to_vec()))?;
let mut perms3 = BTreeMap::default();
let user_perms3 = SequencePublicPermissions::new(true, false);
let _ = perms3.insert(SequenceUser::Key(op_source_pk2), user_perms3);
let op1 = sign_sequence_public_policy_op(
replica1.create_unsigned_public_policy_op(op_source_pk, perms3)?,
&op_source_pk_keypair,
)?;
replica1.apply_public_policy_op(op1.clone())?;
replica2.apply_public_policy_op(op1)?;
let append_op = sign_sequence_data_op(
replica2.create_unsigned_append_op(item2.to_vec())?,
&op_source_pk2_keypair,
)?;
replica2.apply_data_op(append_op.clone())?;
replica1.apply_data_op(append_op)?;
assert_eq!(replica1.len(None)?, replica2.len(None)?);
Ok(())
}
#[test]
fn sequence_private_create_policy_op_and_append_fails_when_no_perms_for_actor(
) -> anyhow::Result<()> {
let op_source_pk_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk = op_source_pk_keypair.public_key();
let op_source_pk2_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk2 = op_source_pk2_keypair.public_key();
let sequence_name = XorName::random();
let sequence_tag = 43_000;
let mut replica1 = Sequence::new_private(
op_source_pk,
"some_identifying_str".to_string(),
sequence_name,
sequence_tag,
);
let mut replica2 = Sequence::new_private(
op_source_pk2,
"some_identifying_str2".to_string(),
sequence_name,
sequence_tag,
);
let mut perms1 = BTreeMap::default();
let user_perms1 = SequencePrivatePermissions::new(true, false, true);
let _ = perms1.insert(op_source_pk, user_perms1);
let mut perms2 = BTreeMap::default();
let user_perms2 = SequencePrivatePermissions::new(false, false, false);
let _ = perms2.insert(op_source_pk2, user_perms2);
let op1 = sign_sequence_private_policy_op(
replica1.create_unsigned_private_policy_op(op_source_pk2, perms1)?,
&op_source_pk_keypair,
)?;
replica1.apply_private_policy_op(op1.clone())?;
let op2 = sign_sequence_private_policy_op(
replica1.create_unsigned_private_policy_op(op_source_pk, perms2)?,
&op_source_pk_keypair,
)?;
replica1.apply_private_policy_op(op2.clone())?;
replica2.apply_private_policy_op(op1)?;
replica2.apply_private_policy_op(op2)?;
assert_eq!(replica1.policy_version(None)?, Some(1));
check_op_not_allowed_failure(replica2.policy_version(None))?;
assert_eq!(replica2.policy_version(Some(op_source_pk))?, Some(1));
let item1 = b"item1";
let item2 = b"item2";
let append_op1 = sign_sequence_data_op(
replica1.create_unsigned_append_op(item1.to_vec())?,
&op_source_pk_keypair,
)?;
replica1.apply_data_op(append_op1.clone())?;
replica2.apply_data_op(append_op1)?;
check_op_not_allowed_failure(replica2.create_unsigned_append_op(item2.to_vec()))?;
Ok(())
}
#[test]
fn sequence_private_create_policy_op_and_get_read_fails_when_no_perms_for_actor(
) -> anyhow::Result<()> {
let op_source_pk_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk = op_source_pk_keypair.public_key();
let op_source_pk2_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk2 = op_source_pk2_keypair.public_key();
let sequence_name = XorName::random();
let sequence_tag = 43_000;
let mut replica1 = Sequence::new_private(
op_source_pk,
"some_identifying_str".to_string(),
sequence_name,
sequence_tag,
);
let mut replica2 = Sequence::new_private(
op_source_pk2,
"some_identifying_str2".to_string(),
sequence_name,
sequence_tag,
);
let mut perms1 = BTreeMap::default();
let user_perms1 = SequencePrivatePermissions::new(true, false, true);
let _ = perms1.insert(op_source_pk, user_perms1);
let mut perms2 = BTreeMap::default();
let user_perms2 = SequencePrivatePermissions::new(false, false, false);
let _ = perms2.insert(op_source_pk2, user_perms2);
let op1 = sign_sequence_private_policy_op(
replica1.create_unsigned_private_policy_op(op_source_pk2, perms1)?,
&op_source_pk_keypair,
)?;
replica1.apply_private_policy_op(op1.clone())?;
let op2 = sign_sequence_private_policy_op(
replica1.create_unsigned_private_policy_op(op_source_pk, perms2)?,
&op_source_pk_keypair,
)?;
replica1.apply_private_policy_op(op2.clone())?;
replica2.apply_private_policy_op(op1)?;
replica2.apply_private_policy_op(op2)?;
assert_eq!(replica1.policy_version(None)?, Some(1));
check_op_not_allowed_failure(replica2.policy_version(None))?;
assert_eq!(replica2.policy_version(Some(op_source_pk))?, Some(1));
let item1 = b"item1".to_vec();
let append_op1 = sign_sequence_data_op(
replica1.create_unsigned_append_op(item1.clone())?,
&op_source_pk_keypair,
)?;
replica1.apply_data_op(append_op1.clone())?;
replica2.apply_data_op(append_op1)?;
let data = replica1.get(SequenceIndex::FromStart(0), None)?;
assert_eq!(data, Some(&item1));
check_op_not_allowed_failure(
replica2.get(SequenceIndex::FromStart(0), Some(op_source_pk2)),
)?;
let data = replica2.get(SequenceIndex::FromStart(0), Some(op_source_pk))?;
assert_eq!(data, Some(&item1));
Ok(())
}
#[test]
fn sequence_private_create_policy_op_and_last_entry_read_fails_when_no_perms_for_actor(
) -> anyhow::Result<()> {
let op_source_pk_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk = op_source_pk_keypair.public_key();
let op_source_pk2_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk2 = op_source_pk2_keypair.public_key();
let sequence_name = XorName::random();
let sequence_tag = 43_000;
let mut replica1 = Sequence::new_private(
op_source_pk,
"some_identifying_str".to_string(),
sequence_name,
sequence_tag,
);
let mut replica2 = Sequence::new_private(
op_source_pk2,
"some_identifying_str2".to_string(),
sequence_name,
sequence_tag,
);
let mut perms1 = BTreeMap::default();
let user_perms1 = SequencePrivatePermissions::new(true, false, true);
let _ = perms1.insert(op_source_pk, user_perms1);
let mut perms2 = BTreeMap::default();
let user_perms2 = SequencePrivatePermissions::new(false, false, false);
let _ = perms2.insert(op_source_pk2, user_perms2);
let op1 = sign_sequence_private_policy_op(
replica1.create_unsigned_private_policy_op(op_source_pk2, perms1)?,
&op_source_pk_keypair,
)?;
replica1.apply_private_policy_op(op1.clone())?;
let op2 = sign_sequence_private_policy_op(
replica1.create_unsigned_private_policy_op(op_source_pk, perms2)?,
&op_source_pk_keypair,
)?;
replica1.apply_private_policy_op(op2.clone())?;
replica2.apply_private_policy_op(op1)?;
replica2.apply_private_policy_op(op2)?;
assert_eq!(replica1.policy_version(None)?, Some(1));
check_op_not_allowed_failure(replica2.policy_version(None))?;
assert_eq!(replica2.policy_version(Some(op_source_pk))?, Some(1));
let item1 = b"item1".to_vec();
let append_op1 = sign_sequence_data_op(
replica1.create_unsigned_append_op(item1.clone())?,
&op_source_pk_keypair,
)?;
replica1.apply_data_op(append_op1.clone())?;
replica2.apply_data_op(append_op1)?;
let data = replica1.last_entry(None)?;
assert_eq!(data, Some(&item1));
check_op_not_allowed_failure(replica2.last_entry(Some(op_source_pk2)))?;
let data = replica2.last_entry(Some(op_source_pk))?;
assert_eq!(data, Some(&item1));
Ok(())
}
#[test]
fn sequence_private_create_policy_op_and_range_read_fails_when_no_perms_for_actor(
) -> anyhow::Result<()> {
let op_source_pk_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk = op_source_pk_keypair.public_key();
let op_source_pk2_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk2 = op_source_pk2_keypair.public_key();
let sequence_name = XorName::random();
let sequence_tag = 43_000;
let mut replica1 = Sequence::new_private(
op_source_pk,
"some_identifying_str".to_string(),
sequence_name,
sequence_tag,
);
let mut replica2 = Sequence::new_private(
op_source_pk2,
"some_identifying_str2".to_string(),
sequence_name,
sequence_tag,
);
let mut perms1 = BTreeMap::default();
let user_perms1 = SequencePrivatePermissions::new(true, false, true);
let _ = perms1.insert(op_source_pk, user_perms1);
let mut perms2 = BTreeMap::default();
let user_perms2 = SequencePrivatePermissions::new(false, false, false);
let _ = perms2.insert(op_source_pk2, user_perms2);
let op1 = sign_sequence_private_policy_op(
replica1.create_unsigned_private_policy_op(op_source_pk2, perms1)?,
&op_source_pk_keypair,
)?;
replica1.apply_private_policy_op(op1.clone())?;
let op2 = sign_sequence_private_policy_op(
replica1.create_unsigned_private_policy_op(op_source_pk, perms2)?,
&op_source_pk_keypair,
)?;
replica1.apply_private_policy_op(op2.clone())?;
replica2.apply_private_policy_op(op1)?;
replica2.apply_private_policy_op(op2)?;
assert_eq!(replica1.policy_version(None)?, Some(1));
check_op_not_allowed_failure(replica2.policy_version(None))?;
assert_eq!(replica2.policy_version(Some(op_source_pk))?, Some(1));
let item1 = b"item1".to_vec();
let append_op1 = sign_sequence_data_op(
replica1.create_unsigned_append_op(item1.clone())?,
&op_source_pk_keypair,
)?;
replica1.apply_data_op(append_op1.clone())?;
replica2.apply_data_op(append_op1)?;
let data = replica1.in_range(
SequenceIndex::FromStart(0),
SequenceIndex::FromStart(1),
None,
)?;
assert_eq!(data, Some(vec![item1.clone()]));
check_op_not_allowed_failure(replica2.in_range(
SequenceIndex::FromStart(0),
SequenceIndex::FromStart(1),
Some(op_source_pk2),
))?;
let data = replica2.in_range(
SequenceIndex::FromStart(0),
SequenceIndex::FromStart(1),
Some(op_source_pk),
)?;
assert_eq!(data, Some(vec![item1]));
Ok(())
}
#[test]
fn sequence_private_create_policy_op_and_read_possible_after_update() -> anyhow::Result<()> {
let op_source_pk_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk = op_source_pk_keypair.public_key();
let op_source_pk2_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk2 = op_source_pk2_keypair.public_key();
let sequence_name = XorName::random();
let sequence_tag = 43_000;
let mut replica1 = Sequence::new_private(
op_source_pk,
"some_identifying_str".to_string(),
sequence_name,
sequence_tag,
);
let mut replica2 = Sequence::new_private(
op_source_pk2,
"some_identifying_str2".to_string(),
sequence_name,
sequence_tag,
);
let mut perms1 = BTreeMap::default();
let user_perms1 = SequencePrivatePermissions::new(true, false, true);
let _ = perms1.insert(op_source_pk, user_perms1);
let mut perms2 = BTreeMap::default();
let user_perms2 = SequencePrivatePermissions::new(false, false, false);
let _ = perms2.insert(op_source_pk2, user_perms2);
let op1 = sign_sequence_private_policy_op(
replica1.create_unsigned_private_policy_op(op_source_pk2, perms1)?,
&op_source_pk_keypair,
)?;
replica1.apply_private_policy_op(op1.clone())?;
let op2 = sign_sequence_private_policy_op(
replica1.create_unsigned_private_policy_op(op_source_pk, perms2)?,
&op_source_pk_keypair,
)?;
replica1.apply_private_policy_op(op2.clone())?;
replica2.apply_private_policy_op(op1)?;
replica2.apply_private_policy_op(op2)?;
assert_eq!(replica1.policy_version(None)?, Some(1));
check_op_not_allowed_failure(replica2.policy_version(None))?;
assert_eq!(replica2.policy_version(Some(op_source_pk))?, Some(1));
let item1 = b"item1".to_vec();
let append_op1 = sign_sequence_data_op(
replica1.create_unsigned_append_op(item1.clone())?,
&op_source_pk_keypair,
)?;
replica1.apply_data_op(append_op1.clone())?;
replica2.apply_data_op(append_op1)?;
let data = replica1.get(SequenceIndex::FromStart(0), None)?;
assert_eq!(data, Some(&item1));
check_op_not_allowed_failure(
replica2.get(SequenceIndex::FromStart(0), Some(op_source_pk2)),
)?;
let mut perms3 = BTreeMap::default();
let user_perms3 = SequencePrivatePermissions::new(true, false, false);
let _ = perms3.insert(op_source_pk2, user_perms3);
let updated_perms_op = sign_sequence_private_policy_op(
replica1.create_unsigned_private_policy_op(op_source_pk, perms3)?,
&op_source_pk_keypair,
)?;
replica1.apply_private_policy_op(updated_perms_op.clone())?;
replica2.apply_private_policy_op(updated_perms_op)?;
let _ = replica1.get(SequenceIndex::FromStart(0), None)?;
let data = replica2.get(SequenceIndex::FromStart(0), None)?;
assert_eq!(data, replica2.last_entry(None)?);
assert_eq!(data, Some(&item1));
let data = replica2.in_range(
SequenceIndex::FromStart(0),
SequenceIndex::FromStart(1),
None,
)?;
assert_eq!(data, Some(vec![item1]));
assert_eq!(replica1.policy_version(None)?, Some(2));
assert_eq!(replica2.policy_version(None)?, Some(2));
Ok(())
}
#[test]
fn sequence_concurrent_policy_and_data_ops() -> Result<()> {
let op_source_pk_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk = op_source_pk_keypair.public_key();
let op_source_pk2_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk2 = op_source_pk2_keypair.public_key();
let sdata_name: XorName = rand::random();
let sdata_tag = 43_000u64;
let mut replica1 = Sequence::new_public(
op_source_pk,
"some_identifying_str".to_string(),
sdata_name,
sdata_tag,
);
let mut replica2 = Sequence::new_public(
op_source_pk2,
"some_identifying_str2".to_string(),
sdata_name,
sdata_tag,
);
let mut perms = BTreeMap::default();
let user_perms =
SequencePublicPermissions::new( true, false);
let _ = perms.insert(SequenceUser::Key(op_source_pk2), user_perms);
let grant_op = sign_sequence_public_policy_op(
replica1.create_unsigned_public_policy_op(op_source_pk, perms)?,
&op_source_pk_keypair,
)?;
replica1.apply_public_policy_op(grant_op.clone())?;
replica2.apply_public_policy_op(grant_op)?;
let item1 = b"item1";
let append_op1 = sign_sequence_data_op(
replica1.create_unsigned_append_op(item1.to_vec())?,
&op_source_pk_keypair,
)?;
replica1.apply_data_op(append_op1.clone())?;
replica2.apply_data_op(append_op1)?;
assert_eq!(replica1.len(None)?, 1);
assert_eq!(replica1.policy_version(None)?, Some(0));
assert_eq!(replica2.len(None)?, 1);
assert_eq!(replica2.policy_version(None)?, Some(0));
let revoke_op = sign_sequence_public_policy_op(
replica1.create_unsigned_public_policy_op(op_source_pk, BTreeMap::default())?,
&op_source_pk_keypair,
)?;
replica1.apply_public_policy_op(revoke_op.clone())?;
assert_eq!(replica1.policy_version(None)?, Some(1));
let item2 = b"item2";
let append_op2 = sign_sequence_data_op(
replica2.create_unsigned_append_op(item2.to_vec())?,
&op_source_pk2_keypair,
)?;
replica2.apply_data_op(append_op2.clone())?;
assert_eq!(replica2.len(None)?, 2);
replica1.apply_data_op(append_op2)?;
assert_eq!(replica1.len(None)?, 1);
replica2.apply_public_policy_op(revoke_op)?;
assert_eq!(replica2.policy_version(None)?, Some(1));
assert_eq!(replica2.len(None)?, 1);
verify_data_convergence(vec![replica1, replica2], 1)?;
Ok(())
}
#[test]
fn sequence_causality_between_data_and_policy_ops() -> anyhow::Result<()> {
let op_source_pk_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk = op_source_pk_keypair.public_key();
let op_source_pk2_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk2 = op_source_pk2_keypair.public_key();
let op_source_pk3_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk3 = op_source_pk3_keypair.public_key();
let sdata_name: XorName = rand::random();
let sdata_tag = 43_001u64;
let mut replica1 = Sequence::new_public(
op_source_pk,
"some_identifying_str".to_string(),
sdata_name,
sdata_tag,
);
let mut replica2 = Sequence::new_public(
op_source_pk2,
"some_identifying_str2".to_string(),
sdata_name,
sdata_tag,
);
let mut replica3 = Sequence::new_public(
op_source_pk3,
"some_identifying_str3".to_string(),
sdata_name,
sdata_tag,
);
let mut perms = BTreeMap::default();
let user_perms =
SequencePublicPermissions::new( true, false);
let _ = perms.insert(SequenceUser::Key(op_source_pk3), user_perms);
let owner_op = sign_sequence_public_policy_op(
replica1.create_unsigned_public_policy_op(op_source_pk, perms)?,
&op_source_pk_keypair,
)?;
replica1.apply_public_policy_op(owner_op.clone())?;
replica2.apply_public_policy_op(owner_op.clone())?;
replica3.apply_public_policy_op(owner_op)?;
let mut perms = BTreeMap::default();
let user_perms =
SequencePublicPermissions::new( true, true);
let _ = perms.insert(SequenceUser::Key(op_source_pk3), user_perms);
let grant_op = sign_sequence_public_policy_op(
replica1.create_unsigned_public_policy_op(op_source_pk, perms)?,
&op_source_pk_keypair,
)?;
replica1.apply_public_policy_op(grant_op.clone())?;
replica3.apply_public_policy_op(grant_op.clone())?;
assert_eq!(replica1.len(None)?, 0);
assert_eq!(replica1.policy_version(None)?, Some(1));
assert_eq!(replica2.len(None)?, 0);
assert_eq!(replica2.policy_version(None)?, Some(0));
assert_eq!(replica3.len(None)?, 0);
assert_eq!(replica3.policy_version(None)?, Some(1));
let item = b"item0";
let append_op = sign_sequence_data_op(
replica3.create_unsigned_append_op(item.to_vec())?,
&op_source_pk3_keypair,
)?;
replica3.apply_data_op(append_op.clone())?;
assert_eq!(replica3.len(None)?, 1);
replica1.apply_data_op(append_op.clone())?;
assert_eq!(replica1.len(None)?, 1);
check_not_causally_ready_failure(replica2.apply_data_op(append_op.clone()))?;
assert_eq!(replica2.len(None)?, 0);
replica2.apply_public_policy_op(grant_op)?;
assert_eq!(replica2.policy_version(None)?, Some(1));
replica2.apply_data_op(append_op)?;
verify_data_convergence(vec![replica1, replica2, replica3], 1)?;
Ok(())
}
#[test]
fn sequence_concurrent_policy_ops() -> Result<()> {
let op_source_pk_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk = op_source_pk_keypair.public_key();
let op_source_pk2_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk2 = op_source_pk2_keypair.public_key();
let sdata_name: XorName = rand::random();
let sdata_tag = 43_001u64;
let mut replica1 = Sequence::new_public(
op_source_pk,
"some_identifying_str".to_string(),
sdata_name,
sdata_tag,
);
let mut replica2 = Sequence::new_public(
op_source_pk2,
"some_identifying_str2".to_string(),
sdata_name,
sdata_tag,
);
let mut perms = BTreeMap::default();
let user_perms =
SequencePublicPermissions::new( true, true);
let _ = perms.insert(SequenceUser::Key(op_source_pk2), user_perms);
let owner_op = sign_sequence_public_policy_op(
replica1.create_unsigned_public_policy_op(op_source_pk, perms.clone())?,
&op_source_pk_keypair,
)?;
replica1.apply_public_policy_op(owner_op.clone())?;
replica2.apply_public_policy_op(owner_op)?;
let item0 = b"item0".to_vec();
let append_op = sign_sequence_data_op(
replica1.create_unsigned_append_op(item0)?,
&op_source_pk_keypair,
)?;
replica1.apply_data_op(append_op.clone())?;
replica2.apply_data_op(append_op)?;
assert_eq!(replica1.len(None)?, 1);
assert_eq!(replica1.policy_version(None)?, Some(0));
assert_eq!(replica2.len(None)?, 1);
assert_eq!(replica2.policy_version(None)?, Some(0));
let _ = perms.insert(SequenceUser::Key(op_source_pk), user_perms);
let owner_op_1 = sign_sequence_public_policy_op(
replica1.create_unsigned_public_policy_op(generate_public_key(), perms.clone())?,
&op_source_pk_keypair,
)?;
replica1.apply_public_policy_op(owner_op_1.clone())?;
let owner_op_2 = sign_sequence_public_policy_op(
replica2.create_unsigned_public_policy_op(generate_public_key(), perms)?,
&op_source_pk2_keypair,
)?;
replica2.apply_public_policy_op(owner_op_2.clone())?;
let item1_r1 = b"item1_replica1".to_vec();
let item1_r2 = b"item1_replica2".to_vec();
let append_op1 = sign_sequence_data_op(
replica1.create_unsigned_append_op(item1_r1)?,
&op_source_pk_keypair,
)?;
replica1.apply_data_op(append_op1.clone())?;
let append_op2 = sign_sequence_data_op(
replica2.create_unsigned_append_op(item1_r2)?,
&op_source_pk2_keypair,
)?;
replica2.apply_data_op(append_op2.clone())?;
assert_eq!(replica1.len(None)?, 2);
assert_eq!(replica2.len(None)?, 2);
replica1.apply_public_policy_op(owner_op_2)?;
replica2.apply_public_policy_op(owner_op_1)?;
assert_eq!(replica1.policy_version(None)?, Some(2));
assert_eq!(replica2.policy_version(None)?, Some(2));
replica1.apply_data_op(append_op2)?;
replica2.apply_data_op(append_op1)?;
verify_data_convergence(vec![replica1, replica2], 2)?;
Ok(())
}
#[test]
fn sequence_old_data_op() -> Result<()> {
let op_source_pk_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk = op_source_pk_keypair.public_key();
let op_source_pk2_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk2 = op_source_pk2_keypair.public_key();
let sdata_name: XorName = rand::random();
let sdata_tag = 43_001u64;
let mut replica1 = Sequence::new_public(
op_source_pk,
"some_identifying_str".to_string(),
sdata_name,
sdata_tag,
);
let mut replica2 = Sequence::new_public(
op_source_pk2,
"some_identifying_str2".to_string(),
sdata_name,
sdata_tag,
);
let mut perms = BTreeMap::default();
let user_perms =
SequencePublicPermissions::new( true, false);
let _ = perms.insert(SequenceUser::Key(op_source_pk2), user_perms);
let owner_op = sign_sequence_public_policy_op(
replica1.create_unsigned_public_policy_op(op_source_pk, perms)?,
&op_source_pk_keypair,
)?;
replica1.apply_public_policy_op(owner_op.clone())?;
replica2.apply_public_policy_op(owner_op)?;
let item0 = b"item0".to_vec();
let append_op = sign_sequence_data_op(
replica1.create_unsigned_append_op(item0)?,
&op_source_pk_keypair,
)?;
replica1.apply_data_op(append_op.clone())?;
let policy_op = sign_sequence_public_policy_op(
replica1.create_unsigned_public_policy_op(op_source_pk, BTreeMap::default())?,
&op_source_pk_keypair,
)?;
replica1.apply_public_policy_op(policy_op.clone())?;
replica2.apply_public_policy_op(policy_op)?;
replica2.apply_data_op(append_op)?;
assert_eq!(replica1.policy_version(None)?, Some(1));
assert_eq!(replica2.policy_version(None)?, Some(1));
verify_data_convergence(vec![replica1, replica2], 1)?;
Ok(())
}
#[test]
fn sequence_old_policy_op() -> Result<()> {
let op_source_pk_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk = op_source_pk_keypair.public_key();
let op_source_pk2_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk2 = op_source_pk2_keypair.public_key();
let sdata_name: XorName = rand::random();
let sdata_tag = 43_001u64;
let mut replica1 = Sequence::new_public(
op_source_pk,
"some_identifying_str".to_string(),
sdata_name,
sdata_tag,
);
let mut replica2 = Sequence::new_public(
op_source_pk2,
"some_identifying_str2".to_string(),
sdata_name,
sdata_tag,
);
let mut perms = BTreeMap::default();
let user_perms =
SequencePublicPermissions::new( true, true);
let _ = perms.insert(SequenceUser::Key(op_source_pk2), user_perms);
let owner_op = sign_sequence_public_policy_op(
replica1.create_unsigned_public_policy_op(op_source_pk, perms)?,
&op_source_pk_keypair,
)?;
replica1.apply_public_policy_op(owner_op.clone())?;
replica2.apply_public_policy_op(owner_op)?;
let perms = BTreeMap::default();
let op_source3_pk = Keypair::new_ed25519(&mut OsRng).public_key();
let old_owner_op = sign_sequence_public_policy_op(
replica1.create_unsigned_public_policy_op(op_source3_pk, perms.clone())?,
&op_source_pk_keypair,
)?;
replica1.apply_public_policy_op(old_owner_op.clone())?;
let owner_op = sign_sequence_public_policy_op(
replica2.create_unsigned_public_policy_op(op_source_pk2, perms)?,
&op_source_pk2_keypair,
)?;
replica2.apply_public_policy_op(owner_op.clone())?;
replica2.apply_public_policy_op(old_owner_op)?;
replica1.apply_public_policy_op(owner_op)?;
assert_eq!(replica1.policy_version(None)?, Some(2));
assert_eq!(replica2.policy_version(None)?, Some(2));
let policy1 = replica1.public_policy_at(0)?;
assert_eq!(policy1.owner, op_source_pk);
assert_eq!(policy1.owner, replica2.public_policy_at(0)?.owner);
let policy2 = replica1.public_policy_at(1)?;
if policy2.owner == op_source3_pk {
assert_eq!(policy2.owner, replica2.public_policy_at(1)?.owner);
let policy3 = replica1.public_policy_at(2)?;
assert_eq!(policy3.owner, op_source_pk2);
assert_eq!(policy3.owner, replica2.public_policy_at(2)?.owner);
} else {
assert_eq!(policy2.owner, op_source_pk2);
assert_eq!(policy2.owner, replica2.public_policy_at(1)?.owner);
let policy3 = replica1.public_policy_at(2)?;
assert_eq!(policy3.owner, op_source3_pk);
assert_eq!(policy3.owner, replica2.public_policy_at(2)?.owner);
}
Ok(())
}
#[test]
fn sequence_falsified_policy_op() -> Result<()> {
let op_source_pk_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk = op_source_pk_keypair.public_key();
let op_source_pk2_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk2 = op_source_pk2_keypair.public_key();
let sdata_name: XorName = rand::random();
let sdata_tag = 43_001u64;
let mut replica1 = Sequence::new_public(
op_source_pk,
"some_identifying_str".to_string(),
sdata_name,
sdata_tag,
);
let mut replica2 = Sequence::new_public(
op_source_pk2,
"some_identifying_str2".to_string(),
sdata_name,
sdata_tag,
);
let perms = BTreeMap::default();
let owner_op = sign_sequence_public_policy_op(
replica1.create_unsigned_public_policy_op(op_source_pk, perms.clone())?,
&op_source_pk_keypair,
)?;
replica1.apply_public_policy_op(owner_op.clone())?;
replica2.apply_public_policy_op(owner_op)?;
let mut temp_replica = replica1.clone();
let owner_op = sign_sequence_public_policy_op(
replica1.create_unsigned_public_policy_op(op_source_pk2, perms.clone())?,
&op_source_pk_keypair,
)?;
replica1.apply_public_policy_op(owner_op.clone())?;
replica2.apply_public_policy_op(owner_op)?;
assert_eq!(replica1.policy_version(None)?, Some(1));
assert_eq!(replica2.policy_version(None)?, Some(1));
let mut owner_op = sign_sequence_public_policy_op(
temp_replica.create_unsigned_public_policy_op(op_source_pk, perms)?,
&op_source_pk_keypair,
)?;
use crdts::lseq::{ident::IdentGen, Op};
let upper_ident = IdentGen::new("some_identifying_str".to_string()).upper();
owner_op.crdt_op = match owner_op.crdt_op {
Op::Insert { dot, val, .. } => Op::Insert {
id: upper_ident,
dot,
val,
},
Op::Delete { remote, dot, .. } => Op::Delete {
remote,
id: upper_ident,
dot,
},
};
owner_op = sign_sequence_public_policy_op(owner_op, &op_source_pk_keypair)?;
replica1.apply_public_policy_op(owner_op.clone())?;
replica2.apply_public_policy_op(owner_op)?;
assert_eq!(replica1.policy_version(None)?, Some(2));
assert_eq!(replica2.policy_version(None)?, Some(2));
assert_eq!(
replica1.public_policy_at(0)?.owner,
replica2.public_policy_at(0)?.owner
);
assert_eq!(
replica1.public_policy_at(1)?.owner,
replica2.public_policy_at(1)?.owner
);
Ok(())
}
fn generate_public_key() -> PublicKey {
let keypair = Keypair::new_ed25519(&mut OsRng);
keypair.public_key()
}
fn check_not_causally_ready_failure(result: Result<()>) -> anyhow::Result<()> {
match result {
Err(Error::OpNotCausallyReady) => Ok(()),
Err(err) => Err(anyhow!("Error returned was the unexpected one: {}", err)),
Ok(()) => Err(anyhow!("Data op applied unexpectedly".to_string(),)),
}
}
fn check_op_not_allowed_failure<T>(result: Result<T>) -> anyhow::Result<()> {
match result {
Err(Error::AccessDenied(_)) => Ok(()),
Err(err) => Err(anyhow!(
"Error returned was the unexpected one for a non-allowed op: {}",
err
)),
Ok(_) => Err(anyhow!(
"Data operation succeded unexpectedly, an AccessDenied error was expected"
.to_string(),
)),
}
}
fn verify_data_convergence(replicas: Vec<Sequence>, expected_len: u64) -> Result<()> {
let index_beyond = SequenceIndex::FromStart(expected_len);
for r in &replicas {
assert_eq!(r.len(None)?, expected_len);
assert_eq!(r.get(index_beyond, None)?, None);
}
for i in 0..expected_len {
let index = SequenceIndex::FromStart(i);
let r0_entry = replicas[0].get(index, None)?;
for r in &replicas {
assert_eq!(r0_entry, r.get(index, None)?);
}
}
Ok(())
}
fn generate_replicas(
max_quantity: usize,
) -> impl Strategy<Value = Result<(Vec<Sequence>, Arc<Keypair>)>> {
let xorname = XorName::random();
let tag = 45_000u64;
let owner_keypair = Arc::new(Keypair::new_ed25519(&mut OsRng));
let owner = owner_keypair.public_key();
(1..max_quantity + 1).prop_map(move |quantity| {
let mut replicas = Vec::with_capacity(quantity);
for _ in 0..quantity {
let actor = Keypair::new_ed25519(&mut OsRng).public_key().to_string();
let replica = Sequence::new_public(owner, actor, xorname, tag);
replicas.push(replica);
}
let perms = BTreeMap::default();
let mut owner_op = replicas[0].create_unsigned_public_policy_op(owner, perms)?;
let bytes = utils::serialise(&owner_op.crdt_op)?;
let signature = owner_keypair.sign(&bytes);
owner_op.signature = Some(signature);
for r in replicas.iter_mut() {
r.apply_public_policy_op(owner_op.clone())?;
}
Ok((replicas, owner_keypair.clone()))
})
}
fn generate_seq_entry() -> impl Strategy<Value = Vec<u8>> {
"\\PC*".prop_map(|s| s.into_bytes())
}
fn generate_dataset(max_quantity: usize) -> impl Strategy<Value = Vec<Vec<u8>>> {
prop::collection::vec(generate_seq_entry(), 1..max_quantity + 1)
}
fn generate_dataset_and_probability(
max_quantity: usize,
) -> impl Strategy<Value = Vec<(Vec<u8>, u8)>> {
prop::collection::vec((generate_seq_entry(), any::<u8>()), 1..max_quantity + 1)
}
#[derive(Clone)]
enum OpType {
Owner(SequencePolicyWriteOp<SequencePublicPolicy>),
Data(SequenceDataWriteOp<SequenceEntry>),
}
proptest! {
#[test]
fn proptest_seq_doesnt_crash_with_random_data(
s in generate_seq_entry()
) {
let op_source_pk_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk = op_source_pk_keypair.public_key();
let sequence_name = XorName::random();
let sdata_tag = 43_001u64;
let mut replica1 = Sequence::new_public(op_source_pk, "some_identifying_str".to_string(), sequence_name, sdata_tag);
let mut replica2 = Sequence::new_public(op_source_pk, "some_identifying_str".to_string(), sequence_name, sdata_tag);
let perms = BTreeMap::default();
let owner_op = sign_sequence_public_policy_op( replica1.create_unsigned_public_policy_op(op_source_pk, perms)?, &op_source_pk_keypair)?;
replica1.apply_public_policy_op(owner_op.clone())?;
replica2.apply_public_policy_op(owner_op)?;
let append_op = sign_sequence_data_op(replica1.create_unsigned_append_op(s)?, &op_source_pk_keypair)?;
replica1.apply_data_op(append_op.clone())?;
replica2.apply_data_op(append_op)?;
verify_data_convergence(vec![replica1, replica2], 1)?;
}
#[test]
fn proptest_seq_converge_with_many_random_data(
dataset in generate_dataset(1000)
) {
let op_source_pk_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk = op_source_pk_keypair.public_key();
let sequence_name = XorName::random();
let sdata_tag = 43_001u64;
let mut replica1 = Sequence::new_public(op_source_pk, "some_identifying_str".to_string(), sequence_name, sdata_tag);
let mut replica2 = Sequence::new_public(op_source_pk, "some_identifying_str".to_string(), sequence_name, sdata_tag);
let perms = BTreeMap::default();
let owner_op = sign_sequence_public_policy_op( replica1.create_unsigned_public_policy_op(op_source_pk, perms)?, &op_source_pk_keypair)?;
replica1.apply_public_policy_op(owner_op.clone())?;
replica2.apply_public_policy_op(owner_op)?;
let dataset_length = dataset.len() as u64;
for data in dataset {
let append_op = sign_sequence_data_op( replica1.create_unsigned_append_op(data)?, &op_source_pk_keypair)?;
replica1.apply_data_op(append_op.clone())?;
replica2.apply_data_op(append_op)?;
}
verify_data_convergence(vec![replica1, replica2], dataset_length)?;
}
#[test]
fn proptest_seq_converge_with_many_random_data_across_arbitrary_number_of_replicas(
dataset in generate_dataset(500),
res in generate_replicas(50)
) {
let (mut replicas, owner_keypair) = res?;
let dataset_length = dataset.len() as u64;
for data in dataset {
let op = sign_sequence_data_op( replicas[0].create_unsigned_append_op(data)?, &owner_keypair )?;
for replica in &mut replicas {
replica.apply_data_op(op.clone())?;
}
}
verify_data_convergence(replicas, dataset_length)?;
}
#[test]
fn proptest_converge_with_shuffled_op_set_across_arbitrary_number_of_replicas(
dataset in generate_dataset(100),
res in generate_replicas(500)
) {
let (mut replicas, owner_keypair) = res?;
let dataset_length = dataset.len() as u64;
let mut ops = vec![];
for data in dataset {
let op = sign_sequence_data_op( replicas[0].create_unsigned_append_op(data)?, &owner_keypair )?;
replicas[0].apply_data_op(op.clone())?;
ops.push(op);
}
for replica in &mut replicas {
let mut ops = ops.clone();
ops.shuffle(&mut OsRng);
for op in ops {
replica.apply_data_op(op)?;
}
}
verify_data_convergence(replicas, dataset_length)?;
}
#[test]
fn proptest_converge_with_shuffled_ops_from_many_replicas_across_arbitrary_number_of_replicas(
dataset in generate_dataset(1000),
res in generate_replicas(100)
) {
let (mut replicas, owner_keypair) = res?;
let dataset_length = dataset.len() as u64;
let mut ops = vec![];
for data in dataset {
if let Some(replica) = replicas.choose_mut(&mut OsRng)
{
let op = sign_sequence_data_op( replica.create_unsigned_append_op(data)?, &owner_keypair )?;
replica.apply_data_op(op.clone())?;
ops.push(op);
}
}
let opslen = ops.len() as u64;
prop_assert_eq!(dataset_length, opslen);
for replica in &mut replicas {
let mut ops = ops.clone();
ops.shuffle(&mut OsRng);
for op in ops {
replica.apply_data_op(op)?;
}
}
verify_data_convergence(replicas, dataset_length)?;
}
#[test]
fn proptest_we_converge_with_ownership_changes(
dataset in generate_dataset_and_probability(1000),
) {
let op_source_pk_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk = op_source_pk_keypair.public_key();
let op_source_pk2_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk2 = op_source_pk2_keypair.public_key();
let sequence_name = XorName::random();
let sdata_tag = 43_001u64;
let mut replica1 = Sequence::new_public(op_source_pk, "some_identifying_str".to_string(), sequence_name, sdata_tag);
let mut replica2 = Sequence::new_public(op_source_pk2, "some_identifying_str2".to_string(), sequence_name, sdata_tag);
let perms = BTreeMap::default();
let owner_op = sign_sequence_public_policy_op( replica1.create_unsigned_public_policy_op(op_source_pk, perms)?, &op_source_pk_keypair)?;
replica1.apply_public_policy_op(owner_op.clone())?;
replica2.apply_public_policy_op(owner_op)?;
let dataset_length = dataset.len() as u64;
let mut ops = vec![];
for (data, policy_change_chance) in dataset {
let op = sign_sequence_data_op(replica1.create_unsigned_append_op(data)?, &op_source_pk_keypair)? ;
replica1.apply_data_op(op.clone())?;
ops.push(OpType::Data(op));
if policy_change_chance < u8::MAX / 3 {
let new_owner = Keypair::new_ed25519(&mut OsRng).public_key();
let mut perms = BTreeMap::default();
let user_perms =
SequencePublicPermissions::new( true, false);
let _ = perms.insert(SequenceUser::Key(op_source_pk), user_perms);
if let Ok(mut op) = replica1.create_unsigned_public_policy_op(new_owner, perms) {
let bytes = utils::serialise( &op.crdt_op )?;
let signature = op_source_pk_keypair.sign(&bytes);
op.signature = Some(signature);
replica1.apply_public_policy_op(op.clone())?;
ops.push(OpType::Owner(op));
};
}
}
let mut suffled_ops = ops.clone();
suffled_ops.shuffle(&mut OsRng);
for op in suffled_ops.clone() {
match op {
OpType::Data(op) => {
let _ = replica2.apply_data_op(op);
},
OpType::Owner(op) => {
let _ = replica2.apply_public_policy_op(op);
},
}
}
for op in ops.clone() {
match op {
OpType::Data(op) => {
replica2.apply_data_op(op)?;
},
OpType::Owner(op) => {
replica2.apply_public_policy_op(op)?;
},
}
}
verify_data_convergence(vec![replica1, replica2], dataset_length)?;
}
#[test]
#[ignore]
fn proptest_we_converge_with_ownership_and_perms_changes(
dataset in prop::collection::vec((generate_seq_entry(), any::<u8>()), 100..1000)
) {
let op_source_pk_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk = op_source_pk_keypair.public_key();
let op_source_pk2_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk2 = op_source_pk2_keypair.public_key();
let sequence_name = XorName::random();
let sdata_tag = 43_001u64;
let mut replica1 = Sequence::new_public(op_source_pk, "some_identifying_str".to_string(), sequence_name, sdata_tag);
let mut replica2 = Sequence::new_public(op_source_pk2, "some_identifying_str2".to_string(), sequence_name, sdata_tag);
let perms = BTreeMap::default();
let owner_op = sign_sequence_public_policy_op( replica1.create_unsigned_public_policy_op(op_source_pk, perms)?, &op_source_pk_keypair)?;
replica1.apply_public_policy_op(owner_op.clone())?;
replica2.apply_public_policy_op(owner_op)?;
let dataset_length = dataset.len() as u64;
let mut ops = vec![];
for (data, policy_change_chance) in dataset {
let op = sign_sequence_data_op(replica1.create_unsigned_append_op(data)?, &op_source_pk_keypair )?;
replica1.apply_data_op(op.clone())?;
ops.push(OpType::Data(op));
let new_owner = Keypair::new_ed25519(&mut OsRng).public_key();
if policy_change_chance < u8::MAX / 8 {
let mut perms = BTreeMap::default();
let user_perms =
SequencePublicPermissions::new( true, false);
let _ = perms.insert(SequenceUser::Key(op_source_pk), user_perms);
let owner_op = sign_sequence_public_policy_op( replica1.create_unsigned_public_policy_op(new_owner, perms)?, &op_source_pk_keypair)?;
replica1.apply_public_policy_op(owner_op.clone())?;
ops.push(OpType::Owner(owner_op));
}
if policy_change_chance < u8::MAX / 4 && policy_change_chance > u8::MAX / 8 {
let mut perms = BTreeMap::default();
let user_perms =
SequencePublicPermissions::new( false, false);
let _ = perms.insert(SequenceUser::Key(new_owner), user_perms);
let owner_op = sign_sequence_public_policy_op( replica1.create_unsigned_public_policy_op(new_owner, perms)?, &op_source_pk_keypair)?;
replica1.apply_public_policy_op(owner_op.clone())?;
ops.push(OpType::Owner(owner_op));
}
if policy_change_chance < u8::MAX / 2 && policy_change_chance > u8::MAX / 4 {
let mut perms = BTreeMap::default();
let user_perms =
SequencePublicPermissions::new( true, false);
let _ = perms.insert(SequenceUser::Key(op_source_pk), user_perms);
let owner_op = sign_sequence_public_policy_op( replica1.create_unsigned_public_policy_op(new_owner, perms)?, &op_source_pk_keypair)?;
replica1.apply_public_policy_op(owner_op.clone())?;
ops.push(OpType::Owner(owner_op));
}
}
let mut suffled_ops = ops.clone();
suffled_ops.shuffle(&mut OsRng);
for op in suffled_ops.clone() {
match op {
OpType::Data(op) => {
let _ = replica2.apply_data_op(op);
},
OpType::Owner(op) => {
let _ = replica2.apply_public_policy_op(op);
},
}
}
assert_ne!(replica2.len(None), replica1.len(None));
for op in ops.clone() {
match op {
OpType::Data(op) => {
replica2.apply_data_op(op)?;
},
OpType::Owner(op) => {
replica2.apply_public_policy_op(op)?;
},
}
}
verify_data_convergence(vec![replica1, replica2], dataset_length)?;
}
#[test]
fn proptest_dropped_data_can_be_reapplied_and_we_converge(
dataset in generate_dataset_and_probability(1000),
) {
let op_source_pk_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk = op_source_pk_keypair.public_key();
let op_source_pk2_keypair = Keypair::new_ed25519(&mut OsRng);
let op_source_pk2 = op_source_pk2_keypair.public_key();
let sequence_name = XorName::random();
let sdata_tag = 43_001u64;
let mut replica1 = Sequence::new_public(op_source_pk, "some_identifying_str".to_string(), sequence_name, sdata_tag);
let mut replica2 = Sequence::new_public(op_source_pk2, "some_identifying_str2".to_string(), sequence_name, sdata_tag);
let perms = BTreeMap::default();
let owner_op = sign_sequence_public_policy_op( replica1.create_unsigned_public_policy_op(op_source_pk, perms)?, &op_source_pk_keypair)?;
replica1.apply_public_policy_op(owner_op.clone())?;
replica2.apply_public_policy_op(owner_op)?;
let dataset_length = dataset.len() as u64;
let mut ops = vec![];
for (data, delivery_chance) in dataset {
let op = sign_sequence_data_op(replica1.create_unsigned_append_op(data)?, &op_source_pk_keypair)?;
replica1.apply_data_op(op.clone())?;
ops.push((op, delivery_chance));
}
for (op, delivery_chance) in ops.clone() {
if delivery_chance < u8::MAX / 3 {
replica2.apply_data_op(op)?;
}
}
if dataset_length > 50 {
assert_ne!(replica2.len(None), replica1.len(None));
}
for (op, _) in ops {
replica2.apply_data_op(op)?;
}
verify_data_convergence(vec![replica1, replica2], dataset_length)?;
}
#[test]
fn proptest_converge_with_shuffled_ops_from_many_while_dropping_some_at_random(
dataset in generate_dataset_and_probability(1000),
res in generate_replicas(100),
) {
let (mut replicas, owner_keypair) = res?;
let dataset_length = dataset.len() as u64;
let mut ops = vec![];
for (data, delivery_chance) in dataset {
let index: usize = OsRng.gen_range( 0, replicas.len());
let replica = &mut replicas[index];
let op = sign_sequence_data_op( replica.create_unsigned_append_op(data)?, &owner_keypair)?;
replica.apply_data_op(op.clone())?;
ops.push((op, delivery_chance));
}
let opslen = ops.len() as u64;
prop_assert_eq!(dataset_length, opslen);
for replica in &mut replicas {
let mut ops = ops.clone();
ops.shuffle(&mut OsRng);
for (op, delivery_chance) in ops.clone() {
if delivery_chance > u8::MAX / 3 {
replica.apply_data_op(op)?;
}
}
for (op, _) in ops {
replica.apply_data_op(op)?;
}
}
verify_data_convergence(replicas, dataset_length)?;
}
#[test]
fn proptest_converge_with_shuffled_ops_including_bad_ops_which_error_and_are_not_applied(
dataset in generate_dataset(10),
bogus_dataset in generate_dataset(10),
res in generate_replicas(10),
) {
let (mut replicas, owner_keypair) = res?;
let dataset_length = dataset.len();
let bogus_dataset_length = bogus_dataset.len();
let number_replicas = replicas.len();
let xorname = XorName::random();
let tag = 45_000u64;
let mut bogus_replica = Sequence::new_public(owner_keypair.public_key(), "actor".to_string(), xorname, tag);
let perms = BTreeMap::default();
let bogus_op = sign_sequence_public_policy_op(bogus_replica.create_unsigned_public_policy_op(owner_keypair.public_key(), perms)?, &owner_keypair )?;
bogus_replica.apply_public_policy_op(bogus_op)?;
let mut ops = vec![];
for data in dataset {
if let Some(replica) = replicas.choose_mut(&mut OsRng)
{
let op = sign_sequence_data_op(replica.create_unsigned_append_op(data)?, &owner_keypair)?;
replica.apply_data_op(op.clone())?;
ops.push(op);
}
}
for data in bogus_dataset {
let bogus_op = sign_sequence_data_op( bogus_replica.create_unsigned_append_op(data)?, &owner_keypair)?;
bogus_replica.apply_data_op(bogus_op.clone())?;
ops.push(bogus_op);
}
let opslen = ops.len();
prop_assert_eq!(dataset_length + bogus_dataset_length, opslen);
let mut err_count = vec![];
for replica in &mut replicas {
let mut ops = ops.clone();
ops.shuffle(&mut OsRng);
for op in ops {
match replica.apply_data_op(op) {
Ok(_) => {},
Err(error) => {err_count.push(error)},
}
}
}
assert_eq!(err_count.len(), bogus_dataset_length * number_replicas);
verify_data_convergence(replicas, dataset_length as u64)?;
}
}
}