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 = PublicKey;
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)
}
}
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 append(&mut self, entry: Entry) -> Result<DataWriteOp<Entry>> {
self.check_permission(Action::Append, None, None)?;
match &mut self.data {
SeqData::Public(data) => data.append(entry, self.operations_pk),
SeqData::Private(data) => data.append(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 set_public_policy(
&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.set_policy(PublicPolicy { owner, permissions }, self.operations_pk)
}
SeqData::Private(_) => Err(Error::InvalidOperation),
}
}
pub fn set_private_policy(
&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.set_policy(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)
}
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)
}
}
}
}
#[cfg(test)]
mod tests {
use crate::{
Error, Keypair, PublicKey, Result, Sequence, SequenceAddress, SequenceDataWriteOp,
SequenceEntry, SequenceIndex, SequenceKind, SequencePermissions, SequencePolicyWriteOp,
SequencePrivatePermissions, SequencePublicPermissions, SequencePublicPolicy, SequenceUser,
};
use proptest::prelude::*;
use rand::rngs::OsRng;
use rand::seq::SliceRandom;
use std::collections::BTreeMap;
use xor_name::XorName;
#[test]
fn sequence_create_public() {
let actor = generate_public_key();
let sequence_name = XorName::random();
let sequence_tag = 43_000;
let sequence = Sequence::new_public(actor, actor, 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 actor = generate_public_key();
let sequence_name = XorName::random();
let sequence_tag = 43_000;
let sequence = Sequence::new_private(actor, actor, 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 actor = generate_public_key();
let sequence_name = XorName::random();
let sequence_tag = 43_000;
let mut replica1 = Sequence::new_public(actor, actor, sequence_name, sequence_tag);
let mut replica2 = Sequence::new_public(actor, actor, 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.set_public_policy(actor, perms1)?;
replica2.apply_public_policy_op(policy_op)?;
let entry1 = b"value0".to_vec();
let entry2 = b"value1".to_vec();
let op1 = replica1.append(entry1.clone())?;
let op2 = replica1.append(entry2.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_public_set_policy_and_apply() -> Result<()> {
let actor = generate_public_key();
let sequence_name = XorName::random();
let sequence_tag = 43_000;
let mut replica1 = Sequence::new_public(actor, actor, sequence_name, sequence_tag);
let mut replica2 = Sequence::new_public(actor, actor, 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 = replica1.set_public_policy(actor, perms1.clone())?;
let op2 = replica1.set_public_policy(actor, perms2.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_set_policy_and_apply() -> Result<()> {
let actor1 = generate_public_key();
let actor2 = generate_public_key();
let sequence_name = XorName::random();
let sequence_tag = 43_000;
let mut replica1 = Sequence::new_private(actor1, actor1, sequence_name, sequence_tag);
let mut replica2 = Sequence::new_private(actor2, actor2, sequence_name, sequence_tag);
let mut perms1 = BTreeMap::default();
let user_perms1 = SequencePrivatePermissions::new(true, false, true);
let _ = perms1.insert(actor1, user_perms1);
let mut perms2 = BTreeMap::default();
let user_perms2 = SequencePrivatePermissions::new(true, true, false);
let _ = perms2.insert(actor2, user_perms2);
let op1 = replica1.set_private_policy(actor2, perms1.clone())?;
let op2 = replica1.set_private_policy(actor1, perms2.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, actor2);
assert_eq!(first_entry, replica2.private_policy_at(index_0, None)?);
assert_eq!(
SequencePermissions::Private(user_perms1),
replica1.permissions_at(SequenceUser::Key(actor1), 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, actor1);
assert_eq!(second_entry, replica2.private_policy_at(index_1, None)?);
assert_eq!(
SequencePermissions::Private(user_perms2),
replica1.permissions_at(SequenceUser::Key(actor2), index_1, None)?
);
Ok(())
}
#[test]
fn sequence_public_set_policy_and_append_fails_when_no_perms_for_actor() -> Result<()> {
let actor1 = generate_public_key();
let actor2 = generate_public_key();
let sequence_name = XorName::random();
let sequence_tag = 43_000;
let mut replica1 = Sequence::new_public(actor1, actor1, sequence_name, sequence_tag);
let mut replica2 = Sequence::new_public(actor2, actor2, sequence_name, sequence_tag);
let mut perms1 = BTreeMap::default();
let user_perms1 = SequencePublicPermissions::new(true, false);
let _ = perms1.insert(SequenceUser::Key(actor1), user_perms1);
let mut perms2 = BTreeMap::default();
let user_perms2 = SequencePublicPermissions::new(false, false);
let _ = perms2.insert(SequenceUser::Key(actor2), user_perms2);
let op1 = replica1.set_public_policy(actor1, perms1)?;
let op2 = replica1.set_public_policy(actor1, perms2)?;
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 = replica1.append(item1.to_vec())?;
replica2.apply_data_op(append_op1)?;
check_op_not_allowed_failure(replica2.append(item2.to_vec()))?;
assert_eq!(replica1.len(None)?, replica2.len(None)?);
Ok(())
}
#[test]
fn sequence_public_set_policy_and_append_succeeds_when_perms_updated_for_actor() -> Result<()> {
let actor1 = generate_public_key();
let actor2 = generate_public_key();
let sequence_name = XorName::random();
let sequence_tag = 43_000;
let mut replica1 = Sequence::new_public(actor1, actor1, sequence_name, sequence_tag);
let mut replica2 = Sequence::new_public(actor2, actor2, sequence_name, sequence_tag);
let mut perms1 = BTreeMap::default();
let user_perms1 = SequencePublicPermissions::new(true, false);
let _ = perms1.insert(SequenceUser::Key(actor1), user_perms1);
let mut perms2 = BTreeMap::default();
let user_perms2 = SequencePublicPermissions::new(false, false);
let _ = perms2.insert(SequenceUser::Key(actor2), user_perms2);
let op1 = replica1.set_public_policy(actor1, perms1)?;
let op2 = replica1.set_public_policy(actor1, perms2)?;
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 = replica1.append(item1.to_vec())?;
replica2.apply_data_op(append_op1)?;
check_op_not_allowed_failure(replica2.append(item2.to_vec()))?;
let mut perms3 = BTreeMap::default();
let user_perms3 = SequencePublicPermissions::new(true, false);
let _ = perms3.insert(SequenceUser::Key(actor2), user_perms3);
let op1 = replica1.set_public_policy(actor1, perms3)?;
replica2.apply_public_policy_op(op1)?;
let append_op = replica2.append(item2.to_vec())?;
replica1.apply_data_op(append_op)?;
assert_eq!(replica1.len(None)?, replica2.len(None)?);
Ok(())
}
#[test]
fn sequence_private_set_policy_and_append_fails_when_no_perms_for_actor() -> Result<()> {
let actor1 = generate_public_key();
let actor2 = generate_public_key();
let sequence_name = XorName::random();
let sequence_tag = 43_000;
let mut replica1 = Sequence::new_private(actor1, actor1, sequence_name, sequence_tag);
let mut replica2 = Sequence::new_private(actor2, actor2, sequence_name, sequence_tag);
let mut perms1 = BTreeMap::default();
let user_perms1 = SequencePrivatePermissions::new(true, false, true);
let _ = perms1.insert(actor1, user_perms1);
let mut perms2 = BTreeMap::default();
let user_perms2 = SequencePrivatePermissions::new(false, false, false);
let _ = perms2.insert(actor2, user_perms2);
let op1 = replica1.set_private_policy(actor2, perms1)?;
let op2 = replica1.set_private_policy(actor1, perms2)?;
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(actor1))?, Some(1));
let item1 = b"item1";
let item2 = b"item2";
let append_op1 = replica1.append(item1.to_vec())?;
replica2.apply_data_op(append_op1)?;
check_op_not_allowed_failure(replica2.append(item2.to_vec()))?;
Ok(())
}
#[test]
fn sequence_private_set_policy_and_get_read_fails_when_no_perms_for_actor() -> Result<()> {
let actor1 = generate_public_key();
let actor2 = generate_public_key();
let sequence_name = XorName::random();
let sequence_tag = 43_000;
let mut replica1 = Sequence::new_private(actor1, actor1, sequence_name, sequence_tag);
let mut replica2 = Sequence::new_private(actor2, actor2, sequence_name, sequence_tag);
let mut perms1 = BTreeMap::default();
let user_perms1 = SequencePrivatePermissions::new(true, false, true);
let _ = perms1.insert(actor1, user_perms1);
let mut perms2 = BTreeMap::default();
let user_perms2 = SequencePrivatePermissions::new(false, false, false);
let _ = perms2.insert(actor2, user_perms2);
let op1 = replica1.set_private_policy(actor2, perms1)?;
let op2 = replica1.set_private_policy(actor1, perms2)?;
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(actor1))?, Some(1));
let item1 = b"item1".to_vec();
let append_op1 = replica1.append(item1.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(actor2)))?;
let data = replica2.get(SequenceIndex::FromStart(0), Some(actor1))?;
assert_eq!(data, Some(&item1));
Ok(())
}
#[test]
fn sequence_private_set_policy_and_last_entry_read_fails_when_no_perms_for_actor() -> Result<()>
{
let actor1 = generate_public_key();
let actor2 = generate_public_key();
let sequence_name = XorName::random();
let sequence_tag = 43_000;
let mut replica1 = Sequence::new_private(actor1, actor1, sequence_name, sequence_tag);
let mut replica2 = Sequence::new_private(actor2, actor2, sequence_name, sequence_tag);
let mut perms1 = BTreeMap::default();
let user_perms1 = SequencePrivatePermissions::new(true, false, true);
let _ = perms1.insert(actor1, user_perms1);
let mut perms2 = BTreeMap::default();
let user_perms2 = SequencePrivatePermissions::new(false, false, false);
let _ = perms2.insert(actor2, user_perms2);
let op1 = replica1.set_private_policy(actor2, perms1)?;
let op2 = replica1.set_private_policy(actor1, perms2)?;
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(actor1))?, Some(1));
let item1 = b"item1".to_vec();
let append_op1 = replica1.append(item1.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(actor2)))?;
let data = replica2.last_entry(Some(actor1))?;
assert_eq!(data, Some(&item1));
Ok(())
}
#[test]
fn sequence_private_set_policy_and_range_read_fails_when_no_perms_for_actor() -> Result<()> {
let actor1 = generate_public_key();
let actor2 = generate_public_key();
let sequence_name = XorName::random();
let sequence_tag = 43_000;
let mut replica1 = Sequence::new_private(actor1, actor1, sequence_name, sequence_tag);
let mut replica2 = Sequence::new_private(actor2, actor2, sequence_name, sequence_tag);
let mut perms1 = BTreeMap::default();
let user_perms1 = SequencePrivatePermissions::new(true, false, true);
let _ = perms1.insert(actor1, user_perms1);
let mut perms2 = BTreeMap::default();
let user_perms2 = SequencePrivatePermissions::new(false, false, false);
let _ = perms2.insert(actor2, user_perms2);
let op1 = replica1.set_private_policy(actor2, perms1)?;
let op2 = replica1.set_private_policy(actor1, perms2)?;
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(actor1))?, Some(1));
let item1 = b"item1".to_vec();
let append_op1 = replica1.append(item1.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(actor2),
))?;
let data = replica2.in_range(
SequenceIndex::FromStart(0),
SequenceIndex::FromStart(1),
Some(actor1),
)?;
assert_eq!(data, Some(vec![item1]));
Ok(())
}
#[test]
fn sequence_private_set_policy_and_read_possible_after_update() -> Result<()> {
let actor1 = generate_public_key();
let actor2 = generate_public_key();
let sequence_name = XorName::random();
let sequence_tag = 43_000;
let mut replica1 = Sequence::new_private(actor1, actor1, sequence_name, sequence_tag);
let mut replica2 = Sequence::new_private(actor2, actor2, sequence_name, sequence_tag);
let mut perms1 = BTreeMap::default();
let user_perms1 = SequencePrivatePermissions::new(true, false, true);
let _ = perms1.insert(actor1, user_perms1);
let mut perms2 = BTreeMap::default();
let user_perms2 = SequencePrivatePermissions::new(false, false, false);
let _ = perms2.insert(actor2, user_perms2);
let op1 = replica1.set_private_policy(actor2, perms1)?;
let op2 = replica1.set_private_policy(actor1, perms2)?;
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(actor1))?, Some(1));
let item1 = b"item1".to_vec();
let append_op1 = replica1.append(item1.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(actor2)))?;
let mut perms3 = BTreeMap::default();
let user_perms3 = SequencePrivatePermissions::new(true, false, false);
let _ = perms3.insert(actor2, user_perms3);
let updated_perms_op = replica1.set_private_policy(actor1, perms3)?;
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 actor1 = generate_public_key();
let actor2 = generate_public_key();
let sdata_name: XorName = rand::random();
let sdata_tag = 43_000u64;
let mut replica1 = Sequence::new_public(actor1, actor1, sdata_name, sdata_tag);
let mut replica2 = Sequence::new_public(actor2, actor2, sdata_name, sdata_tag);
let mut perms = BTreeMap::default();
let user_perms =
SequencePublicPermissions::new( true, false);
let _ = perms.insert(SequenceUser::Key(actor2), user_perms);
let grant_op = replica1.set_public_policy(actor1, perms)?;
replica2.apply_public_policy_op(grant_op)?;
let item1 = b"item1";
let append_op1 = replica1.append(item1.to_vec())?;
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 = replica1.set_public_policy(actor1, BTreeMap::default())?;
assert_eq!(replica1.policy_version(None)?, Some(1));
let item2 = b"item2";
let append_op2 = replica2.append(item2.to_vec())?;
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() -> Result<()> {
let actor1 = generate_public_key();
let actor2 = generate_public_key();
let actor3 = generate_public_key();
let sdata_name: XorName = rand::random();
let sdata_tag = 43_001u64;
let mut replica1 = Sequence::new_public(actor1, actor1, sdata_name, sdata_tag);
let mut replica2 = Sequence::new_public(actor2, actor2, sdata_name, sdata_tag);
let mut replica3 = Sequence::new_public(actor3, actor3, sdata_name, sdata_tag);
let mut perms = BTreeMap::default();
let user_perms =
SequencePublicPermissions::new( true, false);
let _ = perms.insert(SequenceUser::Key(actor3), user_perms);
let owner_op = replica1.set_public_policy(actor1, perms)?;
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(actor3), user_perms);
let grant_op = replica1.set_public_policy(actor1, perms)?;
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 = replica3.append(item.to_vec())?;
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 actor1 = generate_public_key();
let actor2 = generate_public_key();
let sdata_name: XorName = rand::random();
let sdata_tag = 43_001u64;
let mut replica1 = Sequence::new_public(actor1, actor1, sdata_name, sdata_tag);
let mut replica2 = Sequence::new_public(actor2, actor2, sdata_name, sdata_tag);
let mut perms = BTreeMap::default();
let user_perms =
SequencePublicPermissions::new( true, true);
let _ = perms.insert(SequenceUser::Key(actor2), user_perms);
let owner_op = replica1.set_public_policy(actor1, perms.clone())?;
replica2.apply_public_policy_op(owner_op)?;
let item0 = b"item0".to_vec();
let append_op = replica1.append(item0)?;
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(actor1), user_perms);
let owner_op_1 = replica1.set_public_policy(generate_public_key(), perms.clone())?;
let owner_op_2 = replica2.set_public_policy(generate_public_key(), perms)?;
let item1_r1 = b"item1_replica1".to_vec();
let item1_r2 = b"item1_replica2".to_vec();
let append_op1 = replica1.append(item1_r1)?;
let append_op2 = replica2.append(item1_r2)?;
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 actor1 = generate_public_key();
let actor2 = generate_public_key();
let sdata_name: XorName = rand::random();
let sdata_tag = 43_001u64;
let mut replica1 = Sequence::new_public(actor1, actor1, sdata_name, sdata_tag);
let mut replica2 = Sequence::new_public(actor2, actor2, sdata_name, sdata_tag);
let mut perms = BTreeMap::default();
let user_perms =
SequencePublicPermissions::new( true, false);
let _ = perms.insert(SequenceUser::Key(actor2), user_perms);
let owner_op = replica1.set_public_policy(actor1, perms)?;
replica2.apply_public_policy_op(owner_op)?;
let item0 = b"item0".to_vec();
let append_op = replica1.append(item0)?;
let policy_op = replica1.set_public_policy(actor1, BTreeMap::default())?;
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 actor1 = generate_public_key();
let actor2 = generate_public_key();
let sdata_name: XorName = rand::random();
let sdata_tag = 43_001u64;
let mut replica1 = Sequence::new_public(actor1, actor1, sdata_name, sdata_tag);
let mut replica2 = Sequence::new_public(actor2, actor2, sdata_name, sdata_tag);
let mut perms = BTreeMap::default();
let user_perms =
SequencePublicPermissions::new( true, true);
let _ = perms.insert(SequenceUser::Key(actor2), user_perms);
let owner_op = replica1.set_public_policy(actor1, perms)?;
replica2.apply_public_policy_op(owner_op)?;
let perms = BTreeMap::default();
let actor3 = generate_public_key();
let old_owner_op = replica1.set_public_policy(actor3, perms.clone())?;
let owner_op = replica2.set_public_policy(actor2, perms)?;
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, actor1);
assert_eq!(policy1.owner, replica2.public_policy_at(0)?.owner);
let policy2 = replica1.public_policy_at(1)?;
if policy2.owner == actor3 {
assert_eq!(policy2.owner, replica2.public_policy_at(1)?.owner);
let policy3 = replica1.public_policy_at(2)?;
assert_eq!(policy3.owner, actor2);
assert_eq!(policy3.owner, replica2.public_policy_at(2)?.owner);
} else {
assert_eq!(policy2.owner, actor2);
assert_eq!(policy2.owner, replica2.public_policy_at(1)?.owner);
let policy3 = replica1.public_policy_at(2)?;
assert_eq!(policy3.owner, actor3);
assert_eq!(policy3.owner, replica2.public_policy_at(2)?.owner);
}
Ok(())
}
#[test]
fn sequence_falsified_policy_op() -> Result<()> {
let actor1 = generate_public_key();
let actor2 = generate_public_key();
let sdata_name: XorName = rand::random();
let sdata_tag = 43_001u64;
let mut replica1 = Sequence::new_public(actor1, actor1, sdata_name, sdata_tag);
let mut replica2 = Sequence::new_public(actor2, actor2, sdata_name, sdata_tag);
let perms = BTreeMap::default();
let owner_op = replica1.set_public_policy(actor1, perms.clone())?;
replica2.apply_public_policy_op(owner_op)?;
let mut temp_replica = replica1.clone();
let owner_op = replica1.set_public_policy(actor2, perms.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 = temp_replica.set_public_policy(actor1, perms)?;
use crdts::lseq::{ident::IdentGen, Op};
let upper_ident = IdentGen::new(actor1).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,
},
};
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<()>) -> Result<()> {
match result {
Err(Error::OpNotCausallyReady) => Ok(()),
Err(err) => Err(Error::Unexpected(format!(
"Error returned was the unexpected one: {}",
err
))),
Ok(()) => Err(Error::Unexpected(
"Data op applied unexpectedly".to_string(),
)),
}
}
fn check_op_not_allowed_failure<T>(result: Result<T>) -> Result<()> {
match result {
Err(Error::AccessDenied) => Ok(()),
Err(err) => Err(Error::Unexpected(format!(
"Error returned was the unexpected one for a non-allowed op: {}",
err
))),
Ok(_) => Err(Error::Unexpected(
"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 = (Vec<Sequence>, PublicKey)> {
let xorname = XorName::random();
let tag = 45_000u64;
let owner = generate_public_key();
(1..max_quantity + 1).prop_map(move |quantity| {
let mut replicas = Vec::with_capacity(quantity);
for _ in 0..quantity {
let actor = generate_public_key();
let replica = Sequence::new_public(owner, actor, xorname, tag);
replicas.push(replica);
}
let perms = BTreeMap::default();
let owner_op = replicas[0].set_public_policy(owner, perms).unwrap();
for r in replicas.iter_mut() {
r.apply_public_policy_op(owner_op.clone()).unwrap();
}
(replicas, owner)
})
}
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 actor1 = generate_public_key();
let sequence_name = XorName::random();
let sdata_tag = 43_001u64;
let mut replica1 = Sequence::new_public(actor1, actor1, sequence_name, sdata_tag);
let mut replica2 = Sequence::new_public(actor1, actor1, sequence_name, sdata_tag);
let perms = BTreeMap::default();
let owner_op = replica1.set_public_policy(actor1, perms)?;
replica2.apply_public_policy_op(owner_op)?;
let append_op = replica1.append(s)?;
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 actor1 = generate_public_key();
let sequence_name = XorName::random();
let sdata_tag = 43_001u64;
let mut replica1 = Sequence::new_public(actor1, actor1, sequence_name, sdata_tag);
let mut replica2 = Sequence::new_public(actor1, actor1, sequence_name, sdata_tag);
let perms = BTreeMap::default();
let owner_op = replica1.set_public_policy(actor1, perms)?;
replica2.apply_public_policy_op(owner_op)?;
let dataset_length = dataset.len() as u64;
for data in dataset {
let append_op = replica1.append(data)?;
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),
(mut replicas, _pk) in generate_replicas(50)
) {
let dataset_length = dataset.len() as u64;
for data in dataset {
let op = replicas[0].append(data)?;
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),
(mut replicas, _pk) in generate_replicas(500)
) {
let dataset_length = dataset.len() as u64;
let mut ops = vec![];
for data in dataset {
let op = replicas[0].append(data)?;
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),
(mut replicas, _pk) in generate_replicas(100)
) {
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 = replica.append(data)?;
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 actor1 = generate_public_key();
let actor2 = generate_public_key();
let sequence_name = XorName::random();
let sdata_tag = 43_001u64;
let mut replica1 = Sequence::new_public(actor1, actor1, sequence_name, sdata_tag);
let mut replica2 = Sequence::new_public(actor2, actor2, sequence_name, sdata_tag);
let perms = BTreeMap::default();
let owner_op = replica1.set_public_policy(actor1, perms)?;
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 = replica1.append(data)?;
ops.push(OpType::Data(op));
if policy_change_chance < u8::MAX / 3 {
let new_owner = generate_public_key();
let mut perms = BTreeMap::default();
let user_perms =
SequencePublicPermissions::new( true, false);
let _ = perms.insert(SequenceUser::Key(actor1), user_perms);
if let Ok(op) = replica1.set_public_policy(new_owner, perms) {
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 actor1 = generate_public_key();
let actor2 = generate_public_key();
let sequence_name = XorName::random();
let sdata_tag = 43_001u64;
let mut replica1 = Sequence::new_public(actor1, actor1, sequence_name, sdata_tag);
let mut replica2 = Sequence::new_public(actor2, actor2, sequence_name, sdata_tag);
let perms = BTreeMap::default();
let owner_op = replica1.set_public_policy(actor1, perms)?;
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 = replica1.append(data)?;
ops.push(OpType::Data(op));
let new_owner = generate_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(actor1), user_perms);
let owner_op = replica1.set_public_policy(new_owner, perms)?;
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 = replica1.set_public_policy(new_owner, perms)?;
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(actor1), user_perms);
let owner_op = replica1.set_public_policy(new_owner, perms)?;
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 actor1 = generate_public_key();
let actor2 = generate_public_key();
let sequence_name = XorName::random();
let sdata_tag = 43_001u64;
let mut replica1 = Sequence::new_public(actor1, actor1, sequence_name, sdata_tag);
let mut replica2 = Sequence::new_public(actor2, actor2, sequence_name, sdata_tag);
let perms = BTreeMap::default();
let owner_op = replica1.set_public_policy(actor1, perms)?;
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 = replica1.append(data)?;
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),
(mut replicas, _pk) in generate_replicas(100),
) {
let dataset_length = dataset.len() as u64;
let mut ops = vec![];
for (data, delivery_chance) in dataset {
if let Some(replica) = replicas.choose_mut(&mut OsRng)
{
let op = replica.append(data)?;
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(1000),
bogus_dataset in generate_dataset(1000),
(mut replicas, _pk) in generate_replicas(100),
) {
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 owner = generate_public_key();
let actor = generate_public_key();
let mut bogus_replica = Sequence::new_public(owner, actor, xorname, tag);
let perms = BTreeMap::default();
let _ = bogus_replica.set_public_policy(owner, perms).unwrap();
let mut ops = vec![];
for data in dataset {
if let Some(replica) = replicas.choose_mut(&mut OsRng)
{
let op = replica.append(data)?;
ops.push(op);
}
}
for data in bogus_dataset {
let bogus_op = bogus_replica.append(data)?;
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)?;
}
}
}