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