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