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