Skip to main content

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}