Skip to main content

linera_base/
data_types.rs

1// Copyright (c) Facebook, Inc. and its affiliates.
2// Copyright (c) Zefchain Labs, Inc.
3// SPDX-License-Identifier: Apache-2.0
4
5//! Core data-types used in the Linera protocol.
6
7#[cfg(with_testing)]
8use std::ops;
9use std::{
10    collections::{BTreeMap, BTreeSet, HashSet},
11    fmt::{self, Display},
12    hash::Hash,
13    io, iter,
14    num::ParseIntError,
15    str::FromStr,
16    sync::Arc,
17};
18
19use allocative::{Allocative, Visitor};
20use alloy_primitives::U256;
21use async_graphql::{InputObject, SimpleObject};
22use custom_debug_derive::Debug;
23use linera_witty::{WitLoad, WitStore, WitType};
24use serde::{Deserialize, Deserializer, Serialize, Serializer};
25use serde_with::{serde_as, Bytes};
26use thiserror::Error;
27use tracing::instrument;
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 [`BTreeMap`] that serializes like a `Vec<(K, V)>` instead of using BCS's canonical
44/// map encoding.
45///
46/// BCS serializes a [`BTreeMap`] in *canonical* form: on every `serialize` call it re-sorts the
47/// entries by their serialized-key bytes (an `O(n log n)` sort) and verifies that ordering again
48/// on `deserialize`. Since a [`BTreeMap`] already keeps its entries ordered, this is wasted work.
49/// `NonCanonicalBTreeMap` instead (de)serializes the entries as a plain sequence of pairs, exactly
50/// like `Vec<(K, V)>`, trading the canonical wire format for speed.
51///
52/// Use it in *value* position — the value of a `RegisterView<Value>` or `MapView<_, Value>` — so
53/// that `save()` does not pay the canonical sort. Never use it in *key* position
54/// (`MapView<Key, _>`): keys rely on the canonical encoding that this type skips, so use
55/// [`CanonicalBTreeMap`] there instead.
56///
57/// It otherwise behaves like a [`BTreeMap`]: it derefs to one, so all the usual methods are
58/// available.
59#[derive(Debug, Clone, PartialEq, Eq, Allocative)]
60pub struct NonCanonicalBTreeMap<K, V>(BTreeMap<K, V>);
61
62impl<K, V> Default for NonCanonicalBTreeMap<K, V> {
63    fn default() -> Self {
64        Self(BTreeMap::new())
65    }
66}
67
68impl<K, V> std::ops::Deref for NonCanonicalBTreeMap<K, V> {
69    type Target = BTreeMap<K, V>;
70
71    fn deref(&self) -> &Self::Target {
72        &self.0
73    }
74}
75
76impl<K, V> std::ops::DerefMut for NonCanonicalBTreeMap<K, V> {
77    fn deref_mut(&mut self) -> &mut Self::Target {
78        &mut self.0
79    }
80}
81
82impl<K, V> From<BTreeMap<K, V>> for NonCanonicalBTreeMap<K, V> {
83    fn from(map: BTreeMap<K, V>) -> Self {
84        Self(map)
85    }
86}
87
88impl<K, V> From<NonCanonicalBTreeMap<K, V>> for BTreeMap<K, V> {
89    fn from(map: NonCanonicalBTreeMap<K, V>) -> Self {
90        map.0
91    }
92}
93
94impl<K: Ord, V> FromIterator<(K, V)> for NonCanonicalBTreeMap<K, V> {
95    fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
96        Self(BTreeMap::from_iter(iter))
97    }
98}
99
100impl<K, V> IntoIterator for NonCanonicalBTreeMap<K, V> {
101    type Item = (K, V);
102    type IntoIter = std::collections::btree_map::IntoIter<K, V>;
103
104    fn into_iter(self) -> Self::IntoIter {
105        self.0.into_iter()
106    }
107}
108
109impl<'a, K, V> IntoIterator for &'a NonCanonicalBTreeMap<K, V> {
110    type Item = (&'a K, &'a V);
111    type IntoIter = std::collections::btree_map::Iter<'a, K, V>;
112
113    fn into_iter(self) -> Self::IntoIter {
114        self.0.iter()
115    }
116}
117
118impl<K, V> Serialize for NonCanonicalBTreeMap<K, V>
119where
120    K: Serialize,
121    V: Serialize,
122{
123    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
124        // Serialize as a sequence of pairs, exactly like `Vec<(K, V)>`. The entries are already
125        // in key order, so this avoids the canonical re-sorting that BCS does for maps.
126        serializer.collect_seq(self.0.iter())
127    }
128}
129
130impl<'de, K, V> Deserialize<'de> for NonCanonicalBTreeMap<K, V>
131where
132    K: Deserialize<'de> + Ord,
133    V: Deserialize<'de>,
134{
135    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
136        let entries = Vec::<(K, V)>::deserialize(deserializer)?;
137        Ok(Self(entries.into_iter().collect()))
138    }
139}
140
141impl<K, V> async_graphql::OutputType for NonCanonicalBTreeMap<K, V>
142where
143    BTreeMap<K, V>: async_graphql::OutputType,
144{
145    fn type_name() -> std::borrow::Cow<'static, str> {
146        <BTreeMap<K, V> as async_graphql::OutputType>::type_name()
147    }
148
149    fn create_type_info(registry: &mut async_graphql::registry::Registry) -> String {
150        <BTreeMap<K, V> as async_graphql::OutputType>::create_type_info(registry)
151    }
152
153    async fn resolve(
154        &self,
155        ctx: &async_graphql::ContextSelectionSet<'_>,
156        field: &async_graphql::Positioned<async_graphql::parser::types::Field>,
157    ) -> async_graphql::ServerResult<async_graphql::Value> {
158        self.0.resolve(ctx, field).await
159    }
160}
161
162/// A [`BTreeSet`] used in value position; the counterpart to [`NonCanonicalBTreeMap`].
163///
164/// Unlike maps, serde already serializes a [`BTreeSet`] as a plain sequence (it never goes through
165/// `serialize_map`), so BCS does not re-sort it. A type alias is therefore enough; no wrapper is
166/// needed.
167///
168/// Use it in *value* position (`RegisterView<Value>` or `MapView<_, Value>`). In *key* position
169/// (`MapView<Key, _>`) use [`CanonicalBTreeSet`] instead, which enforces the canonical ordering
170/// that keys require.
171pub type NonCanonicalBTreeSet<T> = BTreeSet<T>;
172
173/// A [`BTreeMap`] suitable for *key* position; an alias for [`BTreeMap`] itself.
174///
175/// In key position the canonical BCS encoding is exactly what is wanted — keys are ordered and
176/// compared by their serialized bytes — so no wrapper is needed. Use it for the key type of a
177/// `MapView<Key, _>`. In *value* position prefer [`NonCanonicalBTreeMap`], which skips the
178/// per-`save()` canonical sort. This alias exists to make that intent explicit and to pair with
179/// [`NonCanonicalBTreeMap`].
180pub type CanonicalBTreeMap<K, V> = BTreeMap<K, V>;
181
182/// A [`BTreeSet`] that serializes canonically, like a `BTreeMap<T, ()>`.
183///
184/// A plain [`BTreeSet`] serializes as a serde *sequence*, so BCS keeps the in-memory (Rust `Ord`)
185/// order without enforcing canonical ordering of the serialized elements. That is fine in value
186/// position, but in *key* position the canonical encoding matters. `CanonicalBTreeSet` therefore
187/// (de)serializes through a map of `T -> ()`, so that BCS sorts the elements by their serialized
188/// bytes, exactly as it does for [`BTreeMap`] keys.
189///
190/// Use it for the key type of a `MapView<Key, _>`. In *value* position use
191/// [`NonCanonicalBTreeSet`] instead. It otherwise behaves like a [`BTreeSet`]: it derefs to one,
192/// so all the usual methods are available.
193#[derive(Debug, Clone, PartialEq, Eq, Allocative)]
194pub struct CanonicalBTreeSet<T>(BTreeSet<T>);
195
196impl<T> Default for CanonicalBTreeSet<T> {
197    fn default() -> Self {
198        Self(BTreeSet::new())
199    }
200}
201
202impl<T> std::ops::Deref for CanonicalBTreeSet<T> {
203    type Target = BTreeSet<T>;
204
205    fn deref(&self) -> &Self::Target {
206        &self.0
207    }
208}
209
210impl<T> std::ops::DerefMut for CanonicalBTreeSet<T> {
211    fn deref_mut(&mut self) -> &mut Self::Target {
212        &mut self.0
213    }
214}
215
216impl<T> From<BTreeSet<T>> for CanonicalBTreeSet<T> {
217    fn from(set: BTreeSet<T>) -> Self {
218        Self(set)
219    }
220}
221
222impl<T> From<CanonicalBTreeSet<T>> for BTreeSet<T> {
223    fn from(set: CanonicalBTreeSet<T>) -> Self {
224        set.0
225    }
226}
227
228impl<T: Ord> FromIterator<T> for CanonicalBTreeSet<T> {
229    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
230        Self(BTreeSet::from_iter(iter))
231    }
232}
233
234impl<T> IntoIterator for CanonicalBTreeSet<T> {
235    type Item = T;
236    type IntoIter = std::collections::btree_set::IntoIter<T>;
237
238    fn into_iter(self) -> Self::IntoIter {
239        self.0.into_iter()
240    }
241}
242
243impl<'a, T> IntoIterator for &'a CanonicalBTreeSet<T> {
244    type Item = &'a T;
245    type IntoIter = std::collections::btree_set::Iter<'a, T>;
246
247    fn into_iter(self) -> Self::IntoIter {
248        self.0.iter()
249    }
250}
251
252impl<T> Serialize for CanonicalBTreeSet<T>
253where
254    T: Serialize,
255{
256    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
257        // Serialize as a `BTreeMap<T, ()>`: going through `serialize_map` lets BCS sort the
258        // elements canonically by their serialized bytes, as required in key position.
259        serializer.collect_map(self.0.iter().map(|element| (element, ())))
260    }
261}
262
263impl<'de, T> Deserialize<'de> for CanonicalBTreeSet<T>
264where
265    T: Deserialize<'de> + Ord,
266{
267    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
268        let map = BTreeMap::<T, ()>::deserialize(deserializer)?;
269        Ok(Self(map.into_keys().collect()))
270    }
271}
272
273impl<T> async_graphql::OutputType for CanonicalBTreeSet<T>
274where
275    BTreeSet<T>: async_graphql::OutputType,
276{
277    fn type_name() -> std::borrow::Cow<'static, str> {
278        <BTreeSet<T> as async_graphql::OutputType>::type_name()
279    }
280
281    fn create_type_info(registry: &mut async_graphql::registry::Registry) -> String {
282        <BTreeSet<T> as async_graphql::OutputType>::create_type_info(registry)
283    }
284
285    async fn resolve(
286        &self,
287        ctx: &async_graphql::ContextSelectionSet<'_>,
288        field: &async_graphql::Positioned<async_graphql::parser::types::Field>,
289    ) -> async_graphql::ServerResult<async_graphql::Value> {
290        self.0.resolve(ctx, field).await
291    }
292}
293
294/// A non-negative amount of tokens.
295///
296/// This is a fixed-point fraction, with [`Amount::DECIMAL_PLACES`] digits after the point.
297/// [`Amount::ONE`] is one whole token, divisible into `10.pow(Amount::DECIMAL_PLACES)` parts.
298#[derive(
299    Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Hash, Default, Debug, WitType, WitLoad, WitStore,
300)]
301#[cfg_attr(
302    all(with_testing, not(target_arch = "wasm32")),
303    derive(test_strategy::Arbitrary)
304)]
305pub struct Amount(u128);
306
307impl Allocative for Amount {
308    fn visit<'a, 'b: 'a>(&self, visitor: &'a mut Visitor<'b>) {
309        visitor.visit_simple_sized::<Self>();
310    }
311}
312
313#[derive(Serialize, Deserialize)]
314#[serde(rename = "Amount")]
315struct AmountString(String);
316
317#[derive(Serialize, Deserialize)]
318#[serde(rename = "Amount")]
319struct AmountU128(u128);
320
321impl Serialize for Amount {
322    fn serialize<S: serde::ser::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
323        if serializer.is_human_readable() {
324            AmountString(self.to_string()).serialize(serializer)
325        } else {
326            AmountU128(self.0).serialize(serializer)
327        }
328    }
329}
330
331impl<'de> Deserialize<'de> for Amount {
332    fn deserialize<D: serde::de::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
333        if deserializer.is_human_readable() {
334            let AmountString(s) = AmountString::deserialize(deserializer)?;
335            s.parse().map_err(serde::de::Error::custom)
336        } else {
337            Ok(Amount(AmountU128::deserialize(deserializer)?.0))
338        }
339    }
340}
341
342impl From<Amount> for U256 {
343    fn from(amount: Amount) -> U256 {
344        U256::from(amount.0)
345    }
346}
347
348/// Error converting from `U256` to `Amount`.
349/// This can fail since `Amount` is a `u128`.
350#[derive(Error, Debug)]
351#[error("Failed to convert U256 to Amount. {0} has more than 128 bits")]
352pub struct AmountConversionError(U256);
353
354impl TryFrom<U256> for Amount {
355    type Error = AmountConversionError;
356    fn try_from(value: U256) -> Result<Amount, Self::Error> {
357        let value = u128::try_from(&value).map_err(|_| AmountConversionError(value))?;
358        Ok(Amount(value))
359    }
360}
361
362/// A block height to identify blocks in a chain.
363#[derive(
364    Eq,
365    PartialEq,
366    Ord,
367    PartialOrd,
368    Copy,
369    Clone,
370    Hash,
371    Default,
372    Debug,
373    Serialize,
374    Deserialize,
375    WitType,
376    WitLoad,
377    WitStore,
378    Allocative,
379)]
380#[cfg_attr(with_testing, derive(test_strategy::Arbitrary))]
381pub struct BlockHeight(pub u64);
382
383/// An identifier for successive attempts to decide a value in a consensus protocol.
384#[derive(
385    Eq,
386    PartialEq,
387    Ord,
388    PartialOrd,
389    Copy,
390    Clone,
391    Hash,
392    Default,
393    Debug,
394    Serialize,
395    Deserialize,
396    Allocative,
397)]
398#[cfg_attr(with_testing, derive(test_strategy::Arbitrary))]
399pub enum Round {
400    /// The initial fast round.
401    #[default]
402    Fast,
403    /// The N-th multi-leader round.
404    MultiLeader(u32),
405    /// The N-th single-leader round.
406    SingleLeader(u32),
407    /// The N-th round where the validators rotate as leaders.
408    Validator(u32),
409}
410
411/// A duration in microseconds.
412#[derive(
413    Eq,
414    PartialEq,
415    Ord,
416    PartialOrd,
417    Copy,
418    Clone,
419    Hash,
420    Default,
421    Debug,
422    Serialize,
423    Deserialize,
424    WitType,
425    WitLoad,
426    WitStore,
427    Allocative,
428)]
429pub struct TimeDelta(u64);
430
431impl TimeDelta {
432    /// Returns the given number of microseconds as a [`TimeDelta`].
433    pub const fn from_micros(micros: u64) -> Self {
434        TimeDelta(micros)
435    }
436
437    /// Returns the given number of milliseconds as a [`TimeDelta`].
438    pub const fn from_millis(millis: u64) -> Self {
439        TimeDelta(millis.saturating_mul(1_000))
440    }
441
442    /// Returns the given number of seconds as a [`TimeDelta`].
443    pub const fn from_secs(secs: u64) -> Self {
444        TimeDelta(secs.saturating_mul(1_000_000))
445    }
446
447    /// Returns this [`TimeDelta`] as a number of microseconds.
448    pub const fn as_micros(&self) -> u64 {
449        self.0
450    }
451
452    /// Returns this [`TimeDelta`] as a [`Duration`].
453    pub const fn as_duration(&self) -> Duration {
454        Duration::from_micros(self.as_micros())
455    }
456}
457
458/// A timestamp, in microseconds since the Unix epoch.
459#[derive(
460    Eq,
461    PartialEq,
462    Ord,
463    PartialOrd,
464    Copy,
465    Clone,
466    Hash,
467    Default,
468    Debug,
469    Serialize,
470    Deserialize,
471    WitType,
472    WitLoad,
473    WitStore,
474    Allocative,
475)]
476pub struct Timestamp(u64);
477
478impl Timestamp {
479    /// Returns the current time according to the system clock.
480    pub fn now() -> Timestamp {
481        Timestamp(
482            SystemTime::UNIX_EPOCH
483                .elapsed()
484                .expect("system time should be after Unix epoch")
485                .as_micros()
486                .try_into()
487                .unwrap_or(u64::MAX),
488        )
489    }
490
491    /// Returns the number of microseconds since the Unix epoch.
492    pub const fn micros(&self) -> u64 {
493        self.0
494    }
495
496    /// Returns the [`TimeDelta`] between `other` and `self`, or zero if `other` is not earlier
497    /// than `self`.
498    pub const fn delta_since(&self, other: Timestamp) -> TimeDelta {
499        TimeDelta::from_micros(self.0.saturating_sub(other.0))
500    }
501
502    /// Returns the [`Duration`] between `other` and `self`, or zero if `other` is not
503    /// earlier than `self`.
504    pub const fn duration_since(&self, other: Timestamp) -> Duration {
505        Duration::from_micros(self.0.saturating_sub(other.0))
506    }
507
508    /// Returns the timestamp that is `duration` later than `self`.
509    pub const fn saturating_add(&self, duration: TimeDelta) -> Timestamp {
510        Timestamp(self.0.saturating_add(duration.0))
511    }
512
513    /// Returns the timestamp that is `duration` earlier than `self`.
514    pub const fn saturating_sub(&self, duration: TimeDelta) -> Timestamp {
515        Timestamp(self.0.saturating_sub(duration.0))
516    }
517
518    /// Returns a timestamp `micros` microseconds earlier than `self`, or the lowest possible value
519    /// if it would underflow.
520    pub const fn saturating_sub_micros(&self, micros: u64) -> Timestamp {
521        Timestamp(self.0.saturating_sub(micros))
522    }
523}
524
525impl From<u64> for Timestamp {
526    fn from(t: u64) -> Timestamp {
527        Timestamp(t)
528    }
529}
530
531impl Display for Timestamp {
532    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
533        let seconds = i64::try_from(self.0 / 1_000_000).unwrap_or(i64::MAX);
534        // `% 1_000_000` keeps the value below 10^9, which fits in `u32`.
535        let nanos = u32::try_from((self.0 % 1_000_000) * 1_000)
536            .expect("microseconds modulo 1_000_000 multiplied by 1_000 fits in u32");
537        if let Some(date_time) = chrono::DateTime::from_timestamp(seconds, nanos) {
538            return date_time.naive_utc().fmt(f);
539        }
540        self.0.fmt(f)
541    }
542}
543
544impl FromStr for Timestamp {
545    type Err = chrono::ParseError;
546
547    fn from_str(s: &str) -> Result<Self, Self::Err> {
548        let naive = chrono::NaiveDateTime::parse_from_str(s, "%Y-%m-%dT%H:%M:%S")
549            .or_else(|_| chrono::NaiveDateTime::parse_from_str(s, "%Y-%m-%d %H:%M:%S"))?;
550        let micros = naive
551            .and_utc()
552            .timestamp_micros()
553            .try_into()
554            .unwrap_or(u64::MAX);
555        Ok(Timestamp(micros))
556    }
557}
558
559/// Resources that an application may spend during the execution of transaction or an
560/// application call.
561#[derive(
562    Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize, WitLoad, WitStore, WitType,
563)]
564pub struct Resources {
565    /// An amount of Wasm execution fuel.
566    pub wasm_fuel: u64,
567    /// An amount of EVM execution fuel.
568    pub evm_fuel: u64,
569    /// A number of read operations to be executed.
570    pub read_operations: u32,
571    /// A number of write operations to be executed.
572    pub write_operations: u32,
573    /// A number of bytes read from runtime.
574    pub bytes_runtime: u32,
575    /// A number of bytes to read.
576    pub bytes_to_read: u32,
577    /// A number of bytes to write.
578    pub bytes_to_write: u32,
579    /// A number of blobs to read.
580    pub blobs_to_read: u32,
581    /// A number of blobs to publish.
582    pub blobs_to_publish: u32,
583    /// A number of blob bytes to read.
584    pub blob_bytes_to_read: u32,
585    /// A number of blob bytes to publish.
586    pub blob_bytes_to_publish: u32,
587    /// A number of messages to be sent.
588    pub messages: u32,
589    /// The size of the messages to be sent.
590    // TODO(#1531): Account for the type of message to be sent.
591    pub message_size: u32,
592    /// A number of service-as-oracle requests to be performed.
593    pub service_as_oracle_queries: u32,
594    /// A number of HTTP requests to be performed.
595    pub http_requests: u32,
596    // TODO(#1532): Account for the system calls that we plan on calling.
597    // TODO(#1533): Allow declaring calls to other applications instead of having to count them here.
598}
599
600/// A request to send a message.
601#[derive(Clone, Debug, Deserialize, Serialize, WitLoad, WitType)]
602#[cfg_attr(with_testing, derive(Eq, PartialEq, WitStore))]
603#[witty_specialize_with(Message = Vec<u8>)]
604pub struct SendMessageRequest<Message> {
605    /// The destination of the message.
606    pub destination: ChainId,
607    /// Whether the message is authenticated.
608    pub authenticated: bool,
609    /// Whether the message is tracked.
610    pub is_tracked: bool,
611    /// The grant resources forwarded with the message.
612    pub grant: Resources,
613    /// The message itself.
614    pub message: Message,
615}
616
617/// An error type for arithmetic errors.
618#[derive(Debug, Error)]
619#[allow(missing_docs)]
620pub enum ArithmeticError {
621    #[error("Number overflow")]
622    Overflow,
623    #[error("Number underflow")]
624    Underflow,
625}
626
627macro_rules! impl_wrapped_number {
628    ($name:ident, $wrapped:ident) => {
629        impl $name {
630            /// The zero value.
631            pub const ZERO: Self = Self(0);
632
633            /// The maximum value.
634            pub const MAX: Self = Self($wrapped::MAX);
635
636            /// Checked addition.
637            pub fn try_add(self, other: Self) -> Result<Self, ArithmeticError> {
638                let val = self
639                    .0
640                    .checked_add(other.0)
641                    .ok_or(ArithmeticError::Overflow)?;
642                Ok(Self(val))
643            }
644
645            /// Checked increment.
646            pub fn try_add_one(self) -> Result<Self, ArithmeticError> {
647                let val = self.0.checked_add(1).ok_or(ArithmeticError::Overflow)?;
648                Ok(Self(val))
649            }
650
651            /// Saturating addition.
652            pub const fn saturating_add(self, other: Self) -> Self {
653                let val = self.0.saturating_add(other.0);
654                Self(val)
655            }
656
657            /// Checked subtraction.
658            pub fn try_sub(self, other: Self) -> Result<Self, ArithmeticError> {
659                let val = self
660                    .0
661                    .checked_sub(other.0)
662                    .ok_or(ArithmeticError::Underflow)?;
663                Ok(Self(val))
664            }
665
666            /// Checked decrement.
667            pub fn try_sub_one(self) -> Result<Self, ArithmeticError> {
668                let val = self.0.checked_sub(1).ok_or(ArithmeticError::Underflow)?;
669                Ok(Self(val))
670            }
671
672            /// Saturating subtraction.
673            pub const fn saturating_sub(self, other: Self) -> Self {
674                let val = self.0.saturating_sub(other.0);
675                Self(val)
676            }
677
678            /// Returns the absolute difference between `self` and `other`.
679            pub fn abs_diff(self, other: Self) -> Self {
680                Self(self.0.abs_diff(other.0))
681            }
682
683            /// Returns the midpoint of `self` and `other`, rounded down.
684            pub const fn midpoint(self, other: Self) -> Self {
685                Self(self.0.midpoint(other.0))
686            }
687
688            /// Checked in-place addition.
689            pub fn try_add_assign(&mut self, other: Self) -> Result<(), ArithmeticError> {
690                self.0 = self
691                    .0
692                    .checked_add(other.0)
693                    .ok_or(ArithmeticError::Overflow)?;
694                Ok(())
695            }
696
697            /// Checked in-place increment.
698            pub fn try_add_assign_one(&mut self) -> Result<(), ArithmeticError> {
699                self.0 = self.0.checked_add(1).ok_or(ArithmeticError::Overflow)?;
700                Ok(())
701            }
702
703            /// Saturating in-place addition.
704            pub const fn saturating_add_assign(&mut self, other: Self) {
705                self.0 = self.0.saturating_add(other.0);
706            }
707
708            /// Checked in-place subtraction.
709            pub fn try_sub_assign(&mut self, other: Self) -> Result<(), ArithmeticError> {
710                self.0 = self
711                    .0
712                    .checked_sub(other.0)
713                    .ok_or(ArithmeticError::Underflow)?;
714                Ok(())
715            }
716
717            /// Saturating division.
718            pub fn saturating_div(&self, other: $wrapped) -> Self {
719                Self(self.0.checked_div(other).unwrap_or($wrapped::MAX))
720            }
721
722            /// Saturating multiplication.
723            pub const fn saturating_mul(&self, other: $wrapped) -> Self {
724                Self(self.0.saturating_mul(other))
725            }
726
727            /// Checked multiplication.
728            pub fn try_mul(self, other: $wrapped) -> Result<Self, ArithmeticError> {
729                let val = self.0.checked_mul(other).ok_or(ArithmeticError::Overflow)?;
730                Ok(Self(val))
731            }
732
733            /// Checked in-place multiplication.
734            pub fn try_mul_assign(&mut self, other: $wrapped) -> Result<(), ArithmeticError> {
735                self.0 = self.0.checked_mul(other).ok_or(ArithmeticError::Overflow)?;
736                Ok(())
737            }
738        }
739
740        impl From<$name> for $wrapped {
741            fn from(value: $name) -> Self {
742                value.0
743            }
744        }
745
746        // Cannot directly create values for a wrapped type, except for testing.
747        #[cfg(with_testing)]
748        impl From<$wrapped> for $name {
749            fn from(value: $wrapped) -> Self {
750                Self(value)
751            }
752        }
753
754        #[cfg(with_testing)]
755        impl ops::Add for $name {
756            type Output = Self;
757
758            fn add(self, other: Self) -> Self {
759                Self(self.0 + other.0)
760            }
761        }
762
763        #[cfg(with_testing)]
764        impl ops::Sub for $name {
765            type Output = Self;
766
767            fn sub(self, other: Self) -> Self {
768                Self(self.0 - other.0)
769            }
770        }
771
772        #[cfg(with_testing)]
773        impl ops::Mul<$wrapped> for $name {
774            type Output = Self;
775
776            fn mul(self, other: $wrapped) -> Self {
777                Self(self.0 * other)
778            }
779        }
780    };
781}
782
783impl TryFrom<BlockHeight> for usize {
784    type Error = ArithmeticError;
785
786    fn try_from(height: BlockHeight) -> Result<usize, ArithmeticError> {
787        usize::try_from(height.0).map_err(|_| ArithmeticError::Overflow)
788    }
789}
790
791impl_wrapped_number!(Amount, u128);
792impl_wrapped_number!(BlockHeight, u64);
793impl_wrapped_number!(TimeDelta, u64);
794
795impl Display for Amount {
796    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
797        // Print the wrapped integer, padded with zeros to cover a digit before the decimal point.
798        let places = Amount::DECIMAL_PLACES as usize;
799        let min_digits = places + 1;
800        let decimals = format!("{:0min_digits$}", self.0);
801        let integer_part = &decimals[..(decimals.len() - places)];
802        let fractional_part = decimals[(decimals.len() - places)..].trim_end_matches('0');
803
804        // For now, we never trim non-zero digits so we don't lose any precision.
805        let precision = f.precision().unwrap_or(0).max(fractional_part.len());
806        let sign = if f.sign_plus() && self.0 > 0 { "+" } else { "" };
807        // The amount of padding: desired width minus sign, point and number of digits.
808        let pad_width = f.width().map_or(0, |w| {
809            w.saturating_sub(precision)
810                .saturating_sub(sign.len() + integer_part.len() + 1)
811        });
812        let left_pad = match f.align() {
813            None | Some(fmt::Alignment::Right) => pad_width,
814            Some(fmt::Alignment::Center) => pad_width / 2,
815            Some(fmt::Alignment::Left) => 0,
816        };
817
818        for _ in 0..left_pad {
819            write!(f, "{}", f.fill())?;
820        }
821        write!(f, "{sign}{integer_part}.{fractional_part:0<precision$}")?;
822        for _ in left_pad..pad_width {
823            write!(f, "{}", f.fill())?;
824        }
825        Ok(())
826    }
827}
828
829#[derive(Error, Debug)]
830#[allow(missing_docs)]
831pub enum ParseAmountError {
832    #[error("cannot parse amount")]
833    Parse,
834    #[error("cannot represent amount: number too high")]
835    TooHigh,
836    #[error("cannot represent amount: too many decimal places after the point")]
837    TooManyDigits,
838}
839
840impl FromStr for Amount {
841    type Err = ParseAmountError;
842
843    fn from_str(src: &str) -> Result<Self, Self::Err> {
844        let mut result: u128 = 0;
845        let mut decimals: Option<u8> = None;
846        let mut chars = src.trim().chars().peekable();
847        if chars.peek() == Some(&'+') {
848            chars.next();
849        }
850        for char in chars {
851            match char {
852                '_' => {}
853                '.' if decimals.is_some() => return Err(ParseAmountError::Parse),
854                '.' => decimals = Some(Amount::DECIMAL_PLACES),
855                char => {
856                    let digit = u128::from(char.to_digit(10).ok_or(ParseAmountError::Parse)?);
857                    if let Some(d) = &mut decimals {
858                        *d = d.checked_sub(1).ok_or(ParseAmountError::TooManyDigits)?;
859                    }
860                    result = result
861                        .checked_mul(10)
862                        .and_then(|r| r.checked_add(digit))
863                        .ok_or(ParseAmountError::TooHigh)?;
864                }
865            }
866        }
867        result = result
868            .checked_mul(10u128.pow(decimals.unwrap_or(Amount::DECIMAL_PLACES) as u32))
869            .ok_or(ParseAmountError::TooHigh)?;
870        Ok(Amount(result))
871    }
872}
873
874impl Display for BlockHeight {
875    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
876        self.0.fmt(f)
877    }
878}
879
880impl FromStr for BlockHeight {
881    type Err = ParseIntError;
882
883    fn from_str(src: &str) -> Result<Self, Self::Err> {
884        Ok(Self(u64::from_str(src)?))
885    }
886}
887
888impl Display for Round {
889    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
890        match self {
891            Round::Fast => write!(f, "fast round"),
892            Round::MultiLeader(r) => write!(f, "multi-leader round {r}"),
893            Round::SingleLeader(r) => write!(f, "single-leader round {r}"),
894            Round::Validator(r) => write!(f, "validator round {r}"),
895        }
896    }
897}
898
899impl Round {
900    /// Whether the round is a multi-leader round.
901    pub fn is_multi_leader(&self) -> bool {
902        matches!(self, Round::MultiLeader(_))
903    }
904
905    /// Returns the round number if this is a multi-leader round, `None` otherwise.
906    pub fn multi_leader(&self) -> Option<u32> {
907        match self {
908            Round::MultiLeader(number) => Some(*number),
909            _ => None,
910        }
911    }
912
913    /// Returns whether this is a validator round.
914    pub fn is_validator(&self) -> bool {
915        matches!(self, Round::Validator(_))
916    }
917
918    /// Whether the round is the fast round.
919    pub fn is_fast(&self) -> bool {
920        matches!(self, Round::Fast)
921    }
922
923    /// The index of a round amongst the rounds of the same category.
924    pub fn number(&self) -> u32 {
925        match self {
926            Round::Fast => 0,
927            Round::MultiLeader(r) | Round::SingleLeader(r) | Round::Validator(r) => *r,
928        }
929    }
930
931    /// The category of the round as a string.
932    pub fn type_name(&self) -> &'static str {
933        match self {
934            Round::Fast => "fast",
935            Round::MultiLeader(_) => "multi",
936            Round::SingleLeader(_) => "single",
937            Round::Validator(_) => "validator",
938        }
939    }
940}
941
942impl<'a> iter::Sum<&'a Amount> for Amount {
943    fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
944        iter.fold(Self::ZERO, |a, b| a.saturating_add(*b))
945    }
946}
947
948impl Amount {
949    /// The base-10 exponent representing how much a token can be divided.
950    pub const DECIMAL_PLACES: u8 = 18;
951
952    /// One token.
953    pub const ONE: Amount = Amount(10u128.pow(Amount::DECIMAL_PLACES as u32));
954
955    /// Returns an `Amount` corresponding to that many tokens, or `Amount::MAX` if saturated.
956    pub const fn from_tokens(tokens: u128) -> Amount {
957        Self::ONE.saturating_mul(tokens)
958    }
959
960    /// Returns an `Amount` corresponding to that many millitokens, or `Amount::MAX` if saturated.
961    pub const fn from_millis(millitokens: u128) -> Amount {
962        Amount(10u128.pow(Amount::DECIMAL_PLACES as u32 - 3)).saturating_mul(millitokens)
963    }
964
965    /// Returns an `Amount` corresponding to that many microtokens, or `Amount::MAX` if saturated.
966    pub const fn from_micros(microtokens: u128) -> Amount {
967        Amount(10u128.pow(Amount::DECIMAL_PLACES as u32 - 6)).saturating_mul(microtokens)
968    }
969
970    /// Returns an `Amount` corresponding to that many nanotokens, or `Amount::MAX` if saturated.
971    pub const fn from_nanos(nanotokens: u128) -> Amount {
972        Amount(10u128.pow(Amount::DECIMAL_PLACES as u32 - 9)).saturating_mul(nanotokens)
973    }
974
975    /// Returns an `Amount` corresponding to that many attotokens.
976    pub const fn from_attos(attotokens: u128) -> Amount {
977        Amount(attotokens)
978    }
979
980    /// Returns the number of attotokens.
981    pub const fn to_attos(self) -> u128 {
982        self.0
983    }
984
985    /// Helper function to obtain the 64 most significant bits of the balance.
986    pub const fn upper_half(self) -> u64 {
987        (self.0 >> 64) as u64
988    }
989
990    /// Helper function to obtain the 64 least significant bits of the balance.
991    #[expect(
992        clippy::cast_possible_truncation,
993        reason = "intentional: returns the low 64 bits"
994    )]
995    pub const fn lower_half(self) -> u64 {
996        self.0 as u64
997    }
998
999    /// Divides this by the other amount. If the other is 0, it returns `u128::MAX`.
1000    pub fn saturating_ratio(self, other: Amount) -> u128 {
1001        self.0.checked_div(other.0).unwrap_or(u128::MAX)
1002    }
1003
1004    /// Returns whether this amount is 0.
1005    pub fn is_zero(&self) -> bool {
1006        *self == Amount::ZERO
1007    }
1008}
1009
1010/// What created a chain.
1011#[derive(
1012    Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Hash, Debug, Serialize, Deserialize, Allocative,
1013)]
1014pub enum ChainOrigin {
1015    /// The chain was created by the genesis configuration.
1016    Root(u32),
1017    /// The chain was created by a call from another chain.
1018    Child {
1019        /// The parent of this chain.
1020        parent: ChainId,
1021        /// The block height in the parent at which this chain was created.
1022        block_height: BlockHeight,
1023        /// The index of this chain among chains created at the same block height in the parent
1024        /// chain.
1025        chain_index: u32,
1026    },
1027}
1028
1029impl ChainOrigin {
1030    /// Returns the root chain number, if this is a root chain.
1031    pub fn root(&self) -> Option<u32> {
1032        match self {
1033            ChainOrigin::Root(i) => Some(*i),
1034            ChainOrigin::Child { .. } => None,
1035        }
1036    }
1037}
1038
1039/// A number identifying the configuration of the chain (aka the committee).
1040#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Hash, Default, Debug, Allocative)]
1041pub struct Epoch(pub u32);
1042
1043impl Epoch {
1044    /// The zero epoch.
1045    pub const ZERO: Epoch = Epoch(0);
1046}
1047
1048impl Serialize for Epoch {
1049    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1050    where
1051        S: serde::ser::Serializer,
1052    {
1053        if serializer.is_human_readable() {
1054            serializer.serialize_str(&self.0.to_string())
1055        } else {
1056            serializer.serialize_newtype_struct("Epoch", &self.0)
1057        }
1058    }
1059}
1060
1061impl<'de> Deserialize<'de> for Epoch {
1062    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1063    where
1064        D: serde::de::Deserializer<'de>,
1065    {
1066        if deserializer.is_human_readable() {
1067            let s = String::deserialize(deserializer)?;
1068            Ok(Epoch(u32::from_str(&s).map_err(serde::de::Error::custom)?))
1069        } else {
1070            #[derive(Deserialize)]
1071            #[serde(rename = "Epoch")]
1072            struct EpochDerived(u32);
1073
1074            let value = EpochDerived::deserialize(deserializer)?;
1075            Ok(Self(value.0))
1076        }
1077    }
1078}
1079
1080impl std::fmt::Display for Epoch {
1081    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
1082        write!(f, "{}", self.0)
1083    }
1084}
1085
1086impl std::str::FromStr for Epoch {
1087    type Err = CryptoError;
1088
1089    fn from_str(s: &str) -> Result<Self, Self::Err> {
1090        Ok(Epoch(s.parse()?))
1091    }
1092}
1093
1094impl From<u32> for Epoch {
1095    fn from(value: u32) -> Self {
1096        Epoch(value)
1097    }
1098}
1099
1100impl Epoch {
1101    /// Tries to return an epoch with a number increased by one. Returns an error if an overflow
1102    /// happens.
1103    #[inline]
1104    pub fn try_add_one(self) -> Result<Self, ArithmeticError> {
1105        let val = self.0.checked_add(1).ok_or(ArithmeticError::Overflow)?;
1106        Ok(Self(val))
1107    }
1108
1109    /// Tries to return an epoch with a number decreased by one. Returns an error if an underflow
1110    /// happens.
1111    pub fn try_sub_one(self) -> Result<Self, ArithmeticError> {
1112        let val = self.0.checked_sub(1).ok_or(ArithmeticError::Underflow)?;
1113        Ok(Self(val))
1114    }
1115
1116    /// Tries to add one to this epoch's number. Returns an error if an overflow happens.
1117    #[inline]
1118    pub fn try_add_assign_one(&mut self) -> Result<(), ArithmeticError> {
1119        self.0 = self.0.checked_add(1).ok_or(ArithmeticError::Overflow)?;
1120        Ok(())
1121    }
1122}
1123
1124/// The initial configuration for a new chain.
1125#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, Allocative)]
1126pub struct InitialChainConfig {
1127    /// The ownership configuration of the new chain.
1128    pub ownership: ChainOwnership,
1129    /// The epoch in which the chain is created.
1130    pub epoch: Epoch,
1131    /// The initial chain balance.
1132    pub balance: Amount,
1133    /// The initial application permissions.
1134    pub application_permissions: ApplicationPermissions,
1135}
1136
1137/// Initial chain configuration and chain origin.
1138#[derive(Eq, PartialEq, Clone, Hash, Debug, Serialize, Deserialize, Allocative)]
1139pub struct ChainDescription {
1140    origin: ChainOrigin,
1141    timestamp: Timestamp,
1142    config: InitialChainConfig,
1143}
1144
1145impl ChainDescription {
1146    /// Creates a new [`ChainDescription`].
1147    pub fn new(origin: ChainOrigin, config: InitialChainConfig, timestamp: Timestamp) -> Self {
1148        Self {
1149            origin,
1150            config,
1151            timestamp,
1152        }
1153    }
1154
1155    /// Returns the [`ChainId`] based on this [`ChainDescription`].
1156    pub fn id(&self) -> ChainId {
1157        ChainId::from(self)
1158    }
1159
1160    /// Returns the [`ChainOrigin`] describing who created this chain.
1161    pub fn origin(&self) -> ChainOrigin {
1162        self.origin
1163    }
1164
1165    /// Returns a reference to the [`InitialChainConfig`] of the chain.
1166    pub fn config(&self) -> &InitialChainConfig {
1167        &self.config
1168    }
1169
1170    /// Returns the timestamp of when the chain was created.
1171    pub fn timestamp(&self) -> Timestamp {
1172        self.timestamp
1173    }
1174}
1175
1176impl BcsHashable<'_> for ChainDescription {}
1177
1178/// A description of the current Linera network to be stored in every node's database.
1179#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
1180pub struct NetworkDescription {
1181    /// The name of the network.
1182    pub name: String,
1183    /// Hash of the network's genesis config.
1184    pub genesis_config_hash: CryptoHash,
1185    /// Genesis timestamp.
1186    pub genesis_timestamp: Timestamp,
1187    /// Hash of the blob containing the genesis committee.
1188    pub genesis_committee_blob_hash: CryptoHash,
1189    /// The chain ID of the admin chain.
1190    pub admin_chain_id: ChainId,
1191}
1192
1193/// Permissions for applications on a chain.
1194#[derive(
1195    Default,
1196    Debug,
1197    PartialEq,
1198    Eq,
1199    PartialOrd,
1200    Ord,
1201    Hash,
1202    Clone,
1203    Serialize,
1204    Deserialize,
1205    WitType,
1206    WitLoad,
1207    WitStore,
1208    InputObject,
1209    Allocative,
1210)]
1211pub struct ApplicationPermissions {
1212    /// If this is `None`, all system operations and application operations are allowed.
1213    /// If it is `Some`, only operations from the specified applications are allowed, and
1214    /// no system operations.
1215    #[debug(skip_if = Option::is_none)]
1216    pub execute_operations: Option<Vec<ApplicationId>>,
1217    /// At least one operation or incoming message from each of these applications must occur in
1218    /// every block.
1219    #[graphql(default)]
1220    #[debug(skip_if = Vec::is_empty)]
1221    pub mandatory_applications: Vec<ApplicationId>,
1222    /// These applications are allowed to close the current chain, change the application
1223    /// permissions, and change the ownership.
1224    #[graphql(default)]
1225    #[debug(skip_if = Vec::is_empty)]
1226    pub manage_chain: Vec<ApplicationId>,
1227    /// These applications are allowed to perform calls to services as oracles.
1228    #[graphql(default)]
1229    #[debug(skip_if = Option::is_none)]
1230    pub call_service_as_oracle: Option<Vec<ApplicationId>>,
1231    /// These applications are allowed to perform HTTP requests.
1232    #[graphql(default)]
1233    #[debug(skip_if = Option::is_none)]
1234    pub make_http_requests: Option<Vec<ApplicationId>>,
1235}
1236
1237impl ApplicationPermissions {
1238    /// Creates new `ApplicationPermissions` where the given application is the only one
1239    /// whose operations are allowed and mandatory, and it can also manage the chain.
1240    pub fn new_single(app_id: ApplicationId) -> Self {
1241        Self {
1242            execute_operations: Some(vec![app_id]),
1243            mandatory_applications: vec![app_id],
1244            manage_chain: vec![app_id],
1245            call_service_as_oracle: Some(vec![app_id]),
1246            make_http_requests: Some(vec![app_id]),
1247        }
1248    }
1249
1250    /// Creates new `ApplicationPermissions` where the given applications are the only ones
1251    /// whose operations are allowed and mandatory, and they can also manage the chain.
1252    #[cfg(with_testing)]
1253    pub fn new_multiple(app_ids: Vec<ApplicationId>) -> Self {
1254        Self {
1255            execute_operations: Some(app_ids.clone()),
1256            mandatory_applications: app_ids.clone(),
1257            manage_chain: app_ids.clone(),
1258            call_service_as_oracle: Some(app_ids.clone()),
1259            make_http_requests: Some(app_ids),
1260        }
1261    }
1262
1263    /// Returns whether operations with the given application ID are allowed on this chain.
1264    pub fn can_execute_operations(&self, app_id: &GenericApplicationId) -> bool {
1265        match (app_id, &self.execute_operations) {
1266            (_, None) => true,
1267            (GenericApplicationId::System, Some(_)) => false,
1268            (GenericApplicationId::User(app_id), Some(app_ids)) => app_ids.contains(app_id),
1269        }
1270    }
1271
1272    /// Returns whether the given application is allowed to manage this chain, i.e. close
1273    /// it, change the application permissions, and change the ownership.
1274    pub fn can_manage_chain(&self, app_id: &ApplicationId) -> bool {
1275        self.manage_chain.contains(app_id)
1276    }
1277
1278    /// Returns whether the given application can call services.
1279    pub fn can_call_services(&self, app_id: &ApplicationId) -> bool {
1280        self.call_service_as_oracle
1281            .as_ref()
1282            .is_none_or(|app_ids| app_ids.contains(app_id))
1283    }
1284
1285    /// Returns whether the given application can make HTTP requests.
1286    pub fn can_make_http_requests(&self, app_id: &ApplicationId) -> bool {
1287        self.make_http_requests
1288            .as_ref()
1289            .is_none_or(|app_ids| app_ids.contains(app_id))
1290    }
1291}
1292
1293/// A record of a single oracle response.
1294#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, Allocative)]
1295pub enum OracleResponse {
1296    /// The response from a service query.
1297    Service(
1298        #[debug(with = "hex_debug")]
1299        #[serde(with = "serde_bytes")]
1300        Vec<u8>,
1301    ),
1302    /// The response from an HTTP request.
1303    Http(http::Response),
1304    /// A successful read or write of a blob.
1305    Blob(BlobId),
1306    /// An assertion oracle that passed.
1307    Assert,
1308    /// The block's validation round.
1309    Round(Option<u32>),
1310    /// An event was read.
1311    Event(
1312        EventId,
1313        #[debug(with = "hex_debug")]
1314        #[serde(with = "serde_bytes")]
1315        Vec<u8>,
1316    ),
1317    /// An event exists.
1318    EventExists(EventId),
1319    /// A checkpoint of the chain's execution state was published. The execution-state
1320    /// dump is chunked into one or more `BlobType::CheckpointExecutionState` blobs whose
1321    /// content hashes are listed here in restore order; a bootstrapping node concatenates
1322    /// the bytes and feeds them to `ExecutionStateView::restore_from_content`.
1323    Checkpoint {
1324        /// Content hashes of the execution-state-dump blobs, in restore order.
1325        execution_state_blobs: Vec<CryptoHash>,
1326        /// All blobs the chain references in its `used_blobs` set at the time of the
1327        /// checkpoint. A bootstrapping node must have each of these in shared blob
1328        /// storage before applying the checkpoint, otherwise subsequent operations on
1329        /// the chain could try to read blob content the node doesn't actually have.
1330        used_blobs: Vec<BlobId>,
1331    },
1332}
1333
1334impl BcsHashable<'_> for OracleResponse {}
1335
1336/// Description of a user application.
1337#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Hash, Serialize, WitType, WitLoad, WitStore)]
1338pub struct ApplicationDescription {
1339    /// The unique ID of the bytecode to use for the application.
1340    pub module_id: ModuleId,
1341    /// The chain ID that created the application.
1342    pub creator_chain_id: ChainId,
1343    /// Height of the block that created this application.
1344    pub block_height: BlockHeight,
1345    /// The index of the application among those created in the same block.
1346    pub application_index: u32,
1347    /// The parameters of the application.
1348    #[serde(with = "serde_bytes")]
1349    #[debug(with = "hex_debug")]
1350    pub parameters: Vec<u8>,
1351    /// Required dependencies.
1352    pub required_application_ids: Vec<ApplicationId>,
1353}
1354
1355impl From<&ApplicationDescription> for ApplicationId {
1356    fn from(description: &ApplicationDescription) -> Self {
1357        let mut hash = CryptoHash::new(&BlobContent::new_application_description(description));
1358        if matches!(description.module_id.vm_runtime, VmRuntime::Evm) {
1359            hash.make_evm_compatible();
1360        }
1361        ApplicationId::new(hash)
1362    }
1363}
1364
1365impl BcsHashable<'_> for ApplicationDescription {}
1366
1367impl ApplicationDescription {
1368    /// Gets the serialized bytes for this `ApplicationDescription`.
1369    pub fn to_bytes(&self) -> Vec<u8> {
1370        bcs::to_bytes(self).expect("Serializing blob bytes should not fail!")
1371    }
1372
1373    /// Gets the `BlobId` of the contract
1374    pub fn contract_bytecode_blob_id(&self) -> BlobId {
1375        self.module_id.contract_bytecode_blob_id()
1376    }
1377
1378    /// Gets the `BlobId` of the service
1379    pub fn service_bytecode_blob_id(&self) -> BlobId {
1380        self.module_id.service_bytecode_blob_id()
1381    }
1382}
1383
1384/// A WebAssembly module's bytecode.
1385#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, WitType, WitLoad, WitStore)]
1386pub struct Bytecode {
1387    /// Bytes of the bytecode.
1388    #[serde(with = "serde_bytes")]
1389    #[debug(with = "hex_debug")]
1390    pub bytes: Vec<u8>,
1391}
1392
1393impl Bytecode {
1394    /// Creates a new [`Bytecode`] instance using the provided `bytes`.
1395    pub fn new(bytes: Vec<u8>) -> Self {
1396        Bytecode { bytes }
1397    }
1398
1399    /// Loads bytecode from a Wasm module file.
1400    #[cfg(not(target_arch = "wasm32"))]
1401    pub async fn load_from_file(path: impl AsRef<std::path::Path>) -> std::io::Result<Self> {
1402        let path = path.as_ref();
1403        let bytes = tokio::fs::read(path).await.map_err(|error| {
1404            std::io::Error::new(error.kind(), format!("{}: {error}", path.display()))
1405        })?;
1406        Ok(Bytecode { bytes })
1407    }
1408
1409    /// Compresses the [`Bytecode`] into a [`CompressedBytecode`].
1410    #[cfg(not(target_arch = "wasm32"))]
1411    pub fn compress(&self) -> CompressedBytecode {
1412        #[cfg(with_metrics)]
1413        let _compression_latency = metrics::BYTECODE_COMPRESSION_LATENCY.measure_latency();
1414        let compressed_bytes_vec = zstd::stream::encode_all(&*self.bytes, 19)
1415            .expect("Compressing bytes in memory should not fail");
1416
1417        CompressedBytecode {
1418            compressed_bytes: Arc::new(compressed_bytes_vec.into_boxed_slice()),
1419        }
1420    }
1421
1422    /// Compresses the [`Bytecode`] into a [`CompressedBytecode`].
1423    #[cfg(target_arch = "wasm32")]
1424    pub fn compress(&self) -> CompressedBytecode {
1425        use ruzstd::encoding::{CompressionLevel, FrameCompressor};
1426
1427        #[cfg(with_metrics)]
1428        let _compression_latency = metrics::BYTECODE_COMPRESSION_LATENCY.measure_latency();
1429
1430        let mut compressed_bytes_vec = Vec::new();
1431        let mut compressor = FrameCompressor::new(CompressionLevel::Fastest);
1432        compressor.set_source(&*self.bytes);
1433        compressor.set_drain(&mut compressed_bytes_vec);
1434        compressor.compress();
1435
1436        CompressedBytecode {
1437            compressed_bytes: Arc::new(compressed_bytes_vec.into_boxed_slice()),
1438        }
1439    }
1440}
1441
1442impl AsRef<[u8]> for Bytecode {
1443    fn as_ref(&self) -> &[u8] {
1444        self.bytes.as_ref()
1445    }
1446}
1447
1448/// A type for errors happening during decompression.
1449#[derive(Error, Debug)]
1450pub enum DecompressionError {
1451    /// Compressed bytecode is invalid, and could not be decompressed.
1452    #[error("Bytecode could not be decompressed: {0}")]
1453    InvalidCompressedBytecode(#[from] io::Error),
1454}
1455
1456/// A compressed module bytecode (WebAssembly or EVM).
1457#[serde_as]
1458#[derive(Clone, Debug, Deserialize, Hash, Serialize, WitType, WitStore)]
1459#[cfg_attr(with_testing, derive(Eq, PartialEq))]
1460pub struct CompressedBytecode {
1461    /// Compressed bytes of the bytecode.
1462    #[serde_as(as = "Arc<Bytes>")]
1463    #[debug(skip)]
1464    pub compressed_bytes: Arc<Box<[u8]>>,
1465}
1466
1467#[cfg(not(target_arch = "wasm32"))]
1468impl CompressedBytecode {
1469    /// Returns `true` if the decompressed size does not exceed the limit.
1470    pub fn decompressed_size_at_most(
1471        compressed_bytes: &[u8],
1472        limit: u64,
1473    ) -> Result<bool, DecompressionError> {
1474        let mut decoder = zstd::stream::Decoder::new(compressed_bytes)?;
1475        let limit = usize::try_from(limit).unwrap_or(usize::MAX);
1476        let mut writer = LimitedWriter::new(io::sink(), limit);
1477        match io::copy(&mut decoder, &mut writer) {
1478            Ok(_) => Ok(true),
1479            Err(error) => {
1480                error.downcast::<LimitedWriterError>()?;
1481                Ok(false)
1482            }
1483        }
1484    }
1485
1486    /// Decompresses a [`CompressedBytecode`] into a [`Bytecode`].
1487    pub fn decompress(&self) -> Result<Bytecode, DecompressionError> {
1488        #[cfg(with_metrics)]
1489        let _decompression_latency = metrics::BYTECODE_DECOMPRESSION_LATENCY.measure_latency();
1490        let bytes = zstd::stream::decode_all(&**self.compressed_bytes)?;
1491
1492        #[cfg(with_metrics)]
1493        metrics::BYTECODE_DECOMPRESSED_SIZE_BYTES
1494            .with_label_values(&[])
1495            .observe(bytes.len() as f64);
1496
1497        Ok(Bytecode { bytes })
1498    }
1499}
1500
1501#[cfg(target_arch = "wasm32")]
1502impl CompressedBytecode {
1503    /// Returns `true` if the decompressed size does not exceed the limit.
1504    pub fn decompressed_size_at_most(
1505        compressed_bytes: &[u8],
1506        limit: u64,
1507    ) -> Result<bool, DecompressionError> {
1508        use ruzstd::decoding::StreamingDecoder;
1509        let limit = usize::try_from(limit).unwrap_or(usize::MAX);
1510        let mut writer = LimitedWriter::new(io::sink(), limit);
1511        let mut decoder = StreamingDecoder::new(compressed_bytes).map_err(io::Error::other)?;
1512
1513        // TODO(#2710): Decode multiple frames, if present
1514        match io::copy(&mut decoder, &mut writer) {
1515            Ok(_) => Ok(true),
1516            Err(error) => {
1517                error.downcast::<LimitedWriterError>()?;
1518                Ok(false)
1519            }
1520        }
1521    }
1522
1523    /// Decompresses a [`CompressedBytecode`] into a [`Bytecode`].
1524    pub fn decompress(&self) -> Result<Bytecode, DecompressionError> {
1525        use ruzstd::{decoding::StreamingDecoder, io::Read};
1526
1527        #[cfg(with_metrics)]
1528        let _decompression_latency = BYTECODE_DECOMPRESSION_LATENCY.measure_latency();
1529
1530        let compressed_bytes = &*self.compressed_bytes;
1531        let mut bytes = Vec::new();
1532        let mut decoder = StreamingDecoder::new(&**compressed_bytes).map_err(io::Error::other)?;
1533
1534        // TODO(#2710): Decode multiple frames, if present
1535        while !decoder.get_ref().is_empty() {
1536            decoder
1537                .read_to_end(&mut bytes)
1538                .expect("Reading from a slice in memory should not result in I/O errors");
1539        }
1540
1541        #[cfg(with_metrics)]
1542        BYTECODE_DECOMPRESSED_SIZE_BYTES
1543            .with_label_values(&[])
1544            .observe(bytes.len() as f64);
1545
1546        Ok(Bytecode { bytes })
1547    }
1548}
1549
1550impl BcsHashable<'_> for BlobContent {}
1551
1552/// A blob of binary data.
1553#[serde_as]
1554#[derive(Hash, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Allocative)]
1555pub struct BlobContent {
1556    /// The type of data represented by the bytes.
1557    blob_type: BlobType,
1558    /// The binary data.
1559    #[debug(skip)]
1560    #[serde_as(as = "Arc<Bytes>")]
1561    bytes: Arc<Box<[u8]>>,
1562}
1563
1564impl BlobContent {
1565    /// Creates a new [`BlobContent`] from the provided bytes and [`BlobId`].
1566    pub fn new(blob_type: BlobType, bytes: impl Into<Box<[u8]>>) -> Self {
1567        let bytes = bytes.into();
1568        BlobContent {
1569            blob_type,
1570            bytes: Arc::new(bytes),
1571        }
1572    }
1573
1574    /// Creates a new data [`BlobContent`] from the provided bytes.
1575    pub fn new_data(bytes: impl Into<Box<[u8]>>) -> Self {
1576        BlobContent::new(BlobType::Data, bytes)
1577    }
1578
1579    /// Creates a new contract bytecode [`BlobContent`] from the provided bytes.
1580    pub fn new_contract_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1581        BlobContent {
1582            blob_type: BlobType::ContractBytecode,
1583            bytes: compressed_bytecode.compressed_bytes,
1584        }
1585    }
1586
1587    /// Creates a new contract bytecode [`BlobContent`] from the provided bytes.
1588    pub fn new_evm_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1589        BlobContent {
1590            blob_type: BlobType::EvmBytecode,
1591            bytes: compressed_bytecode.compressed_bytes,
1592        }
1593    }
1594
1595    /// Creates a new service bytecode [`BlobContent`] from the provided bytes.
1596    pub fn new_service_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1597        BlobContent {
1598            blob_type: BlobType::ServiceBytecode,
1599            bytes: compressed_bytecode.compressed_bytes,
1600        }
1601    }
1602
1603    /// Creates a new application description [`BlobContent`] from a [`ApplicationDescription`].
1604    pub fn new_application_description(application_description: &ApplicationDescription) -> Self {
1605        let bytes = application_description.to_bytes();
1606        BlobContent::new(BlobType::ApplicationDescription, bytes)
1607    }
1608
1609    /// Creates a new application formats [`BlobContent`] from the JSON-encoded
1610    /// `Formats` description bytes.
1611    pub fn new_application_formats(bytes: impl Into<Box<[u8]>>) -> Self {
1612        BlobContent::new(BlobType::ApplicationFormats, bytes)
1613    }
1614
1615    /// Creates a new committee [`BlobContent`] from the provided serialized committee.
1616    pub fn new_committee(committee: impl Into<Box<[u8]>>) -> Self {
1617        BlobContent::new(BlobType::Committee, committee)
1618    }
1619
1620    /// Creates a new chain description [`BlobContent`] from a [`ChainDescription`].
1621    pub fn new_chain_description(chain_description: &ChainDescription) -> Self {
1622        let bytes = bcs::to_bytes(&chain_description)
1623            .expect("Serializing a ChainDescription should not fail!");
1624        BlobContent::new(BlobType::ChainDescription, bytes)
1625    }
1626
1627    /// Gets a reference to the blob's bytes.
1628    pub fn bytes(&self) -> &[u8] {
1629        &self.bytes
1630    }
1631
1632    /// Converts a `BlobContent` into `Vec<u8>` without cloning if possible.
1633    pub fn into_vec_or_clone(self) -> Vec<u8> {
1634        let bytes = Arc::unwrap_or_clone(self.bytes);
1635        bytes.into_vec()
1636    }
1637
1638    /// Gets the `Arc<Box<[u8]>>` directly without cloning.
1639    pub fn into_arc_bytes(self) -> Arc<Box<[u8]>> {
1640        self.bytes
1641    }
1642
1643    /// Returns the type of data represented by this blob's bytes.
1644    pub fn blob_type(&self) -> BlobType {
1645        self.blob_type
1646    }
1647}
1648
1649impl From<Blob> for BlobContent {
1650    fn from(blob: Blob) -> BlobContent {
1651        blob.content
1652    }
1653}
1654
1655impl From<Arc<Blob>> for BlobContent {
1656    fn from(blob: Arc<Blob>) -> BlobContent {
1657        blob.content().clone()
1658    }
1659}
1660
1661/// A blob of binary data, with its hash.
1662#[derive(Debug, Hash, PartialEq, Eq, Clone, Allocative)]
1663pub struct Blob {
1664    /// ID of the blob.
1665    hash: CryptoHash,
1666    /// A blob of binary data.
1667    content: BlobContent,
1668}
1669
1670impl Blob {
1671    /// Computes the hash and returns the hashed blob for the given content.
1672    pub fn new(content: BlobContent) -> Self {
1673        let mut hash = CryptoHash::new(&content);
1674        if matches!(content.blob_type, BlobType::ApplicationDescription) {
1675            let application_description = bcs::from_bytes::<ApplicationDescription>(&content.bytes)
1676                .expect("to obtain an application description");
1677            if matches!(application_description.module_id.vm_runtime, VmRuntime::Evm) {
1678                hash.make_evm_compatible();
1679            }
1680        }
1681        Blob { hash, content }
1682    }
1683
1684    /// Creates a blob from ud and content without checks
1685    pub fn new_with_hash_unchecked(blob_id: BlobId, content: BlobContent) -> Self {
1686        Blob {
1687            hash: blob_id.hash,
1688            content,
1689        }
1690    }
1691
1692    /// Creates a blob without checking that the hash actually matches the content.
1693    pub fn new_with_id_unchecked(blob_id: BlobId, bytes: impl Into<Box<[u8]>>) -> Self {
1694        let bytes = bytes.into();
1695        Blob {
1696            hash: blob_id.hash,
1697            content: BlobContent {
1698                blob_type: blob_id.blob_type,
1699                bytes: Arc::new(bytes),
1700            },
1701        }
1702    }
1703
1704    /// Creates a new data [`Blob`] from the provided bytes.
1705    pub fn new_data(bytes: impl Into<Box<[u8]>>) -> Self {
1706        Blob::new(BlobContent::new_data(bytes))
1707    }
1708
1709    /// Creates a new contract bytecode [`Blob`] from the provided bytes.
1710    pub fn new_contract_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1711        Blob::new(BlobContent::new_contract_bytecode(compressed_bytecode))
1712    }
1713
1714    /// Creates a new contract bytecode [`BlobContent`] from the provided bytes.
1715    pub fn new_evm_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1716        Blob::new(BlobContent::new_evm_bytecode(compressed_bytecode))
1717    }
1718
1719    /// Creates a new service bytecode [`Blob`] from the provided bytes.
1720    pub fn new_service_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1721        Blob::new(BlobContent::new_service_bytecode(compressed_bytecode))
1722    }
1723
1724    /// Creates a new application description [`Blob`] from the provided description.
1725    pub fn new_application_description(application_description: &ApplicationDescription) -> Self {
1726        Blob::new(BlobContent::new_application_description(
1727            application_description,
1728        ))
1729    }
1730
1731    /// Creates a new application formats [`Blob`] from the JSON-encoded
1732    /// `Formats` description bytes.
1733    pub fn new_application_formats(bytes: impl Into<Box<[u8]>>) -> Self {
1734        Blob::new(BlobContent::new_application_formats(bytes))
1735    }
1736
1737    /// Creates a new committee [`Blob`] from the provided bytes.
1738    pub fn new_committee(committee: impl Into<Box<[u8]>>) -> Self {
1739        Blob::new(BlobContent::new_committee(committee))
1740    }
1741
1742    /// Creates a new chain description [`Blob`] from a [`ChainDescription`].
1743    pub fn new_chain_description(chain_description: &ChainDescription) -> Self {
1744        Blob::new(BlobContent::new_chain_description(chain_description))
1745    }
1746
1747    /// A content-addressed blob ID i.e. the hash of the `Blob`.
1748    pub fn id(&self) -> BlobId {
1749        BlobId {
1750            hash: self.hash,
1751            blob_type: self.content.blob_type,
1752        }
1753    }
1754
1755    /// Returns a reference to the inner `BlobContent`, without the hash.
1756    pub fn content(&self) -> &BlobContent {
1757        &self.content
1758    }
1759
1760    /// Moves ownership of the blob of binary data
1761    pub fn into_content(self) -> BlobContent {
1762        self.content
1763    }
1764
1765    /// Gets a reference to the inner blob's bytes.
1766    pub fn bytes(&self) -> &[u8] {
1767        self.content.bytes()
1768    }
1769
1770    /// Returns whether the blob is of [`BlobType::Committee`] variant.
1771    pub fn is_committee_blob(&self) -> bool {
1772        self.content().blob_type().is_committee_blob()
1773    }
1774
1775    /// Returns whether the blob carries a chunk of a checkpoint's execution-state dump.
1776    pub fn is_checkpoint_blob(&self) -> bool {
1777        self.content().blob_type().is_checkpoint_blob()
1778    }
1779}
1780
1781impl Serialize for Blob {
1782    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1783    where
1784        S: Serializer,
1785    {
1786        if serializer.is_human_readable() {
1787            let blob_bytes = bcs::to_bytes(&self.content).map_err(serde::ser::Error::custom)?;
1788            serializer.serialize_str(&hex::encode(blob_bytes))
1789        } else {
1790            BlobContent::serialize(self.content(), serializer)
1791        }
1792    }
1793}
1794
1795impl<'a> Deserialize<'a> for Blob {
1796    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1797    where
1798        D: Deserializer<'a>,
1799    {
1800        if deserializer.is_human_readable() {
1801            let s = String::deserialize(deserializer)?;
1802            let content_bytes = hex::decode(s).map_err(serde::de::Error::custom)?;
1803            let content: BlobContent =
1804                bcs::from_bytes(&content_bytes).map_err(serde::de::Error::custom)?;
1805
1806            Ok(Blob::new(content))
1807        } else {
1808            let content = BlobContent::deserialize(deserializer)?;
1809            Ok(Blob::new(content))
1810        }
1811    }
1812}
1813
1814impl BcsHashable<'_> for Blob {}
1815
1816/// An event recorded in a block.
1817#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, SimpleObject, Allocative)]
1818pub struct Event {
1819    /// The ID of the stream this event belongs to.
1820    pub stream_id: StreamId,
1821    /// The event index, i.e. the number of events in the stream before this one.
1822    pub index: u32,
1823    /// The payload data.
1824    #[debug(with = "hex_debug")]
1825    #[serde(with = "serde_bytes")]
1826    pub value: Vec<u8>,
1827}
1828
1829impl Event {
1830    /// Returns the ID of this event record, given the publisher chain ID.
1831    pub fn id(&self, chain_id: ChainId) -> EventId {
1832        EventId {
1833            chain_id,
1834            stream_id: self.stream_id.clone(),
1835            index: self.index,
1836        }
1837    }
1838}
1839
1840/// An update for a stream with new events.
1841#[derive(Clone, Debug, Serialize, Deserialize, WitType, WitLoad, WitStore)]
1842pub struct StreamUpdate {
1843    /// The publishing chain.
1844    pub chain_id: ChainId,
1845    /// The stream ID.
1846    pub stream_id: StreamId,
1847    /// The lowest index of a new event. See [`StreamUpdate::new_indices`].
1848    pub previous_index: u32,
1849    /// The index of the next event, i.e. the lowest for which no event is known yet.
1850    pub next_index: u32,
1851}
1852
1853impl StreamUpdate {
1854    /// Returns the indices of all new events in the stream.
1855    pub fn new_indices(&self) -> impl Iterator<Item = u32> {
1856        self.previous_index..self.next_index
1857    }
1858}
1859
1860impl BcsHashable<'_> for Event {}
1861
1862/// Policies for automatically handling incoming messages.
1863#[derive(
1864    Clone,
1865    Debug,
1866    Default,
1867    PartialEq,
1868    serde::Serialize,
1869    serde::Deserialize,
1870    async_graphql::SimpleObject,
1871)]
1872pub struct MessagePolicy {
1873    /// The blanket policy applied to all messages.
1874    pub blanket: BlanketMessagePolicy,
1875    /// A collection of chains which restrict the origin of messages to be
1876    /// accepted. `Option::None` means that messages from all chains are accepted. An empty
1877    /// `HashSet` denotes that messages from no chains are accepted.
1878    pub restrict_chain_ids_to: Option<HashSet<ChainId>>,
1879    /// A collection of chains whose incoming messages should be ignored.
1880    pub ignore_chain_ids: HashSet<ChainId>,
1881    /// A collection of applications: If `Some`, only bundles with at least one message by any
1882    /// of these applications will be accepted.
1883    pub reject_message_bundles_without_application_ids: Option<HashSet<GenericApplicationId>>,
1884    /// A collection of applications: If `Some`, only bundles all of whose messages are by these
1885    /// applications will be accepted.
1886    pub reject_message_bundles_with_other_application_ids: Option<HashSet<GenericApplicationId>>,
1887    /// A collection of applications: If `Some`, only event streams from those
1888    /// applications will be processed.
1889    pub process_events_from_application_ids: Option<HashSet<GenericApplicationId>>,
1890    /// A collection of applications whose messages must never be rejected. Bundles whose
1891    /// messages are all from one of these applications bypass the other rejection rules
1892    /// (except `restrict_chain_ids_to`), and on execution failure they are discarded for
1893    /// later retry instead of being rejected. A bundle that contains any message from an
1894    /// application not on this list can be rejected. An empty set disables this feature.
1895    pub never_reject_application_ids: HashSet<GenericApplicationId>,
1896}
1897
1898/// A blanket policy to apply to all messages by default.
1899#[derive(
1900    Default,
1901    Copy,
1902    Clone,
1903    Debug,
1904    PartialEq,
1905    Eq,
1906    serde::Serialize,
1907    serde::Deserialize,
1908    async_graphql::Enum,
1909)]
1910#[cfg_attr(web, derive(tsify::Tsify), tsify(from_wasm_abi, into_wasm_abi))]
1911#[cfg_attr(any(web, not(target_arch = "wasm32")), derive(clap::ValueEnum))]
1912pub enum BlanketMessagePolicy {
1913    /// Automatically accept all incoming messages. Reject them only if execution fails.
1914    #[default]
1915    Accept,
1916    /// Automatically reject tracked messages, ignore or skip untracked messages, but accept
1917    /// protected ones.
1918    Reject,
1919    /// Don't include any messages in blocks, and don't make any decision whether to accept or
1920    /// reject.
1921    Ignore,
1922}
1923
1924impl MessagePolicy {
1925    /// Returns `true` if the blanket policy is to ignore messages.
1926    #[instrument(level = "trace", skip(self))]
1927    pub fn is_ignore(&self) -> bool {
1928        matches!(self.blanket, BlanketMessagePolicy::Ignore)
1929    }
1930
1931    /// Returns `true` if the blanket policy is to reject messages.
1932    #[instrument(level = "trace", skip(self))]
1933    pub fn is_reject(&self) -> bool {
1934        matches!(self.blanket, BlanketMessagePolicy::Reject)
1935    }
1936
1937    /// Returns `true` if every message from `origin` would be unconditionally dropped:
1938    /// blanket policy is `Ignore`, the origin is in `ignore_chain_ids`, or
1939    /// `restrict_chain_ids_to` is `Some` and does not contain the origin.
1940    #[instrument(level = "trace", skip(self))]
1941    pub fn ignores_origin(&self, origin: &ChainId) -> bool {
1942        self.is_ignore()
1943            || self.ignore_chain_ids.contains(origin)
1944            || self
1945                .restrict_chain_ids_to
1946                .as_ref()
1947                .is_some_and(|set| !set.contains(origin))
1948    }
1949}
1950
1951doc_scalar!(Bytecode, "A module bytecode (WebAssembly or EVM)");
1952doc_scalar!(Amount, "A non-negative amount of tokens.");
1953doc_scalar!(
1954    Epoch,
1955    "A number identifying the configuration of the chain (aka the committee)"
1956);
1957doc_scalar!(BlockHeight, "A block height to identify blocks in a chain");
1958doc_scalar!(
1959    Timestamp,
1960    "A timestamp, in microseconds since the Unix epoch"
1961);
1962doc_scalar!(TimeDelta, "A duration in microseconds");
1963doc_scalar!(
1964    Round,
1965    "A number to identify successive attempts to decide a value in a consensus protocol."
1966);
1967doc_scalar!(
1968    ChainDescription,
1969    "Initial chain configuration and chain origin."
1970);
1971doc_scalar!(OracleResponse, "A record of a single oracle response.");
1972doc_scalar!(BlobContent, "A blob of binary data.");
1973doc_scalar!(
1974    Blob,
1975    "A blob of binary data, with its content-addressed blob ID."
1976);
1977doc_scalar!(ApplicationDescription, "Description of a user application");
1978
1979#[cfg(with_metrics)]
1980mod metrics {
1981    use std::sync::LazyLock;
1982
1983    use prometheus::HistogramVec;
1984
1985    use crate::prometheus_util::{
1986        exponential_bucket_interval, exponential_bucket_latencies, register_histogram_vec,
1987    };
1988
1989    /// The time it takes to compress a bytecode.
1990    pub static BYTECODE_COMPRESSION_LATENCY: LazyLock<HistogramVec> = LazyLock::new(|| {
1991        register_histogram_vec(
1992            "bytecode_compression_latency",
1993            "Bytecode compression latency",
1994            &[],
1995            exponential_bucket_latencies(10.0),
1996        )
1997    });
1998
1999    /// The time it takes to decompress a bytecode.
2000    pub static BYTECODE_DECOMPRESSION_LATENCY: LazyLock<HistogramVec> = LazyLock::new(|| {
2001        register_histogram_vec(
2002            "bytecode_decompression_latency",
2003            "Bytecode decompression latency",
2004            &[],
2005            exponential_bucket_latencies(10.0),
2006        )
2007    });
2008
2009    pub static BYTECODE_DECOMPRESSED_SIZE_BYTES: LazyLock<HistogramVec> = LazyLock::new(|| {
2010        register_histogram_vec(
2011            "wasm_bytecode_decompressed_size_bytes",
2012            "Decompressed size in bytes of WASM bytecodes stored on-chain",
2013            &[],
2014            exponential_bucket_interval(10_000.0, 100_000_000.0),
2015        )
2016    });
2017}
2018
2019#[cfg(test)]
2020mod tests {
2021    use std::str::FromStr;
2022
2023    use alloy_primitives::U256;
2024
2025    use super::{Amount, ApplicationDescription, BlobContent};
2026    use crate::{
2027        crypto::CryptoHash,
2028        data_types::BlockHeight,
2029        identifiers::{BlobType, ChainId, ModuleId},
2030        vm::VmRuntime,
2031    };
2032
2033    #[test]
2034    fn non_canonical_btree_map_serializes_like_vec() {
2035        use std::collections::BTreeMap;
2036
2037        use super::NonCanonicalBTreeMap;
2038
2039        // `256u32` is chosen so that its little-endian BCS bytes sort *before* `1u32`'s,
2040        // i.e. the canonical (serialized-byte) order differs from the numeric `Ord` order.
2041        let map = NonCanonicalBTreeMap::from(BTreeMap::from([
2042            (1u32, 10u8),
2043            (256u32, 20u8),
2044            (2u32, 30u8),
2045        ]));
2046
2047        // It serializes as a plain `Vec<(K, V)>` in the map's `Ord` key order, with no canonical
2048        // re-sorting.
2049        let entries = map
2050            .iter()
2051            .map(|(k, v)| (*k, *v))
2052            .collect::<Vec<(u32, u8)>>();
2053        assert_eq!(
2054            bcs::to_bytes(&map).unwrap(),
2055            bcs::to_bytes(&entries).unwrap()
2056        );
2057
2058        // ... which differs from the canonical `BTreeMap` encoding that re-sorts by serialized key.
2059        let canonical = map
2060            .iter()
2061            .map(|(k, v)| (*k, *v))
2062            .collect::<BTreeMap<u32, u8>>();
2063        assert_ne!(
2064            bcs::to_bytes(&map).unwrap(),
2065            bcs::to_bytes(&canonical).unwrap()
2066        );
2067
2068        // It round-trips.
2069        let deserialized: NonCanonicalBTreeMap<u32, u8> =
2070            bcs::from_bytes(&bcs::to_bytes(&map).unwrap()).unwrap();
2071        assert_eq!(map, deserialized);
2072    }
2073
2074    #[test]
2075    fn canonical_btree_set_serializes_like_map() {
2076        use std::collections::{BTreeMap, BTreeSet};
2077
2078        use super::CanonicalBTreeSet;
2079
2080        let set = CanonicalBTreeSet::from(BTreeSet::from([1u32, 256u32, 2u32]));
2081
2082        // It serializes exactly like a `BTreeMap<T, ()>`, i.e. canonically sorted by serialized
2083        // bytes.
2084        let map = set.iter().map(|t| (*t, ())).collect::<BTreeMap<u32, ()>>();
2085        assert_eq!(bcs::to_bytes(&set).unwrap(), bcs::to_bytes(&map).unwrap());
2086
2087        // That canonical order differs from a plain `BTreeSet`'s sequence encoding, which keeps
2088        // the numeric `Ord` order.
2089        let plain = set.iter().copied().collect::<BTreeSet<u32>>();
2090        assert_ne!(bcs::to_bytes(&set).unwrap(), bcs::to_bytes(&plain).unwrap());
2091
2092        // It round-trips.
2093        let deserialized: CanonicalBTreeSet<u32> =
2094            bcs::from_bytes(&bcs::to_bytes(&set).unwrap()).unwrap();
2095        assert_eq!(set, deserialized);
2096    }
2097
2098    #[test]
2099    fn display_amount() {
2100        assert_eq!("1.", Amount::ONE.to_string());
2101        assert_eq!("1.", Amount::from_str("1.").unwrap().to_string());
2102        assert_eq!(
2103            Amount(10_000_000_000_000_000_000),
2104            Amount::from_str("10").unwrap()
2105        );
2106        assert_eq!("10.", Amount(10_000_000_000_000_000_000).to_string());
2107        assert_eq!(
2108            "1001.3",
2109            (Amount::from_str("1.1")
2110                .unwrap()
2111                .saturating_add(Amount::from_str("1_000.2").unwrap()))
2112            .to_string()
2113        );
2114        assert_eq!(
2115            "   1.00000000000000000000",
2116            format!("{:25.20}", Amount::ONE)
2117        );
2118        assert_eq!(
2119            "~+12.34~~",
2120            format!("{:~^+9.1}", Amount::from_str("12.34").unwrap())
2121        );
2122    }
2123
2124    #[test]
2125    fn blob_content_serialization_deserialization() {
2126        let test_data = b"Hello, world!".as_slice();
2127        let original_blob = BlobContent::new(BlobType::Data, test_data);
2128
2129        let serialized = bcs::to_bytes(&original_blob).expect("Failed to serialize BlobContent");
2130        let deserialized: BlobContent =
2131            bcs::from_bytes(&serialized).expect("Failed to deserialize BlobContent");
2132        assert_eq!(original_blob, deserialized);
2133
2134        let serialized =
2135            serde_json::to_vec(&original_blob).expect("Failed to serialize BlobContent");
2136        let deserialized: BlobContent =
2137            serde_json::from_slice(&serialized).expect("Failed to deserialize BlobContent");
2138        assert_eq!(original_blob, deserialized);
2139    }
2140
2141    #[test]
2142    fn blob_content_hash_consistency() {
2143        let test_data = b"Hello, world!";
2144        let blob1 = BlobContent::new(BlobType::Data, test_data.as_slice());
2145        let blob2 = BlobContent::new(BlobType::Data, Vec::from(test_data.as_slice()));
2146
2147        // Both should have same hash since they contain the same data
2148        let hash1 = crate::crypto::CryptoHash::new(&blob1);
2149        let hash2 = crate::crypto::CryptoHash::new(&blob2);
2150
2151        assert_eq!(hash1, hash2, "Hashes should be equal for same content");
2152        assert_eq!(blob1.bytes(), blob2.bytes(), "Byte content should be equal");
2153    }
2154
2155    #[test]
2156    fn test_conversion_amount_u256() {
2157        let value_amount = Amount::from_tokens(15656565652209004332);
2158        let value_u256: U256 = value_amount.into();
2159        let value_amount_rev = Amount::try_from(value_u256).expect("Failed conversion");
2160        assert_eq!(value_amount, value_amount_rev);
2161    }
2162
2163    /// `linera-explorer` running on `wasm32` does not have access to the
2164    /// strongly-typed `ApplicationDescription`: the GraphQL client substitutes
2165    /// it for `serde_json::Value`. The explorer therefore fetches the module ID
2166    /// for an application by indexing into the JSON object as
2167    /// `description["module_id"]`. This test pins that field name and the
2168    /// hex-string shape of the serialized `ModuleId` so a future rename or
2169    /// representation change immediately breaks here instead of silently in the
2170    /// browser.
2171    #[test]
2172    fn application_description_serializes_module_id_as_hex_string() {
2173        let module_id = ModuleId::new(
2174            CryptoHash::test_hash("contract-bytecode"),
2175            CryptoHash::test_hash("service-bytecode"),
2176            VmRuntime::Wasm,
2177        );
2178        let description = ApplicationDescription {
2179            module_id,
2180            creator_chain_id: ChainId(CryptoHash::test_hash("chain")),
2181            block_height: BlockHeight(0),
2182            application_index: 0,
2183            parameters: Vec::new(),
2184            required_application_ids: Vec::new(),
2185        };
2186
2187        let value = serde_json::to_value(&description).unwrap();
2188        let module_id_value = value
2189            .get("module_id")
2190            .expect("`module_id` is the field name the explorer indexes into");
2191        let hex = module_id_value
2192            .as_str()
2193            .expect("`module_id` must serialize as a hex string in human-readable form");
2194        let roundtrip: ModuleId =
2195            serde_json::from_value(serde_json::Value::String(hex.to_owned())).unwrap();
2196        assert_eq!(roundtrip, module_id);
2197    }
2198}