linera_base/
data_types.rs

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