linera_base/
data_types.rs

1// Copyright (c) Facebook, Inc. and its affiliates.
2// Copyright (c) Zefchain Labs, Inc.
3// SPDX-License-Identifier: Apache-2.0
4
5//! Core data-types used in the Linera protocol.
6
7#[cfg(with_testing)]
8use std::ops;
9use std::{
10    collections::BTreeMap,
11    fmt::{self, Display},
12    fs,
13    hash::Hash,
14    io, iter,
15    num::ParseIntError,
16    ops::{Bound, RangeBounds},
17    path::Path,
18    str::FromStr,
19};
20
21use async_graphql::{InputObject, SimpleObject};
22use custom_debug_derive::Debug;
23use linera_witty::{WitLoad, WitStore, WitType};
24use serde::{Deserialize, Deserializer, Serialize, Serializer};
25use thiserror::Error;
26
27#[cfg(with_metrics)]
28use crate::prometheus_util::MeasureLatency as _;
29use crate::{
30    crypto::{BcsHashable, CryptoError, CryptoHash},
31    doc_scalar, hex_debug, http,
32    identifiers::{
33        ApplicationId, BlobId, BlobType, ChainId, EventId, GenericApplicationId, ModuleId, StreamId,
34    },
35    limited_writer::{LimitedWriter, LimitedWriterError},
36    ownership::ChainOwnership,
37    time::{Duration, SystemTime},
38    vm::VmRuntime,
39};
40
41/// A non-negative amount of tokens.
42///
43/// This is a fixed-point fraction, with [`Amount::DECIMAL_PLACES`] digits after the point.
44/// [`Amount::ONE`] is one whole token, divisible into `10.pow(Amount::DECIMAL_PLACES)` parts.
45#[derive(
46    Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Hash, Default, Debug, WitType, WitLoad, WitStore,
47)]
48#[cfg_attr(
49    all(with_testing, not(target_arch = "wasm32")),
50    derive(test_strategy::Arbitrary)
51)]
52pub struct Amount(u128);
53
54#[derive(Serialize, Deserialize)]
55#[serde(rename = "Amount")]
56struct AmountString(String);
57
58#[derive(Serialize, Deserialize)]
59#[serde(rename = "Amount")]
60struct AmountU128(u128);
61
62impl Serialize for Amount {
63    fn serialize<S: serde::ser::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
64        if serializer.is_human_readable() {
65            AmountString(self.to_string()).serialize(serializer)
66        } else {
67            AmountU128(self.0).serialize(serializer)
68        }
69    }
70}
71
72impl<'de> Deserialize<'de> for Amount {
73    fn deserialize<D: serde::de::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
74        if deserializer.is_human_readable() {
75            let AmountString(s) = AmountString::deserialize(deserializer)?;
76            s.parse().map_err(serde::de::Error::custom)
77        } else {
78            Ok(Amount(AmountU128::deserialize(deserializer)?.0))
79        }
80    }
81}
82
83/// A block height to identify blocks in a chain.
84#[derive(
85    Eq,
86    PartialEq,
87    Ord,
88    PartialOrd,
89    Copy,
90    Clone,
91    Hash,
92    Default,
93    Debug,
94    Serialize,
95    Deserialize,
96    WitType,
97    WitLoad,
98    WitStore,
99)]
100#[cfg_attr(with_testing, derive(test_strategy::Arbitrary))]
101pub struct BlockHeight(pub u64);
102
103/// An identifier for successive attempts to decide a value in a consensus protocol.
104#[derive(
105    Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Hash, Default, Debug, Serialize, Deserialize,
106)]
107pub enum Round {
108    /// The initial fast round.
109    #[default]
110    Fast,
111    /// The N-th multi-leader round.
112    MultiLeader(u32),
113    /// The N-th single-leader round.
114    SingleLeader(u32),
115    /// The N-th round where the validators rotate as leaders.
116    Validator(u32),
117}
118
119/// A duration in microseconds.
120#[derive(
121    Eq,
122    PartialEq,
123    Ord,
124    PartialOrd,
125    Copy,
126    Clone,
127    Hash,
128    Default,
129    Debug,
130    Serialize,
131    Deserialize,
132    WitType,
133    WitLoad,
134    WitStore,
135)]
136pub struct TimeDelta(u64);
137
138impl TimeDelta {
139    /// Returns the given number of microseconds as a [`TimeDelta`].
140    pub const fn from_micros(micros: u64) -> Self {
141        TimeDelta(micros)
142    }
143
144    /// Returns the given number of milliseconds as a [`TimeDelta`].
145    pub const fn from_millis(millis: u64) -> Self {
146        TimeDelta(millis.saturating_mul(1_000))
147    }
148
149    /// Returns the given number of seconds as a [`TimeDelta`].
150    pub const fn from_secs(secs: u64) -> Self {
151        TimeDelta(secs.saturating_mul(1_000_000))
152    }
153
154    /// Returns the given duration, rounded to the nearest microsecond and capped to the maximum
155    /// [`TimeDelta`] value.
156    pub fn from_duration(duration: Duration) -> Self {
157        TimeDelta::from_micros(u64::try_from(duration.as_micros()).unwrap_or(u64::MAX))
158    }
159
160    /// Returns this [`TimeDelta`] as a number of microseconds.
161    pub const fn as_micros(&self) -> u64 {
162        self.0
163    }
164
165    /// Returns this [`TimeDelta`] as a [`Duration`].
166    pub const fn as_duration(&self) -> Duration {
167        Duration::from_micros(self.as_micros())
168    }
169}
170
171/// A timestamp, in microseconds since the Unix epoch.
172#[derive(
173    Eq,
174    PartialEq,
175    Ord,
176    PartialOrd,
177    Copy,
178    Clone,
179    Hash,
180    Default,
181    Debug,
182    Serialize,
183    Deserialize,
184    WitType,
185    WitLoad,
186    WitStore,
187)]
188pub struct Timestamp(u64);
189
190impl Timestamp {
191    /// Returns the current time according to the system clock.
192    pub fn now() -> Timestamp {
193        Timestamp(
194            SystemTime::UNIX_EPOCH
195                .elapsed()
196                .expect("system time should be after Unix epoch")
197                .as_micros()
198                .try_into()
199                .unwrap_or(u64::MAX),
200        )
201    }
202
203    /// Returns the number of microseconds since the Unix epoch.
204    pub const fn micros(&self) -> u64 {
205        self.0
206    }
207
208    /// Returns the [`TimeDelta`] between `other` and `self`, or zero if `other` is not earlier
209    /// than `self`.
210    pub const fn delta_since(&self, other: Timestamp) -> TimeDelta {
211        TimeDelta::from_micros(self.0.saturating_sub(other.0))
212    }
213
214    /// Returns the [`Duration`] between `other` and `self`, or zero if `other` is not
215    /// earlier than `self`.
216    pub const fn duration_since(&self, other: Timestamp) -> Duration {
217        Duration::from_micros(self.0.saturating_sub(other.0))
218    }
219
220    /// Returns the timestamp that is `duration` later than `self`.
221    pub const fn saturating_add(&self, duration: TimeDelta) -> Timestamp {
222        Timestamp(self.0.saturating_add(duration.0))
223    }
224
225    /// Returns the timestamp that is `duration` earlier than `self`.
226    pub const fn saturating_sub(&self, duration: TimeDelta) -> Timestamp {
227        Timestamp(self.0.saturating_sub(duration.0))
228    }
229
230    /// Returns a timestamp `micros` microseconds earlier than `self`, or the lowest possible value
231    /// if it would underflow.
232    pub const fn saturating_sub_micros(&self, micros: u64) -> Timestamp {
233        Timestamp(self.0.saturating_sub(micros))
234    }
235}
236
237impl From<u64> for Timestamp {
238    fn from(t: u64) -> Timestamp {
239        Timestamp(t)
240    }
241}
242
243impl Display for Timestamp {
244    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
245        if let Some(date_time) = chrono::DateTime::from_timestamp(
246            (self.0 / 1_000_000) as i64,
247            ((self.0 % 1_000_000) * 1_000) as u32,
248        ) {
249            return date_time.naive_utc().fmt(f);
250        }
251        self.0.fmt(f)
252    }
253}
254
255/// Resources that an application may spend during the execution of transaction or an
256/// application call.
257#[derive(
258    Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize, WitLoad, WitStore, WitType,
259)]
260pub struct Resources {
261    /// An amount of Wasm execution fuel.
262    pub wasm_fuel: u64,
263    /// An amount of EVM execution fuel.
264    pub evm_fuel: u64,
265    /// A number of read operations to be executed.
266    pub read_operations: u32,
267    /// A number of write operations to be executed.
268    pub write_operations: u32,
269    /// A number of bytes to read.
270    pub bytes_to_read: u32,
271    /// A number of bytes to write.
272    pub bytes_to_write: u32,
273    /// A number of blobs to read.
274    pub blobs_to_read: u32,
275    /// A number of blobs to publish.
276    pub blobs_to_publish: u32,
277    /// A number of blob bytes to read.
278    pub blob_bytes_to_read: u32,
279    /// A number of blob bytes to publish.
280    pub blob_bytes_to_publish: u32,
281    /// A number of messages to be sent.
282    pub messages: u32,
283    /// The size of the messages to be sent.
284    // TODO(#1531): Account for the type of message to be sent.
285    pub message_size: u32,
286    /// An increase in the amount of storage space.
287    pub storage_size_delta: u32,
288    /// A number of service-as-oracle requests to be performed.
289    pub service_as_oracle_queries: u32,
290    /// A number of HTTP requests to be performed.
291    pub http_requests: u32,
292    // TODO(#1532): Account for the system calls that we plan on calling.
293    // TODO(#1533): Allow declaring calls to other applications instead of having to count them here.
294}
295
296/// A request to send a message.
297#[derive(Clone, Debug, Deserialize, Serialize, WitLoad, WitType)]
298#[cfg_attr(with_testing, derive(Eq, PartialEq, WitStore))]
299#[witty_specialize_with(Message = Vec<u8>)]
300pub struct SendMessageRequest<Message> {
301    /// The destination of the message.
302    pub destination: ChainId,
303    /// Whether the message is authenticated.
304    pub authenticated: bool,
305    /// Whether the message is tracked.
306    pub is_tracked: bool,
307    /// The grant resources forwarded with the message.
308    pub grant: Resources,
309    /// The message itself.
310    pub message: Message,
311}
312
313impl<Message> SendMessageRequest<Message>
314where
315    Message: Serialize,
316{
317    /// Serializes the internal `Message` type into raw bytes.
318    pub fn into_raw(self) -> SendMessageRequest<Vec<u8>> {
319        let message = bcs::to_bytes(&self.message).expect("Failed to serialize message");
320
321        SendMessageRequest {
322            destination: self.destination,
323            authenticated: self.authenticated,
324            is_tracked: self.is_tracked,
325            grant: self.grant,
326            message,
327        }
328    }
329}
330
331/// An error type for arithmetic errors.
332#[derive(Debug, Error)]
333#[allow(missing_docs)]
334pub enum ArithmeticError {
335    #[error("Number overflow")]
336    Overflow,
337    #[error("Number underflow")]
338    Underflow,
339}
340
341macro_rules! impl_wrapped_number {
342    ($name:ident, $wrapped:ident) => {
343        impl $name {
344            /// The zero value.
345            pub const ZERO: Self = Self(0);
346
347            /// The maximum value.
348            pub const MAX: Self = Self($wrapped::MAX);
349
350            /// Checked addition.
351            pub fn try_add(self, other: Self) -> Result<Self, ArithmeticError> {
352                let val = self
353                    .0
354                    .checked_add(other.0)
355                    .ok_or(ArithmeticError::Overflow)?;
356                Ok(Self(val))
357            }
358
359            /// Checked increment.
360            pub fn try_add_one(self) -> Result<Self, ArithmeticError> {
361                let val = self.0.checked_add(1).ok_or(ArithmeticError::Overflow)?;
362                Ok(Self(val))
363            }
364
365            /// Saturating addition.
366            pub const fn saturating_add(self, other: Self) -> Self {
367                let val = self.0.saturating_add(other.0);
368                Self(val)
369            }
370
371            /// Checked subtraction.
372            pub fn try_sub(self, other: Self) -> Result<Self, ArithmeticError> {
373                let val = self
374                    .0
375                    .checked_sub(other.0)
376                    .ok_or(ArithmeticError::Underflow)?;
377                Ok(Self(val))
378            }
379
380            /// Checked decrement.
381            pub fn try_sub_one(self) -> Result<Self, ArithmeticError> {
382                let val = self.0.checked_sub(1).ok_or(ArithmeticError::Underflow)?;
383                Ok(Self(val))
384            }
385
386            /// Saturating subtraction.
387            pub const fn saturating_sub(self, other: Self) -> Self {
388                let val = self.0.saturating_sub(other.0);
389                Self(val)
390            }
391
392            /// Checked in-place addition.
393            pub fn try_add_assign(&mut self, other: Self) -> Result<(), ArithmeticError> {
394                self.0 = self
395                    .0
396                    .checked_add(other.0)
397                    .ok_or(ArithmeticError::Overflow)?;
398                Ok(())
399            }
400
401            /// Checked in-place increment.
402            pub fn try_add_assign_one(&mut self) -> Result<(), ArithmeticError> {
403                self.0 = self.0.checked_add(1).ok_or(ArithmeticError::Overflow)?;
404                Ok(())
405            }
406
407            /// Saturating in-place addition.
408            pub const fn saturating_add_assign(&mut self, other: Self) {
409                self.0 = self.0.saturating_add(other.0);
410            }
411
412            /// Checked in-place subtraction.
413            pub fn try_sub_assign(&mut self, other: Self) -> Result<(), ArithmeticError> {
414                self.0 = self
415                    .0
416                    .checked_sub(other.0)
417                    .ok_or(ArithmeticError::Underflow)?;
418                Ok(())
419            }
420
421            /// Saturating multiplication.
422            pub const fn saturating_mul(&self, other: $wrapped) -> Self {
423                Self(self.0.saturating_mul(other))
424            }
425
426            /// Checked multiplication.
427            pub fn try_mul(self, other: $wrapped) -> Result<Self, ArithmeticError> {
428                let val = self.0.checked_mul(other).ok_or(ArithmeticError::Overflow)?;
429                Ok(Self(val))
430            }
431
432            /// Checked in-place multiplication.
433            pub fn try_mul_assign(&mut self, other: $wrapped) -> Result<(), ArithmeticError> {
434                self.0 = self.0.checked_mul(other).ok_or(ArithmeticError::Overflow)?;
435                Ok(())
436            }
437        }
438
439        impl From<$name> for $wrapped {
440            fn from(value: $name) -> Self {
441                value.0
442            }
443        }
444
445        // Cannot directly create values for a wrapped type, except for testing.
446        #[cfg(with_testing)]
447        impl From<$wrapped> for $name {
448            fn from(value: $wrapped) -> Self {
449                Self(value)
450            }
451        }
452
453        #[cfg(with_testing)]
454        impl ops::Add for $name {
455            type Output = Self;
456
457            fn add(self, other: Self) -> Self {
458                Self(self.0 + other.0)
459            }
460        }
461
462        #[cfg(with_testing)]
463        impl ops::Sub for $name {
464            type Output = Self;
465
466            fn sub(self, other: Self) -> Self {
467                Self(self.0 - other.0)
468            }
469        }
470
471        #[cfg(with_testing)]
472        impl ops::Mul<$wrapped> for $name {
473            type Output = Self;
474
475            fn mul(self, other: $wrapped) -> Self {
476                Self(self.0 * other)
477            }
478        }
479    };
480}
481
482impl TryFrom<BlockHeight> for usize {
483    type Error = ArithmeticError;
484
485    fn try_from(height: BlockHeight) -> Result<usize, ArithmeticError> {
486        usize::try_from(height.0).map_err(|_| ArithmeticError::Overflow)
487    }
488}
489
490/// Allows converting [`BlockHeight`] ranges to inclusive tuples of bounds.
491pub trait BlockHeightRangeBounds {
492    /// Returns the range as a tuple of inclusive bounds.
493    /// If the range is empty, returns `None`.
494    fn to_inclusive(&self) -> Option<(BlockHeight, BlockHeight)>;
495}
496
497impl<T: RangeBounds<BlockHeight>> BlockHeightRangeBounds for T {
498    fn to_inclusive(&self) -> Option<(BlockHeight, BlockHeight)> {
499        let start = match self.start_bound() {
500            Bound::Included(height) => *height,
501            Bound::Excluded(height) => height.try_add_one().ok()?,
502            Bound::Unbounded => BlockHeight(0),
503        };
504        let end = match self.end_bound() {
505            Bound::Included(height) => *height,
506            Bound::Excluded(height) => height.try_sub_one().ok()?,
507            Bound::Unbounded => BlockHeight::MAX,
508        };
509        if start > end {
510            return None;
511        }
512        Some((start, end))
513    }
514}
515
516impl_wrapped_number!(Amount, u128);
517impl_wrapped_number!(BlockHeight, u64);
518impl_wrapped_number!(TimeDelta, u64);
519
520impl Display for Amount {
521    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
522        // Print the wrapped integer, padded with zeros to cover a digit before the decimal point.
523        let places = Amount::DECIMAL_PLACES as usize;
524        let min_digits = places + 1;
525        let decimals = format!("{:0min_digits$}", self.0);
526        let integer_part = &decimals[..(decimals.len() - places)];
527        let fractional_part = decimals[(decimals.len() - places)..].trim_end_matches('0');
528
529        // For now, we never trim non-zero digits so we don't lose any precision.
530        let precision = f.precision().unwrap_or(0).max(fractional_part.len());
531        let sign = if f.sign_plus() && self.0 > 0 { "+" } else { "" };
532        // The amount of padding: desired width minus sign, point and number of digits.
533        let pad_width = f.width().map_or(0, |w| {
534            w.saturating_sub(precision)
535                .saturating_sub(sign.len() + integer_part.len() + 1)
536        });
537        let left_pad = match f.align() {
538            None | Some(fmt::Alignment::Right) => pad_width,
539            Some(fmt::Alignment::Center) => pad_width / 2,
540            Some(fmt::Alignment::Left) => 0,
541        };
542
543        for _ in 0..left_pad {
544            write!(f, "{}", f.fill())?;
545        }
546        write!(f, "{sign}{integer_part}.{fractional_part:0<precision$}")?;
547        for _ in left_pad..pad_width {
548            write!(f, "{}", f.fill())?;
549        }
550        Ok(())
551    }
552}
553
554#[derive(Error, Debug)]
555#[allow(missing_docs)]
556pub enum ParseAmountError {
557    #[error("cannot parse amount")]
558    Parse,
559    #[error("cannot represent amount: number too high")]
560    TooHigh,
561    #[error("cannot represent amount: too many decimal places after the point")]
562    TooManyDigits,
563}
564
565impl FromStr for Amount {
566    type Err = ParseAmountError;
567
568    fn from_str(src: &str) -> Result<Self, Self::Err> {
569        let mut result: u128 = 0;
570        let mut decimals: Option<u8> = None;
571        let mut chars = src.trim().chars().peekable();
572        if chars.peek() == Some(&'+') {
573            chars.next();
574        }
575        for char in chars {
576            match char {
577                '_' => {}
578                '.' if decimals.is_some() => return Err(ParseAmountError::Parse),
579                '.' => decimals = Some(Amount::DECIMAL_PLACES),
580                char => {
581                    let digit = u128::from(char.to_digit(10).ok_or(ParseAmountError::Parse)?);
582                    if let Some(d) = &mut decimals {
583                        *d = d.checked_sub(1).ok_or(ParseAmountError::TooManyDigits)?;
584                    }
585                    result = result
586                        .checked_mul(10)
587                        .and_then(|r| r.checked_add(digit))
588                        .ok_or(ParseAmountError::TooHigh)?;
589                }
590            }
591        }
592        result = result
593            .checked_mul(10u128.pow(decimals.unwrap_or(Amount::DECIMAL_PLACES) as u32))
594            .ok_or(ParseAmountError::TooHigh)?;
595        Ok(Amount(result))
596    }
597}
598
599impl Display for BlockHeight {
600    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
601        self.0.fmt(f)
602    }
603}
604
605impl FromStr for BlockHeight {
606    type Err = ParseIntError;
607
608    fn from_str(src: &str) -> Result<Self, Self::Err> {
609        Ok(Self(u64::from_str(src)?))
610    }
611}
612
613impl Display for Round {
614    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
615        match self {
616            Round::Fast => write!(f, "fast round"),
617            Round::MultiLeader(r) => write!(f, "multi-leader round {}", r),
618            Round::SingleLeader(r) => write!(f, "single-leader round {}", r),
619            Round::Validator(r) => write!(f, "validator round {}", r),
620        }
621    }
622}
623
624impl Round {
625    /// Whether the round is a multi-leader round.
626    pub fn is_multi_leader(&self) -> bool {
627        matches!(self, Round::MultiLeader(_))
628    }
629
630    /// Returns the round number if this is a multi-leader round, `None` otherwise.
631    pub fn multi_leader(&self) -> Option<u32> {
632        match self {
633            Round::MultiLeader(number) => Some(*number),
634            _ => None,
635        }
636    }
637
638    /// Whether the round is the fast round.
639    pub fn is_fast(&self) -> bool {
640        matches!(self, Round::Fast)
641    }
642
643    /// The index of a round amongst the rounds of the same category.
644    pub fn number(&self) -> u32 {
645        match self {
646            Round::Fast => 0,
647            Round::MultiLeader(r) | Round::SingleLeader(r) | Round::Validator(r) => *r,
648        }
649    }
650
651    /// The category of the round as a string.
652    pub fn type_name(&self) -> &'static str {
653        match self {
654            Round::Fast => "fast",
655            Round::MultiLeader(_) => "multi",
656            Round::SingleLeader(_) => "single",
657            Round::Validator(_) => "validator",
658        }
659    }
660}
661
662impl<'a> iter::Sum<&'a Amount> for Amount {
663    fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
664        iter.fold(Self::ZERO, |a, b| a.saturating_add(*b))
665    }
666}
667
668impl Amount {
669    /// The base-10 exponent representing how much a token can be divided.
670    pub const DECIMAL_PLACES: u8 = 18;
671
672    /// One token.
673    pub const ONE: Amount = Amount(10u128.pow(Amount::DECIMAL_PLACES as u32));
674
675    /// Returns an `Amount` corresponding to that many tokens, or `Amount::MAX` if saturated.
676    pub const fn from_tokens(tokens: u128) -> Amount {
677        Self::ONE.saturating_mul(tokens)
678    }
679
680    /// Returns an `Amount` corresponding to that many millitokens, or `Amount::MAX` if saturated.
681    pub const fn from_millis(millitokens: u128) -> Amount {
682        Amount(10u128.pow(Amount::DECIMAL_PLACES as u32 - 3)).saturating_mul(millitokens)
683    }
684
685    /// Returns an `Amount` corresponding to that many microtokens, or `Amount::MAX` if saturated.
686    pub const fn from_micros(microtokens: u128) -> Amount {
687        Amount(10u128.pow(Amount::DECIMAL_PLACES as u32 - 6)).saturating_mul(microtokens)
688    }
689
690    /// Returns an `Amount` corresponding to that many nanotokens, or `Amount::MAX` if saturated.
691    pub const fn from_nanos(nanotokens: u128) -> Amount {
692        Amount(10u128.pow(Amount::DECIMAL_PLACES as u32 - 9)).saturating_mul(nanotokens)
693    }
694
695    /// Returns an `Amount` corresponding to that many attotokens.
696    pub const fn from_attos(attotokens: u128) -> Amount {
697        Amount(attotokens)
698    }
699
700    /// Helper function to obtain the 64 most significant bits of the balance.
701    pub const fn upper_half(self) -> u64 {
702        (self.0 >> 64) as u64
703    }
704
705    /// Helper function to obtain the 64 least significant bits of the balance.
706    pub const fn lower_half(self) -> u64 {
707        self.0 as u64
708    }
709
710    /// Divides this by the other amount. If the other is 0, it returns `u128::MAX`.
711    pub fn saturating_div(self, other: Amount) -> u128 {
712        self.0.checked_div(other.0).unwrap_or(u128::MAX)
713    }
714
715    /// Returns whether this amount is 0.
716    pub fn is_zero(&self) -> bool {
717        *self == Amount::ZERO
718    }
719}
720
721/// What created a chain.
722#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Hash, Debug, Serialize, Deserialize)]
723pub enum ChainOrigin {
724    /// The chain was created by the genesis configuration.
725    Root(u32),
726    /// The chain was created by a call from another chain.
727    Child {
728        /// The parent of this chain.
729        parent: ChainId,
730        /// The block height in the parent at which this chain was created.
731        block_height: BlockHeight,
732        /// The index of this chain among chains created at the same block height in the parent
733        /// chain.
734        chain_index: u32,
735    },
736}
737
738impl ChainOrigin {
739    /// Whether the chain was created by another chain.
740    pub fn is_child(&self) -> bool {
741        matches!(self, ChainOrigin::Child { .. })
742    }
743}
744
745/// A number identifying the configuration of the chain (aka the committee).
746#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Hash, Default, Debug)]
747pub struct Epoch(pub u32);
748
749impl Epoch {
750    /// The zero epoch.
751    pub const ZERO: Epoch = Epoch(0);
752}
753
754impl Serialize for Epoch {
755    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
756    where
757        S: serde::ser::Serializer,
758    {
759        if serializer.is_human_readable() {
760            serializer.serialize_str(&self.0.to_string())
761        } else {
762            serializer.serialize_newtype_struct("Epoch", &self.0)
763        }
764    }
765}
766
767impl<'de> Deserialize<'de> for Epoch {
768    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
769    where
770        D: serde::de::Deserializer<'de>,
771    {
772        if deserializer.is_human_readable() {
773            let s = String::deserialize(deserializer)?;
774            Ok(Epoch(u32::from_str(&s).map_err(serde::de::Error::custom)?))
775        } else {
776            #[derive(Deserialize)]
777            #[serde(rename = "Epoch")]
778            struct EpochDerived(u32);
779
780            let value = EpochDerived::deserialize(deserializer)?;
781            Ok(Self(value.0))
782        }
783    }
784}
785
786impl std::fmt::Display for Epoch {
787    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
788        write!(f, "{}", self.0)
789    }
790}
791
792impl std::str::FromStr for Epoch {
793    type Err = CryptoError;
794
795    fn from_str(s: &str) -> Result<Self, Self::Err> {
796        Ok(Epoch(s.parse()?))
797    }
798}
799
800impl From<u32> for Epoch {
801    fn from(value: u32) -> Self {
802        Epoch(value)
803    }
804}
805
806impl Epoch {
807    /// Tries to return an epoch with a number increased by one. Returns an error if an overflow
808    /// happens.
809    #[inline]
810    pub fn try_add_one(self) -> Result<Self, ArithmeticError> {
811        let val = self.0.checked_add(1).ok_or(ArithmeticError::Overflow)?;
812        Ok(Self(val))
813    }
814
815    /// Tries to return an epoch with a number decreased by one. Returns an error if an underflow
816    /// happens.
817    pub fn try_sub_one(self) -> Result<Self, ArithmeticError> {
818        let val = self.0.checked_sub(1).ok_or(ArithmeticError::Underflow)?;
819        Ok(Self(val))
820    }
821
822    /// Tries to add one to this epoch's number. Returns an error if an overflow happens.
823    #[inline]
824    pub fn try_add_assign_one(&mut self) -> Result<(), ArithmeticError> {
825        self.0 = self.0.checked_add(1).ok_or(ArithmeticError::Overflow)?;
826        Ok(())
827    }
828}
829
830/// The initial configuration for a new chain.
831#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
832pub struct InitialChainConfig {
833    /// The ownership configuration of the new chain.
834    pub ownership: ChainOwnership,
835    /// The epoch in which the chain is created.
836    pub epoch: Epoch,
837    /// Serialized committees corresponding to epochs.
838    pub committees: BTreeMap<Epoch, Vec<u8>>,
839    /// The initial chain balance.
840    pub balance: Amount,
841    /// The initial application permissions.
842    pub application_permissions: ApplicationPermissions,
843}
844
845/// Initial chain configuration and chain origin.
846#[derive(Eq, PartialEq, Clone, Hash, Debug, Serialize, Deserialize)]
847pub struct ChainDescription {
848    origin: ChainOrigin,
849    timestamp: Timestamp,
850    config: InitialChainConfig,
851}
852
853impl ChainDescription {
854    /// Creates a new [`ChainDescription`].
855    pub fn new(origin: ChainOrigin, config: InitialChainConfig, timestamp: Timestamp) -> Self {
856        Self {
857            origin,
858            config,
859            timestamp,
860        }
861    }
862
863    /// Returns the [`ChainId`] based on this [`ChainDescription`].
864    pub fn id(&self) -> ChainId {
865        ChainId::from(self)
866    }
867
868    /// Returns the [`ChainOrigin`] describing who created this chain.
869    pub fn origin(&self) -> ChainOrigin {
870        self.origin
871    }
872
873    /// Returns a reference to the [`InitialChainConfig`] of the chain.
874    pub fn config(&self) -> &InitialChainConfig {
875        &self.config
876    }
877
878    /// Returns the timestamp of when the chain was created.
879    pub fn timestamp(&self) -> Timestamp {
880        self.timestamp
881    }
882
883    /// Whether the chain was created by another chain.
884    pub fn is_child(&self) -> bool {
885        self.origin.is_child()
886    }
887}
888
889impl BcsHashable<'_> for ChainDescription {}
890
891/// A description of the current Linera network to be stored in every node's database.
892#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
893pub struct NetworkDescription {
894    /// The name of the network.
895    pub name: String,
896    /// Hash of the network's genesis config.
897    pub genesis_config_hash: CryptoHash,
898    /// Genesis timestamp.
899    pub genesis_timestamp: Timestamp,
900    /// The chain ID of the admin chain.
901    pub admin_chain_id: ChainId,
902}
903
904/// Permissions for applications on a chain.
905#[derive(
906    Default,
907    Debug,
908    PartialEq,
909    Eq,
910    PartialOrd,
911    Ord,
912    Hash,
913    Clone,
914    Serialize,
915    Deserialize,
916    WitType,
917    WitLoad,
918    WitStore,
919    InputObject,
920)]
921pub struct ApplicationPermissions {
922    /// If this is `None`, all system operations and application operations are allowed.
923    /// If it is `Some`, only operations from the specified applications are allowed, and
924    /// no system operations.
925    #[debug(skip_if = Option::is_none)]
926    pub execute_operations: Option<Vec<ApplicationId>>,
927    /// At least one operation or incoming message from each of these applications must occur in
928    /// every block.
929    #[graphql(default)]
930    #[debug(skip_if = Vec::is_empty)]
931    pub mandatory_applications: Vec<ApplicationId>,
932    /// These applications are allowed to close the current chain using the system API.
933    #[graphql(default)]
934    #[debug(skip_if = Vec::is_empty)]
935    pub close_chain: Vec<ApplicationId>,
936    /// These applications are allowed to change the application permissions using the system API.
937    #[graphql(default)]
938    #[debug(skip_if = Vec::is_empty)]
939    pub change_application_permissions: Vec<ApplicationId>,
940    /// These applications are allowed to perform calls to services as oracles.
941    #[graphql(default)]
942    #[debug(skip_if = Option::is_none)]
943    pub call_service_as_oracle: Option<Vec<ApplicationId>>,
944    /// These applications are allowed to perform HTTP requests.
945    #[graphql(default)]
946    #[debug(skip_if = Option::is_none)]
947    pub make_http_requests: Option<Vec<ApplicationId>>,
948}
949
950impl ApplicationPermissions {
951    /// Creates new `ApplicationPermissions` where the given application is the only one
952    /// whose operations are allowed and mandatory, and it can also close the chain.
953    pub fn new_single(app_id: ApplicationId) -> Self {
954        Self {
955            execute_operations: Some(vec![app_id]),
956            mandatory_applications: vec![app_id],
957            close_chain: vec![app_id],
958            change_application_permissions: vec![app_id],
959            call_service_as_oracle: Some(vec![app_id]),
960            make_http_requests: Some(vec![app_id]),
961        }
962    }
963
964    /// Creates new `ApplicationPermissions` where the given applications are the only ones
965    /// whose operations are allowed and mandatory, and they can also close the chain.
966    pub fn new_multiple(app_ids: Vec<ApplicationId>) -> Self {
967        Self {
968            execute_operations: Some(app_ids.clone()),
969            mandatory_applications: app_ids.clone(),
970            close_chain: app_ids.clone(),
971            change_application_permissions: app_ids.clone(),
972            call_service_as_oracle: Some(app_ids.clone()),
973            make_http_requests: Some(app_ids),
974        }
975    }
976
977    /// Returns whether operations with the given application ID are allowed on this chain.
978    pub fn can_execute_operations(&self, app_id: &GenericApplicationId) -> bool {
979        match (app_id, &self.execute_operations) {
980            (_, None) => true,
981            (GenericApplicationId::System, Some(_)) => false,
982            (GenericApplicationId::User(app_id), Some(app_ids)) => app_ids.contains(app_id),
983        }
984    }
985
986    /// Returns whether the given application is allowed to close this chain.
987    pub fn can_close_chain(&self, app_id: &ApplicationId) -> bool {
988        self.close_chain.contains(app_id)
989    }
990
991    /// Returns whether the given application is allowed to change the application
992    /// permissions for this chain.
993    pub fn can_change_application_permissions(&self, app_id: &ApplicationId) -> bool {
994        self.change_application_permissions.contains(app_id)
995    }
996
997    /// Returns whether the given application can call services.
998    pub fn can_call_services(&self, app_id: &ApplicationId) -> bool {
999        self.call_service_as_oracle
1000            .as_ref()
1001            .map(|app_ids| app_ids.contains(app_id))
1002            .unwrap_or(true)
1003    }
1004
1005    /// Returns whether the given application can make HTTP requests.
1006    pub fn can_make_http_requests(&self, app_id: &ApplicationId) -> bool {
1007        self.make_http_requests
1008            .as_ref()
1009            .map(|app_ids| app_ids.contains(app_id))
1010            .unwrap_or(true)
1011    }
1012}
1013
1014/// A record of a single oracle response.
1015#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
1016pub enum OracleResponse {
1017    /// The response from a service query.
1018    Service(
1019        #[debug(with = "hex_debug")]
1020        #[serde(with = "serde_bytes")]
1021        Vec<u8>,
1022    ),
1023    /// The response from an HTTP request.
1024    Http(http::Response),
1025    /// A successful read or write of a blob.
1026    Blob(BlobId),
1027    /// An assertion oracle that passed.
1028    Assert,
1029    /// The block's validation round.
1030    Round(Option<u32>),
1031    /// An event was read.
1032    Event(EventId, Vec<u8>),
1033}
1034
1035impl BcsHashable<'_> for OracleResponse {}
1036
1037/// Description of a user application.
1038#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Hash, Serialize)]
1039pub struct ApplicationDescription {
1040    /// The unique ID of the bytecode to use for the application.
1041    pub module_id: ModuleId,
1042    /// The chain ID that created the application.
1043    pub creator_chain_id: ChainId,
1044    /// Height of the block that created this application.
1045    pub block_height: BlockHeight,
1046    /// The index of the application among those created in the same block.
1047    pub application_index: u32,
1048    /// The parameters of the application.
1049    #[serde(with = "serde_bytes")]
1050    #[debug(with = "hex_debug")]
1051    pub parameters: Vec<u8>,
1052    /// Required dependencies.
1053    pub required_application_ids: Vec<ApplicationId>,
1054}
1055
1056impl From<&ApplicationDescription> for ApplicationId {
1057    fn from(description: &ApplicationDescription) -> Self {
1058        let mut hash = CryptoHash::new(&BlobContent::new_application_description(description));
1059        if matches!(description.module_id.vm_runtime, VmRuntime::Evm) {
1060            hash.make_evm_compatible();
1061        }
1062        ApplicationId::new(hash)
1063    }
1064}
1065
1066impl BcsHashable<'_> for ApplicationDescription {}
1067
1068impl ApplicationDescription {
1069    /// Gets the serialized bytes for this `ApplicationDescription`.
1070    pub fn to_bytes(&self) -> Vec<u8> {
1071        bcs::to_bytes(self).expect("Serializing blob bytes should not fail!")
1072    }
1073
1074    /// Gets the `BlobId` of the contract
1075    pub fn contract_bytecode_blob_id(&self) -> BlobId {
1076        self.module_id.contract_bytecode_blob_id()
1077    }
1078
1079    /// Gets the `BlobId` of the service
1080    pub fn service_bytecode_blob_id(&self) -> BlobId {
1081        self.module_id.service_bytecode_blob_id()
1082    }
1083}
1084
1085/// A WebAssembly module's bytecode.
1086#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
1087pub struct Bytecode {
1088    /// Bytes of the bytecode.
1089    #[serde(with = "serde_bytes")]
1090    #[debug(with = "hex_debug")]
1091    pub bytes: Vec<u8>,
1092}
1093
1094impl Bytecode {
1095    /// Creates a new [`Bytecode`] instance using the provided `bytes`.
1096    pub fn new(bytes: Vec<u8>) -> Self {
1097        Bytecode { bytes }
1098    }
1099
1100    /// Load bytecode from a Wasm module file.
1101    pub async fn load_from_file(path: impl AsRef<std::path::Path>) -> std::io::Result<Self> {
1102        let bytes = fs::read(path)?;
1103        Ok(Bytecode { bytes })
1104    }
1105
1106    /// Compresses the [`Bytecode`] into a [`CompressedBytecode`].
1107    #[cfg(not(target_arch = "wasm32"))]
1108    pub fn compress(&self) -> CompressedBytecode {
1109        #[cfg(with_metrics)]
1110        let _compression_latency = metrics::BYTECODE_COMPRESSION_LATENCY.measure_latency();
1111        let compressed_bytes = zstd::stream::encode_all(&*self.bytes, 19)
1112            .expect("Compressing bytes in memory should not fail");
1113
1114        CompressedBytecode { compressed_bytes }
1115    }
1116}
1117
1118impl AsRef<[u8]> for Bytecode {
1119    fn as_ref(&self) -> &[u8] {
1120        self.bytes.as_ref()
1121    }
1122}
1123
1124/// A type for errors happening during decompression.
1125#[derive(Error, Debug)]
1126pub enum DecompressionError {
1127    /// Compressed bytecode is invalid, and could not be decompressed.
1128    #[error("Bytecode could not be decompressed: {0}")]
1129    InvalidCompressedBytecode(#[from] io::Error),
1130}
1131
1132/// A compressed WebAssembly module's bytecode.
1133#[derive(Clone, Debug, Deserialize, Hash, Serialize, WitType, WitStore)]
1134#[cfg_attr(with_testing, derive(Eq, PartialEq))]
1135pub struct CompressedBytecode {
1136    /// Compressed bytes of the bytecode.
1137    #[serde(with = "serde_bytes")]
1138    #[debug(with = "hex_debug")]
1139    pub compressed_bytes: Vec<u8>,
1140}
1141
1142#[cfg(not(target_arch = "wasm32"))]
1143impl CompressedBytecode {
1144    /// Returns `true` if the decompressed size does not exceed the limit.
1145    pub fn decompressed_size_at_most(
1146        compressed_bytes: &[u8],
1147        limit: u64,
1148    ) -> Result<bool, DecompressionError> {
1149        let mut decoder = zstd::stream::Decoder::new(compressed_bytes)?;
1150        let limit = usize::try_from(limit).unwrap_or(usize::MAX);
1151        let mut writer = LimitedWriter::new(io::sink(), limit);
1152        match io::copy(&mut decoder, &mut writer) {
1153            Ok(_) => Ok(true),
1154            Err(error) => {
1155                error.downcast::<LimitedWriterError>()?;
1156                Ok(false)
1157            }
1158        }
1159    }
1160
1161    /// Decompresses a [`CompressedBytecode`] into a [`Bytecode`].
1162    pub fn decompress(&self) -> Result<Bytecode, DecompressionError> {
1163        #[cfg(with_metrics)]
1164        let _decompression_latency = metrics::BYTECODE_DECOMPRESSION_LATENCY.measure_latency();
1165        let bytes = zstd::stream::decode_all(&*self.compressed_bytes)?;
1166
1167        Ok(Bytecode { bytes })
1168    }
1169}
1170
1171#[cfg(target_arch = "wasm32")]
1172impl CompressedBytecode {
1173    /// Returns `true` if the decompressed size does not exceed the limit.
1174    pub fn decompressed_size_at_most(
1175        compressed_bytes: &[u8],
1176        limit: u64,
1177    ) -> Result<bool, DecompressionError> {
1178        let limit = usize::try_from(limit).unwrap_or(usize::MAX);
1179        let mut writer = LimitedWriter::new(io::sink(), limit);
1180        let mut decoder = ruzstd::streaming_decoder::StreamingDecoder::new(compressed_bytes)
1181            .map_err(io::Error::other)?;
1182
1183        // TODO(#2710): Decode multiple frames, if present
1184        match io::copy(&mut decoder, &mut writer) {
1185            Ok(_) => Ok(true),
1186            Err(error) => {
1187                error.downcast::<LimitedWriterError>()?;
1188                Ok(false)
1189            }
1190        }
1191    }
1192
1193    /// Decompresses a [`CompressedBytecode`] into a [`Bytecode`].
1194    pub fn decompress(&self) -> Result<Bytecode, DecompressionError> {
1195        use ruzstd::{io::Read, streaming_decoder::StreamingDecoder};
1196
1197        #[cfg(with_metrics)]
1198        let _decompression_latency = BYTECODE_DECOMPRESSION_LATENCY.measure_latency();
1199
1200        let compressed_bytes = &*self.compressed_bytes;
1201        let mut bytes = Vec::new();
1202        let mut decoder = StreamingDecoder::new(compressed_bytes).map_err(io::Error::other)?;
1203
1204        // TODO(#2710): Decode multiple frames, if present
1205        while !decoder.get_ref().is_empty() {
1206            decoder
1207                .read_to_end(&mut bytes)
1208                .expect("Reading from a slice in memory should not result in I/O errors");
1209        }
1210
1211        Ok(Bytecode { bytes })
1212    }
1213}
1214
1215impl BcsHashable<'_> for BlobContent {}
1216
1217/// A blob of binary data.
1218#[derive(Hash, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
1219pub struct BlobContent {
1220    /// The type of data represented by the bytes.
1221    blob_type: BlobType,
1222    /// The binary data.
1223    #[serde(with = "serde_bytes")]
1224    #[debug(skip)]
1225    bytes: Box<[u8]>,
1226}
1227
1228impl BlobContent {
1229    /// Creates a new [`BlobContent`] from the provided bytes and [`BlobId`].
1230    pub fn new(blob_type: BlobType, bytes: impl Into<Box<[u8]>>) -> Self {
1231        let bytes = bytes.into();
1232        BlobContent { blob_type, bytes }
1233    }
1234
1235    /// Creates a new data [`BlobContent`] from the provided bytes.
1236    pub fn new_data(bytes: impl Into<Box<[u8]>>) -> Self {
1237        BlobContent::new(BlobType::Data, bytes)
1238    }
1239
1240    /// Creates a new contract bytecode [`BlobContent`] from the provided bytes.
1241    pub fn new_contract_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1242        BlobContent::new(
1243            BlobType::ContractBytecode,
1244            compressed_bytecode.compressed_bytes,
1245        )
1246    }
1247
1248    /// Creates a new contract bytecode [`BlobContent`] from the provided bytes.
1249    pub fn new_evm_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1250        BlobContent::new(BlobType::EvmBytecode, compressed_bytecode.compressed_bytes)
1251    }
1252
1253    /// Creates a new service bytecode [`BlobContent`] from the provided bytes.
1254    pub fn new_service_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1255        BlobContent::new(
1256            BlobType::ServiceBytecode,
1257            compressed_bytecode.compressed_bytes,
1258        )
1259    }
1260
1261    /// Creates a new application description [`BlobContent`] from a [`ApplicationDescription`].
1262    pub fn new_application_description(application_description: &ApplicationDescription) -> Self {
1263        let bytes = application_description.to_bytes();
1264        BlobContent::new(BlobType::ApplicationDescription, bytes)
1265    }
1266
1267    /// Creates a new committee [`BlobContent`] from the provided serialized committee.
1268    pub fn new_committee(committee: impl Into<Box<[u8]>>) -> Self {
1269        BlobContent::new(BlobType::Committee, committee)
1270    }
1271
1272    /// Creates a new chain description [`BlobContent`] from a [`ChainDescription`].
1273    pub fn new_chain_description(chain_description: &ChainDescription) -> Self {
1274        let bytes = bcs::to_bytes(&chain_description)
1275            .expect("Serializing a ChainDescription should not fail!");
1276        BlobContent::new(BlobType::ChainDescription, bytes)
1277    }
1278
1279    /// Gets a reference to the blob's bytes.
1280    pub fn bytes(&self) -> &[u8] {
1281        &self.bytes
1282    }
1283
1284    /// Gets the inner blob's bytes, consuming the blob.
1285    pub fn into_bytes(self) -> Box<[u8]> {
1286        self.bytes
1287    }
1288
1289    /// Returns the type of data represented by this blob's bytes.
1290    pub fn blob_type(&self) -> BlobType {
1291        self.blob_type
1292    }
1293}
1294
1295impl From<Blob> for BlobContent {
1296    fn from(blob: Blob) -> BlobContent {
1297        blob.content
1298    }
1299}
1300
1301/// A blob of binary data, with its hash.
1302#[derive(Debug, Hash, PartialEq, Eq, Clone)]
1303pub struct Blob {
1304    /// ID of the blob.
1305    hash: CryptoHash,
1306    /// A blob of binary data.
1307    content: BlobContent,
1308}
1309
1310impl Blob {
1311    /// Computes the hash and returns the hashed blob for the given content.
1312    pub fn new(content: BlobContent) -> Self {
1313        let mut hash = CryptoHash::new(&content);
1314        if matches!(content.blob_type, BlobType::ApplicationDescription) {
1315            let application_description = bcs::from_bytes::<ApplicationDescription>(&content.bytes)
1316                .expect("to obtain an application description");
1317            if matches!(application_description.module_id.vm_runtime, VmRuntime::Evm) {
1318                hash.make_evm_compatible();
1319            }
1320        }
1321        Blob { hash, content }
1322    }
1323
1324    /// Creates a blob without checking that the hash actually matches the content.
1325    pub fn new_with_id_unchecked(blob_id: BlobId, bytes: impl Into<Box<[u8]>>) -> Self {
1326        Blob {
1327            hash: blob_id.hash,
1328            content: BlobContent {
1329                blob_type: blob_id.blob_type,
1330                bytes: bytes.into(),
1331            },
1332        }
1333    }
1334
1335    /// Creates a new data [`Blob`] from the provided bytes.
1336    pub fn new_data(bytes: impl Into<Box<[u8]>>) -> Self {
1337        Blob::new(BlobContent::new_data(bytes))
1338    }
1339
1340    /// Creates a new contract bytecode [`Blob`] from the provided bytes.
1341    pub fn new_contract_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1342        Blob::new(BlobContent::new_contract_bytecode(compressed_bytecode))
1343    }
1344
1345    /// Creates a new contract bytecode [`BlobContent`] from the provided bytes.
1346    pub fn new_evm_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1347        Blob::new(BlobContent::new_evm_bytecode(compressed_bytecode))
1348    }
1349
1350    /// Creates a new service bytecode [`Blob`] from the provided bytes.
1351    pub fn new_service_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1352        Blob::new(BlobContent::new_service_bytecode(compressed_bytecode))
1353    }
1354
1355    /// Creates a new application description [`Blob`] from the provided description.
1356    pub fn new_application_description(application_description: &ApplicationDescription) -> Self {
1357        Blob::new(BlobContent::new_application_description(
1358            application_description,
1359        ))
1360    }
1361
1362    /// Creates a new committee [`Blob`] from the provided bytes.
1363    pub fn new_committee(committee: impl Into<Box<[u8]>>) -> Self {
1364        Blob::new(BlobContent::new_committee(committee))
1365    }
1366
1367    /// Creates a new chain description [`Blob`] from a [`ChainDescription`].
1368    pub fn new_chain_description(chain_description: &ChainDescription) -> Self {
1369        Blob::new(BlobContent::new_chain_description(chain_description))
1370    }
1371
1372    /// A content-addressed blob ID i.e. the hash of the `Blob`.
1373    pub fn id(&self) -> BlobId {
1374        BlobId {
1375            hash: self.hash,
1376            blob_type: self.content.blob_type,
1377        }
1378    }
1379
1380    /// Returns a reference to the inner `BlobContent`, without the hash.
1381    pub fn content(&self) -> &BlobContent {
1382        &self.content
1383    }
1384
1385    /// Moves ownership of the blob of binary data
1386    pub fn into_content(self) -> BlobContent {
1387        self.content
1388    }
1389
1390    /// Gets a reference to the inner blob's bytes.
1391    pub fn bytes(&self) -> &[u8] {
1392        self.content.bytes()
1393    }
1394
1395    /// Gets the inner blob's bytes.
1396    pub fn into_bytes(self) -> Box<[u8]> {
1397        self.content.into_bytes()
1398    }
1399
1400    /// Loads data blob from a file.
1401    pub async fn load_data_blob_from_file(path: impl AsRef<Path>) -> io::Result<Self> {
1402        Ok(Self::new_data(fs::read(path)?))
1403    }
1404
1405    /// Returns whether the blob is of [`BlobType::Committee`] variant.
1406    pub fn is_committee_blob(&self) -> bool {
1407        self.content().blob_type().is_committee_blob()
1408    }
1409}
1410
1411impl Serialize for Blob {
1412    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1413    where
1414        S: Serializer,
1415    {
1416        if serializer.is_human_readable() {
1417            let blob_bytes = bcs::to_bytes(&self.content).map_err(serde::ser::Error::custom)?;
1418            serializer.serialize_str(&hex::encode(blob_bytes))
1419        } else {
1420            BlobContent::serialize(self.content(), serializer)
1421        }
1422    }
1423}
1424
1425impl<'a> Deserialize<'a> for Blob {
1426    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1427    where
1428        D: Deserializer<'a>,
1429    {
1430        if deserializer.is_human_readable() {
1431            let s = String::deserialize(deserializer)?;
1432            let content_bytes = hex::decode(s).map_err(serde::de::Error::custom)?;
1433            let content: BlobContent =
1434                bcs::from_bytes(&content_bytes).map_err(serde::de::Error::custom)?;
1435
1436            Ok(Blob::new(content))
1437        } else {
1438            let content = BlobContent::deserialize(deserializer)?;
1439            Ok(Blob::new(content))
1440        }
1441    }
1442}
1443
1444impl BcsHashable<'_> for Blob {}
1445
1446/// An event recorded in a block.
1447#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, SimpleObject)]
1448pub struct Event {
1449    /// The ID of the stream this event belongs to.
1450    pub stream_id: StreamId,
1451    /// The event index, i.e. the number of events in the stream before this one.
1452    pub index: u32,
1453    /// The payload data.
1454    #[debug(with = "hex_debug")]
1455    #[serde(with = "serde_bytes")]
1456    pub value: Vec<u8>,
1457}
1458
1459impl Event {
1460    /// Returns the ID of this event record, given the publisher chain ID.
1461    pub fn id(&self, chain_id: ChainId) -> EventId {
1462        EventId {
1463            chain_id,
1464            stream_id: self.stream_id.clone(),
1465            index: self.index,
1466        }
1467    }
1468}
1469
1470/// An update for a stream with new events.
1471#[derive(Clone, Debug, Serialize, Deserialize, WitType, WitLoad, WitStore)]
1472pub struct StreamUpdate {
1473    /// The publishing chain.
1474    pub chain_id: ChainId,
1475    /// The stream ID.
1476    pub stream_id: StreamId,
1477    /// The lowest index of a new event. See [`StreamUpdate::new_indices`].
1478    pub previous_index: u32,
1479    /// The index of the next event, i.e. the lowest for which no event is known yet.
1480    pub next_index: u32,
1481}
1482
1483impl StreamUpdate {
1484    /// Returns the indices of all new events in the stream.
1485    pub fn new_indices(&self) -> impl Iterator<Item = u32> {
1486        self.previous_index..self.next_index
1487    }
1488}
1489
1490impl BcsHashable<'_> for Event {}
1491
1492doc_scalar!(Bytecode, "A WebAssembly module's bytecode");
1493doc_scalar!(Amount, "A non-negative amount of tokens.");
1494doc_scalar!(
1495    Epoch,
1496    "A number identifying the configuration of the chain (aka the committee)"
1497);
1498doc_scalar!(BlockHeight, "A block height to identify blocks in a chain");
1499doc_scalar!(
1500    Timestamp,
1501    "A timestamp, in microseconds since the Unix epoch"
1502);
1503doc_scalar!(TimeDelta, "A duration in microseconds");
1504doc_scalar!(
1505    Round,
1506    "A number to identify successive attempts to decide a value in a consensus protocol."
1507);
1508doc_scalar!(
1509    ChainDescription,
1510    "Initial chain configuration and chain origin."
1511);
1512doc_scalar!(OracleResponse, "A record of a single oracle response.");
1513doc_scalar!(BlobContent, "A blob of binary data.");
1514doc_scalar!(
1515    Blob,
1516    "A blob of binary data, with its content-addressed blob ID."
1517);
1518doc_scalar!(ApplicationDescription, "Description of a user application");
1519
1520#[cfg(with_metrics)]
1521mod metrics {
1522    use std::sync::LazyLock;
1523
1524    use prometheus::HistogramVec;
1525
1526    use crate::prometheus_util::{exponential_bucket_latencies, register_histogram_vec};
1527
1528    /// The time it takes to compress a bytecode.
1529    pub static BYTECODE_COMPRESSION_LATENCY: LazyLock<HistogramVec> = LazyLock::new(|| {
1530        register_histogram_vec(
1531            "bytecode_compression_latency",
1532            "Bytecode compression latency",
1533            &[],
1534            exponential_bucket_latencies(10.0),
1535        )
1536    });
1537
1538    /// The time it takes to decompress a bytecode.
1539    pub static BYTECODE_DECOMPRESSION_LATENCY: LazyLock<HistogramVec> = LazyLock::new(|| {
1540        register_histogram_vec(
1541            "bytecode_decompression_latency",
1542            "Bytecode decompression latency",
1543            &[],
1544            exponential_bucket_latencies(10.0),
1545        )
1546    });
1547}
1548
1549#[cfg(test)]
1550mod tests {
1551    use std::str::FromStr;
1552
1553    use super::Amount;
1554
1555    #[test]
1556    fn display_amount() {
1557        assert_eq!("1.", Amount::ONE.to_string());
1558        assert_eq!("1.", Amount::from_str("1.").unwrap().to_string());
1559        assert_eq!(
1560            Amount(10_000_000_000_000_000_000),
1561            Amount::from_str("10").unwrap()
1562        );
1563        assert_eq!("10.", Amount(10_000_000_000_000_000_000).to_string());
1564        assert_eq!(
1565            "1001.3",
1566            (Amount::from_str("1.1")
1567                .unwrap()
1568                .saturating_add(Amount::from_str("1_000.2").unwrap()))
1569            .to_string()
1570        );
1571        assert_eq!(
1572            "   1.00000000000000000000",
1573            format!("{:25.20}", Amount::ONE)
1574        );
1575        assert_eq!(
1576            "~+12.34~~",
1577            format!("{:~^+9.1}", Amount::from_str("12.34").unwrap())
1578        );
1579    }
1580}