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