holochain_integrity_types/
entry.rs

1//! An Entry is a unit of data in a Holochain Source Chain.
2//!
3//! This module contains all the necessary definitions for Entry, which broadly speaking
4//! refers to any data which will be written into the ContentAddressableStorage, or the EntityAttributeValueStorage.
5//! It defines serialization behaviour for entries. Here you can find the complete list of
6//! entry_types, and special entries, like deletion_entry and cap_entry.
7
8use crate::capability::CapClaim;
9use crate::capability::CapGrant;
10use crate::capability::ZomeCallCapGrant;
11use crate::countersigning::CounterSigningSessionData;
12use crate::AppEntryDef;
13use crate::EntryDefIndex;
14use crate::EntryType;
15use crate::ZomeIndex;
16use holo_hash::hash_type;
17use holo_hash::ActionHash;
18use holo_hash::AgentPubKey;
19use holo_hash::EntryHash;
20use holo_hash::HashableContent;
21use holo_hash::HashableContentBytes;
22use holochain_serialized_bytes::prelude::*;
23
24mod app_entry_bytes;
25mod error;
26pub use app_entry_bytes::*;
27pub use error::*;
28
29/// Entries larger than this number of bytes cannot be created
30pub const ENTRY_SIZE_LIMIT: usize = 4 * 1000 * 1000; // 4MB
31
32/// The data type written to the source chain when explicitly granting a capability.
33/// NB: this is not simply `CapGrant`, because the `CapGrant::ChainAuthor`
34/// grant is already implied by `Entry::Agent`, so that should not be committed
35/// to a chain. This is a type alias because if we add other capability types
36/// in the future, we may want to include them
37pub type CapGrantEntry = ZomeCallCapGrant;
38
39/// The data type written to the source chain to denote a capability claim
40pub type CapClaimEntry = CapClaim;
41
42/// An Entry paired with its EntryHash
43pub type EntryHashed = holo_hash::HoloHashed<Entry>;
44
45/// Helper trait for deserializing [`Entry`]s to the correct type.
46///
47/// This is implemented by the `hdk_entry_types` proc_macro.
48pub trait EntryTypesHelper: Sized {
49    /// The error associated with this conversion.
50    type Error;
51    /// Check if the [`ZomeIndex`] and [`EntryDefIndex`] matches one of the
52    /// `ZomeEntryTypesKey::from(Self::variant)` and if
53    /// it does deserialize the [`Entry`] into that type.
54    fn deserialize_from_type<Z, I>(
55        zome_index: Z,
56        entry_def_index: I,
57        entry: &Entry,
58    ) -> Result<Option<Self>, Self::Error>
59    where
60        Z: Into<ZomeIndex>,
61        I: Into<EntryDefIndex>;
62}
63
64impl EntryTypesHelper for () {
65    type Error = core::convert::Infallible;
66
67    fn deserialize_from_type<Z, I>(
68        _zome_index: Z,
69        _entry_def_index: I,
70        _entry: &Entry,
71    ) -> Result<Option<Self>, Self::Error>
72    where
73        Z: Into<ZomeIndex>,
74        I: Into<EntryDefIndex>,
75    {
76        Ok(Some(()))
77    }
78}
79
80impl From<EntryHashed> for Entry {
81    fn from(entry_hashed: EntryHashed) -> Self {
82        entry_hashed.into_content()
83    }
84}
85
86/// Structure holding the entry portion of a chain record.
87#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash, SerializedBytes)]
88#[serde(tag = "entry_type", content = "entry")]
89pub enum Entry {
90    /// The `Agent` system entry, the third entry of every source chain,
91    /// which grants authoring capability for this agent.
92    Agent(AgentPubKey),
93    /// The application entry data for entries that aren't system created entries
94    App(AppEntryBytes),
95    /// Application entry data for entries that need countersigning to move forward multiple chains together.
96    CounterSign(Box<CounterSigningSessionData>, AppEntryBytes),
97    /// The capability claim system entry which allows committing a granted permission
98    /// for later use
99    CapClaim(CapClaimEntry),
100    /// The capability grant system entry which allows granting of application defined
101    /// capabilities
102    CapGrant(CapGrantEntry),
103}
104
105impl Entry {
106    /// If this entry represents a capability grant, return a `CapGrant`.
107    pub fn as_cap_grant(&self) -> Option<CapGrant> {
108        match self {
109            Entry::Agent(key) => Some(CapGrant::ChainAuthor(key.clone())),
110            Entry::CapGrant(data) => Some(CapGrant::RemoteAgent(data.clone())),
111            _ => None,
112        }
113    }
114
115    /// If this entry represents a capability claim, return a `CapClaim`.
116    pub fn as_cap_claim(&self) -> Option<&CapClaim> {
117        match self {
118            Entry::CapClaim(claim) => Some(claim),
119            _ => None,
120        }
121    }
122
123    /// If this entry represents an App entry, return `AppEntryBytes`.
124    pub fn as_app_entry(&self) -> Option<&AppEntryBytes> {
125        match self {
126            Entry::App(bytes) => Some(bytes),
127            _ => None,
128        }
129    }
130
131    /// Create an Entry::App from SerializedBytes
132    pub fn app(sb: SerializedBytes) -> Result<Self, EntryError> {
133        Ok(Entry::App(AppEntryBytes::try_from(sb)?))
134    }
135
136    /// Create an Entry::App from SerializedBytes
137    pub fn app_fancy<SB: TryInto<SerializedBytes, Error = SerializedBytesError>>(
138        sb: SB,
139    ) -> Result<Self, EntryError> {
140        Ok(Entry::App(AppEntryBytes::try_from(sb.try_into()?)?))
141    }
142
143    /// Get an EntryType based on the type of this Entry.
144    /// If the entry type is Entry, and no entry def is specified, return None
145    pub fn entry_type(&self, entry_def: Option<AppEntryDef>) -> Option<EntryType> {
146        match (self, entry_def) {
147            (Entry::Agent(_), _) => Some(EntryType::AgentPubKey),
148            (Entry::CapClaim(_), _) => Some(EntryType::CapClaim),
149            (Entry::CapGrant(_), _) => Some(EntryType::CapGrant),
150            (Entry::App(_), Some(aed)) | (Entry::CounterSign(_, _), Some(aed)) => {
151                Some(EntryType::App(aed))
152            }
153            _ => None,
154        }
155    }
156}
157
158impl HashableContent for Entry {
159    type HashType = hash_type::Entry;
160
161    fn hash_type(&self) -> Self::HashType {
162        hash_type::Entry
163    }
164
165    fn hashable_content(&self) -> HashableContentBytes {
166        match self {
167            Entry::Agent(agent_pubkey) => {
168                // We must retype this AgentPubKey as an EntryHash so that the
169                // prefix bytes match the Entry prefix
170                HashableContentBytes::Prehashed39(
171                    EntryHash::from(agent_pubkey.clone()).into_inner(),
172                )
173            }
174            entry => HashableContentBytes::Content(
175                entry
176                    .try_into()
177                    .expect("Could not serialize HashableContent"),
178            ),
179        }
180    }
181}
182
183/// Zome input for must_get_valid_record.
184#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
185pub struct MustGetValidRecordInput(pub ActionHash);
186
187impl MustGetValidRecordInput {
188    /// Constructor.
189    pub fn new(action_hash: ActionHash) -> Self {
190        Self(action_hash)
191    }
192
193    /// Consumes self for inner.
194    pub fn into_inner(self) -> ActionHash {
195        self.0
196    }
197}
198
199/// Zome input for must_get_entry.
200#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
201pub struct MustGetEntryInput(pub EntryHash);
202
203impl MustGetEntryInput {
204    /// Constructor.
205    pub fn new(entry_hash: EntryHash) -> Self {
206        Self(entry_hash)
207    }
208
209    /// Consumes self for inner.
210    pub fn into_inner(self) -> EntryHash {
211        self.0
212    }
213}
214
215/// Zome input for must_get_action.
216#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
217pub struct MustGetActionInput(pub ActionHash);
218
219impl MustGetActionInput {
220    /// Constructor.
221    pub fn new(action_hash: ActionHash) -> Self {
222        Self(action_hash)
223    }
224
225    /// Consumes self for inner.
226    pub fn into_inner(self) -> ActionHash {
227        self.0
228    }
229}