p2panda_core/traits.rs
1// SPDX-License-Identifier: MIT OR Apache-2.0tra
2
3//! Traits expressing core features of peer-to-peer data types.
4use std::fmt::{Debug, Display};
5use std::hash::Hash as StdHash;
6
7use serde::{Deserialize, Serialize};
8
9use crate::logs::SeqNum;
10use crate::operation::{Body, PayloadSize};
11
12/// Identifier of an operation author.
13pub trait Author:
14 Copy
15 + Clone
16 + Display
17 + Debug
18 + PartialEq
19 + Eq
20 + Ord
21 + StdHash
22 + Serialize
23 + for<'de> Deserialize<'de>
24{
25}
26
27/// Identifier of a single operation.
28pub trait OperationId: Copy + Clone + Display + Debug + PartialEq + Eq + Ord + StdHash {}
29
30#[cfg(any(test, feature = "test_utils"))]
31impl OperationId for u32 {}
32#[cfg(any(test, feature = "test_utils"))]
33impl OperationId for &str {}
34
35/// Returns (unique) hash digest, which can be used as identifier of this published data type.
36pub trait Digest<ID>
37where
38 ID: OperationId,
39{
40 /// Hash digest of peer-to-peer data-type which can be used as the identifier.
41 fn hash(&self) -> ID;
42}
43
44/// Returns the author of this published data type and a method to verify the authenticity of it.
45pub trait Provenance<A>
46where
47 A: Author,
48{
49 /// Identity of the author of data-type.
50 fn author(&self) -> A;
51
52 /// Checks if data-type and given author is authentic.
53 fn verify(&self) -> bool;
54}
55
56/// Hash-chain structure with integrity guarantees and sequence numbers as a performance
57/// optimization.
58pub trait Chain<ID> {
59 /// Pointer at previous entry in log which gives us the integrity guarantee of the "hash chain".
60 /// The first entry in a log returns `None`.
61 fn backlink(&self) -> Option<ID>;
62
63 /// Sequence numbers are helpful to fastly detect forks and use the much faster and optimized
64 /// diffing strategy when the local log is not forked.
65 fn seq_num(&self) -> SeqNum;
66}
67
68/// Additional data which can be removed from the on-chain data-type.
69pub trait Offchain<ID> {
70 /// Authenticated payload.
71 ///
72 /// Can be requested or removed independently from the peer-to-peer data-type (off-chain). Don't
73 /// expect this to always be available.
74 fn payload(&self) -> Option<&Body>;
75
76 /// Hash digest of the payload.
77 fn payload_hash(&self) -> Option<ID>;
78
79 /// Size in bytes of the payload.
80 fn payload_size(&self) -> PayloadSize;
81}
82
83/// Custom header extensions type.
84///
85/// User-defined extensions can be added to an operation's [`Header`](crate::Header) in order to
86/// extend the basic functionality of the core p2panda data types or to encode application-specific
87/// fields which should not be contained in the [`Body`].
88///
89/// This might be system-specific information relating to capabilities or key-agreement schemes
90/// which is required to enforce access-control restrictions during sync. Alternatively, extensions
91/// might be used to set expiration timestamps and deletion flags in order to facilitate garbage
92/// collection of stale data from the network. The core p2panda data types intentionally don't
93/// enforce a single approach to such areas where there are rightly many different approaches, with
94/// the most suitable being dependent on specific use-case requirements.
95///
96/// Interfaces which use p2panda core data types can require certain extensions to be present on any
97/// headers that their APIs accept using trait bounds. `p2panda-stream`, for example, uses the
98/// [`PruneFlag`](crate::PruneFlag) in order to implement automatic network-wide garbage collection.
99///
100/// Extensions are encoded on a header and sent over the wire. We need to satisfy all trait
101/// requirements that `Header` requires, including `Serialize` and `Deserialize`.
102///
103/// ## Example
104///
105/// ```
106/// use p2panda_core::{Hash, Header, SigningKey};
107/// use serde::{Serialize, Deserialize};
108///
109/// #[derive(Clone, Debug, Serialize, Deserialize)]
110/// struct LogId(Hash);
111///
112/// #[derive(Clone, Debug, Serialize, Deserialize)]
113/// struct CustomExtensions {
114/// log_id: Option<LogId>,
115/// expires: u64,
116/// }
117///
118/// let extensions = CustomExtensions {
119/// log_id: None,
120/// expires: 1787246796,
121/// };
122///
123/// let signing_key = SigningKey::generate();
124///
125/// let header = Header::builder()
126/// .body("Hello, Sloth".as_bytes())
127/// .build(&signing_key, extensions.clone());
128///
129/// assert_eq!(header.extensions.expires, 1787246796);
130/// ```
131pub trait Extensions: Clone + Debug + for<'de> Deserialize<'de> + Serialize {}
132
133impl<T> Extensions for T where T: Clone + Debug + for<'de> Deserialize<'de> + Serialize {}
134
135/// Returns a displayable string representing the underlying value in a short format, easy to read
136/// during debugging and logging.
137pub trait ShortFormat {
138 fn fmt_short(&self) -> String;
139}