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;
9#[cfg(with_metrics)]
10use std::sync::LazyLock;
11use std::{
12    fmt::{self, Display},
13    fs,
14    hash::Hash,
15    io, iter,
16    num::ParseIntError,
17    path::Path,
18    str::FromStr,
19};
20
21use async_graphql::{InputObject, SimpleObject};
22use custom_debug_derive::Debug;
23use linera_witty::{WitLoad, WitStore, WitType};
24#[cfg(with_metrics)]
25use prometheus::HistogramVec;
26use serde::{Deserialize, Deserializer, Serialize, Serializer};
27use thiserror::Error;
28
29#[cfg(with_metrics)]
30use crate::prometheus_util::{
31    exponential_bucket_latencies, register_histogram_vec, MeasureLatency,
32};
33use crate::{
34    crypto::{BcsHashable, CryptoHash},
35    doc_scalar, hex_debug, http,
36    identifiers::{
37        ApplicationId, BlobId, BlobType, ChainId, Destination, EventId, GenericApplicationId,
38        ModuleId, StreamId,
39    },
40    limited_writer::{LimitedWriter, LimitedWriterError},
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
58#[derive(Serialize, Deserialize)]
59#[serde(rename = "Amount")]
60struct AmountString(String);
61
62#[derive(Serialize, Deserialize)]
63#[serde(rename = "Amount")]
64struct AmountU128(u128);
65
66impl Serialize for Amount {
67    fn serialize<S: serde::ser::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
68        if serializer.is_human_readable() {
69            AmountString(self.to_string()).serialize(serializer)
70        } else {
71            AmountU128(self.0).serialize(serializer)
72        }
73    }
74}
75
76impl<'de> Deserialize<'de> for Amount {
77    fn deserialize<D: serde::de::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
78        if deserializer.is_human_readable() {
79            let AmountString(s) = AmountString::deserialize(deserializer)?;
80            s.parse().map_err(serde::de::Error::custom)
81        } else {
82            Ok(Amount(AmountU128::deserialize(deserializer)?.0))
83        }
84    }
85}
86
87/// A block height to identify blocks in a chain.
88#[derive(
89    Eq,
90    PartialEq,
91    Ord,
92    PartialOrd,
93    Copy,
94    Clone,
95    Hash,
96    Default,
97    Debug,
98    Serialize,
99    Deserialize,
100    WitType,
101    WitLoad,
102    WitStore,
103)]
104#[cfg_attr(with_testing, derive(test_strategy::Arbitrary))]
105pub struct BlockHeight(pub u64);
106
107/// An identifier for successive attempts to decide a value in a consensus protocol.
108#[derive(
109    Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Hash, Default, Debug, Serialize, Deserialize,
110)]
111pub enum Round {
112    /// The initial fast round.
113    #[default]
114    Fast,
115    /// The N-th multi-leader round.
116    MultiLeader(u32),
117    /// The N-th single-leader round.
118    SingleLeader(u32),
119    /// The N-th round where the validators rotate as leaders.
120    Validator(u32),
121}
122
123/// A duration in microseconds.
124#[derive(
125    Eq,
126    PartialEq,
127    Ord,
128    PartialOrd,
129    Copy,
130    Clone,
131    Hash,
132    Default,
133    Debug,
134    Serialize,
135    Deserialize,
136    WitType,
137    WitLoad,
138    WitStore,
139)]
140pub struct TimeDelta(u64);
141
142impl TimeDelta {
143    /// Returns the given number of microseconds as a [`TimeDelta`].
144    pub fn from_micros(micros: u64) -> Self {
145        TimeDelta(micros)
146    }
147
148    /// Returns the given number of milliseconds as a [`TimeDelta`].
149    pub fn from_millis(millis: u64) -> Self {
150        TimeDelta(millis.saturating_mul(1_000))
151    }
152
153    /// Returns the given number of seconds as a [`TimeDelta`].
154    pub fn from_secs(secs: u64) -> Self {
155        TimeDelta(secs.saturating_mul(1_000_000))
156    }
157
158    /// Returns the given duration, rounded to the nearest microsecond and capped to the maximum
159    /// [`TimeDelta`] value.
160    pub fn from_duration(duration: Duration) -> Self {
161        TimeDelta::from_micros(u64::try_from(duration.as_micros()).unwrap_or(u64::MAX))
162    }
163
164    /// Returns this [`TimeDelta`] as a number of microseconds.
165    pub fn as_micros(&self) -> u64 {
166        self.0
167    }
168
169    /// Returns this [`TimeDelta`] as a [`Duration`].
170    pub fn as_duration(&self) -> Duration {
171        Duration::from_micros(self.as_micros())
172    }
173}
174
175/// A timestamp, in microseconds since the Unix epoch.
176#[derive(
177    Eq,
178    PartialEq,
179    Ord,
180    PartialOrd,
181    Copy,
182    Clone,
183    Hash,
184    Default,
185    Debug,
186    Serialize,
187    Deserialize,
188    WitType,
189    WitLoad,
190    WitStore,
191)]
192pub struct Timestamp(u64);
193
194impl Timestamp {
195    /// Returns the current time according to the system clock.
196    pub fn now() -> Timestamp {
197        Timestamp(
198            SystemTime::UNIX_EPOCH
199                .elapsed()
200                .expect("system time should be after Unix epoch")
201                .as_micros()
202                .try_into()
203                .unwrap_or(u64::MAX),
204        )
205    }
206
207    /// Returns the number of microseconds since the Unix epoch.
208    pub fn micros(&self) -> u64 {
209        self.0
210    }
211
212    /// Returns the [`TimeDelta`] between `other` and `self`, or zero if `other` is not earlier
213    /// than `self`.
214    pub fn delta_since(&self, other: Timestamp) -> TimeDelta {
215        TimeDelta::from_micros(self.0.saturating_sub(other.0))
216    }
217
218    /// Returns the [`Duration`] between `other` and `self`, or zero if `other` is not
219    /// earlier than `self`.
220    pub fn duration_since(&self, other: Timestamp) -> Duration {
221        Duration::from_micros(self.0.saturating_sub(other.0))
222    }
223
224    /// Returns the timestamp that is `duration` later than `self`.
225    pub fn saturating_add(&self, duration: TimeDelta) -> Timestamp {
226        Timestamp(self.0.saturating_add(duration.0))
227    }
228
229    /// Returns the timestamp that is `duration` earlier than `self`.
230    pub fn saturating_sub(&self, duration: TimeDelta) -> Timestamp {
231        Timestamp(self.0.saturating_sub(duration.0))
232    }
233
234    /// Returns a timestamp `micros` microseconds later than `self`, or the highest possible value
235    /// if it would overflow.
236    pub fn saturating_add_micros(&self, micros: u64) -> Timestamp {
237        Timestamp(self.0.saturating_add(micros))
238    }
239
240    /// Returns a timestamp `micros` microseconds earlier than `self`, or the lowest possible value
241    /// if it would underflow.
242    pub fn saturating_sub_micros(&self, micros: u64) -> Timestamp {
243        Timestamp(self.0.saturating_sub(micros))
244    }
245}
246
247impl From<u64> for Timestamp {
248    fn from(t: u64) -> Timestamp {
249        Timestamp(t)
250    }
251}
252
253impl Display for Timestamp {
254    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
255        if let Some(date_time) = chrono::DateTime::from_timestamp(
256            (self.0 / 1_000_000) as i64,
257            ((self.0 % 1_000_000) * 1_000) as u32,
258        ) {
259            return date_time.naive_utc().fmt(f);
260        }
261        self.0.fmt(f)
262    }
263}
264
265/// Resources that an application may spend during the execution of transaction or an
266/// application call.
267#[derive(
268    Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize, WitLoad, WitStore, WitType,
269)]
270pub struct Resources {
271    /// An amount of execution fuel.
272    pub fuel: u64,
273    /// A number of read operations to be executed.
274    pub read_operations: u32,
275    /// A number of write operations to be executed.
276    pub write_operations: u32,
277    /// A number of bytes to read.
278    pub bytes_to_read: u32,
279    /// A number of bytes to write.
280    pub bytes_to_write: u32,
281    /// A number of blobs to read.
282    pub blobs_to_read: u32,
283    /// A number of blobs to publish.
284    pub blobs_to_publish: u32,
285    /// A number of blob bytes to read.
286    pub blob_bytes_to_read: u32,
287    /// A number of blob bytes to publish.
288    pub blob_bytes_to_publish: u32,
289    /// A number of messages to be sent.
290    pub messages: u32,
291    /// The size of the messages to be sent.
292    // TODO(#1531): Account for the type of message to be sent.
293    pub message_size: u32,
294    /// An increase in the amount of storage space.
295    pub storage_size_delta: u32,
296    /// A number of service-as-oracle requests to be performed.
297    pub service_as_oracle_queries: u32,
298    /// A number of HTTP requests to be performed.
299    pub http_requests: u32,
300    // TODO(#1532): Account for the system calls that we plan on calling.
301    // TODO(#1533): Allow declaring calls to other applications instead of having to count them here.
302}
303
304/// A request to send a message.
305#[derive(Clone, Debug, Deserialize, Serialize, WitLoad, WitType)]
306#[cfg_attr(with_testing, derive(Eq, PartialEq, WitStore))]
307#[witty_specialize_with(Message = Vec<u8>)]
308pub struct SendMessageRequest<Message> {
309    /// The destination of the message.
310    pub destination: Destination,
311    /// Whether the message is authenticated.
312    pub authenticated: bool,
313    /// Whether the message is tracked.
314    pub is_tracked: bool,
315    /// The grant resources forwarded with the message.
316    pub grant: Resources,
317    /// The message itself.
318    pub message: Message,
319}
320
321impl<Message> SendMessageRequest<Message>
322where
323    Message: Serialize,
324{
325    /// Serializes the internal `Message` type into raw bytes.
326    pub fn into_raw(self) -> SendMessageRequest<Vec<u8>> {
327        let message = bcs::to_bytes(&self.message).expect("Failed to serialize message");
328
329        SendMessageRequest {
330            destination: self.destination,
331            authenticated: self.authenticated,
332            is_tracked: self.is_tracked,
333            grant: self.grant,
334            message,
335        }
336    }
337}
338
339/// An error type for arithmetic errors.
340#[derive(Debug, Error)]
341#[allow(missing_docs)]
342pub enum ArithmeticError {
343    #[error("Number overflow")]
344    Overflow,
345    #[error("Number underflow")]
346    Underflow,
347}
348
349macro_rules! impl_wrapped_number {
350    ($name:ident, $wrapped:ident) => {
351        impl $name {
352            /// The zero value.
353            pub const ZERO: Self = Self(0);
354
355            /// The maximum value.
356            pub const MAX: Self = Self($wrapped::MAX);
357
358            /// Checked addition.
359            pub fn try_add(self, other: Self) -> Result<Self, ArithmeticError> {
360                let val = self
361                    .0
362                    .checked_add(other.0)
363                    .ok_or(ArithmeticError::Overflow)?;
364                Ok(Self(val))
365            }
366
367            /// Checked increment.
368            pub fn try_add_one(self) -> Result<Self, ArithmeticError> {
369                let val = self.0.checked_add(1).ok_or(ArithmeticError::Overflow)?;
370                Ok(Self(val))
371            }
372
373            /// Saturating addition.
374            pub const fn saturating_add(self, other: Self) -> Self {
375                let val = self.0.saturating_add(other.0);
376                Self(val)
377            }
378
379            /// Checked subtraction.
380            pub fn try_sub(self, other: Self) -> Result<Self, ArithmeticError> {
381                let val = self
382                    .0
383                    .checked_sub(other.0)
384                    .ok_or(ArithmeticError::Underflow)?;
385                Ok(Self(val))
386            }
387
388            /// Checked decrement.
389            pub fn try_sub_one(self) -> Result<Self, ArithmeticError> {
390                let val = self.0.checked_sub(1).ok_or(ArithmeticError::Underflow)?;
391                Ok(Self(val))
392            }
393
394            /// Saturating subtraction.
395            pub const fn saturating_sub(self, other: Self) -> Self {
396                let val = self.0.saturating_sub(other.0);
397                Self(val)
398            }
399
400            /// Checked in-place addition.
401            pub fn try_add_assign(&mut self, other: Self) -> Result<(), ArithmeticError> {
402                self.0 = self
403                    .0
404                    .checked_add(other.0)
405                    .ok_or(ArithmeticError::Overflow)?;
406                Ok(())
407            }
408
409            /// Checked in-place increment.
410            pub fn try_add_assign_one(&mut self) -> Result<(), ArithmeticError> {
411                self.0 = self.0.checked_add(1).ok_or(ArithmeticError::Overflow)?;
412                Ok(())
413            }
414
415            /// Saturating in-place addition.
416            pub const fn saturating_add_assign(&mut self, other: Self) {
417                self.0 = self.0.saturating_add(other.0);
418            }
419
420            /// Checked in-place subtraction.
421            pub fn try_sub_assign(&mut self, other: Self) -> Result<(), ArithmeticError> {
422                self.0 = self
423                    .0
424                    .checked_sub(other.0)
425                    .ok_or(ArithmeticError::Underflow)?;
426                Ok(())
427            }
428
429            /// Saturating multiplication.
430            pub const fn saturating_mul(&self, other: $wrapped) -> Self {
431                Self(self.0.saturating_mul(other))
432            }
433
434            /// Checked multiplication.
435            pub fn try_mul(self, other: $wrapped) -> Result<Self, ArithmeticError> {
436                let val = self.0.checked_mul(other).ok_or(ArithmeticError::Overflow)?;
437                Ok(Self(val))
438            }
439
440            /// Checked in-place multiplication.
441            pub fn try_mul_assign(&mut self, other: $wrapped) -> Result<(), ArithmeticError> {
442                self.0 = self.0.checked_mul(other).ok_or(ArithmeticError::Overflow)?;
443                Ok(())
444            }
445        }
446
447        impl From<$name> for $wrapped {
448            fn from(value: $name) -> Self {
449                value.0
450            }
451        }
452
453        // Cannot directly create values for a wrapped type, except for testing.
454        #[cfg(with_testing)]
455        impl From<$wrapped> for $name {
456            fn from(value: $wrapped) -> Self {
457                Self(value)
458            }
459        }
460
461        #[cfg(with_testing)]
462        impl ops::Add for $name {
463            type Output = Self;
464
465            fn add(self, other: Self) -> Self {
466                Self(self.0 + other.0)
467            }
468        }
469
470        #[cfg(with_testing)]
471        impl ops::Sub for $name {
472            type Output = Self;
473
474            fn sub(self, other: Self) -> Self {
475                Self(self.0 - other.0)
476            }
477        }
478
479        #[cfg(with_testing)]
480        impl ops::Mul<$wrapped> for $name {
481            type Output = Self;
482
483            fn mul(self, other: $wrapped) -> Self {
484                Self(self.0 * other)
485            }
486        }
487    };
488}
489
490impl TryFrom<BlockHeight> for usize {
491    type Error = ArithmeticError;
492
493    fn try_from(height: BlockHeight) -> Result<usize, ArithmeticError> {
494        usize::try_from(height.0).map_err(|_| ArithmeticError::Overflow)
495    }
496}
497
498#[cfg(not(with_testing))]
499impl From<u64> for BlockHeight {
500    fn from(value: u64) -> Self {
501        Self(value)
502    }
503}
504
505impl_wrapped_number!(Amount, u128);
506impl_wrapped_number!(BlockHeight, u64);
507impl_wrapped_number!(TimeDelta, u64);
508
509impl Display for Amount {
510    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
511        // Print the wrapped integer, padded with zeros to cover a digit before the decimal point.
512        let places = Amount::DECIMAL_PLACES as usize;
513        let min_digits = places + 1;
514        let decimals = format!("{:0min_digits$}", self.0);
515        let integer_part = &decimals[..(decimals.len() - places)];
516        let fractional_part = decimals[(decimals.len() - places)..].trim_end_matches('0');
517
518        // For now, we never trim non-zero digits so we don't lose any precision.
519        let precision = f.precision().unwrap_or(0).max(fractional_part.len());
520        let sign = if f.sign_plus() && self.0 > 0 { "+" } else { "" };
521        // The amount of padding: desired width minus sign, point and number of digits.
522        let pad_width = f.width().map_or(0, |w| {
523            w.saturating_sub(precision)
524                .saturating_sub(sign.len() + integer_part.len() + 1)
525        });
526        let left_pad = match f.align() {
527            None | Some(fmt::Alignment::Right) => pad_width,
528            Some(fmt::Alignment::Center) => pad_width / 2,
529            Some(fmt::Alignment::Left) => 0,
530        };
531
532        for _ in 0..left_pad {
533            write!(f, "{}", f.fill())?;
534        }
535        write!(f, "{sign}{integer_part}.{fractional_part:0<precision$}")?;
536        for _ in left_pad..pad_width {
537            write!(f, "{}", f.fill())?;
538        }
539        Ok(())
540    }
541}
542
543#[derive(Error, Debug)]
544#[allow(missing_docs)]
545pub enum ParseAmountError {
546    #[error("cannot parse amount")]
547    Parse,
548    #[error("cannot represent amount: number too high")]
549    TooHigh,
550    #[error("cannot represent amount: too many decimal places after the point")]
551    TooManyDigits,
552}
553
554impl FromStr for Amount {
555    type Err = ParseAmountError;
556
557    fn from_str(src: &str) -> Result<Self, Self::Err> {
558        let mut result: u128 = 0;
559        let mut decimals: Option<u8> = None;
560        let mut chars = src.trim().chars().peekable();
561        if chars.peek() == Some(&'+') {
562            chars.next();
563        }
564        for char in chars {
565            match char {
566                '_' => {}
567                '.' if decimals.is_some() => return Err(ParseAmountError::Parse),
568                '.' => decimals = Some(Amount::DECIMAL_PLACES),
569                char => {
570                    let digit = u128::from(char.to_digit(10).ok_or(ParseAmountError::Parse)?);
571                    if let Some(d) = &mut decimals {
572                        *d = d.checked_sub(1).ok_or(ParseAmountError::TooManyDigits)?;
573                    }
574                    result = result
575                        .checked_mul(10)
576                        .and_then(|r| r.checked_add(digit))
577                        .ok_or(ParseAmountError::TooHigh)?;
578                }
579            }
580        }
581        result = result
582            .checked_mul(10u128.pow(decimals.unwrap_or(Amount::DECIMAL_PLACES) as u32))
583            .ok_or(ParseAmountError::TooHigh)?;
584        Ok(Amount(result))
585    }
586}
587
588impl Display for BlockHeight {
589    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
590        self.0.fmt(f)
591    }
592}
593
594impl FromStr for BlockHeight {
595    type Err = ParseIntError;
596
597    fn from_str(src: &str) -> Result<Self, Self::Err> {
598        Ok(Self(u64::from_str(src)?))
599    }
600}
601
602impl Display for Round {
603    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
604        match self {
605            Round::Fast => write!(f, "fast round"),
606            Round::MultiLeader(r) => write!(f, "multi-leader round {}", r),
607            Round::SingleLeader(r) => write!(f, "single-leader round {}", r),
608            Round::Validator(r) => write!(f, "validator round {}", r),
609        }
610    }
611}
612
613impl Round {
614    /// Whether the round is a multi-leader round.
615    pub fn is_multi_leader(&self) -> bool {
616        matches!(self, Round::MultiLeader(_))
617    }
618
619    /// Returns the round number if this is a multi-leader round, `None` otherwise.
620    pub fn multi_leader(&self) -> Option<u32> {
621        match self {
622            Round::MultiLeader(number) => Some(*number),
623            _ => None,
624        }
625    }
626
627    /// Whether the round is the fast round.
628    pub fn is_fast(&self) -> bool {
629        matches!(self, Round::Fast)
630    }
631
632    /// The index of a round amongst the rounds of the same category.
633    pub fn number(&self) -> u32 {
634        match self {
635            Round::Fast => 0,
636            Round::MultiLeader(r) | Round::SingleLeader(r) | Round::Validator(r) => *r,
637        }
638    }
639
640    /// The category of the round as a string.
641    pub fn type_name(&self) -> &'static str {
642        match self {
643            Round::Fast => "fast",
644            Round::MultiLeader(_) => "multi",
645            Round::SingleLeader(_) => "single",
646            Round::Validator(_) => "validator",
647        }
648    }
649}
650
651impl<'a> iter::Sum<&'a Amount> for Amount {
652    fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
653        iter.fold(Self::ZERO, |a, b| a.saturating_add(*b))
654    }
655}
656
657impl Amount {
658    /// The base-10 exponent representing how much a token can be divided.
659    pub const DECIMAL_PLACES: u8 = 18;
660
661    /// One token.
662    pub const ONE: Amount = Amount(10u128.pow(Amount::DECIMAL_PLACES as u32));
663
664    /// Returns an `Amount` corresponding to that many tokens, or `Amount::MAX` if saturated.
665    pub const fn from_tokens(tokens: u128) -> Amount {
666        Self::ONE.saturating_mul(tokens)
667    }
668
669    /// Returns an `Amount` corresponding to that many millitokens, or `Amount::MAX` if saturated.
670    pub const fn from_millis(millitokens: u128) -> Amount {
671        Amount(10u128.pow(Amount::DECIMAL_PLACES as u32 - 3)).saturating_mul(millitokens)
672    }
673
674    /// Returns an `Amount` corresponding to that many microtokens, or `Amount::MAX` if saturated.
675    pub const fn from_micros(microtokens: u128) -> Amount {
676        Amount(10u128.pow(Amount::DECIMAL_PLACES as u32 - 6)).saturating_mul(microtokens)
677    }
678
679    /// Returns an `Amount` corresponding to that many nanotokens, or `Amount::MAX` if saturated.
680    pub const fn from_nanos(nanotokens: u128) -> Amount {
681        Amount(10u128.pow(Amount::DECIMAL_PLACES as u32 - 9)).saturating_mul(nanotokens)
682    }
683
684    /// Returns an `Amount` corresponding to that many attotokens.
685    pub const fn from_attos(attotokens: u128) -> Amount {
686        Amount(attotokens)
687    }
688
689    /// Helper function to obtain the 64 most significant bits of the balance.
690    pub const fn upper_half(self) -> u64 {
691        (self.0 >> 64) as u64
692    }
693
694    /// Helper function to obtain the 64 least significant bits of the balance.
695    pub const fn lower_half(self) -> u64 {
696        self.0 as u64
697    }
698
699    /// Divides this by the other amount. If the other is 0, it returns `u128::MAX`.
700    pub fn saturating_div(self, other: Amount) -> u128 {
701        self.0.checked_div(other.0).unwrap_or(u128::MAX)
702    }
703
704    /// Returns whether this amount is 0.
705    pub fn is_zero(&self) -> bool {
706        *self == Amount::ZERO
707    }
708}
709
710/// Permissions for applications on a chain.
711#[derive(
712    Default,
713    Debug,
714    PartialEq,
715    Eq,
716    Hash,
717    Clone,
718    Serialize,
719    Deserialize,
720    WitType,
721    WitLoad,
722    WitStore,
723    InputObject,
724)]
725pub struct ApplicationPermissions {
726    /// If this is `None`, all system operations and application operations are allowed.
727    /// If it is `Some`, only operations from the specified applications are allowed, and
728    /// no system operations.
729    #[debug(skip_if = Option::is_none)]
730    pub execute_operations: Option<Vec<ApplicationId>>,
731    /// At least one operation or incoming message from each of these applications must occur in
732    /// every block.
733    #[graphql(default)]
734    #[debug(skip_if = Vec::is_empty)]
735    pub mandatory_applications: Vec<ApplicationId>,
736    /// These applications are allowed to close the current chain using the system API.
737    #[graphql(default)]
738    #[debug(skip_if = Vec::is_empty)]
739    pub close_chain: Vec<ApplicationId>,
740    /// These applications are allowed to change the application permissions using the system API.
741    #[graphql(default)]
742    #[debug(skip_if = Vec::is_empty)]
743    pub change_application_permissions: Vec<ApplicationId>,
744    /// These applications are allowed to perform calls to services as oracles.
745    #[graphql(default)]
746    #[debug(skip_if = Option::is_none)]
747    pub call_service_as_oracle: Option<Vec<ApplicationId>>,
748    /// These applications are allowed to perform HTTP requests.
749    #[graphql(default)]
750    #[debug(skip_if = Option::is_none)]
751    pub make_http_requests: Option<Vec<ApplicationId>>,
752}
753
754impl ApplicationPermissions {
755    /// Creates new `ApplicationPermissions` where the given application is the only one
756    /// whose operations are allowed and mandatory, and it can also close the chain.
757    pub fn new_single(app_id: ApplicationId) -> Self {
758        Self {
759            execute_operations: Some(vec![app_id]),
760            mandatory_applications: vec![app_id],
761            close_chain: vec![app_id],
762            change_application_permissions: vec![app_id],
763            call_service_as_oracle: Some(vec![app_id]),
764            make_http_requests: Some(vec![app_id]),
765        }
766    }
767
768    /// Returns whether operations with the given application ID are allowed on this chain.
769    pub fn can_execute_operations(&self, app_id: &GenericApplicationId) -> bool {
770        match (app_id, &self.execute_operations) {
771            (_, None) => true,
772            (GenericApplicationId::System, Some(_)) => false,
773            (GenericApplicationId::User(app_id), Some(app_ids)) => app_ids.contains(app_id),
774        }
775    }
776
777    /// Returns whether the given application is allowed to close this chain.
778    pub fn can_close_chain(&self, app_id: &ApplicationId) -> bool {
779        self.close_chain.contains(app_id)
780    }
781
782    /// Returns whether the given application is allowed to change the application
783    /// permissions for this chain.
784    pub fn can_change_application_permissions(&self, app_id: &ApplicationId) -> bool {
785        self.change_application_permissions.contains(app_id)
786    }
787
788    /// Returns whether the given application can call services.
789    pub fn can_call_services(&self, app_id: &ApplicationId) -> bool {
790        self.call_service_as_oracle
791            .as_ref()
792            .map(|app_ids| app_ids.contains(app_id))
793            .unwrap_or(true)
794    }
795
796    /// Returns whether the given application can make HTTP requests.
797    pub fn can_make_http_requests(&self, app_id: &ApplicationId) -> bool {
798        self.make_http_requests
799            .as_ref()
800            .map(|app_ids| app_ids.contains(app_id))
801            .unwrap_or(true)
802    }
803}
804
805/// A record of a single oracle response.
806#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
807pub enum OracleResponse {
808    /// The response from a service query.
809    Service(
810        #[debug(with = "hex_debug")]
811        #[serde(with = "serde_bytes")]
812        Vec<u8>,
813    ),
814    /// The response from an HTTP request.
815    Http(http::Response),
816    /// A successful read or write of a blob.
817    Blob(BlobId),
818    /// An assertion oracle that passed.
819    Assert,
820    /// The block's validation round.
821    Round(Option<u32>),
822    /// An event was read.
823    Event(EventId, Vec<u8>),
824}
825
826impl BcsHashable<'_> for OracleResponse {}
827
828/// Description of a user application.
829#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Hash, Serialize)]
830pub struct ApplicationDescription {
831    /// The unique ID of the bytecode to use for the application.
832    pub module_id: ModuleId,
833    /// The chain ID that created the application.
834    pub creator_chain_id: ChainId,
835    /// Height of the block that created this application.
836    pub block_height: BlockHeight,
837    /// The index of the application among those created in the same block.
838    pub application_index: u32,
839    /// The parameters of the application.
840    #[serde(with = "serde_bytes")]
841    #[debug(with = "hex_debug")]
842    pub parameters: Vec<u8>,
843    /// Required dependencies.
844    pub required_application_ids: Vec<ApplicationId>,
845}
846
847impl From<&ApplicationDescription> for ApplicationId {
848    fn from(description: &ApplicationDescription) -> Self {
849        let mut hash = CryptoHash::new(&BlobContent::new_application_description(description));
850        if matches!(description.module_id.vm_runtime, VmRuntime::Evm) {
851            hash.make_evm_compatible();
852        }
853        ApplicationId::new(hash)
854    }
855}
856
857impl BcsHashable<'_> for ApplicationDescription {}
858
859impl ApplicationDescription {
860    /// Gets the serialized bytes for this `ApplicationDescription`.
861    pub fn to_bytes(&self) -> Vec<u8> {
862        bcs::to_bytes(self).expect("Serializing blob bytes should not fail!")
863    }
864
865    /// Gets the `BlobId` of the contract
866    pub fn contract_bytecode_blob_id(&self) -> BlobId {
867        self.module_id.contract_bytecode_blob_id()
868    }
869
870    /// Gets the `BlobId` of the service
871    pub fn service_bytecode_blob_id(&self) -> BlobId {
872        self.module_id.service_bytecode_blob_id()
873    }
874}
875
876/// A WebAssembly module's bytecode.
877#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
878pub struct Bytecode {
879    /// Bytes of the bytecode.
880    #[serde(with = "serde_bytes")]
881    #[debug(with = "hex_debug")]
882    pub bytes: Vec<u8>,
883}
884
885impl Bytecode {
886    /// Creates a new [`Bytecode`] instance using the provided `bytes`.
887    pub fn new(bytes: Vec<u8>) -> Self {
888        Bytecode { bytes }
889    }
890
891    /// Load bytecode from a Wasm module file.
892    pub async fn load_from_file(path: impl AsRef<std::path::Path>) -> std::io::Result<Self> {
893        let bytes = fs::read(path)?;
894        Ok(Bytecode { bytes })
895    }
896
897    /// Compresses the [`Bytecode`] into a [`CompressedBytecode`].
898    #[cfg(not(target_arch = "wasm32"))]
899    pub fn compress(&self) -> CompressedBytecode {
900        #[cfg(with_metrics)]
901        let _compression_latency = BYTECODE_COMPRESSION_LATENCY.measure_latency();
902        let compressed_bytes = zstd::stream::encode_all(&*self.bytes, 19)
903            .expect("Compressing bytes in memory should not fail");
904
905        CompressedBytecode { compressed_bytes }
906    }
907}
908
909impl AsRef<[u8]> for Bytecode {
910    fn as_ref(&self) -> &[u8] {
911        self.bytes.as_ref()
912    }
913}
914
915/// A type for errors happening during decompression.
916#[derive(Error, Debug)]
917pub enum DecompressionError {
918    /// Compressed bytecode is invalid, and could not be decompressed.
919    #[error("Bytecode could not be decompressed: {0}")]
920    InvalidCompressedBytecode(#[from] io::Error),
921}
922
923/// A compressed WebAssembly module's bytecode.
924#[derive(Clone, Debug, Deserialize, Hash, Serialize, WitType, WitStore)]
925#[cfg_attr(with_testing, derive(Eq, PartialEq))]
926pub struct CompressedBytecode {
927    /// Compressed bytes of the bytecode.
928    #[serde(with = "serde_bytes")]
929    #[debug(with = "hex_debug")]
930    pub compressed_bytes: Vec<u8>,
931}
932
933#[cfg(not(target_arch = "wasm32"))]
934impl CompressedBytecode {
935    /// Returns `true` if the decompressed size does not exceed the limit.
936    pub fn decompressed_size_at_most(
937        compressed_bytes: &[u8],
938        limit: u64,
939    ) -> Result<bool, DecompressionError> {
940        let mut decoder = zstd::stream::Decoder::new(compressed_bytes)?;
941        let limit = usize::try_from(limit).unwrap_or(usize::MAX);
942        let mut writer = LimitedWriter::new(io::sink(), limit);
943        match io::copy(&mut decoder, &mut writer) {
944            Ok(_) => Ok(true),
945            Err(error) => {
946                error.downcast::<LimitedWriterError>()?;
947                Ok(false)
948            }
949        }
950    }
951
952    /// Decompresses a [`CompressedBytecode`] into a [`Bytecode`].
953    pub fn decompress(&self) -> Result<Bytecode, DecompressionError> {
954        #[cfg(with_metrics)]
955        let _decompression_latency = BYTECODE_DECOMPRESSION_LATENCY.measure_latency();
956        let bytes = zstd::stream::decode_all(&*self.compressed_bytes)?;
957
958        Ok(Bytecode { bytes })
959    }
960}
961
962#[cfg(target_arch = "wasm32")]
963impl CompressedBytecode {
964    /// Returns `true` if the decompressed size does not exceed the limit.
965    pub fn decompressed_size_at_most(
966        compressed_bytes: &[u8],
967        limit: u64,
968    ) -> Result<bool, DecompressionError> {
969        let limit = usize::try_from(limit).unwrap_or(usize::MAX);
970        let mut writer = LimitedWriter::new(io::sink(), limit);
971        let mut decoder = ruzstd::streaming_decoder::StreamingDecoder::new(compressed_bytes)
972            .map_err(io::Error::other)?;
973
974        // TODO(#2710): Decode multiple frames, if present
975        match io::copy(&mut decoder, &mut writer) {
976            Ok(_) => Ok(true),
977            Err(error) => {
978                error.downcast::<LimitedWriterError>()?;
979                Ok(false)
980            }
981        }
982    }
983
984    /// Decompresses a [`CompressedBytecode`] into a [`Bytecode`].
985    pub fn decompress(&self) -> Result<Bytecode, DecompressionError> {
986        use ruzstd::{io::Read, streaming_decoder::StreamingDecoder};
987
988        #[cfg(with_metrics)]
989        let _decompression_latency = BYTECODE_DECOMPRESSION_LATENCY.measure_latency();
990
991        let compressed_bytes = &*self.compressed_bytes;
992        let mut bytes = Vec::new();
993        let mut decoder = StreamingDecoder::new(compressed_bytes).map_err(io::Error::other)?;
994
995        // TODO(#2710): Decode multiple frames, if present
996        while !decoder.get_ref().is_empty() {
997            decoder
998                .read_to_end(&mut bytes)
999                .expect("Reading from a slice in memory should not result in I/O errors");
1000        }
1001
1002        Ok(Bytecode { bytes })
1003    }
1004}
1005
1006impl BcsHashable<'_> for BlobContent {}
1007
1008/// A blob of binary data.
1009#[derive(Hash, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
1010pub struct BlobContent {
1011    /// The type of data represented by the bytes.
1012    blob_type: BlobType,
1013    /// The binary data.
1014    #[serde(with = "serde_bytes")]
1015    #[debug(skip)]
1016    bytes: Box<[u8]>,
1017}
1018
1019impl BlobContent {
1020    /// Creates a new [`BlobContent`] from the provided bytes and [`BlobId`].
1021    pub fn new(blob_type: BlobType, bytes: impl Into<Box<[u8]>>) -> Self {
1022        let bytes = bytes.into();
1023        BlobContent { blob_type, bytes }
1024    }
1025
1026    /// Creates a new data [`BlobContent`] from the provided bytes.
1027    pub fn new_data(bytes: impl Into<Box<[u8]>>) -> Self {
1028        BlobContent::new(BlobType::Data, bytes)
1029    }
1030
1031    /// Creates a new contract bytecode [`BlobContent`] from the provided bytes.
1032    pub fn new_contract_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1033        BlobContent::new(
1034            BlobType::ContractBytecode,
1035            compressed_bytecode.compressed_bytes,
1036        )
1037    }
1038
1039    /// Creates a new contract bytecode [`BlobContent`] from the provided bytes.
1040    pub fn new_evm_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1041        BlobContent::new(BlobType::EvmBytecode, compressed_bytecode.compressed_bytes)
1042    }
1043
1044    /// Creates a new service bytecode [`BlobContent`] from the provided bytes.
1045    pub fn new_service_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1046        BlobContent::new(
1047            BlobType::ServiceBytecode,
1048            compressed_bytecode.compressed_bytes,
1049        )
1050    }
1051
1052    /// Creates a new application description [`BlobContent`] from a [`ApplicationDescription`].
1053    pub fn new_application_description(application_description: &ApplicationDescription) -> Self {
1054        let bytes = application_description.to_bytes();
1055        BlobContent::new(BlobType::ApplicationDescription, bytes)
1056    }
1057
1058    /// Creates a new committee [`BlobContent`] from the provided serialized committee.
1059    pub fn new_committee(committee: impl Into<Box<[u8]>>) -> Self {
1060        BlobContent::new(BlobType::Committee, committee)
1061    }
1062
1063    /// Gets a reference to the blob's bytes.
1064    pub fn bytes(&self) -> &[u8] {
1065        &self.bytes
1066    }
1067
1068    /// Gets the inner blob's bytes, consuming the blob.
1069    pub fn into_bytes(self) -> Box<[u8]> {
1070        self.bytes
1071    }
1072
1073    /// Returns the type of data represented by this blob's bytes.
1074    pub fn blob_type(&self) -> BlobType {
1075        self.blob_type
1076    }
1077}
1078
1079impl From<Blob> for BlobContent {
1080    fn from(blob: Blob) -> BlobContent {
1081        blob.content
1082    }
1083}
1084
1085/// A blob of binary data, with its hash.
1086#[derive(Debug, Hash, PartialEq, Eq, Clone)]
1087pub struct Blob {
1088    /// ID of the blob.
1089    hash: CryptoHash,
1090    /// A blob of binary data.
1091    content: BlobContent,
1092}
1093
1094impl Blob {
1095    /// Computes the hash and returns the hashed blob for the given content.
1096    pub fn new(content: BlobContent) -> Self {
1097        let mut hash = CryptoHash::new(&content);
1098        if matches!(content.blob_type, BlobType::ApplicationDescription) {
1099            let application_description = bcs::from_bytes::<ApplicationDescription>(&content.bytes)
1100                .expect("to obtain an application description");
1101            if matches!(application_description.module_id.vm_runtime, VmRuntime::Evm) {
1102                hash.make_evm_compatible();
1103            }
1104        }
1105        Blob { hash, content }
1106    }
1107
1108    /// Creates a blob without checking that the hash actually matches the content.
1109    pub fn new_with_id_unchecked(blob_id: BlobId, bytes: impl Into<Box<[u8]>>) -> Self {
1110        Blob {
1111            hash: blob_id.hash,
1112            content: BlobContent {
1113                blob_type: blob_id.blob_type,
1114                bytes: bytes.into(),
1115            },
1116        }
1117    }
1118
1119    /// Creates a new data [`Blob`] from the provided bytes.
1120    pub fn new_data(bytes: impl Into<Box<[u8]>>) -> Self {
1121        Blob::new(BlobContent::new_data(bytes))
1122    }
1123
1124    /// Creates a new contract bytecode [`BlobContent`] from the provided bytes.
1125    pub fn new_contract_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1126        Blob::new(BlobContent::new_contract_bytecode(compressed_bytecode))
1127    }
1128
1129    /// Creates a new contract bytecode [`BlobContent`] from the provided bytes.
1130    pub fn new_evm_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1131        Blob::new(BlobContent::new_evm_bytecode(compressed_bytecode))
1132    }
1133
1134    /// Creates a new service bytecode [`BlobContent`] from the provided bytes.
1135    pub fn new_service_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1136        Blob::new(BlobContent::new_service_bytecode(compressed_bytecode))
1137    }
1138
1139    /// Creates a new application description [`BlobContent`] from the provided
1140    /// description.
1141    pub fn new_application_description(application_description: &ApplicationDescription) -> Self {
1142        Blob::new(BlobContent::new_application_description(
1143            application_description,
1144        ))
1145    }
1146
1147    /// A content-addressed blob ID i.e. the hash of the `Blob`.
1148    pub fn id(&self) -> BlobId {
1149        BlobId {
1150            hash: self.hash,
1151            blob_type: self.content.blob_type,
1152        }
1153    }
1154
1155    /// Returns a reference to the inner `BlobContent`, without the hash.
1156    pub fn content(&self) -> &BlobContent {
1157        &self.content
1158    }
1159
1160    /// Moves ownership of the blob of binary data
1161    pub fn into_content(self) -> BlobContent {
1162        self.content
1163    }
1164
1165    /// Gets a reference to the inner blob's bytes.
1166    pub fn bytes(&self) -> &[u8] {
1167        self.content.bytes()
1168    }
1169
1170    /// Gets the inner blob's bytes.
1171    pub fn into_bytes(self) -> Box<[u8]> {
1172        self.content.into_bytes()
1173    }
1174
1175    /// Loads data blob from a file.
1176    pub async fn load_data_blob_from_file(path: impl AsRef<Path>) -> io::Result<Self> {
1177        Ok(Self::new_data(fs::read(path)?))
1178    }
1179}
1180
1181impl Serialize for Blob {
1182    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1183    where
1184        S: Serializer,
1185    {
1186        if serializer.is_human_readable() {
1187            let blob_bytes = bcs::to_bytes(&self.content).map_err(serde::ser::Error::custom)?;
1188            serializer.serialize_str(&hex::encode(blob_bytes))
1189        } else {
1190            BlobContent::serialize(self.content(), serializer)
1191        }
1192    }
1193}
1194
1195impl<'a> Deserialize<'a> for Blob {
1196    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1197    where
1198        D: Deserializer<'a>,
1199    {
1200        if deserializer.is_human_readable() {
1201            let s = String::deserialize(deserializer)?;
1202            let content_bytes = hex::decode(s).map_err(serde::de::Error::custom)?;
1203            let content: BlobContent =
1204                bcs::from_bytes(&content_bytes).map_err(serde::de::Error::custom)?;
1205
1206            Ok(Blob::new(content))
1207        } else {
1208            let content = BlobContent::deserialize(deserializer)?;
1209            Ok(Blob::new(content))
1210        }
1211    }
1212}
1213
1214impl BcsHashable<'_> for Blob {}
1215
1216/// An event recorded in a block.
1217#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, SimpleObject)]
1218pub struct Event {
1219    /// The ID of the stream this event belongs to.
1220    pub stream_id: StreamId,
1221    /// The event index, i.e. the number of events in the stream before this one.
1222    pub index: u32,
1223    /// The payload data.
1224    #[debug(with = "hex_debug")]
1225    #[serde(with = "serde_bytes")]
1226    pub value: Vec<u8>,
1227}
1228
1229impl Event {
1230    /// Returns the ID of this event record, given the publisher chain ID.
1231    pub fn id(&self, chain_id: ChainId) -> EventId {
1232        EventId {
1233            chain_id,
1234            stream_id: self.stream_id.clone(),
1235            index: self.index,
1236        }
1237    }
1238}
1239
1240impl BcsHashable<'_> for Event {}
1241
1242doc_scalar!(Bytecode, "A WebAssembly module's bytecode");
1243doc_scalar!(Amount, "A non-negative amount of tokens.");
1244doc_scalar!(BlockHeight, "A block height to identify blocks in a chain");
1245doc_scalar!(
1246    Timestamp,
1247    "A timestamp, in microseconds since the Unix epoch"
1248);
1249doc_scalar!(TimeDelta, "A duration in microseconds");
1250doc_scalar!(
1251    Round,
1252    "A number to identify successive attempts to decide a value in a consensus protocol."
1253);
1254doc_scalar!(OracleResponse, "A record of a single oracle response.");
1255doc_scalar!(BlobContent, "A blob of binary data.");
1256doc_scalar!(
1257    Blob,
1258    "A blob of binary data, with its content-addressed blob ID."
1259);
1260doc_scalar!(ApplicationDescription, "Description of a user application");
1261
1262/// The time it takes to compress a bytecode.
1263#[cfg(with_metrics)]
1264static BYTECODE_COMPRESSION_LATENCY: LazyLock<HistogramVec> = LazyLock::new(|| {
1265    register_histogram_vec(
1266        "bytecode_compression_latency",
1267        "Bytecode compression latency",
1268        &[],
1269        exponential_bucket_latencies(10.0),
1270    )
1271});
1272
1273/// The time it takes to decompress a bytecode.
1274#[cfg(with_metrics)]
1275static BYTECODE_DECOMPRESSION_LATENCY: LazyLock<HistogramVec> = LazyLock::new(|| {
1276    register_histogram_vec(
1277        "bytecode_decompression_latency",
1278        "Bytecode decompression latency",
1279        &[],
1280        exponential_bucket_latencies(10.0),
1281    )
1282});
1283
1284#[cfg(test)]
1285mod tests {
1286    use std::str::FromStr;
1287
1288    use super::Amount;
1289
1290    #[test]
1291    fn display_amount() {
1292        assert_eq!("1.", Amount::ONE.to_string());
1293        assert_eq!("1.", Amount::from_str("1.").unwrap().to_string());
1294        assert_eq!(
1295            Amount(10_000_000_000_000_000_000),
1296            Amount::from_str("10").unwrap()
1297        );
1298        assert_eq!("10.", Amount(10_000_000_000_000_000_000).to_string());
1299        assert_eq!(
1300            "1001.3",
1301            (Amount::from_str("1.1")
1302                .unwrap()
1303                .saturating_add(Amount::from_str("1_000.2").unwrap()))
1304            .to_string()
1305        );
1306        assert_eq!(
1307            "   1.00000000000000000000",
1308            format!("{:25.20}", Amount::ONE)
1309        );
1310        assert_eq!(
1311            "~+12.34~~",
1312            format!("{:~^+9.1}", Amount::from_str("12.34").unwrap())
1313        );
1314    }
1315}