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