Skip to main content

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
99impl TryFrom<U256> for Amount {
100    type Error = ArithmeticError;
101
102    fn try_from(value: U256) -> Result<Amount, ArithmeticError> {
103        let value: u128 = value.try_into().map_err(|_| ArithmeticError::Overflow)?;
104        Ok(Amount::from_attos(value))
105    }
106}
107
108/// A block height to identify blocks in a chain.
109#[derive(
110    Eq,
111    PartialEq,
112    Ord,
113    PartialOrd,
114    Copy,
115    Clone,
116    Hash,
117    Default,
118    Debug,
119    Serialize,
120    Deserialize,
121    WitType,
122    WitLoad,
123    WitStore,
124    Allocative,
125)]
126#[cfg_attr(with_testing, derive(test_strategy::Arbitrary))]
127pub struct BlockHeight(pub u64);
128
129/// An identifier for successive attempts to decide a value in a consensus protocol.
130#[derive(
131    Eq,
132    PartialEq,
133    Ord,
134    PartialOrd,
135    Copy,
136    Clone,
137    Hash,
138    Default,
139    Debug,
140    Serialize,
141    Deserialize,
142    Allocative,
143)]
144#[cfg_attr(with_testing, derive(test_strategy::Arbitrary))]
145pub enum Round {
146    /// The initial fast round.
147    #[default]
148    Fast,
149    /// The N-th multi-leader round.
150    MultiLeader(u32),
151    /// The N-th single-leader round.
152    SingleLeader(u32),
153    /// The N-th round where the validators rotate as leaders.
154    Validator(u32),
155}
156
157/// A duration in microseconds.
158#[derive(
159    Eq,
160    PartialEq,
161    Ord,
162    PartialOrd,
163    Copy,
164    Clone,
165    Hash,
166    Default,
167    Debug,
168    Serialize,
169    Deserialize,
170    WitType,
171    WitLoad,
172    WitStore,
173    Allocative,
174)]
175pub struct TimeDelta(u64);
176
177impl TimeDelta {
178    /// Returns the given number of microseconds as a [`TimeDelta`].
179    pub const fn from_micros(micros: u64) -> Self {
180        TimeDelta(micros)
181    }
182
183    /// Returns the given number of milliseconds as a [`TimeDelta`].
184    pub const fn from_millis(millis: u64) -> Self {
185        TimeDelta(millis.saturating_mul(1_000))
186    }
187
188    /// Returns the given number of seconds as a [`TimeDelta`].
189    pub const fn from_secs(secs: u64) -> Self {
190        TimeDelta(secs.saturating_mul(1_000_000))
191    }
192
193    /// Returns the given duration, rounded to the nearest microsecond and capped to the maximum
194    /// [`TimeDelta`] value.
195    pub fn from_duration(duration: Duration) -> Self {
196        TimeDelta::from_micros(u64::try_from(duration.as_micros()).unwrap_or(u64::MAX))
197    }
198
199    /// Returns this [`TimeDelta`] as a number of microseconds.
200    pub const fn as_micros(&self) -> u64 {
201        self.0
202    }
203
204    /// Returns this [`TimeDelta`] as a [`Duration`].
205    pub const fn as_duration(&self) -> Duration {
206        Duration::from_micros(self.as_micros())
207    }
208}
209
210/// A timestamp, in microseconds since the Unix epoch.
211#[derive(
212    Eq,
213    PartialEq,
214    Ord,
215    PartialOrd,
216    Copy,
217    Clone,
218    Hash,
219    Default,
220    Debug,
221    Serialize,
222    Deserialize,
223    WitType,
224    WitLoad,
225    WitStore,
226    Allocative,
227)]
228pub struct Timestamp(u64);
229
230impl Timestamp {
231    /// Returns the current time according to the system clock.
232    pub fn now() -> Timestamp {
233        Timestamp(
234            SystemTime::UNIX_EPOCH
235                .elapsed()
236                .expect("system time should be after Unix epoch")
237                .as_micros()
238                .try_into()
239                .unwrap_or(u64::MAX),
240        )
241    }
242
243    /// Returns the number of microseconds since the Unix epoch.
244    pub const fn micros(&self) -> u64 {
245        self.0
246    }
247
248    /// Returns the [`TimeDelta`] between `other` and `self`, or zero if `other` is not earlier
249    /// than `self`.
250    pub const fn delta_since(&self, other: Timestamp) -> TimeDelta {
251        TimeDelta::from_micros(self.0.saturating_sub(other.0))
252    }
253
254    /// Returns the [`Duration`] between `other` and `self`, or zero if `other` is not
255    /// earlier than `self`.
256    pub const fn duration_since(&self, other: Timestamp) -> Duration {
257        Duration::from_micros(self.0.saturating_sub(other.0))
258    }
259
260    /// Returns the timestamp that is `duration` later than `self`.
261    pub const fn saturating_add(&self, duration: TimeDelta) -> Timestamp {
262        Timestamp(self.0.saturating_add(duration.0))
263    }
264
265    /// Returns the timestamp that is `duration` earlier than `self`.
266    pub const fn saturating_sub(&self, duration: TimeDelta) -> Timestamp {
267        Timestamp(self.0.saturating_sub(duration.0))
268    }
269
270    /// Returns a timestamp `micros` microseconds earlier than `self`, or the lowest possible value
271    /// if it would underflow.
272    pub const fn saturating_sub_micros(&self, micros: u64) -> Timestamp {
273        Timestamp(self.0.saturating_sub(micros))
274    }
275}
276
277impl From<u64> for Timestamp {
278    fn from(t: u64) -> Timestamp {
279        Timestamp(t)
280    }
281}
282
283impl Display for Timestamp {
284    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
285        if let Some(date_time) = chrono::DateTime::from_timestamp(
286            (self.0 / 1_000_000) as i64,
287            ((self.0 % 1_000_000) * 1_000) as u32,
288        ) {
289            return date_time.naive_utc().fmt(f);
290        }
291        self.0.fmt(f)
292    }
293}
294
295impl FromStr for Timestamp {
296    type Err = chrono::ParseError;
297
298    fn from_str(s: &str) -> Result<Self, Self::Err> {
299        let naive = chrono::NaiveDateTime::parse_from_str(s, "%Y-%m-%dT%H:%M:%S")
300            .or_else(|_| chrono::NaiveDateTime::parse_from_str(s, "%Y-%m-%d %H:%M:%S"))?;
301        let micros = naive
302            .and_utc()
303            .timestamp_micros()
304            .try_into()
305            .unwrap_or(u64::MAX);
306        Ok(Timestamp(micros))
307    }
308}
309
310/// Resources that an application may spend during the execution of transaction or an
311/// application call.
312#[derive(
313    Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize, WitLoad, WitStore, WitType,
314)]
315pub struct Resources {
316    /// An amount of Wasm execution fuel.
317    pub wasm_fuel: u64,
318    /// An amount of EVM execution fuel.
319    pub evm_fuel: u64,
320    /// A number of read operations to be executed.
321    pub read_operations: u32,
322    /// A number of write operations to be executed.
323    pub write_operations: u32,
324    /// A number of bytes read from runtime.
325    pub bytes_runtime: u32,
326    /// A number of bytes to read.
327    pub bytes_to_read: u32,
328    /// A number of bytes to write.
329    pub bytes_to_write: u32,
330    /// A number of blobs to read.
331    pub blobs_to_read: u32,
332    /// A number of blobs to publish.
333    pub blobs_to_publish: u32,
334    /// A number of blob bytes to read.
335    pub blob_bytes_to_read: u32,
336    /// A number of blob bytes to publish.
337    pub blob_bytes_to_publish: u32,
338    /// A number of messages to be sent.
339    pub messages: u32,
340    /// The size of the messages to be sent.
341    // TODO(#1531): Account for the type of message to be sent.
342    pub message_size: u32,
343    /// An increase in the amount of storage space.
344    pub storage_size_delta: u32,
345    /// A number of service-as-oracle requests to be performed.
346    pub service_as_oracle_queries: u32,
347    /// A number of HTTP requests to be performed.
348    pub http_requests: u32,
349    // TODO(#1532): Account for the system calls that we plan on calling.
350    // TODO(#1533): Allow declaring calls to other applications instead of having to count them here.
351}
352
353/// A request to send a message.
354#[derive(Clone, Debug, Deserialize, Serialize, WitLoad, WitType)]
355#[cfg_attr(with_testing, derive(Eq, PartialEq, WitStore))]
356#[witty_specialize_with(Message = Vec<u8>)]
357pub struct SendMessageRequest<Message> {
358    /// The destination of the message.
359    pub destination: ChainId,
360    /// Whether the message is authenticated.
361    pub authenticated: bool,
362    /// Whether the message is tracked.
363    pub is_tracked: bool,
364    /// The grant resources forwarded with the message.
365    pub grant: Resources,
366    /// The message itself.
367    pub message: Message,
368}
369
370impl<Message> SendMessageRequest<Message>
371where
372    Message: Serialize,
373{
374    /// Serializes the internal `Message` type into raw bytes.
375    pub fn into_raw(self) -> SendMessageRequest<Vec<u8>> {
376        let message = bcs::to_bytes(&self.message).expect("Failed to serialize message");
377
378        SendMessageRequest {
379            destination: self.destination,
380            authenticated: self.authenticated,
381            is_tracked: self.is_tracked,
382            grant: self.grant,
383            message,
384        }
385    }
386}
387
388/// An error type for arithmetic errors.
389#[derive(Debug, Error)]
390#[allow(missing_docs)]
391pub enum ArithmeticError {
392    #[error("Number overflow")]
393    Overflow,
394    #[error("Number underflow")]
395    Underflow,
396}
397
398macro_rules! impl_wrapped_number {
399    ($name:ident, $wrapped:ident) => {
400        impl $name {
401            /// The zero value.
402            pub const ZERO: Self = Self(0);
403
404            /// The maximum value.
405            pub const MAX: Self = Self($wrapped::MAX);
406
407            /// Checked addition.
408            pub fn try_add(self, other: Self) -> Result<Self, ArithmeticError> {
409                let val = self
410                    .0
411                    .checked_add(other.0)
412                    .ok_or(ArithmeticError::Overflow)?;
413                Ok(Self(val))
414            }
415
416            /// Checked increment.
417            pub fn try_add_one(self) -> Result<Self, ArithmeticError> {
418                let val = self.0.checked_add(1).ok_or(ArithmeticError::Overflow)?;
419                Ok(Self(val))
420            }
421
422            /// Saturating addition.
423            pub const fn saturating_add(self, other: Self) -> Self {
424                let val = self.0.saturating_add(other.0);
425                Self(val)
426            }
427
428            /// Checked subtraction.
429            pub fn try_sub(self, other: Self) -> Result<Self, ArithmeticError> {
430                let val = self
431                    .0
432                    .checked_sub(other.0)
433                    .ok_or(ArithmeticError::Underflow)?;
434                Ok(Self(val))
435            }
436
437            /// Checked decrement.
438            pub fn try_sub_one(self) -> Result<Self, ArithmeticError> {
439                let val = self.0.checked_sub(1).ok_or(ArithmeticError::Underflow)?;
440                Ok(Self(val))
441            }
442
443            /// Saturating subtraction.
444            pub const fn saturating_sub(self, other: Self) -> Self {
445                let val = self.0.saturating_sub(other.0);
446                Self(val)
447            }
448
449            /// Returns the absolute difference between `self` and `other`.
450            pub fn abs_diff(self, other: Self) -> Self {
451                Self(self.0.abs_diff(other.0))
452            }
453
454            /// Checked in-place addition.
455            pub fn try_add_assign(&mut self, other: Self) -> Result<(), ArithmeticError> {
456                self.0 = self
457                    .0
458                    .checked_add(other.0)
459                    .ok_or(ArithmeticError::Overflow)?;
460                Ok(())
461            }
462
463            /// Checked in-place increment.
464            pub fn try_add_assign_one(&mut self) -> Result<(), ArithmeticError> {
465                self.0 = self.0.checked_add(1).ok_or(ArithmeticError::Overflow)?;
466                Ok(())
467            }
468
469            /// Saturating in-place addition.
470            pub const fn saturating_add_assign(&mut self, other: Self) {
471                self.0 = self.0.saturating_add(other.0);
472            }
473
474            /// Checked in-place subtraction.
475            pub fn try_sub_assign(&mut self, other: Self) -> Result<(), ArithmeticError> {
476                self.0 = self
477                    .0
478                    .checked_sub(other.0)
479                    .ok_or(ArithmeticError::Underflow)?;
480                Ok(())
481            }
482
483            /// Saturating division.
484            pub fn saturating_div(&self, other: $wrapped) -> Self {
485                Self(self.0.checked_div(other).unwrap_or($wrapped::MAX))
486            }
487
488            /// Saturating multiplication.
489            pub const fn saturating_mul(&self, other: $wrapped) -> Self {
490                Self(self.0.saturating_mul(other))
491            }
492
493            /// Checked multiplication.
494            pub fn try_mul(self, other: $wrapped) -> Result<Self, ArithmeticError> {
495                let val = self.0.checked_mul(other).ok_or(ArithmeticError::Overflow)?;
496                Ok(Self(val))
497            }
498
499            /// Checked in-place multiplication.
500            pub fn try_mul_assign(&mut self, other: $wrapped) -> Result<(), ArithmeticError> {
501                self.0 = self.0.checked_mul(other).ok_or(ArithmeticError::Overflow)?;
502                Ok(())
503            }
504        }
505
506        impl From<$name> for $wrapped {
507            fn from(value: $name) -> Self {
508                value.0
509            }
510        }
511
512        // Cannot directly create values for a wrapped type, except for testing.
513        #[cfg(with_testing)]
514        impl From<$wrapped> for $name {
515            fn from(value: $wrapped) -> Self {
516                Self(value)
517            }
518        }
519
520        #[cfg(with_testing)]
521        impl ops::Add for $name {
522            type Output = Self;
523
524            fn add(self, other: Self) -> Self {
525                Self(self.0 + other.0)
526            }
527        }
528
529        #[cfg(with_testing)]
530        impl ops::Sub for $name {
531            type Output = Self;
532
533            fn sub(self, other: Self) -> Self {
534                Self(self.0 - other.0)
535            }
536        }
537
538        #[cfg(with_testing)]
539        impl ops::Mul<$wrapped> for $name {
540            type Output = Self;
541
542            fn mul(self, other: $wrapped) -> Self {
543                Self(self.0 * other)
544            }
545        }
546    };
547}
548
549impl TryFrom<BlockHeight> for usize {
550    type Error = ArithmeticError;
551
552    fn try_from(height: BlockHeight) -> Result<usize, ArithmeticError> {
553        usize::try_from(height.0).map_err(|_| ArithmeticError::Overflow)
554    }
555}
556
557impl_wrapped_number!(Amount, u128);
558impl_wrapped_number!(BlockHeight, u64);
559impl_wrapped_number!(TimeDelta, u64);
560
561impl Display for Amount {
562    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
563        // Print the wrapped integer, padded with zeros to cover a digit before the decimal point.
564        let places = Amount::DECIMAL_PLACES as usize;
565        let min_digits = places + 1;
566        let decimals = format!("{:0min_digits$}", self.0);
567        let integer_part = &decimals[..(decimals.len() - places)];
568        let fractional_part = decimals[(decimals.len() - places)..].trim_end_matches('0');
569
570        // For now, we never trim non-zero digits so we don't lose any precision.
571        let precision = f.precision().unwrap_or(0).max(fractional_part.len());
572        let sign = if f.sign_plus() && self.0 > 0 { "+" } else { "" };
573        // The amount of padding: desired width minus sign, point and number of digits.
574        let pad_width = f.width().map_or(0, |w| {
575            w.saturating_sub(precision)
576                .saturating_sub(sign.len() + integer_part.len() + 1)
577        });
578        let left_pad = match f.align() {
579            None | Some(fmt::Alignment::Right) => pad_width,
580            Some(fmt::Alignment::Center) => pad_width / 2,
581            Some(fmt::Alignment::Left) => 0,
582        };
583
584        for _ in 0..left_pad {
585            write!(f, "{}", f.fill())?;
586        }
587        write!(f, "{sign}{integer_part}.{fractional_part:0<precision$}")?;
588        for _ in left_pad..pad_width {
589            write!(f, "{}", f.fill())?;
590        }
591        Ok(())
592    }
593}
594
595#[derive(Error, Debug)]
596#[allow(missing_docs)]
597pub enum ParseAmountError {
598    #[error("cannot parse amount")]
599    Parse,
600    #[error("cannot represent amount: number too high")]
601    TooHigh,
602    #[error("cannot represent amount: too many decimal places after the point")]
603    TooManyDigits,
604}
605
606impl FromStr for Amount {
607    type Err = ParseAmountError;
608
609    fn from_str(src: &str) -> Result<Self, Self::Err> {
610        let mut result: u128 = 0;
611        let mut decimals: Option<u8> = None;
612        let mut chars = src.trim().chars().peekable();
613        if chars.peek() == Some(&'+') {
614            chars.next();
615        }
616        for char in chars {
617            match char {
618                '_' => {}
619                '.' if decimals.is_some() => return Err(ParseAmountError::Parse),
620                '.' => decimals = Some(Amount::DECIMAL_PLACES),
621                char => {
622                    let digit = u128::from(char.to_digit(10).ok_or(ParseAmountError::Parse)?);
623                    if let Some(d) = &mut decimals {
624                        *d = d.checked_sub(1).ok_or(ParseAmountError::TooManyDigits)?;
625                    }
626                    result = result
627                        .checked_mul(10)
628                        .and_then(|r| r.checked_add(digit))
629                        .ok_or(ParseAmountError::TooHigh)?;
630                }
631            }
632        }
633        result = result
634            .checked_mul(10u128.pow(decimals.unwrap_or(Amount::DECIMAL_PLACES) as u32))
635            .ok_or(ParseAmountError::TooHigh)?;
636        Ok(Amount(result))
637    }
638}
639
640impl Display for BlockHeight {
641    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
642        self.0.fmt(f)
643    }
644}
645
646impl FromStr for BlockHeight {
647    type Err = ParseIntError;
648
649    fn from_str(src: &str) -> Result<Self, Self::Err> {
650        Ok(Self(u64::from_str(src)?))
651    }
652}
653
654impl Display for Round {
655    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
656        match self {
657            Round::Fast => write!(f, "fast round"),
658            Round::MultiLeader(r) => write!(f, "multi-leader round {}", r),
659            Round::SingleLeader(r) => write!(f, "single-leader round {}", r),
660            Round::Validator(r) => write!(f, "validator round {}", r),
661        }
662    }
663}
664
665impl Round {
666    /// Whether the round is a multi-leader round.
667    pub fn is_multi_leader(&self) -> bool {
668        matches!(self, Round::MultiLeader(_))
669    }
670
671    /// Returns the round number if this is a multi-leader round, `None` otherwise.
672    pub fn multi_leader(&self) -> Option<u32> {
673        match self {
674            Round::MultiLeader(number) => Some(*number),
675            _ => None,
676        }
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 using the system API.
994    #[graphql(default)]
995    #[debug(skip_if = Vec::is_empty)]
996    pub close_chain: Vec<ApplicationId>,
997    /// These applications are allowed to change the application permissions using the system API.
998    #[graphql(default)]
999    #[debug(skip_if = Vec::is_empty)]
1000    pub change_application_permissions: Vec<ApplicationId>,
1001    /// These applications are allowed to perform calls to services as oracles.
1002    #[graphql(default)]
1003    #[debug(skip_if = Option::is_none)]
1004    pub call_service_as_oracle: Option<Vec<ApplicationId>>,
1005    /// These applications are allowed to perform HTTP requests.
1006    #[graphql(default)]
1007    #[debug(skip_if = Option::is_none)]
1008    pub make_http_requests: Option<Vec<ApplicationId>>,
1009}
1010
1011impl ApplicationPermissions {
1012    /// Creates new `ApplicationPermissions` where the given application is the only one
1013    /// whose operations are allowed and mandatory, and it can also close the chain.
1014    pub fn new_single(app_id: ApplicationId) -> Self {
1015        Self {
1016            execute_operations: Some(vec![app_id]),
1017            mandatory_applications: vec![app_id],
1018            close_chain: vec![app_id],
1019            change_application_permissions: vec![app_id],
1020            call_service_as_oracle: Some(vec![app_id]),
1021            make_http_requests: Some(vec![app_id]),
1022        }
1023    }
1024
1025    /// Creates new `ApplicationPermissions` where the given applications are the only ones
1026    /// whose operations are allowed and mandatory, and they can also close the chain.
1027    pub fn new_multiple(app_ids: Vec<ApplicationId>) -> Self {
1028        Self {
1029            execute_operations: Some(app_ids.clone()),
1030            mandatory_applications: app_ids.clone(),
1031            close_chain: app_ids.clone(),
1032            change_application_permissions: app_ids.clone(),
1033            call_service_as_oracle: Some(app_ids.clone()),
1034            make_http_requests: Some(app_ids),
1035        }
1036    }
1037
1038    /// Returns whether operations with the given application ID are allowed on this chain.
1039    pub fn can_execute_operations(&self, app_id: &GenericApplicationId) -> bool {
1040        match (app_id, &self.execute_operations) {
1041            (_, None) => true,
1042            (GenericApplicationId::System, Some(_)) => false,
1043            (GenericApplicationId::User(app_id), Some(app_ids)) => app_ids.contains(app_id),
1044        }
1045    }
1046
1047    /// Returns whether the given application is allowed to close this chain.
1048    pub fn can_close_chain(&self, app_id: &ApplicationId) -> bool {
1049        self.close_chain.contains(app_id)
1050    }
1051
1052    /// Returns whether the given application is allowed to change the application
1053    /// permissions for this chain.
1054    pub fn can_change_application_permissions(&self, app_id: &ApplicationId) -> bool {
1055        self.change_application_permissions.contains(app_id)
1056    }
1057
1058    /// Returns whether the given application can call services.
1059    pub fn can_call_services(&self, app_id: &ApplicationId) -> bool {
1060        self.call_service_as_oracle
1061            .as_ref()
1062            .is_none_or(|app_ids| app_ids.contains(app_id))
1063    }
1064
1065    /// Returns whether the given application can make HTTP requests.
1066    pub fn can_make_http_requests(&self, app_id: &ApplicationId) -> bool {
1067        self.make_http_requests
1068            .as_ref()
1069            .is_none_or(|app_ids| app_ids.contains(app_id))
1070    }
1071}
1072
1073/// A record of a single oracle response.
1074#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, Allocative)]
1075pub enum OracleResponse {
1076    /// The response from a service query.
1077    Service(
1078        #[debug(with = "hex_debug")]
1079        #[serde(with = "serde_bytes")]
1080        Vec<u8>,
1081    ),
1082    /// The response from an HTTP request.
1083    Http(http::Response),
1084    /// A successful read or write of a blob.
1085    Blob(BlobId),
1086    /// An assertion oracle that passed.
1087    Assert,
1088    /// The block's validation round.
1089    Round(Option<u32>),
1090    /// An event was read.
1091    Event(
1092        EventId,
1093        #[debug(with = "hex_debug")]
1094        #[serde(with = "serde_bytes")]
1095        Vec<u8>,
1096    ),
1097    /// An event exists.
1098    EventExists(EventId),
1099}
1100
1101impl BcsHashable<'_> for OracleResponse {}
1102
1103/// Description of a user application.
1104#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Hash, Serialize, WitType, WitLoad, WitStore)]
1105pub struct ApplicationDescription {
1106    /// The unique ID of the bytecode to use for the application.
1107    pub module_id: ModuleId,
1108    /// The chain ID that created the application.
1109    pub creator_chain_id: ChainId,
1110    /// Height of the block that created this application.
1111    pub block_height: BlockHeight,
1112    /// The index of the application among those created in the same block.
1113    pub application_index: u32,
1114    /// The parameters of the application.
1115    #[serde(with = "serde_bytes")]
1116    #[debug(with = "hex_debug")]
1117    pub parameters: Vec<u8>,
1118    /// Required dependencies.
1119    pub required_application_ids: Vec<ApplicationId>,
1120}
1121
1122impl From<&ApplicationDescription> for ApplicationId {
1123    fn from(description: &ApplicationDescription) -> Self {
1124        let mut hash = CryptoHash::new(&BlobContent::new_application_description(description));
1125        if matches!(description.module_id.vm_runtime, VmRuntime::Evm) {
1126            hash.make_evm_compatible();
1127        }
1128        ApplicationId::new(hash)
1129    }
1130}
1131
1132impl BcsHashable<'_> for ApplicationDescription {}
1133
1134impl ApplicationDescription {
1135    /// Gets the serialized bytes for this `ApplicationDescription`.
1136    pub fn to_bytes(&self) -> Vec<u8> {
1137        bcs::to_bytes(self).expect("Serializing blob bytes should not fail!")
1138    }
1139
1140    /// Gets the `BlobId` of the contract
1141    pub fn contract_bytecode_blob_id(&self) -> BlobId {
1142        self.module_id.contract_bytecode_blob_id()
1143    }
1144
1145    /// Gets the `BlobId` of the service
1146    pub fn service_bytecode_blob_id(&self) -> BlobId {
1147        self.module_id.service_bytecode_blob_id()
1148    }
1149}
1150
1151/// A WebAssembly module's bytecode.
1152#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, WitType, WitLoad, WitStore)]
1153pub struct Bytecode {
1154    /// Bytes of the bytecode.
1155    #[serde(with = "serde_bytes")]
1156    #[debug(with = "hex_debug")]
1157    pub bytes: Vec<u8>,
1158}
1159
1160impl Bytecode {
1161    /// Creates a new [`Bytecode`] instance using the provided `bytes`.
1162    pub fn new(bytes: Vec<u8>) -> Self {
1163        Bytecode { bytes }
1164    }
1165
1166    /// Load bytecode from a Wasm module file.
1167    pub fn load_from_file(path: impl AsRef<std::path::Path>) -> std::io::Result<Self> {
1168        let path = path.as_ref();
1169        let bytes = fs::read(path).map_err(|error| {
1170            std::io::Error::new(error.kind(), format!("{}: {error}", path.display()))
1171        })?;
1172        Ok(Bytecode { bytes })
1173    }
1174
1175    /// Compresses the [`Bytecode`] into a [`CompressedBytecode`].
1176    #[cfg(not(target_arch = "wasm32"))]
1177    pub fn compress(&self) -> CompressedBytecode {
1178        #[cfg(with_metrics)]
1179        let _compression_latency = metrics::BYTECODE_COMPRESSION_LATENCY.measure_latency();
1180        let compressed_bytes_vec = zstd::stream::encode_all(&*self.bytes, 19)
1181            .expect("Compressing bytes in memory should not fail");
1182
1183        CompressedBytecode {
1184            compressed_bytes: Arc::new(compressed_bytes_vec.into_boxed_slice()),
1185        }
1186    }
1187
1188    /// Compresses the [`Bytecode`] into a [`CompressedBytecode`].
1189    #[cfg(target_arch = "wasm32")]
1190    pub fn compress(&self) -> CompressedBytecode {
1191        use ruzstd::encoding::{CompressionLevel, FrameCompressor};
1192
1193        #[cfg(with_metrics)]
1194        let _compression_latency = metrics::BYTECODE_COMPRESSION_LATENCY.measure_latency();
1195
1196        let mut compressed_bytes_vec = Vec::new();
1197        let mut compressor = FrameCompressor::new(CompressionLevel::Fastest);
1198        compressor.set_source(&*self.bytes);
1199        compressor.set_drain(&mut compressed_bytes_vec);
1200        compressor.compress();
1201
1202        CompressedBytecode {
1203            compressed_bytes: Arc::new(compressed_bytes_vec.into_boxed_slice()),
1204        }
1205    }
1206}
1207
1208impl AsRef<[u8]> for Bytecode {
1209    fn as_ref(&self) -> &[u8] {
1210        self.bytes.as_ref()
1211    }
1212}
1213
1214/// A type for errors happening during decompression.
1215#[derive(Error, Debug)]
1216pub enum DecompressionError {
1217    /// Compressed bytecode is invalid, and could not be decompressed.
1218    #[error("Bytecode could not be decompressed: {0}")]
1219    InvalidCompressedBytecode(#[from] io::Error),
1220}
1221
1222/// A compressed module bytecode (WebAssembly or EVM).
1223#[serde_as]
1224#[derive(Clone, Debug, Deserialize, Hash, Serialize, WitType, WitStore)]
1225#[cfg_attr(with_testing, derive(Eq, PartialEq))]
1226pub struct CompressedBytecode {
1227    /// Compressed bytes of the bytecode.
1228    #[serde_as(as = "Arc<Bytes>")]
1229    #[debug(skip)]
1230    pub compressed_bytes: Arc<Box<[u8]>>,
1231}
1232
1233#[cfg(not(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        let mut decoder = zstd::stream::Decoder::new(compressed_bytes)?;
1241        let limit = usize::try_from(limit).unwrap_or(usize::MAX);
1242        let mut writer = LimitedWriter::new(io::sink(), limit);
1243        match io::copy(&mut decoder, &mut writer) {
1244            Ok(_) => Ok(true),
1245            Err(error) => {
1246                error.downcast::<LimitedWriterError>()?;
1247                Ok(false)
1248            }
1249        }
1250    }
1251
1252    /// Decompresses a [`CompressedBytecode`] into a [`Bytecode`].
1253    pub fn decompress(&self) -> Result<Bytecode, DecompressionError> {
1254        #[cfg(with_metrics)]
1255        let _decompression_latency = metrics::BYTECODE_DECOMPRESSION_LATENCY.measure_latency();
1256        let bytes = zstd::stream::decode_all(&**self.compressed_bytes)?;
1257
1258        #[cfg(with_metrics)]
1259        metrics::BYTECODE_DECOMPRESSED_SIZE_BYTES
1260            .with_label_values(&[])
1261            .observe(bytes.len() as f64);
1262
1263        Ok(Bytecode { bytes })
1264    }
1265}
1266
1267#[cfg(target_arch = "wasm32")]
1268impl CompressedBytecode {
1269    /// Returns `true` if the decompressed size does not exceed the limit.
1270    pub fn decompressed_size_at_most(
1271        compressed_bytes: &[u8],
1272        limit: u64,
1273    ) -> Result<bool, DecompressionError> {
1274        use ruzstd::decoding::StreamingDecoder;
1275        let limit = usize::try_from(limit).unwrap_or(usize::MAX);
1276        let mut writer = LimitedWriter::new(io::sink(), limit);
1277        let mut decoder = StreamingDecoder::new(compressed_bytes).map_err(io::Error::other)?;
1278
1279        // TODO(#2710): Decode multiple frames, if present
1280        match io::copy(&mut decoder, &mut writer) {
1281            Ok(_) => Ok(true),
1282            Err(error) => {
1283                error.downcast::<LimitedWriterError>()?;
1284                Ok(false)
1285            }
1286        }
1287    }
1288
1289    /// Decompresses a [`CompressedBytecode`] into a [`Bytecode`].
1290    pub fn decompress(&self) -> Result<Bytecode, DecompressionError> {
1291        use ruzstd::{decoding::StreamingDecoder, io::Read};
1292
1293        #[cfg(with_metrics)]
1294        let _decompression_latency = BYTECODE_DECOMPRESSION_LATENCY.measure_latency();
1295
1296        let compressed_bytes = &*self.compressed_bytes;
1297        let mut bytes = Vec::new();
1298        let mut decoder = StreamingDecoder::new(&**compressed_bytes).map_err(io::Error::other)?;
1299
1300        // TODO(#2710): Decode multiple frames, if present
1301        while !decoder.get_ref().is_empty() {
1302            decoder
1303                .read_to_end(&mut bytes)
1304                .expect("Reading from a slice in memory should not result in I/O errors");
1305        }
1306
1307        #[cfg(with_metrics)]
1308        BYTECODE_DECOMPRESSED_SIZE_BYTES
1309            .with_label_values(&[])
1310            .observe(bytes.len() as f64);
1311
1312        Ok(Bytecode { bytes })
1313    }
1314}
1315
1316impl BcsHashable<'_> for BlobContent {}
1317
1318/// A blob of binary data.
1319#[serde_as]
1320#[derive(Hash, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Allocative)]
1321pub struct BlobContent {
1322    /// The type of data represented by the bytes.
1323    blob_type: BlobType,
1324    /// The binary data.
1325    #[debug(skip)]
1326    #[serde_as(as = "Arc<Bytes>")]
1327    bytes: Arc<Box<[u8]>>,
1328}
1329
1330impl BlobContent {
1331    /// Creates a new [`BlobContent`] from the provided bytes and [`BlobId`].
1332    pub fn new(blob_type: BlobType, bytes: impl Into<Box<[u8]>>) -> Self {
1333        let bytes = bytes.into();
1334        BlobContent {
1335            blob_type,
1336            bytes: Arc::new(bytes),
1337        }
1338    }
1339
1340    /// Creates a new data [`BlobContent`] from the provided bytes.
1341    pub fn new_data(bytes: impl Into<Box<[u8]>>) -> Self {
1342        BlobContent::new(BlobType::Data, bytes)
1343    }
1344
1345    /// Creates a new contract bytecode [`BlobContent`] from the provided bytes.
1346    pub fn new_contract_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1347        BlobContent {
1348            blob_type: BlobType::ContractBytecode,
1349            bytes: compressed_bytecode.compressed_bytes,
1350        }
1351    }
1352
1353    /// Creates a new contract bytecode [`BlobContent`] from the provided bytes.
1354    pub fn new_evm_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1355        BlobContent {
1356            blob_type: BlobType::EvmBytecode,
1357            bytes: compressed_bytecode.compressed_bytes,
1358        }
1359    }
1360
1361    /// Creates a new service bytecode [`BlobContent`] from the provided bytes.
1362    pub fn new_service_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1363        BlobContent {
1364            blob_type: BlobType::ServiceBytecode,
1365            bytes: compressed_bytecode.compressed_bytes,
1366        }
1367    }
1368
1369    /// Creates a new application description [`BlobContent`] from a [`ApplicationDescription`].
1370    pub fn new_application_description(application_description: &ApplicationDescription) -> Self {
1371        let bytes = application_description.to_bytes();
1372        BlobContent::new(BlobType::ApplicationDescription, bytes)
1373    }
1374
1375    /// Creates a new committee [`BlobContent`] from the provided serialized committee.
1376    pub fn new_committee(committee: impl Into<Box<[u8]>>) -> Self {
1377        BlobContent::new(BlobType::Committee, committee)
1378    }
1379
1380    /// Creates a new chain description [`BlobContent`] from a [`ChainDescription`].
1381    pub fn new_chain_description(chain_description: &ChainDescription) -> Self {
1382        let bytes = bcs::to_bytes(&chain_description)
1383            .expect("Serializing a ChainDescription should not fail!");
1384        BlobContent::new(BlobType::ChainDescription, bytes)
1385    }
1386
1387    /// Gets a reference to the blob's bytes.
1388    pub fn bytes(&self) -> &[u8] {
1389        &self.bytes
1390    }
1391
1392    /// Converts a `BlobContent` into `Vec<u8>` without cloning if possible.
1393    pub fn into_vec_or_clone(self) -> Vec<u8> {
1394        let bytes = Arc::unwrap_or_clone(self.bytes);
1395        bytes.into_vec()
1396    }
1397
1398    /// Gets the `Arc<Box<[u8]>>` directly without cloning.
1399    pub fn into_arc_bytes(self) -> Arc<Box<[u8]>> {
1400        self.bytes
1401    }
1402
1403    /// Returns the type of data represented by this blob's bytes.
1404    pub fn blob_type(&self) -> BlobType {
1405        self.blob_type
1406    }
1407}
1408
1409impl From<Blob> for BlobContent {
1410    fn from(blob: Blob) -> BlobContent {
1411        blob.content
1412    }
1413}
1414
1415/// A blob of binary data, with its hash.
1416#[derive(Debug, Hash, PartialEq, Eq, Clone, Allocative)]
1417pub struct Blob {
1418    /// ID of the blob.
1419    hash: CryptoHash,
1420    /// A blob of binary data.
1421    content: BlobContent,
1422}
1423
1424impl Blob {
1425    /// Computes the hash and returns the hashed blob for the given content.
1426    pub fn new(content: BlobContent) -> Self {
1427        let mut hash = CryptoHash::new(&content);
1428        if matches!(content.blob_type, BlobType::ApplicationDescription) {
1429            let application_description = bcs::from_bytes::<ApplicationDescription>(&content.bytes)
1430                .expect("to obtain an application description");
1431            if matches!(application_description.module_id.vm_runtime, VmRuntime::Evm) {
1432                hash.make_evm_compatible();
1433            }
1434        }
1435        Blob { hash, content }
1436    }
1437
1438    /// Creates a blob from ud and content without checks
1439    pub fn new_with_hash_unchecked(blob_id: BlobId, content: BlobContent) -> Self {
1440        Blob {
1441            hash: blob_id.hash,
1442            content,
1443        }
1444    }
1445
1446    /// Creates a blob without checking that the hash actually matches the content.
1447    pub fn new_with_id_unchecked(blob_id: BlobId, bytes: impl Into<Box<[u8]>>) -> Self {
1448        let bytes = bytes.into();
1449        Blob {
1450            hash: blob_id.hash,
1451            content: BlobContent {
1452                blob_type: blob_id.blob_type,
1453                bytes: Arc::new(bytes),
1454            },
1455        }
1456    }
1457
1458    /// Creates a new data [`Blob`] from the provided bytes.
1459    pub fn new_data(bytes: impl Into<Box<[u8]>>) -> Self {
1460        Blob::new(BlobContent::new_data(bytes))
1461    }
1462
1463    /// Creates a new contract bytecode [`Blob`] from the provided bytes.
1464    pub fn new_contract_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1465        Blob::new(BlobContent::new_contract_bytecode(compressed_bytecode))
1466    }
1467
1468    /// Creates a new contract bytecode [`BlobContent`] from the provided bytes.
1469    pub fn new_evm_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1470        Blob::new(BlobContent::new_evm_bytecode(compressed_bytecode))
1471    }
1472
1473    /// Creates a new service bytecode [`Blob`] from the provided bytes.
1474    pub fn new_service_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1475        Blob::new(BlobContent::new_service_bytecode(compressed_bytecode))
1476    }
1477
1478    /// Creates a new application description [`Blob`] from the provided description.
1479    pub fn new_application_description(application_description: &ApplicationDescription) -> Self {
1480        Blob::new(BlobContent::new_application_description(
1481            application_description,
1482        ))
1483    }
1484
1485    /// Creates a new committee [`Blob`] from the provided bytes.
1486    pub fn new_committee(committee: impl Into<Box<[u8]>>) -> Self {
1487        Blob::new(BlobContent::new_committee(committee))
1488    }
1489
1490    /// Creates a new chain description [`Blob`] from a [`ChainDescription`].
1491    pub fn new_chain_description(chain_description: &ChainDescription) -> Self {
1492        Blob::new(BlobContent::new_chain_description(chain_description))
1493    }
1494
1495    /// A content-addressed blob ID i.e. the hash of the `Blob`.
1496    pub fn id(&self) -> BlobId {
1497        BlobId {
1498            hash: self.hash,
1499            blob_type: self.content.blob_type,
1500        }
1501    }
1502
1503    /// Returns a reference to the inner `BlobContent`, without the hash.
1504    pub fn content(&self) -> &BlobContent {
1505        &self.content
1506    }
1507
1508    /// Moves ownership of the blob of binary data
1509    pub fn into_content(self) -> BlobContent {
1510        self.content
1511    }
1512
1513    /// Gets a reference to the inner blob's bytes.
1514    pub fn bytes(&self) -> &[u8] {
1515        self.content.bytes()
1516    }
1517
1518    /// Loads data blob from a file.
1519    pub fn load_data_blob_from_file(path: impl AsRef<Path>) -> io::Result<Self> {
1520        Ok(Self::new_data(fs::read(path)?))
1521    }
1522
1523    /// Returns whether the blob is of [`BlobType::Committee`] variant.
1524    pub fn is_committee_blob(&self) -> bool {
1525        self.content().blob_type().is_committee_blob()
1526    }
1527}
1528
1529impl Serialize for Blob {
1530    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1531    where
1532        S: Serializer,
1533    {
1534        if serializer.is_human_readable() {
1535            let blob_bytes = bcs::to_bytes(&self.content).map_err(serde::ser::Error::custom)?;
1536            serializer.serialize_str(&hex::encode(blob_bytes))
1537        } else {
1538            BlobContent::serialize(self.content(), serializer)
1539        }
1540    }
1541}
1542
1543impl<'a> Deserialize<'a> for Blob {
1544    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1545    where
1546        D: Deserializer<'a>,
1547    {
1548        if deserializer.is_human_readable() {
1549            let s = String::deserialize(deserializer)?;
1550            let content_bytes = hex::decode(s).map_err(serde::de::Error::custom)?;
1551            let content: BlobContent =
1552                bcs::from_bytes(&content_bytes).map_err(serde::de::Error::custom)?;
1553
1554            Ok(Blob::new(content))
1555        } else {
1556            let content = BlobContent::deserialize(deserializer)?;
1557            Ok(Blob::new(content))
1558        }
1559    }
1560}
1561
1562impl BcsHashable<'_> for Blob {}
1563
1564/// An event recorded in a block.
1565#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, SimpleObject, Allocative)]
1566pub struct Event {
1567    /// The ID of the stream this event belongs to.
1568    pub stream_id: StreamId,
1569    /// The event index, i.e. the number of events in the stream before this one.
1570    pub index: u32,
1571    /// The payload data.
1572    #[debug(with = "hex_debug")]
1573    #[serde(with = "serde_bytes")]
1574    pub value: Vec<u8>,
1575}
1576
1577impl Event {
1578    /// Returns the ID of this event record, given the publisher chain ID.
1579    pub fn id(&self, chain_id: ChainId) -> EventId {
1580        EventId {
1581            chain_id,
1582            stream_id: self.stream_id.clone(),
1583            index: self.index,
1584        }
1585    }
1586}
1587
1588/// An update for a stream with new events.
1589#[derive(Clone, Debug, Serialize, Deserialize, WitType, WitLoad, WitStore)]
1590pub struct StreamUpdate {
1591    /// The publishing chain.
1592    pub chain_id: ChainId,
1593    /// The stream ID.
1594    pub stream_id: StreamId,
1595    /// The lowest index of a new event. See [`StreamUpdate::new_indices`].
1596    pub previous_index: u32,
1597    /// The index of the next event, i.e. the lowest for which no event is known yet.
1598    pub next_index: u32,
1599}
1600
1601impl StreamUpdate {
1602    /// Returns the indices of all new events in the stream.
1603    pub fn new_indices(&self) -> impl Iterator<Item = u32> {
1604        self.previous_index..self.next_index
1605    }
1606}
1607
1608impl BcsHashable<'_> for Event {}
1609
1610/// Policies for automatically handling incoming messages.
1611#[derive(
1612    Clone, Debug, Default, serde::Serialize, serde::Deserialize, async_graphql::SimpleObject,
1613)]
1614pub struct MessagePolicy {
1615    /// The blanket policy applied to all messages.
1616    pub blanket: BlanketMessagePolicy,
1617    /// A collection of chains which restrict the origin of messages to be
1618    /// accepted. `Option::None` means that messages from all chains are accepted. An empty
1619    /// `HashSet` denotes that messages from no chains are accepted.
1620    pub restrict_chain_ids_to: Option<HashSet<ChainId>>,
1621    /// A collection of applications: If `Some`, only bundles with at least one message by any
1622    /// of these applications will be accepted.
1623    pub reject_message_bundles_without_application_ids: Option<HashSet<GenericApplicationId>>,
1624    /// A collection of applications: If `Some`, only bundles all of whose messages are by these
1625    /// applications will be accepted.
1626    pub reject_message_bundles_with_other_application_ids: Option<HashSet<GenericApplicationId>>,
1627    /// A collection of applications: If `Some`, only event streams from those
1628    /// applications will be processed.
1629    pub process_events_from_application_ids: Option<HashSet<GenericApplicationId>>,
1630}
1631
1632/// A blanket policy to apply to all messages by default.
1633#[derive(
1634    Default,
1635    Copy,
1636    Clone,
1637    Debug,
1638    PartialEq,
1639    Eq,
1640    serde::Serialize,
1641    serde::Deserialize,
1642    async_graphql::Enum,
1643)]
1644#[cfg_attr(web, derive(tsify::Tsify), tsify(from_wasm_abi, into_wasm_abi))]
1645#[cfg_attr(any(web, not(target_arch = "wasm32")), derive(clap::ValueEnum))]
1646pub enum BlanketMessagePolicy {
1647    /// Automatically accept all incoming messages. Reject them only if execution fails.
1648    #[default]
1649    Accept,
1650    /// Automatically reject tracked messages, ignore or skip untracked messages, but accept
1651    /// protected ones.
1652    Reject,
1653    /// Don't include any messages in blocks, and don't make any decision whether to accept or
1654    /// reject.
1655    Ignore,
1656}
1657
1658impl MessagePolicy {
1659    /// Constructs a new `MessagePolicy`.
1660    pub fn new(
1661        blanket: BlanketMessagePolicy,
1662        restrict_chain_ids_to: Option<HashSet<ChainId>>,
1663        reject_message_bundles_without_application_ids: Option<HashSet<GenericApplicationId>>,
1664        reject_message_bundles_with_other_application_ids: Option<HashSet<GenericApplicationId>>,
1665        process_events_from_application_ids: Option<HashSet<GenericApplicationId>>,
1666    ) -> Self {
1667        Self {
1668            blanket,
1669            restrict_chain_ids_to,
1670            reject_message_bundles_without_application_ids,
1671            reject_message_bundles_with_other_application_ids,
1672            process_events_from_application_ids,
1673        }
1674    }
1675
1676    /// Constructs a new `MessagePolicy` that accepts all messages.
1677    #[cfg(with_testing)]
1678    pub fn new_accept_all() -> Self {
1679        Self {
1680            blanket: BlanketMessagePolicy::Accept,
1681            restrict_chain_ids_to: None,
1682            reject_message_bundles_without_application_ids: None,
1683            reject_message_bundles_with_other_application_ids: None,
1684            process_events_from_application_ids: None,
1685        }
1686    }
1687
1688    /// Returns `true` if the blanket policy is to ignore messages.
1689    #[instrument(level = "trace", skip(self))]
1690    pub fn is_ignore(&self) -> bool {
1691        matches!(self.blanket, BlanketMessagePolicy::Ignore)
1692    }
1693
1694    /// Returns `true` if the blanket policy is to reject messages.
1695    #[instrument(level = "trace", skip(self))]
1696    pub fn is_reject(&self) -> bool {
1697        matches!(self.blanket, BlanketMessagePolicy::Reject)
1698    }
1699}
1700
1701doc_scalar!(Bytecode, "A WebAssembly module's bytecode");
1702doc_scalar!(Amount, "A non-negative amount of tokens.");
1703doc_scalar!(
1704    Epoch,
1705    "A number identifying the configuration of the chain (aka the committee)"
1706);
1707doc_scalar!(BlockHeight, "A block height to identify blocks in a chain");
1708doc_scalar!(
1709    Timestamp,
1710    "A timestamp, in microseconds since the Unix epoch"
1711);
1712doc_scalar!(TimeDelta, "A duration in microseconds");
1713doc_scalar!(
1714    Round,
1715    "A number to identify successive attempts to decide a value in a consensus protocol."
1716);
1717doc_scalar!(
1718    ChainDescription,
1719    "Initial chain configuration and chain origin."
1720);
1721doc_scalar!(OracleResponse, "A record of a single oracle response.");
1722doc_scalar!(BlobContent, "A blob of binary data.");
1723doc_scalar!(
1724    Blob,
1725    "A blob of binary data, with its content-addressed blob ID."
1726);
1727doc_scalar!(ApplicationDescription, "Description of a user application");
1728
1729#[cfg(with_metrics)]
1730mod metrics {
1731    use std::sync::LazyLock;
1732
1733    use prometheus::HistogramVec;
1734
1735    use crate::prometheus_util::{
1736        exponential_bucket_interval, exponential_bucket_latencies, register_histogram_vec,
1737    };
1738
1739    /// The time it takes to compress a bytecode.
1740    pub static BYTECODE_COMPRESSION_LATENCY: LazyLock<HistogramVec> = LazyLock::new(|| {
1741        register_histogram_vec(
1742            "bytecode_compression_latency",
1743            "Bytecode compression latency",
1744            &[],
1745            exponential_bucket_latencies(10.0),
1746        )
1747    });
1748
1749    /// The time it takes to decompress a bytecode.
1750    pub static BYTECODE_DECOMPRESSION_LATENCY: LazyLock<HistogramVec> = LazyLock::new(|| {
1751        register_histogram_vec(
1752            "bytecode_decompression_latency",
1753            "Bytecode decompression latency",
1754            &[],
1755            exponential_bucket_latencies(10.0),
1756        )
1757    });
1758
1759    pub static BYTECODE_DECOMPRESSED_SIZE_BYTES: LazyLock<HistogramVec> = LazyLock::new(|| {
1760        register_histogram_vec(
1761            "wasm_bytecode_decompressed_size_bytes",
1762            "Decompressed size in bytes of WASM bytecodes stored on-chain",
1763            &[],
1764            exponential_bucket_interval(10_000.0, 100_000_000.0),
1765        )
1766    });
1767}
1768
1769#[cfg(test)]
1770mod tests {
1771    use std::str::FromStr;
1772
1773    use super::{Amount, BlobContent};
1774    use crate::identifiers::BlobType;
1775
1776    #[test]
1777    fn display_amount() {
1778        assert_eq!("1.", Amount::ONE.to_string());
1779        assert_eq!("1.", Amount::from_str("1.").unwrap().to_string());
1780        assert_eq!(
1781            Amount(10_000_000_000_000_000_000),
1782            Amount::from_str("10").unwrap()
1783        );
1784        assert_eq!("10.", Amount(10_000_000_000_000_000_000).to_string());
1785        assert_eq!(
1786            "1001.3",
1787            (Amount::from_str("1.1")
1788                .unwrap()
1789                .saturating_add(Amount::from_str("1_000.2").unwrap()))
1790            .to_string()
1791        );
1792        assert_eq!(
1793            "   1.00000000000000000000",
1794            format!("{:25.20}", Amount::ONE)
1795        );
1796        assert_eq!(
1797            "~+12.34~~",
1798            format!("{:~^+9.1}", Amount::from_str("12.34").unwrap())
1799        );
1800    }
1801
1802    #[test]
1803    fn blob_content_serialization_deserialization() {
1804        let test_data = b"Hello, world!".as_slice();
1805        let original_blob = BlobContent::new(BlobType::Data, test_data);
1806
1807        let serialized = bcs::to_bytes(&original_blob).expect("Failed to serialize BlobContent");
1808        let deserialized: BlobContent =
1809            bcs::from_bytes(&serialized).expect("Failed to deserialize BlobContent");
1810        assert_eq!(original_blob, deserialized);
1811
1812        let serialized =
1813            serde_json::to_vec(&original_blob).expect("Failed to serialize BlobContent");
1814        let deserialized: BlobContent =
1815            serde_json::from_slice(&serialized).expect("Failed to deserialize BlobContent");
1816        assert_eq!(original_blob, deserialized);
1817    }
1818
1819    #[test]
1820    fn blob_content_hash_consistency() {
1821        let test_data = b"Hello, world!";
1822        let blob1 = BlobContent::new(BlobType::Data, test_data.as_slice());
1823        let blob2 = BlobContent::new(BlobType::Data, Vec::from(test_data.as_slice()));
1824
1825        // Both should have same hash since they contain the same data
1826        let hash1 = crate::crypto::CryptoHash::new(&blob1);
1827        let hash2 = crate::crypto::CryptoHash::new(&blob2);
1828
1829        assert_eq!(hash1, hash2, "Hashes should be equal for same content");
1830        assert_eq!(blob1.bytes(), blob2.bytes(), "Byte content should be equal");
1831    }
1832}