linera_base/
data_types.rs

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