cml_crypto/chain_core/
property.rs

1//! chain core properties
2//!
3//! define the different properties a _supported_ chain needs to
4//! implement to work in our models.
5//!
6//! # Block
7//!
8//! The Block is the atomic element that compose a chain. Or in other
9//! words the chain is composed of a succession of `Block`.
10//!
11//! the `Block` trait implements the necessary feature we expect of
12//! a `Block` in the chain. Having a function that requires the object
13//! to implement the Block traits means that we are expecting to have
14//! only access to:
15//!
16//! * the block and its parent's identifier (the block hash);
17//! * the block number, its position in the blockchain relative
18//!   to the beginning of the chain. We often call this number
19//!   the block Date.
20//!
21//! # Ledger
22//!
23//! this trait is to make sure we are following the Transactions of the chain
24//! appropriately.
25//!
26//! # LeaderSelection
27//!
28//! This trait is following the protocol of the blockchain is followed
29//! properly and determined a given instance of the LeaderSelection object
30//! is selected to write a block in the chain.
31//!
32
33use std::{fmt::Debug, hash::Hash};
34
35/// Trait identifying the block identifier type.
36pub trait BlockId: Eq + Ord + Clone + Debug + Hash + Serialize + Deserialize {
37    /// A special ID used to denote a non-existent block (e.g. the
38    /// parent of the first block).
39    fn zero() -> Self;
40}
41
42/// A trait representing block dates.
43pub trait BlockDate: Eq + Ord + Clone {
44    fn from_epoch_slot_id(epoch: u32, slot_id: u32) -> Self;
45}
46
47pub trait ChainLength: Eq + Ord + Clone + Debug {
48    fn next(&self) -> Self;
49}
50
51/// Trait identifying the transaction identifier type.
52pub trait TransactionId: Eq + Hash + Debug {}
53
54/// Trait identifying the block header type.
55pub trait Header: Serialize {
56    /// The block header id.
57    type Id: BlockId;
58
59    /// The block date.
60    type Date: BlockDate;
61
62    /// the length of the blockchain (number of blocks)
63    type ChainLength: ChainLength;
64
65    /// the type associated to the version of a block
66    type Version;
67
68    /// Retrieves the block's header id.
69    fn id(&self) -> Self::Id;
70
71    /// get the parent block identifier (the previous block in the
72    /// blockchain).
73    fn parent_id(&self) -> Self::Id;
74
75    /// Retrieves the block's date.
76    fn date(&self) -> Self::Date;
77
78    /// access the version of a given block
79    fn version(&self) -> Self::Version;
80
81    /// get the block's chain length. The number of block
82    /// created following this thread of blocks on the blockchain
83    /// (including Self).
84    fn chain_length(&self) -> Self::ChainLength;
85}
86
87/// Block property
88///
89/// a block is part of a chain of block called Blockchain.
90/// the chaining is done via one block pointing to another block,
91/// the parent block (the previous block).
92///
93/// This means that a blockchain is a link-list, ordered from the most
94/// recent block to the furthest/oldest block.
95///
96/// The Oldest block is called the Genesis Block.
97pub trait Block: Serialize + Deserialize {
98    /// the Block identifier. It must be unique. This mean that
99    /// 2 different blocks have 2 different identifiers.
100    ///
101    /// In bitcoin this block is a SHA2 256bits. For Cardano's
102    /// blockchain it is Blake2b 256bits.
103    type Id: BlockId;
104
105    /// the block date (also known as a block number) represents the
106    /// absolute position of the block in the chain. This can be used
107    /// for random access (if the storage algorithm allows it) or for
108    /// identifying the position of a block in a given epoch or era.
109    type Date: BlockDate;
110
111    /// the type associated to the version of a block
112    type Version;
113
114    /// the length of the blockchain (number of blocks)
115    type ChainLength: ChainLength;
116
117    /// return the Block's identifier.
118    fn id(&self) -> Self::Id;
119
120    /// get the parent block identifier (the previous block in the
121    /// blockchain).
122    fn parent_id(&self) -> Self::Id;
123
124    /// get the block date of the block
125    fn date(&self) -> Self::Date;
126
127    /// access the version of a given block
128    fn version(&self) -> Self::Version;
129
130    /// get the block's chain length. The number of block
131    /// created following this thread of blocks on the blockchain
132    /// (including Self).
133    fn chain_length(&self) -> Self::ChainLength;
134}
135
136/// Access to the block header.
137///
138/// If featured by the blockchain, the header can be used to transmit
139/// block's metadata via a network protocol or in other uses where the
140/// full content of the block is too bulky and not necessary.
141pub trait HasHeader {
142    /// The block header type.
143    type Header: Header;
144
145    /// Retrieves the block's header.
146    fn header(&self) -> Self::Header;
147}
148
149/// Trait identifying the fragment identifier type.
150pub trait FragmentId: Eq + Hash + Clone + Debug + Serialize + Deserialize {}
151
152/// A fragment is some item contained in a block, such as a
153/// transaction, a delegation-related certificate, an update proposal,
154/// and so on. Fragments can be serialized (so that they can be
155/// concatenated to form a binary block( and have a unique ID
156/// (typically the hash of their serialization).
157pub trait Fragment: Serialize + Deserialize {
158    type Id: FragmentId;
159
160    /// Return the message's identifier.
161    fn id(&self) -> Self::Id;
162}
163
164/// Accessor to fragments within a block.
165///
166/// This trait has a lifetime parameter and is normally implemented by
167/// reference types.
168pub trait HasFragments<'a> {
169    /// The type representing fragments in this block.
170    type Fragment: 'a + Fragment;
171
172    /// A by-reference iterator over block's fragments.
173    type Fragments: 'a + Iterator<Item = &'a Self::Fragment>;
174
175    /// Returns a by-reference iterator over the fragments in the block.
176    fn fragments(self) -> Self::Fragments;
177}
178
179/// define a transaction within the blockchain. This transaction can be used
180/// for the UTxO model. However it can also be used for any other elements that
181/// the blockchain has (a transaction type to add Stacking Pools and so on...).
182///
183pub trait Transaction: Serialize + Deserialize {
184    /// The input type of the transaction (if none use `()`).
185    type Input;
186    /// The output type of the transaction (if none use `()`).
187    type Output;
188    /// The iterable type of transaction inputs (if none use `Option<()>` and return `None`).
189    type Inputs: ?Sized;
190    /// The iterable type of transaction outputs (if none use `Option<()>` and return `None`).
191    type Outputs: ?Sized;
192
193    /// Returns a reference that can be used to iterate over transaction's inputs.
194    fn inputs(&self) -> &Self::Inputs;
195
196    /// Returns a reference that can be used to iterate over transaction's outputs.
197    fn outputs(&self) -> &Self::Outputs;
198}
199
200pub trait State: Sized + Clone {
201    type Error: std::error::Error;
202    type Header: Header;
203    type Content: Fragment;
204
205    /// yield a new block in the state
206    ///
207    /// This will change the state in the sense that it acknowledge the creation
208    /// of a new block in its internal state.
209    fn apply_block<'a, I>(&self, header: &Self::Header, contents: I) -> Result<Self, Self::Error>
210    where
211        I: IntoIterator<Item = &'a Self::Content>,
212        Self::Content: 'a;
213
214    /// apply new block contents. This modify the state in small steps
215    /// however it does not acknowledge the creation of a new block
216    fn apply_contents<'a, I>(&self, contents: I) -> Result<Self, Self::Error>
217    where
218        I: IntoIterator<Item = &'a Self::Content>,
219        Self::Content: 'a;
220}
221
222/// Define the Ledger side of the blockchain. This is not really on the blockchain
223/// but should be able to maintain a valid state of the overall blockchain at a given
224/// `Block`.
225pub trait Ledger<T: Transaction>: Sized {
226    /// Ledger's errors
227    type Error: std::error::Error;
228
229    fn input<I>(
230        &self,
231        input: <T as Transaction>::Input,
232    ) -> Result<&<T as Transaction>::Output, Self::Error>;
233}
234
235/// Trait identifying the leader identifier type.
236pub trait LeaderId: Eq + Clone + Hash + Debug {}
237
238/// interface for the leader selection algorithm
239///
240/// this is the interface that is responsible to verify the Block are
241/// created by the right Leaders (i.e. that everyone follows the
242/// consensus algorithm).
243///
244/// This is also the same interface that is used to detect if we are the
245/// leader for the block at the given date.
246pub trait LeaderSelection {
247    /// the block that we will get the information from
248    type Block: Block;
249
250    /// Leader Selection error type
251    type Error: std::error::Error;
252
253    /// Identifier of the leader (e.g. a public key).
254    type LeaderId: LeaderId;
255
256    type State: State;
257
258    fn retrieve(state: &Self::State) -> Self;
259
260    /// return the ID of the leader of the blockchain at the given
261    /// date.
262    fn get_leader_at(
263        &self,
264        date: <Self::Block as Block>::Date,
265    ) -> Result<Self::LeaderId, Self::Error>;
266}
267
268/// the settings of the blockchain this is something that can be used to maintain
269/// the blockchain protocol update details:
270///
271pub trait Settings {
272    type Block: Block;
273
274    /// return the tip of the current branch
275    ///
276    fn tip(&self) -> <Self::Block as Block>::Id;
277
278    /// the current chain_length
279    fn chain_length(&self) -> <Self::Block as Block>::ChainLength;
280
281    /// the number of transactions in a block
282    fn max_number_of_transactions_per_block(&self) -> u32;
283
284    /// the block version format
285    fn block_version(&self) -> <Self::Block as Block>::Version;
286}
287
288/// Define that an object can be written to a `Write` object.
289pub trait Serialize {
290    type Error: std::error::Error + From<std::io::Error>;
291
292    fn serialize<W: std::io::Write>(&self, writer: W) -> Result<(), Self::Error>;
293
294    /// Convenience method to serialize into a byte vector.
295    fn serialize_as_vec(&self) -> Result<Vec<u8>, Self::Error> {
296        let mut data = vec![];
297        self.serialize(&mut data)?;
298        Ok(data)
299    }
300}
301
302/// Define that an object can be read from a `Read` object.
303pub trait Deserialize: Sized {
304    type Error: std::error::Error + From<std::io::Error> + Send + Sync + 'static;
305
306    fn deserialize<R: std::io::BufRead>(reader: R) -> Result<Self, Self::Error>;
307}
308
309/// Defines the way to parse the object from a UTF-8 string.
310///
311/// This is like the standard `FromStr` trait, except that it imposes
312/// additional bounds on the error type to make it more usable for
313/// aggregation to higher level errors and passing between threads.
314pub trait FromStr: Sized {
315    type Error: std::error::Error + Send + Sync + 'static;
316
317    fn from_str(s: &str) -> Result<Self, Self::Error>;
318}
319
320impl<T> FromStr for T
321where
322    T: std::str::FromStr,
323    <T as std::str::FromStr>::Err: std::error::Error + Send + Sync + 'static,
324{
325    type Error = <T as std::str::FromStr>::Err;
326
327    fn from_str(s: &str) -> Result<Self, Self::Error> {
328        std::str::FromStr::from_str(s)
329    }
330}
331
332impl<T: Serialize> Serialize for &T {
333    type Error = T::Error;
334
335    fn serialize<W: std::io::Write>(&self, writer: W) -> Result<(), T::Error> {
336        (**self).serialize(writer)
337    }
338}
339
340#[cfg(feature = "property-test-api")]
341pub mod testing {
342    use super::super::mempack::{ReadBuf, Readable};
343    use super::*;
344    use quickcheck::{Arbitrary, TestResult};
345
346    /// test that any arbitrary given object can serialize and deserialize
347    /// back into itself (i.e. it is a bijection,  or a one to one match
348    /// between the serialized bytes and the object)
349    pub fn serialization_bijection<T>(t: T) -> TestResult
350    where
351        T: Arbitrary + Serialize + Deserialize + Eq,
352    {
353        let vec = match t.serialize_as_vec() {
354            Err(error) => return TestResult::error(format!("serialization: {}", error)),
355            Ok(v) => v,
356        };
357        let decoded_t = match T::deserialize(&vec[..]) {
358            Err(error) => return TestResult::error(format!("deserialization: {}", error)),
359            Ok(v) => v,
360        };
361        TestResult::from_bool(decoded_t == t)
362    }
363
364    /// test that any arbitrary given object can serialize and deserialize
365    /// back into itself (i.e. it is a bijection,  or a one to one match
366    /// between the serialized bytes and the object)
367    pub fn serialization_bijection_r<T>(t: T) -> TestResult
368    where
369        T: Arbitrary + Serialize + Readable + Eq,
370    {
371        let vec = match t.serialize_as_vec() {
372            Err(error) => return TestResult::error(format!("serialization: {}", error)),
373            Ok(v) => v,
374        };
375        let mut buf = ReadBuf::from(&vec);
376        let decoded_t = match T::read(&mut buf) {
377            Err(error) => {
378                return TestResult::error(format!("deserialization: {:?}\n{}", error, buf.debug()))
379            }
380            Ok(v) => v,
381        };
382        TestResult::from_bool(buf.expect_end().is_ok() && decoded_t == t)
383    }
384}