use std::borrow::Borrow;
use std::fmt::{Display, Formatter};
use crate::entry_def::EntryVisibility;
use crate::link::LinkTag;
use crate::link::LinkType;
use crate::timestamp::Timestamp;
use crate::EntryRateWeight;
use crate::MembraneProof;
use crate::RateWeight;
use holo_hash::impl_hashable_content;
use holo_hash::ActionHash;
use holo_hash::AgentPubKey;
use holo_hash::AnyLinkableHash;
use holo_hash::DnaHash;
use holo_hash::EntryHash;
use holo_hash::HashableContent;
use holo_hash::HoloHashed;
use holochain_serialized_bytes::prelude::*;
pub mod builder;
pub mod conversions;
pub const POST_GENESIS_SEQ_THRESHOLD: u32 = 3;
#[allow(missing_docs)]
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, SerializedBytes, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[serde(tag = "type")]
pub enum Action {
Dna(Dna),
AgentValidationPkg(AgentValidationPkg),
InitZomesComplete(InitZomesComplete),
CreateLink(CreateLink),
DeleteLink(DeleteLink),
OpenChain(OpenChain),
CloseChain(CloseChain),
Create(Create),
Update(Update),
Delete(Delete),
}
impl Display for Action {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Action::Dna(dna) =>
write!(f, "dna={:?}", dna),
Action::AgentValidationPkg(avp) =>
write!(
f,
"agent_validation_pkg=[author={}, timestamp={}]",
avp.author, avp.timestamp
),
Action::InitZomesComplete(izc) =>
write!(
f,
"init_zomes_complete=[author={}, timestamp={}]",
izc.author, izc.timestamp
),
Action::CreateLink(link) => write!(f, "create_link=[author={}, timestamp={}, base_address={}, target_address={}, zome_index={}, link_type={:?}]", link.author, link.timestamp, link.base_address, link.target_address, link.zome_index, link.link_type),
Action::DeleteLink(link) => write!(f, "delete_link=[author={}, timestamp={}]", link.author, link.timestamp),
Action::OpenChain(oc) => write!(
f,
"open_chain=[author={}, timestamp={}]",
oc.author, oc.timestamp
),
Action::CloseChain(cc) => write!(
f,
"close_chain=[author={}, timestamp={}]",
cc.author, cc.timestamp
),
Action::Create(create) => write!(f, "create=[author={}, timestamp={}, entry_type={:?}, entry_hash={}]", create.author, create.timestamp, create.entry_type, create.entry_hash),
Action::Update(update) => write!(f, "create=[author={}, timestamp={}, original_action_address={}, original_entry_address={}, entry_type={:?}, entry_hash={}]", update.author, update.timestamp, update.original_action_address, update.original_entry_address, update.entry_type, update.entry_hash),
Action::Delete(delete) => write!(f, "create=[author={}, timestamp={}, deletes_address={}, deletes_entry_address={}]", delete.author, delete.timestamp, delete.deletes_address, delete.deletes_entry_address),
}
}
}
#[derive(Clone, Debug, Serialize, PartialEq, Eq, Hash)]
#[serde(tag = "type")]
pub(crate) enum ActionRef<'a> {
Dna(&'a Dna),
AgentValidationPkg(&'a AgentValidationPkg),
InitZomesComplete(&'a InitZomesComplete),
CreateLink(&'a CreateLink),
DeleteLink(&'a DeleteLink),
OpenChain(&'a OpenChain),
CloseChain(&'a CloseChain),
Create(&'a Create),
Update(&'a Update),
Delete(&'a Delete),
}
pub type ActionHashed = HoloHashed<Action>;
macro_rules! write_into_action {
($($n:ident $(<$w : ty>)?),*,) => {
#[derive(serde::Serialize, serde::Deserialize, SerializedBytes, PartialEq, Eq, Clone, Debug)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum ActionType {
$($n,)*
}
impl std::fmt::Display for ActionType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
$( ActionType::$n => stringify!($n), )*
}
)
}
}
impl From<&Action> for ActionType {
fn from(action: &Action) -> ActionType {
match action {
$(
Action::$n(_) => ActionType::$n,
)*
}
}
}
};
}
pub trait ActionWeighed {
type Unweighed: ActionUnweighed;
type Weight: Default;
fn into_action(self) -> Action;
fn unweighed(self) -> Self::Unweighed;
}
pub trait ActionUnweighed: Sized {
type Weighed: ActionWeighed;
type Weight: Default;
fn weighed(self, weight: Self::Weight) -> Self::Weighed;
#[cfg(feature = "test_utils")]
fn weightless(self) -> Self::Weighed {
self.weighed(Default::default())
}
}
impl<I: ActionWeighed> From<I> for Action {
fn from(i: I) -> Self {
i.into_action()
}
}
write_into_action! {
Dna,
AgentValidationPkg,
InitZomesComplete,
OpenChain,
CloseChain,
Create<EntryRateWeight>,
Update<EntryRateWeight>,
Delete<RateWeight>,
CreateLink<RateWeight>,
DeleteLink,
}
macro_rules! match_action {
($h:ident => |$i:ident| { $($t:tt)* }) => {
match $h {
Action::Dna($i) => { $($t)* }
Action::AgentValidationPkg($i) => { $($t)* }
Action::InitZomesComplete($i) => { $($t)* }
Action::CreateLink($i) => { $($t)* }
Action::DeleteLink($i) => { $($t)* }
Action::OpenChain($i) => { $($t)* }
Action::CloseChain($i) => { $($t)* }
Action::Create($i) => { $($t)* }
Action::Update($i) => { $($t)* }
Action::Delete($i) => { $($t)* }
}
};
}
impl Action {
pub fn entry_data(&self) -> Option<(&EntryHash, &EntryType)> {
match self {
Self::Create(Create {
entry_hash,
entry_type,
..
}) => Some((entry_hash, entry_type)),
Self::Update(Update {
entry_hash,
entry_type,
..
}) => Some((entry_hash, entry_type)),
_ => None,
}
}
pub fn into_entry_data(self) -> Option<(EntryHash, EntryType)> {
match self {
Self::Create(Create {
entry_hash,
entry_type,
..
}) => Some((entry_hash, entry_type)),
Self::Update(Update {
entry_hash,
entry_type,
..
}) => Some((entry_hash, entry_type)),
_ => None,
}
}
pub fn entry_visibility(&self) -> Option<&EntryVisibility> {
self.entry_data()
.map(|(_, entry_type)| entry_type.visibility())
}
pub fn entry_hash(&self) -> Option<&EntryHash> {
self.entry_data().map(|d| d.0)
}
pub fn entry_type(&self) -> Option<&EntryType> {
self.entry_data().map(|d| d.1)
}
pub fn action_type(&self) -> ActionType {
self.into()
}
pub fn author(&self) -> &AgentPubKey {
match_action!(self => |i| { &i.author })
}
pub fn timestamp(&self) -> Timestamp {
match_action!(self => |i| { i.timestamp })
}
pub fn action_seq(&self) -> u32 {
match self {
Self::Dna(Dna { .. }) => 0,
Self::AgentValidationPkg(AgentValidationPkg { action_seq, .. })
| Self::InitZomesComplete(InitZomesComplete { action_seq, .. })
| Self::CreateLink(CreateLink { action_seq, .. })
| Self::DeleteLink(DeleteLink { action_seq, .. })
| Self::Delete(Delete { action_seq, .. })
| Self::CloseChain(CloseChain { action_seq, .. })
| Self::OpenChain(OpenChain { action_seq, .. })
| Self::Create(Create { action_seq, .. })
| Self::Update(Update { action_seq, .. }) => *action_seq,
}
}
pub fn prev_action(&self) -> Option<&ActionHash> {
Some(match self {
Self::Dna(Dna { .. }) => return None,
Self::AgentValidationPkg(AgentValidationPkg { prev_action, .. }) => prev_action,
Self::InitZomesComplete(InitZomesComplete { prev_action, .. }) => prev_action,
Self::CreateLink(CreateLink { prev_action, .. }) => prev_action,
Self::DeleteLink(DeleteLink { prev_action, .. }) => prev_action,
Self::Delete(Delete { prev_action, .. }) => prev_action,
Self::CloseChain(CloseChain { prev_action, .. }) => prev_action,
Self::OpenChain(OpenChain { prev_action, .. }) => prev_action,
Self::Create(Create { prev_action, .. }) => prev_action,
Self::Update(Update { prev_action, .. }) => prev_action,
})
}
pub fn is_genesis(&self) -> bool {
self.action_seq() < POST_GENESIS_SEQ_THRESHOLD
}
pub fn rate_data(&self) -> RateWeight {
match self {
Self::CreateLink(CreateLink { weight, .. }) => weight.clone(),
Self::Delete(Delete { weight, .. }) => weight.clone(),
Self::Create(Create { weight, .. }) => weight.clone().into(),
Self::Update(Update { weight, .. }) => weight.clone().into(),
Self::Dna(Dna { .. })
| Self::AgentValidationPkg(AgentValidationPkg { .. })
| Self::InitZomesComplete(InitZomesComplete { .. })
| Self::DeleteLink(DeleteLink { .. })
| Self::CloseChain(CloseChain { .. })
| Self::OpenChain(OpenChain { .. }) => RateWeight::default(),
}
}
pub fn entry_rate_data(&self) -> Option<EntryRateWeight> {
match self {
Self::Create(Create { weight, .. }) => Some(weight.clone()),
Self::Update(Update { weight, .. }) => Some(weight.clone()),
Self::CreateLink(CreateLink { .. }) => None,
Self::Delete(Delete { .. }) => None,
Self::Dna(Dna { .. })
| Self::AgentValidationPkg(AgentValidationPkg { .. })
| Self::InitZomesComplete(InitZomesComplete { .. })
| Self::DeleteLink(DeleteLink { .. })
| Self::CloseChain(CloseChain { .. })
| Self::OpenChain(OpenChain { .. }) => Some(EntryRateWeight::default()),
}
}
}
impl_hashable_content!(Action, Action);
macro_rules! impl_hashable_content_for_ref {
($n: ident) => {
impl HashableContent for $n {
type HashType = holo_hash::hash_type::Action;
fn hash_type(&self) -> Self::HashType {
use holo_hash::PrimitiveHashType;
holo_hash::hash_type::Action::new()
}
fn hashable_content(&self) -> holo_hash::HashableContentBytes {
let h = ActionRef::$n(self);
let sb = SerializedBytes::from(UnsafeBytes::from(
holochain_serialized_bytes::encode(&h)
.expect("Could not serialize HashableContent"),
));
holo_hash::HashableContentBytes::Content(sb)
}
}
};
}
impl_hashable_content_for_ref!(Dna);
impl_hashable_content_for_ref!(AgentValidationPkg);
impl_hashable_content_for_ref!(InitZomesComplete);
impl_hashable_content_for_ref!(CreateLink);
impl_hashable_content_for_ref!(DeleteLink);
impl_hashable_content_for_ref!(CloseChain);
impl_hashable_content_for_ref!(OpenChain);
impl_hashable_content_for_ref!(Create);
impl_hashable_content_for_ref!(Update);
impl_hashable_content_for_ref!(Delete);
#[derive(
Debug,
Copy,
Clone,
Hash,
PartialEq,
Eq,
PartialOrd,
Ord,
Serialize,
Deserialize,
SerializedBytes,
)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct ZomeIndex(pub u8);
impl ZomeIndex {
pub fn new(u: u8) -> Self {
Self(u)
}
}
#[derive(
Debug,
Copy,
Clone,
Hash,
PartialEq,
Eq,
PartialOrd,
Ord,
Serialize,
Deserialize,
SerializedBytes,
)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct EntryDefIndex(pub u8);
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, SerializedBytes, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct Dna {
pub author: AgentPubKey,
pub timestamp: Timestamp,
pub hash: DnaHash,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, SerializedBytes, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct AgentValidationPkg {
pub author: AgentPubKey,
pub timestamp: Timestamp,
pub action_seq: u32,
pub prev_action: ActionHash,
pub membrane_proof: Option<MembraneProof>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, SerializedBytes, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct InitZomesComplete {
pub author: AgentPubKey,
pub timestamp: Timestamp,
pub action_seq: u32,
pub prev_action: ActionHash,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, SerializedBytes, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct CreateLink<W = RateWeight> {
pub author: AgentPubKey,
pub timestamp: Timestamp,
pub action_seq: u32,
pub prev_action: ActionHash,
pub base_address: AnyLinkableHash,
pub target_address: AnyLinkableHash,
pub zome_index: ZomeIndex,
pub link_type: LinkType,
pub tag: LinkTag,
pub weight: W,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, SerializedBytes, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct DeleteLink {
pub author: AgentPubKey,
pub timestamp: Timestamp,
pub action_seq: u32,
pub prev_action: ActionHash,
pub base_address: AnyLinkableHash,
pub link_add_address: ActionHash,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, SerializedBytes, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct OpenChain {
pub author: AgentPubKey,
pub timestamp: Timestamp,
pub action_seq: u32,
pub prev_action: ActionHash,
pub prev_dna_hash: DnaHash,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, SerializedBytes, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct CloseChain {
pub author: AgentPubKey,
pub timestamp: Timestamp,
pub action_seq: u32,
pub prev_action: ActionHash,
pub new_dna_hash: DnaHash,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, SerializedBytes, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct Create<W = EntryRateWeight> {
pub author: AgentPubKey,
pub timestamp: Timestamp,
pub action_seq: u32,
pub prev_action: ActionHash,
pub entry_type: EntryType,
pub entry_hash: EntryHash,
pub weight: W,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, SerializedBytes, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct Update<W = EntryRateWeight> {
pub author: AgentPubKey,
pub timestamp: Timestamp,
pub action_seq: u32,
pub prev_action: ActionHash,
pub original_action_address: ActionHash,
pub original_entry_address: EntryHash,
pub entry_type: EntryType,
pub entry_hash: EntryHash,
pub weight: W,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, SerializedBytes, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct Delete<W = RateWeight> {
pub author: AgentPubKey,
pub timestamp: Timestamp,
pub action_seq: u32,
pub prev_action: ActionHash,
pub deletes_address: ActionHash,
pub deletes_entry_address: EntryHash,
pub weight: W,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, SerializedBytes, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct UpdateAction {
pub author: AgentPubKey,
pub timestamp: Timestamp,
pub action_seq: u32,
pub prev_action: ActionHash,
pub original_action_address: ActionHash,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, SerializedBytes, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct DeleteAction {
pub author: AgentPubKey,
pub timestamp: Timestamp,
pub action_seq: u32,
pub prev_action: ActionHash,
pub deletes_address: ActionHash,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, SerializedBytes, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum EntryType {
AgentPubKey,
App(AppEntryDef),
CapClaim,
CapGrant,
}
impl EntryType {
pub fn visibility(&self) -> &EntryVisibility {
match self {
EntryType::AgentPubKey => &EntryVisibility::Public,
EntryType::App(app_entry_def) => app_entry_def.visibility(),
EntryType::CapClaim => &EntryVisibility::Private,
EntryType::CapGrant => &EntryVisibility::Private,
}
}
}
impl std::fmt::Display for EntryType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
EntryType::AgentPubKey => writeln!(f, "AgentPubKey"),
EntryType::App(app_entry_def) => writeln!(
f,
"App({:?}, {:?})",
app_entry_def.entry_index(),
app_entry_def.visibility()
),
EntryType::CapClaim => writeln!(f, "CapClaim"),
EntryType::CapGrant => writeln!(f, "CapGrant"),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, SerializedBytes, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct AppEntryDef {
pub entry_index: EntryDefIndex,
pub zome_index: ZomeIndex,
pub visibility: EntryVisibility,
}
impl AppEntryDef {
pub fn new(
entry_index: EntryDefIndex,
zome_index: ZomeIndex,
visibility: EntryVisibility,
) -> Self {
Self {
entry_index,
zome_index,
visibility,
}
}
pub fn entry_index(&self) -> EntryDefIndex {
self.entry_index
}
pub fn zome_index(&self) -> ZomeIndex {
self.zome_index
}
pub fn visibility(&self) -> &EntryVisibility {
&self.visibility
}
}
impl From<EntryDefIndex> for u8 {
fn from(ei: EntryDefIndex) -> Self {
ei.0
}
}
impl ZomeIndex {
pub fn index(&self) -> usize {
self.0 as usize
}
}
impl std::ops::Deref for ZomeIndex {
type Target = u8;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Borrow<u8> for ZomeIndex {
fn borrow(&self) -> &u8 {
&self.0
}
}