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        AccountOwner, ApplicationId, BlobId, BlobType, ChainId, EventId, GenericApplicationId,
36        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
358/// Error converting from `U256` to `Amount`.
359/// This can fail since `Amount` is a `u128`.
360#[derive(Error, Debug)]
361#[error("Failed to convert U256 to Amount. {0} has more than 128 bits")]
362pub struct AmountConversionError(U256);
363
364impl TryFrom<U256> for Amount {
365    type Error = AmountConversionError;
366    fn try_from(value: U256) -> Result<Amount, Self::Error> {
367        let value = u128::try_from(&value).map_err(|_| AmountConversionError(value))?;
368        Ok(Amount(value))
369    }
370}
371
372/// A `u128` newtype that serializes as a decimal string in human-readable
373/// formats (JSON / GraphQL) and as a bare `u128` in binary (BCS).
374#[derive(
375    Clone,
376    Copy,
377    Debug,
378    Default,
379    Eq,
380    Ord,
381    PartialEq,
382    PartialOrd,
383    Hash,
384    derive_more::Display,
385    derive_more::Deref,
386    derive_more::DerefMut,
387    derive_more::FromStr,
388)]
389pub struct U128(pub u128);
390
391impl Serialize for U128 {
392    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
393    where
394        S: Serializer,
395    {
396        if serializer.is_human_readable() {
397            serializer.serialize_str(&self.0.to_string())
398        } else {
399            self.0.serialize(serializer)
400        }
401    }
402}
403
404impl<'de> Deserialize<'de> for U128 {
405    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
406    where
407        D: Deserializer<'de>,
408    {
409        if deserializer.is_human_readable() {
410            let s = String::deserialize(deserializer)?;
411            s.parse().map(U128).map_err(serde::de::Error::custom)
412        } else {
413            u128::deserialize(deserializer).map(U128)
414        }
415    }
416}
417
418/// A block height to identify blocks in a chain.
419#[derive(
420    Eq,
421    PartialEq,
422    Ord,
423    PartialOrd,
424    Copy,
425    Clone,
426    Hash,
427    Default,
428    Debug,
429    Serialize,
430    Deserialize,
431    WitType,
432    WitLoad,
433    WitStore,
434    Allocative,
435)]
436#[cfg_attr(with_testing, derive(test_strategy::Arbitrary))]
437pub struct BlockHeight(pub u64);
438
439/// An identifier for successive attempts to decide a value in a consensus protocol.
440#[derive(
441    Eq,
442    PartialEq,
443    Ord,
444    PartialOrd,
445    Copy,
446    Clone,
447    Hash,
448    Default,
449    Debug,
450    Serialize,
451    Deserialize,
452    Allocative,
453)]
454#[cfg_attr(with_testing, derive(test_strategy::Arbitrary))]
455pub enum Round {
456    /// The initial fast round.
457    #[default]
458    Fast,
459    /// The N-th multi-leader round.
460    MultiLeader(u32),
461    /// The N-th single-leader round.
462    SingleLeader(u32),
463    /// The N-th round where the validators rotate as leaders.
464    Validator(u32),
465}
466
467/// A duration in microseconds.
468#[derive(
469    Eq,
470    PartialEq,
471    Ord,
472    PartialOrd,
473    Copy,
474    Clone,
475    Hash,
476    Default,
477    Debug,
478    Serialize,
479    Deserialize,
480    WitType,
481    WitLoad,
482    WitStore,
483    Allocative,
484)]
485pub struct TimeDelta(u64);
486
487impl TimeDelta {
488    /// Returns the given number of microseconds as a [`TimeDelta`].
489    pub const fn from_micros(micros: u64) -> Self {
490        TimeDelta(micros)
491    }
492
493    /// Returns the given number of milliseconds as a [`TimeDelta`].
494    pub const fn from_millis(millis: u64) -> Self {
495        TimeDelta(millis.saturating_mul(1_000))
496    }
497
498    /// Returns the given number of seconds as a [`TimeDelta`].
499    pub const fn from_secs(secs: u64) -> Self {
500        TimeDelta(secs.saturating_mul(1_000_000))
501    }
502
503    /// Returns the given [`Duration`] as a [`TimeDelta`], saturating at the maximum on overflow.
504    pub fn from_duration(duration: Duration) -> Self {
505        TimeDelta(u64::try_from(duration.as_micros()).unwrap_or(u64::MAX))
506    }
507
508    /// Returns this [`TimeDelta`] as a number of microseconds.
509    pub const fn as_micros(&self) -> u64 {
510        self.0
511    }
512
513    /// Returns this [`TimeDelta`] as a [`Duration`].
514    pub const fn as_duration(&self) -> Duration {
515        Duration::from_micros(self.as_micros())
516    }
517}
518
519/// A timestamp, in microseconds since the Unix epoch.
520#[derive(
521    Eq,
522    PartialEq,
523    Ord,
524    PartialOrd,
525    Copy,
526    Clone,
527    Hash,
528    Default,
529    Debug,
530    Serialize,
531    Deserialize,
532    WitType,
533    WitLoad,
534    WitStore,
535    Allocative,
536)]
537pub struct Timestamp(u64);
538
539impl Timestamp {
540    /// Returns the current time according to the system clock.
541    pub fn now() -> Timestamp {
542        Timestamp(
543            SystemTime::UNIX_EPOCH
544                .elapsed()
545                .expect("system time should be after Unix epoch")
546                .as_micros()
547                .try_into()
548                .unwrap_or(u64::MAX),
549        )
550    }
551
552    /// Returns the number of microseconds since the Unix epoch.
553    pub const fn micros(&self) -> u64 {
554        self.0
555    }
556
557    /// Returns the [`TimeDelta`] between `other` and `self`, or zero if `other` is not earlier
558    /// than `self`.
559    pub const fn delta_since(&self, other: Timestamp) -> TimeDelta {
560        TimeDelta::from_micros(self.0.saturating_sub(other.0))
561    }
562
563    /// Returns the [`Duration`] between `other` and `self`, or zero if `other` is not
564    /// earlier than `self`.
565    pub const fn duration_since(&self, other: Timestamp) -> Duration {
566        Duration::from_micros(self.0.saturating_sub(other.0))
567    }
568
569    /// Returns the timestamp that is `duration` later than `self`.
570    pub const fn saturating_add(&self, duration: TimeDelta) -> Timestamp {
571        Timestamp(self.0.saturating_add(duration.0))
572    }
573
574    /// Returns the timestamp that is `duration` earlier than `self`.
575    pub const fn saturating_sub(&self, duration: TimeDelta) -> Timestamp {
576        Timestamp(self.0.saturating_sub(duration.0))
577    }
578
579    /// Returns a timestamp `micros` microseconds earlier than `self`, or the lowest possible value
580    /// if it would underflow.
581    pub const fn saturating_sub_micros(&self, micros: u64) -> Timestamp {
582        Timestamp(self.0.saturating_sub(micros))
583    }
584}
585
586impl From<u64> for Timestamp {
587    fn from(t: u64) -> Timestamp {
588        Timestamp(t)
589    }
590}
591
592impl Display for Timestamp {
593    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
594        let seconds = i64::try_from(self.0 / 1_000_000).unwrap_or(i64::MAX);
595        // `% 1_000_000` keeps the value below 10^9, which fits in `u32`.
596        let nanos = u32::try_from((self.0 % 1_000_000) * 1_000)
597            .expect("microseconds modulo 1_000_000 multiplied by 1_000 fits in u32");
598        if let Some(date_time) = chrono::DateTime::from_timestamp(seconds, nanos) {
599            return date_time.naive_utc().fmt(f);
600        }
601        self.0.fmt(f)
602    }
603}
604
605impl FromStr for Timestamp {
606    type Err = chrono::ParseError;
607
608    fn from_str(s: &str) -> Result<Self, Self::Err> {
609        let naive = chrono::NaiveDateTime::parse_from_str(s, "%Y-%m-%dT%H:%M:%S")
610            .or_else(|_| chrono::NaiveDateTime::parse_from_str(s, "%Y-%m-%d %H:%M:%S"))?;
611        let micros = naive
612            .and_utc()
613            .timestamp_micros()
614            .try_into()
615            .unwrap_or(u64::MAX);
616        Ok(Timestamp(micros))
617    }
618}
619
620/// Resources that an application may spend during the execution of transaction or an
621/// application call.
622#[derive(
623    Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize, WitLoad, WitStore, WitType,
624)]
625pub struct Resources {
626    /// An amount of Wasm execution fuel.
627    pub wasm_fuel: u64,
628    /// An amount of EVM execution fuel.
629    pub evm_fuel: u64,
630    /// A number of read operations to be executed.
631    pub read_operations: u32,
632    /// A number of write operations to be executed.
633    pub write_operations: u32,
634    /// A number of bytes read from runtime.
635    pub bytes_runtime: u32,
636    /// A number of bytes to read.
637    pub bytes_to_read: u32,
638    /// A number of bytes to write.
639    pub bytes_to_write: u32,
640    /// A number of blobs to read.
641    pub blobs_to_read: u32,
642    /// A number of blobs to publish.
643    pub blobs_to_publish: u32,
644    /// A number of blob bytes to read.
645    pub blob_bytes_to_read: u32,
646    /// A number of blob bytes to publish.
647    pub blob_bytes_to_publish: u32,
648    /// A number of messages to be sent.
649    pub messages: u32,
650    /// The size of the messages to be sent.
651    // TODO(#1531): Account for the type of message to be sent.
652    pub message_size: u32,
653    /// A number of service-as-oracle requests to be performed.
654    pub service_as_oracle_queries: u32,
655    /// A number of HTTP requests to be performed.
656    pub http_requests: u32,
657    // TODO(#1532): Account for the system calls that we plan on calling.
658    // TODO(#1533): Allow declaring calls to other applications instead of having to count them here.
659}
660
661/// A request to send a message.
662#[derive(Clone, Debug, Deserialize, Serialize, WitLoad, WitType)]
663#[cfg_attr(with_testing, derive(Eq, PartialEq, WitStore))]
664#[witty_specialize_with(Message = Vec<u8>)]
665pub struct SendMessageRequest<Message> {
666    /// The destination of the message.
667    pub destination: ChainId,
668    /// Whether the message is authenticated.
669    pub authenticated: bool,
670    /// Whether the message is tracked.
671    pub is_tracked: bool,
672    /// The grant resources forwarded with the message.
673    pub grant: Resources,
674    /// The message itself.
675    pub message: Message,
676}
677
678/// An error type for arithmetic errors.
679#[derive(Debug, Error)]
680#[allow(missing_docs)]
681pub enum ArithmeticError {
682    #[error("Number overflow")]
683    Overflow,
684    #[error("Number underflow")]
685    Underflow,
686}
687
688macro_rules! impl_wrapped_number {
689    ($name:ident, $wrapped:ident) => {
690        impl $name {
691            /// The zero value.
692            pub const ZERO: Self = Self(0);
693
694            /// The maximum value.
695            pub const MAX: Self = Self($wrapped::MAX);
696
697            /// Checked addition.
698            pub fn try_add(self, other: Self) -> Result<Self, ArithmeticError> {
699                let val = self
700                    .0
701                    .checked_add(other.0)
702                    .ok_or(ArithmeticError::Overflow)?;
703                Ok(Self(val))
704            }
705
706            /// Checked increment.
707            pub fn try_add_one(self) -> Result<Self, ArithmeticError> {
708                let val = self.0.checked_add(1).ok_or(ArithmeticError::Overflow)?;
709                Ok(Self(val))
710            }
711
712            /// Saturating addition.
713            pub const fn saturating_add(self, other: Self) -> Self {
714                let val = self.0.saturating_add(other.0);
715                Self(val)
716            }
717
718            /// Checked subtraction.
719            pub fn try_sub(self, other: Self) -> Result<Self, ArithmeticError> {
720                let val = self
721                    .0
722                    .checked_sub(other.0)
723                    .ok_or(ArithmeticError::Underflow)?;
724                Ok(Self(val))
725            }
726
727            /// Checked decrement.
728            pub fn try_sub_one(self) -> Result<Self, ArithmeticError> {
729                let val = self.0.checked_sub(1).ok_or(ArithmeticError::Underflow)?;
730                Ok(Self(val))
731            }
732
733            /// Saturating subtraction.
734            pub const fn saturating_sub(self, other: Self) -> Self {
735                let val = self.0.saturating_sub(other.0);
736                Self(val)
737            }
738
739            /// Returns the absolute difference between `self` and `other`.
740            pub fn abs_diff(self, other: Self) -> Self {
741                Self(self.0.abs_diff(other.0))
742            }
743
744            /// Returns the midpoint of `self` and `other`, rounded down.
745            pub const fn midpoint(self, other: Self) -> Self {
746                Self(self.0.midpoint(other.0))
747            }
748
749            /// Checked in-place addition.
750            pub fn try_add_assign(&mut self, other: Self) -> Result<(), ArithmeticError> {
751                self.0 = self
752                    .0
753                    .checked_add(other.0)
754                    .ok_or(ArithmeticError::Overflow)?;
755                Ok(())
756            }
757
758            /// Checked in-place increment.
759            pub fn try_add_assign_one(&mut self) -> Result<(), ArithmeticError> {
760                self.0 = self.0.checked_add(1).ok_or(ArithmeticError::Overflow)?;
761                Ok(())
762            }
763
764            /// Saturating in-place addition.
765            pub const fn saturating_add_assign(&mut self, other: Self) {
766                self.0 = self.0.saturating_add(other.0);
767            }
768
769            /// Checked in-place subtraction.
770            pub fn try_sub_assign(&mut self, other: Self) -> Result<(), ArithmeticError> {
771                self.0 = self
772                    .0
773                    .checked_sub(other.0)
774                    .ok_or(ArithmeticError::Underflow)?;
775                Ok(())
776            }
777
778            /// Saturating division.
779            pub fn saturating_div(&self, other: $wrapped) -> Self {
780                Self(self.0.checked_div(other).unwrap_or($wrapped::MAX))
781            }
782
783            /// Saturating multiplication.
784            pub const fn saturating_mul(&self, other: $wrapped) -> Self {
785                Self(self.0.saturating_mul(other))
786            }
787
788            /// Checked multiplication.
789            pub fn try_mul(self, other: $wrapped) -> Result<Self, ArithmeticError> {
790                let val = self.0.checked_mul(other).ok_or(ArithmeticError::Overflow)?;
791                Ok(Self(val))
792            }
793
794            /// Checked in-place multiplication.
795            pub fn try_mul_assign(&mut self, other: $wrapped) -> Result<(), ArithmeticError> {
796                self.0 = self.0.checked_mul(other).ok_or(ArithmeticError::Overflow)?;
797                Ok(())
798            }
799        }
800
801        impl From<$name> for $wrapped {
802            fn from(value: $name) -> Self {
803                value.0
804            }
805        }
806
807        // Cannot directly create values for a wrapped type, except for testing.
808        #[cfg(with_testing)]
809        impl From<$wrapped> for $name {
810            fn from(value: $wrapped) -> Self {
811                Self(value)
812            }
813        }
814
815        #[cfg(with_testing)]
816        impl ops::Add for $name {
817            type Output = Self;
818
819            fn add(self, other: Self) -> Self {
820                Self(self.0 + other.0)
821            }
822        }
823
824        #[cfg(with_testing)]
825        impl ops::Sub for $name {
826            type Output = Self;
827
828            fn sub(self, other: Self) -> Self {
829                Self(self.0 - other.0)
830            }
831        }
832
833        #[cfg(with_testing)]
834        impl ops::Mul<$wrapped> for $name {
835            type Output = Self;
836
837            fn mul(self, other: $wrapped) -> Self {
838                Self(self.0 * other)
839            }
840        }
841    };
842}
843
844impl TryFrom<BlockHeight> for usize {
845    type Error = ArithmeticError;
846
847    fn try_from(height: BlockHeight) -> Result<usize, ArithmeticError> {
848        usize::try_from(height.0).map_err(|_| ArithmeticError::Overflow)
849    }
850}
851
852impl_wrapped_number!(Amount, u128);
853impl_wrapped_number!(U128, u128);
854impl_wrapped_number!(BlockHeight, u64);
855impl_wrapped_number!(TimeDelta, u64);
856
857impl Display for Amount {
858    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
859        // Print the wrapped integer, padded with zeros to cover a digit before the decimal point.
860        let places = Amount::DECIMAL_PLACES as usize;
861        let min_digits = places + 1;
862        let decimals = format!("{:0min_digits$}", self.0);
863        let integer_part = &decimals[..(decimals.len() - places)];
864        let fractional_part = decimals[(decimals.len() - places)..].trim_end_matches('0');
865
866        // For now, we never trim non-zero digits so we don't lose any precision.
867        let precision = f.precision().unwrap_or(0).max(fractional_part.len());
868        let sign = if f.sign_plus() && self.0 > 0 { "+" } else { "" };
869        // The amount of padding: desired width minus sign, point and number of digits.
870        let pad_width = f.width().map_or(0, |w| {
871            w.saturating_sub(precision)
872                .saturating_sub(sign.len() + integer_part.len() + 1)
873        });
874        let left_pad = match f.align() {
875            None | Some(fmt::Alignment::Right) => pad_width,
876            Some(fmt::Alignment::Center) => pad_width / 2,
877            Some(fmt::Alignment::Left) => 0,
878        };
879
880        for _ in 0..left_pad {
881            write!(f, "{}", f.fill())?;
882        }
883        write!(f, "{sign}{integer_part}.{fractional_part:0<precision$}")?;
884        for _ in left_pad..pad_width {
885            write!(f, "{}", f.fill())?;
886        }
887        Ok(())
888    }
889}
890
891#[derive(Error, Debug)]
892#[allow(missing_docs)]
893pub enum ParseAmountError {
894    #[error("cannot parse amount")]
895    Parse,
896    #[error("cannot represent amount: number too high")]
897    TooHigh,
898    #[error("cannot represent amount: too many decimal places after the point")]
899    TooManyDigits,
900}
901
902impl FromStr for Amount {
903    type Err = ParseAmountError;
904
905    fn from_str(src: &str) -> Result<Self, Self::Err> {
906        let mut result: u128 = 0;
907        let mut decimals: Option<u8> = None;
908        let mut chars = src.trim().chars().peekable();
909        if chars.peek() == Some(&'+') {
910            chars.next();
911        }
912        for char in chars {
913            match char {
914                '_' => {}
915                '.' if decimals.is_some() => return Err(ParseAmountError::Parse),
916                '.' => decimals = Some(Amount::DECIMAL_PLACES),
917                char => {
918                    let digit = u128::from(char.to_digit(10).ok_or(ParseAmountError::Parse)?);
919                    if let Some(d) = &mut decimals {
920                        *d = d.checked_sub(1).ok_or(ParseAmountError::TooManyDigits)?;
921                    }
922                    result = result
923                        .checked_mul(10)
924                        .and_then(|r| r.checked_add(digit))
925                        .ok_or(ParseAmountError::TooHigh)?;
926                }
927            }
928        }
929        result = result
930            .checked_mul(10u128.pow(decimals.unwrap_or(Amount::DECIMAL_PLACES) as u32))
931            .ok_or(ParseAmountError::TooHigh)?;
932        Ok(Amount(result))
933    }
934}
935
936impl Display for BlockHeight {
937    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
938        self.0.fmt(f)
939    }
940}
941
942impl FromStr for BlockHeight {
943    type Err = ParseIntError;
944
945    fn from_str(src: &str) -> Result<Self, Self::Err> {
946        Ok(Self(u64::from_str(src)?))
947    }
948}
949
950/// A logical position in a chain's stream of outgoing messages: the height of the block
951/// that produced the message and the index of the message-producing transaction within
952/// that block.
953#[derive(
954    Debug,
955    Default,
956    Clone,
957    Copy,
958    Hash,
959    Eq,
960    PartialEq,
961    Ord,
962    PartialOrd,
963    Serialize,
964    Deserialize,
965    SimpleObject,
966    Allocative,
967)]
968pub struct Cursor {
969    /// The height of the producing block.
970    pub height: BlockHeight,
971    /// The transaction index within the block.
972    pub index: u32,
973}
974
975impl Cursor {
976    /// Returns the cursor pointing to the next position within the same block, or
977    /// [`ArithmeticError::Overflow`] if `index` is already at the maximum.
978    pub fn try_add_one(self) -> Result<Self, ArithmeticError> {
979        let value = Self {
980            height: self.height,
981            index: self.index.checked_add(1).ok_or(ArithmeticError::Overflow)?,
982        };
983        Ok(value)
984    }
985}
986
987impl Display for Round {
988    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
989        match self {
990            Round::Fast => write!(f, "fast round"),
991            Round::MultiLeader(r) => write!(f, "multi-leader round {r}"),
992            Round::SingleLeader(r) => write!(f, "single-leader round {r}"),
993            Round::Validator(r) => write!(f, "validator round {r}"),
994        }
995    }
996}
997
998impl Round {
999    /// Whether the round is a multi-leader round.
1000    pub fn is_multi_leader(&self) -> bool {
1001        matches!(self, Round::MultiLeader(_))
1002    }
1003
1004    /// Returns the round number if this is a multi-leader round, `None` otherwise.
1005    pub fn multi_leader(&self) -> Option<u32> {
1006        match self {
1007            Round::MultiLeader(number) => Some(*number),
1008            _ => None,
1009        }
1010    }
1011
1012    /// Returns whether this is a validator round.
1013    pub fn is_validator(&self) -> bool {
1014        matches!(self, Round::Validator(_))
1015    }
1016
1017    /// Whether the round is the fast round.
1018    pub fn is_fast(&self) -> bool {
1019        matches!(self, Round::Fast)
1020    }
1021
1022    /// The index of a round amongst the rounds of the same category.
1023    pub fn number(&self) -> u32 {
1024        match self {
1025            Round::Fast => 0,
1026            Round::MultiLeader(r) | Round::SingleLeader(r) | Round::Validator(r) => *r,
1027        }
1028    }
1029
1030    /// The category of the round as a string.
1031    pub fn type_name(&self) -> &'static str {
1032        match self {
1033            Round::Fast => "fast",
1034            Round::MultiLeader(_) => "multi",
1035            Round::SingleLeader(_) => "single",
1036            Round::Validator(_) => "validator",
1037        }
1038    }
1039}
1040
1041impl<'a> iter::Sum<&'a Amount> for Amount {
1042    fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
1043        iter.fold(Self::ZERO, |a, b| a.saturating_add(*b))
1044    }
1045}
1046
1047impl Amount {
1048    /// The base-10 exponent representing how much a token can be divided.
1049    pub const DECIMAL_PLACES: u8 = 18;
1050
1051    /// One token.
1052    pub const ONE: Amount = Amount(10u128.pow(Amount::DECIMAL_PLACES as u32));
1053
1054    /// Returns an `Amount` corresponding to that many tokens, or `Amount::MAX` if saturated.
1055    pub const fn from_tokens(tokens: u128) -> Amount {
1056        Self::ONE.saturating_mul(tokens)
1057    }
1058
1059    /// Returns an `Amount` corresponding to that many millitokens, or `Amount::MAX` if saturated.
1060    pub const fn from_millis(millitokens: u128) -> Amount {
1061        Amount(10u128.pow(Amount::DECIMAL_PLACES as u32 - 3)).saturating_mul(millitokens)
1062    }
1063
1064    /// Returns an `Amount` corresponding to that many microtokens, or `Amount::MAX` if saturated.
1065    pub const fn from_micros(microtokens: u128) -> Amount {
1066        Amount(10u128.pow(Amount::DECIMAL_PLACES as u32 - 6)).saturating_mul(microtokens)
1067    }
1068
1069    /// Returns an `Amount` corresponding to that many nanotokens, or `Amount::MAX` if saturated.
1070    pub const fn from_nanos(nanotokens: u128) -> Amount {
1071        Amount(10u128.pow(Amount::DECIMAL_PLACES as u32 - 9)).saturating_mul(nanotokens)
1072    }
1073
1074    /// Returns an `Amount` corresponding to that many attotokens.
1075    pub const fn from_attos(attotokens: u128) -> Amount {
1076        Amount(attotokens)
1077    }
1078
1079    /// Returns the number of attotokens.
1080    pub const fn to_attos(self) -> u128 {
1081        self.0
1082    }
1083
1084    /// Helper function to obtain the 64 most significant bits of the balance.
1085    pub const fn upper_half(self) -> u64 {
1086        (self.0 >> 64) as u64
1087    }
1088
1089    /// Helper function to obtain the 64 least significant bits of the balance.
1090    #[expect(
1091        clippy::cast_possible_truncation,
1092        reason = "intentional: returns the low 64 bits"
1093    )]
1094    pub const fn lower_half(self) -> u64 {
1095        self.0 as u64
1096    }
1097
1098    /// Divides this by the other amount. If the other is 0, it returns `u128::MAX`.
1099    pub fn saturating_ratio(self, other: Amount) -> u128 {
1100        self.0.checked_div(other.0).unwrap_or(u128::MAX)
1101    }
1102
1103    /// Returns whether this amount is 0.
1104    pub fn is_zero(&self) -> bool {
1105        *self == Amount::ZERO
1106    }
1107}
1108
1109/// What created a chain.
1110#[derive(
1111    Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Hash, Debug, Serialize, Deserialize, Allocative,
1112)]
1113pub enum ChainOrigin {
1114    /// The chain was created by the genesis configuration.
1115    Root(u32),
1116    /// The chain was created by a call from another chain.
1117    Child {
1118        /// The parent of this chain.
1119        parent: ChainId,
1120        /// The block height in the parent at which this chain was created.
1121        block_height: BlockHeight,
1122        /// The index of this chain among chains created at the same block height in the parent
1123        /// chain.
1124        chain_index: u32,
1125    },
1126}
1127
1128impl ChainOrigin {
1129    /// Returns the root chain number, if this is a root chain.
1130    pub fn root(&self) -> Option<u32> {
1131        match self {
1132            ChainOrigin::Root(i) => Some(*i),
1133            ChainOrigin::Child { .. } => None,
1134        }
1135    }
1136}
1137
1138/// A number identifying the configuration of the chain (aka the committee).
1139#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Hash, Default, Debug, Allocative)]
1140pub struct Epoch(pub u32);
1141
1142impl Epoch {
1143    /// The zero epoch.
1144    pub const ZERO: Epoch = Epoch(0);
1145}
1146
1147impl Serialize for Epoch {
1148    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1149    where
1150        S: serde::ser::Serializer,
1151    {
1152        if serializer.is_human_readable() {
1153            serializer.serialize_str(&self.0.to_string())
1154        } else {
1155            serializer.serialize_newtype_struct("Epoch", &self.0)
1156        }
1157    }
1158}
1159
1160impl<'de> Deserialize<'de> for Epoch {
1161    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1162    where
1163        D: serde::de::Deserializer<'de>,
1164    {
1165        if deserializer.is_human_readable() {
1166            let s = String::deserialize(deserializer)?;
1167            Ok(Epoch(u32::from_str(&s).map_err(serde::de::Error::custom)?))
1168        } else {
1169            #[derive(Deserialize)]
1170            #[serde(rename = "Epoch")]
1171            struct EpochDerived(u32);
1172
1173            let value = EpochDerived::deserialize(deserializer)?;
1174            Ok(Self(value.0))
1175        }
1176    }
1177}
1178
1179impl std::fmt::Display for Epoch {
1180    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
1181        write!(f, "{}", self.0)
1182    }
1183}
1184
1185impl std::str::FromStr for Epoch {
1186    type Err = CryptoError;
1187
1188    fn from_str(s: &str) -> Result<Self, Self::Err> {
1189        Ok(Epoch(s.parse()?))
1190    }
1191}
1192
1193impl From<u32> for Epoch {
1194    fn from(value: u32) -> Self {
1195        Epoch(value)
1196    }
1197}
1198
1199impl Epoch {
1200    /// Tries to return an epoch with a number increased by one. Returns an error if an overflow
1201    /// happens.
1202    #[inline]
1203    pub fn try_add_one(self) -> Result<Self, ArithmeticError> {
1204        let val = self.0.checked_add(1).ok_or(ArithmeticError::Overflow)?;
1205        Ok(Self(val))
1206    }
1207
1208    /// Tries to return an epoch with a number decreased by one. Returns an error if an underflow
1209    /// happens.
1210    pub fn try_sub_one(self) -> Result<Self, ArithmeticError> {
1211        let val = self.0.checked_sub(1).ok_or(ArithmeticError::Underflow)?;
1212        Ok(Self(val))
1213    }
1214
1215    /// Tries to add one to this epoch's number. Returns an error if an overflow happens.
1216    #[inline]
1217    pub fn try_add_assign_one(&mut self) -> Result<(), ArithmeticError> {
1218        self.0 = self.0.checked_add(1).ok_or(ArithmeticError::Overflow)?;
1219        Ok(())
1220    }
1221}
1222
1223/// The initial configuration for a new chain.
1224#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, Allocative)]
1225pub struct InitialChainConfig {
1226    /// The ownership configuration of the new chain.
1227    pub ownership: ChainOwnership,
1228    /// The epoch in which the chain is created.
1229    pub epoch: Epoch,
1230    /// The account on the new chain credited with `balance`. Use [`AccountOwner::CHAIN`] to
1231    /// fund the chain account itself.
1232    pub account: AccountOwner,
1233    /// The initial balance of `account`.
1234    pub balance: Amount,
1235    /// The initial application permissions.
1236    pub application_permissions: ApplicationPermissions,
1237}
1238
1239/// Initial chain configuration and chain origin.
1240#[derive(Eq, PartialEq, Clone, Hash, Debug, Serialize, Deserialize, Allocative)]
1241pub struct ChainDescription {
1242    origin: ChainOrigin,
1243    timestamp: Timestamp,
1244    config: InitialChainConfig,
1245}
1246
1247impl ChainDescription {
1248    /// Creates a new [`ChainDescription`].
1249    pub fn new(origin: ChainOrigin, config: InitialChainConfig, timestamp: Timestamp) -> Self {
1250        Self {
1251            origin,
1252            config,
1253            timestamp,
1254        }
1255    }
1256
1257    /// Returns the [`ChainId`] based on this [`ChainDescription`].
1258    pub fn id(&self) -> ChainId {
1259        ChainId::from(self)
1260    }
1261
1262    /// Returns the [`ChainOrigin`] describing who created this chain.
1263    pub fn origin(&self) -> ChainOrigin {
1264        self.origin
1265    }
1266
1267    /// Returns a reference to the [`InitialChainConfig`] of the chain.
1268    pub fn config(&self) -> &InitialChainConfig {
1269        &self.config
1270    }
1271
1272    /// Returns the timestamp of when the chain was created.
1273    pub fn timestamp(&self) -> Timestamp {
1274        self.timestamp
1275    }
1276}
1277
1278impl BcsHashable<'_> for ChainDescription {}
1279
1280/// A description of the current Linera network to be stored in every node's database.
1281#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
1282pub struct NetworkDescription {
1283    /// The name of the network.
1284    pub name: String,
1285    /// Hash of the network's genesis config.
1286    pub genesis_config_hash: CryptoHash,
1287    /// Genesis timestamp.
1288    pub genesis_timestamp: Timestamp,
1289    /// Hash of the blob containing the genesis committee.
1290    pub genesis_committee_blob_hash: CryptoHash,
1291    /// The chain ID of the admin chain.
1292    pub admin_chain_id: ChainId,
1293}
1294
1295/// Permissions for applications on a chain.
1296#[derive(
1297    Default,
1298    Debug,
1299    PartialEq,
1300    Eq,
1301    PartialOrd,
1302    Ord,
1303    Hash,
1304    Clone,
1305    Serialize,
1306    Deserialize,
1307    WitType,
1308    WitLoad,
1309    WitStore,
1310    InputObject,
1311    Allocative,
1312)]
1313pub struct ApplicationPermissions {
1314    /// If this is `None`, all system operations and application operations are allowed.
1315    /// If it is `Some`, only operations from the specified applications are allowed, and
1316    /// no system operations.
1317    #[debug(skip_if = Option::is_none)]
1318    pub execute_operations: Option<Vec<ApplicationId>>,
1319    /// At least one operation or incoming message from each of these applications must occur in
1320    /// every block.
1321    #[graphql(default)]
1322    #[debug(skip_if = Vec::is_empty)]
1323    pub mandatory_applications: Vec<ApplicationId>,
1324    /// These applications are allowed to close the current chain, change the application
1325    /// permissions, and change the ownership.
1326    #[graphql(default)]
1327    #[debug(skip_if = Vec::is_empty)]
1328    pub manage_chain: Vec<ApplicationId>,
1329    /// These applications are allowed to perform calls to services as oracles.
1330    #[graphql(default)]
1331    #[debug(skip_if = Option::is_none)]
1332    pub call_service_as_oracle: Option<Vec<ApplicationId>>,
1333    /// These applications are allowed to perform HTTP requests.
1334    #[graphql(default)]
1335    #[debug(skip_if = Option::is_none)]
1336    pub make_http_requests: Option<Vec<ApplicationId>>,
1337}
1338
1339impl ApplicationPermissions {
1340    /// Creates new `ApplicationPermissions` where the given application is the only one
1341    /// whose operations are allowed and mandatory, and it can also manage the chain.
1342    pub fn new_single(app_id: ApplicationId) -> Self {
1343        Self {
1344            execute_operations: Some(vec![app_id]),
1345            mandatory_applications: vec![app_id],
1346            manage_chain: vec![app_id],
1347            call_service_as_oracle: Some(vec![app_id]),
1348            make_http_requests: Some(vec![app_id]),
1349        }
1350    }
1351
1352    /// Creates new `ApplicationPermissions` where the given applications are the only ones
1353    /// whose operations are allowed and mandatory, and they can also manage the chain.
1354    #[cfg(with_testing)]
1355    pub fn new_multiple(app_ids: Vec<ApplicationId>) -> Self {
1356        Self {
1357            execute_operations: Some(app_ids.clone()),
1358            mandatory_applications: app_ids.clone(),
1359            manage_chain: app_ids.clone(),
1360            call_service_as_oracle: Some(app_ids.clone()),
1361            make_http_requests: Some(app_ids),
1362        }
1363    }
1364
1365    /// Returns whether operations with the given application ID are allowed on this chain.
1366    pub fn can_execute_operations(&self, app_id: &GenericApplicationId) -> bool {
1367        match (app_id, &self.execute_operations) {
1368            (_, None) => true,
1369            (GenericApplicationId::System, Some(_)) => false,
1370            (GenericApplicationId::User(app_id), Some(app_ids)) => app_ids.contains(app_id),
1371        }
1372    }
1373
1374    /// Returns whether the given application is allowed to manage this chain, i.e. close
1375    /// it, change the application permissions, and change the ownership.
1376    pub fn can_manage_chain(&self, app_id: &ApplicationId) -> bool {
1377        self.manage_chain.contains(app_id)
1378    }
1379
1380    /// Returns whether the given application can call services.
1381    pub fn can_call_services(&self, app_id: &ApplicationId) -> bool {
1382        self.call_service_as_oracle
1383            .as_ref()
1384            .is_none_or(|app_ids| app_ids.contains(app_id))
1385    }
1386
1387    /// Returns whether the given application can make HTTP requests.
1388    pub fn can_make_http_requests(&self, app_id: &ApplicationId) -> bool {
1389        self.make_http_requests
1390            .as_ref()
1391            .is_none_or(|app_ids| app_ids.contains(app_id))
1392    }
1393}
1394
1395/// A record of a single oracle response.
1396#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, Allocative)]
1397pub enum OracleResponse {
1398    /// The response from a service query.
1399    Service(
1400        #[debug(with = "hex_debug")]
1401        #[serde(with = "serde_bytes")]
1402        Vec<u8>,
1403    ),
1404    /// The response from an HTTP request.
1405    Http(http::Response),
1406    /// A successful read or write of a blob.
1407    Blob(BlobId),
1408    /// An assertion oracle that passed.
1409    Assert,
1410    /// The block's validation round.
1411    Round(Option<u32>),
1412    /// An event was read.
1413    Event(
1414        EventId,
1415        #[debug(with = "hex_debug")]
1416        #[serde(with = "serde_bytes")]
1417        Vec<u8>,
1418    ),
1419    /// An event exists.
1420    EventExists(EventId),
1421    /// A checkpoint of the chain's execution state was published. The execution-state
1422    /// dump is chunked into one or more `BlobType::CheckpointExecutionState` blobs whose
1423    /// content hashes are listed here in restore order; a bootstrapping node concatenates
1424    /// the bytes and feeds them to `ExecutionStateView::restore_from_content`.
1425    Checkpoint {
1426        /// Content hashes of the execution-state-dump blobs, in restore order.
1427        execution_state_blobs: Vec<CryptoHash>,
1428        /// All blobs the chain references in its `used_blobs` set at the time of the
1429        /// checkpoint. A bootstrapping node must have each of these in shared blob
1430        /// storage before applying the checkpoint, otherwise subsequent operations on
1431        /// the chain could try to read blob content the node doesn't actually have.
1432        used_blobs: Vec<BlobId>,
1433        /// Hashes of every block on this chain that the chain's outboxes still reference
1434        /// at the time of the checkpoint — i.e. the heights with cross-chain messages
1435        /// that recipients haven't acknowledged yet. The current-epoch certificate over
1436        /// the checkpoint block transitively certifies these older blocks: a node that
1437        /// later receives one of these block's bytes can verify the bytes hash to a
1438        /// hash in this set, without trusting the (possibly revoked) validator
1439        /// signatures on the older block's own certificate.
1440        outbox_block_hashes: Vec<CryptoHash>,
1441        /// For each chain whose messages we've consumed, the `next_cursor_to_remove`
1442        /// of the corresponding inbox. A bootstrapping node uses these to seed each
1443        /// inbox's `restored_cursor`, so subsequent sender re-pushes below that cursor
1444        /// are silently dropped (their effects are already baked into the restored
1445        /// execution state).
1446        inbox_cursors: Vec<(ChainId, Cursor)>,
1447    },
1448}
1449
1450impl BcsHashable<'_> for OracleResponse {}
1451
1452/// Description of a user application.
1453#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Hash, Serialize, WitType, WitLoad, WitStore)]
1454pub struct ApplicationDescription {
1455    /// The unique ID of the bytecode to use for the application.
1456    pub module_id: ModuleId,
1457    /// The chain ID that created the application.
1458    pub creator_chain_id: ChainId,
1459    /// Height of the block that created this application.
1460    pub block_height: BlockHeight,
1461    /// The index of the application among those created in the same block.
1462    pub application_index: u32,
1463    /// The parameters of the application.
1464    #[serde(with = "serde_bytes")]
1465    #[debug(with = "hex_debug")]
1466    pub parameters: Vec<u8>,
1467    /// Required dependencies.
1468    pub required_application_ids: Vec<ApplicationId>,
1469}
1470
1471impl From<&ApplicationDescription> for ApplicationId {
1472    fn from(description: &ApplicationDescription) -> Self {
1473        let mut hash = CryptoHash::new(&BlobContent::new_application_description(description));
1474        if matches!(description.module_id.vm_runtime, VmRuntime::Evm) {
1475            hash.make_evm_compatible();
1476        }
1477        ApplicationId::new(hash)
1478    }
1479}
1480
1481impl BcsHashable<'_> for ApplicationDescription {}
1482
1483impl ApplicationDescription {
1484    /// Gets the serialized bytes for this `ApplicationDescription`.
1485    pub fn to_bytes(&self) -> Vec<u8> {
1486        bcs::to_bytes(self).expect("Serializing blob bytes should not fail!")
1487    }
1488
1489    /// Gets the `BlobId` of the contract
1490    pub fn contract_bytecode_blob_id(&self) -> BlobId {
1491        self.module_id.contract_bytecode_blob_id()
1492    }
1493
1494    /// Gets the `BlobId` of the service
1495    pub fn service_bytecode_blob_id(&self) -> BlobId {
1496        self.module_id.service_bytecode_blob_id()
1497    }
1498}
1499
1500/// A WebAssembly module's bytecode.
1501#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, WitType, WitLoad, WitStore)]
1502pub struct Bytecode {
1503    /// Bytes of the bytecode.
1504    #[serde(with = "serde_bytes")]
1505    #[debug(with = "hex_debug")]
1506    pub bytes: Vec<u8>,
1507}
1508
1509impl Bytecode {
1510    /// Creates a new [`Bytecode`] instance using the provided `bytes`.
1511    pub fn new(bytes: Vec<u8>) -> Self {
1512        Bytecode { bytes }
1513    }
1514
1515    /// Loads bytecode from a Wasm module file.
1516    #[cfg(not(target_arch = "wasm32"))]
1517    pub async fn load_from_file(path: impl AsRef<std::path::Path>) -> std::io::Result<Self> {
1518        let path = path.as_ref();
1519        let bytes = tokio::fs::read(path).await.map_err(|error| {
1520            std::io::Error::new(error.kind(), format!("{}: {error}", path.display()))
1521        })?;
1522        Ok(Bytecode { bytes })
1523    }
1524
1525    /// Compresses the [`Bytecode`] into a [`CompressedBytecode`].
1526    #[cfg(not(target_arch = "wasm32"))]
1527    pub fn compress(&self) -> CompressedBytecode {
1528        #[cfg(with_metrics)]
1529        let _compression_latency = metrics::BYTECODE_COMPRESSION_LATENCY.measure_latency();
1530        let compressed_bytes_vec = zstd::stream::encode_all(&*self.bytes, 19)
1531            .expect("Compressing bytes in memory should not fail");
1532
1533        CompressedBytecode {
1534            compressed_bytes: Arc::new(compressed_bytes_vec.into_boxed_slice()),
1535        }
1536    }
1537
1538    /// Compresses the [`Bytecode`] into a [`CompressedBytecode`].
1539    #[cfg(target_arch = "wasm32")]
1540    pub fn compress(&self) -> CompressedBytecode {
1541        use ruzstd::encoding::{CompressionLevel, FrameCompressor};
1542
1543        #[cfg(with_metrics)]
1544        let _compression_latency = metrics::BYTECODE_COMPRESSION_LATENCY.measure_latency();
1545
1546        let mut compressed_bytes_vec = Vec::new();
1547        let mut compressor = FrameCompressor::new(CompressionLevel::Fastest);
1548        compressor.set_source(&*self.bytes);
1549        compressor.set_drain(&mut compressed_bytes_vec);
1550        compressor.compress();
1551
1552        CompressedBytecode {
1553            compressed_bytes: Arc::new(compressed_bytes_vec.into_boxed_slice()),
1554        }
1555    }
1556}
1557
1558impl AsRef<[u8]> for Bytecode {
1559    fn as_ref(&self) -> &[u8] {
1560        self.bytes.as_ref()
1561    }
1562}
1563
1564/// A type for errors happening during decompression.
1565#[derive(Error, Debug)]
1566pub enum DecompressionError {
1567    /// Compressed bytecode is invalid, and could not be decompressed.
1568    #[error("Bytecode could not be decompressed: {0}")]
1569    InvalidCompressedBytecode(#[from] io::Error),
1570}
1571
1572/// A compressed module bytecode (WebAssembly or EVM).
1573#[serde_as]
1574#[derive(Clone, Debug, Deserialize, Hash, Serialize, WitType, WitStore)]
1575#[cfg_attr(with_testing, derive(Eq, PartialEq))]
1576pub struct CompressedBytecode {
1577    /// Compressed bytes of the bytecode.
1578    #[serde_as(as = "Arc<Bytes>")]
1579    #[debug(skip)]
1580    pub compressed_bytes: Arc<Box<[u8]>>,
1581}
1582
1583#[cfg(not(target_arch = "wasm32"))]
1584impl CompressedBytecode {
1585    /// Returns `true` if the decompressed size does not exceed the limit.
1586    pub fn decompressed_size_at_most(
1587        compressed_bytes: &[u8],
1588        limit: u64,
1589    ) -> Result<bool, DecompressionError> {
1590        let mut decoder = zstd::stream::Decoder::new(compressed_bytes)?;
1591        let limit = usize::try_from(limit).unwrap_or(usize::MAX);
1592        let mut writer = LimitedWriter::new(io::sink(), limit);
1593        match io::copy(&mut decoder, &mut writer) {
1594            Ok(_) => Ok(true),
1595            Err(error) => {
1596                error.downcast::<LimitedWriterError>()?;
1597                Ok(false)
1598            }
1599        }
1600    }
1601
1602    /// Decompresses a [`CompressedBytecode`] into a [`Bytecode`].
1603    pub fn decompress(&self) -> Result<Bytecode, DecompressionError> {
1604        #[cfg(with_metrics)]
1605        let _decompression_latency = metrics::BYTECODE_DECOMPRESSION_LATENCY.measure_latency();
1606        let bytes = zstd::stream::decode_all(&**self.compressed_bytes)?;
1607
1608        #[cfg(with_metrics)]
1609        metrics::BYTECODE_DECOMPRESSED_SIZE_BYTES
1610            .with_label_values(&[])
1611            .observe(bytes.len() as f64);
1612
1613        Ok(Bytecode { bytes })
1614    }
1615}
1616
1617/// Decompresses all the zstd frames in `compressed_bytes`, writing the result to `writer`.
1618///
1619/// A [`StreamingDecoder`](ruzstd::decoding::StreamingDecoder) decodes a single frame, so one is
1620/// created per frame, and skippable frames are stepped over using the length in their header.
1621#[cfg(any(target_arch = "wasm32", test))]
1622fn decompress_frames(
1623    mut compressed_bytes: &[u8],
1624    writer: &mut impl io::Write,
1625) -> Result<(), io::Error> {
1626    use ruzstd::decoding::{
1627        errors::{FrameDecoderError, ReadFrameHeaderError},
1628        StreamingDecoder,
1629    };
1630
1631    while !compressed_bytes.is_empty() {
1632        match StreamingDecoder::new(&mut compressed_bytes) {
1633            Ok(mut decoder) => {
1634                io::copy(&mut decoder, writer)?;
1635            }
1636            Err(FrameDecoderError::ReadFrameHeaderError(ReadFrameHeaderError::SkipFrame {
1637                length,
1638                ..
1639            })) => {
1640                compressed_bytes = compressed_bytes
1641                    .get(length as usize..)
1642                    .ok_or_else(|| io::Error::other("Truncated skippable frame"))?;
1643            }
1644            Err(error) => return Err(io::Error::other(error)),
1645        }
1646    }
1647
1648    Ok(())
1649}
1650
1651#[cfg(target_arch = "wasm32")]
1652impl CompressedBytecode {
1653    /// Returns `true` if the decompressed size does not exceed the limit.
1654    pub fn decompressed_size_at_most(
1655        compressed_bytes: &[u8],
1656        limit: u64,
1657    ) -> Result<bool, DecompressionError> {
1658        let limit = usize::try_from(limit).unwrap_or(usize::MAX);
1659        let mut writer = LimitedWriter::new(io::sink(), limit);
1660
1661        match decompress_frames(compressed_bytes, &mut writer) {
1662            Ok(()) => Ok(true),
1663            Err(error) => {
1664                error.downcast::<LimitedWriterError>()?;
1665                Ok(false)
1666            }
1667        }
1668    }
1669
1670    /// Decompresses a [`CompressedBytecode`] into a [`Bytecode`].
1671    pub fn decompress(&self) -> Result<Bytecode, DecompressionError> {
1672        let mut bytes = Vec::new();
1673        decompress_frames(&self.compressed_bytes, &mut bytes)?;
1674
1675        Ok(Bytecode { bytes })
1676    }
1677}
1678
1679impl BcsHashable<'_> for BlobContent {}
1680
1681/// A blob of binary data.
1682#[serde_as]
1683#[derive(Hash, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Allocative)]
1684pub struct BlobContent {
1685    /// The type of data represented by the bytes.
1686    blob_type: BlobType,
1687    /// The binary data.
1688    #[debug(skip)]
1689    #[serde_as(as = "Arc<Bytes>")]
1690    bytes: Arc<Box<[u8]>>,
1691}
1692
1693impl BlobContent {
1694    /// Creates a new [`BlobContent`] from the provided bytes and [`BlobId`].
1695    pub fn new(blob_type: BlobType, bytes: impl Into<Box<[u8]>>) -> Self {
1696        let bytes = bytes.into();
1697        BlobContent {
1698            blob_type,
1699            bytes: Arc::new(bytes),
1700        }
1701    }
1702
1703    /// Creates a new data [`BlobContent`] from the provided bytes.
1704    pub fn new_data(bytes: impl Into<Box<[u8]>>) -> Self {
1705        BlobContent::new(BlobType::Data, bytes)
1706    }
1707
1708    /// Creates a new contract bytecode [`BlobContent`] from the provided bytes.
1709    pub fn new_contract_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1710        BlobContent {
1711            blob_type: BlobType::ContractBytecode,
1712            bytes: compressed_bytecode.compressed_bytes,
1713        }
1714    }
1715
1716    /// Creates a new contract bytecode [`BlobContent`] from the provided bytes.
1717    pub fn new_evm_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1718        BlobContent {
1719            blob_type: BlobType::EvmBytecode,
1720            bytes: compressed_bytecode.compressed_bytes,
1721        }
1722    }
1723
1724    /// Creates a new service bytecode [`BlobContent`] from the provided bytes.
1725    pub fn new_service_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1726        BlobContent {
1727            blob_type: BlobType::ServiceBytecode,
1728            bytes: compressed_bytecode.compressed_bytes,
1729        }
1730    }
1731
1732    /// Creates a new application description [`BlobContent`] from a [`ApplicationDescription`].
1733    pub fn new_application_description(application_description: &ApplicationDescription) -> Self {
1734        let bytes = application_description.to_bytes();
1735        BlobContent::new(BlobType::ApplicationDescription, bytes)
1736    }
1737
1738    /// Creates a new application formats [`BlobContent`] from the BCS-encoded
1739    /// `Formats` description bytes.
1740    pub fn new_application_formats(bytes: impl Into<Box<[u8]>>) -> Self {
1741        BlobContent::new(BlobType::ApplicationFormats, bytes)
1742    }
1743
1744    /// Creates a new committee [`BlobContent`] from the provided serialized committee.
1745    pub fn new_committee(committee: impl Into<Box<[u8]>>) -> Self {
1746        BlobContent::new(BlobType::Committee, committee)
1747    }
1748
1749    /// Creates a new chain description [`BlobContent`] from a [`ChainDescription`].
1750    pub fn new_chain_description(chain_description: &ChainDescription) -> Self {
1751        let bytes = bcs::to_bytes(&chain_description)
1752            .expect("Serializing a ChainDescription should not fail!");
1753        BlobContent::new(BlobType::ChainDescription, bytes)
1754    }
1755
1756    /// Gets a reference to the blob's bytes.
1757    pub fn bytes(&self) -> &[u8] {
1758        &self.bytes
1759    }
1760
1761    /// Converts a `BlobContent` into `Vec<u8>` without cloning if possible.
1762    pub fn into_vec_or_clone(self) -> Vec<u8> {
1763        let bytes = Arc::unwrap_or_clone(self.bytes);
1764        bytes.into_vec()
1765    }
1766
1767    /// Gets the `Arc<Box<[u8]>>` directly without cloning.
1768    pub fn into_arc_bytes(self) -> Arc<Box<[u8]>> {
1769        self.bytes
1770    }
1771
1772    /// Returns the type of data represented by this blob's bytes.
1773    pub fn blob_type(&self) -> BlobType {
1774        self.blob_type
1775    }
1776}
1777
1778impl From<Blob> for BlobContent {
1779    fn from(blob: Blob) -> BlobContent {
1780        blob.content
1781    }
1782}
1783
1784impl From<Arc<Blob>> for BlobContent {
1785    fn from(blob: Arc<Blob>) -> BlobContent {
1786        blob.content().clone()
1787    }
1788}
1789
1790/// A blob of binary data, with its hash.
1791#[derive(Debug, Hash, PartialEq, Eq, Clone, Allocative)]
1792pub struct Blob {
1793    /// ID of the blob.
1794    hash: CryptoHash,
1795    /// A blob of binary data.
1796    content: BlobContent,
1797}
1798
1799impl Blob {
1800    /// Computes the hash and returns the hashed blob for the given content.
1801    pub fn new(content: BlobContent) -> Self {
1802        let mut hash = CryptoHash::new(&content);
1803        if matches!(content.blob_type, BlobType::ApplicationDescription) {
1804            let application_description = bcs::from_bytes::<ApplicationDescription>(&content.bytes)
1805                .expect("to obtain an application description");
1806            if matches!(application_description.module_id.vm_runtime, VmRuntime::Evm) {
1807                hash.make_evm_compatible();
1808            }
1809        }
1810        Blob { hash, content }
1811    }
1812
1813    /// Creates a blob from ud and content without checks
1814    pub fn new_with_hash_unchecked(blob_id: BlobId, content: BlobContent) -> Self {
1815        Blob {
1816            hash: blob_id.hash,
1817            content,
1818        }
1819    }
1820
1821    /// Creates a blob without checking that the hash actually matches the content.
1822    pub fn new_with_id_unchecked(blob_id: BlobId, bytes: impl Into<Box<[u8]>>) -> Self {
1823        let bytes = bytes.into();
1824        Blob {
1825            hash: blob_id.hash,
1826            content: BlobContent {
1827                blob_type: blob_id.blob_type,
1828                bytes: Arc::new(bytes),
1829            },
1830        }
1831    }
1832
1833    /// Creates a new data [`Blob`] from the provided bytes.
1834    pub fn new_data(bytes: impl Into<Box<[u8]>>) -> Self {
1835        Blob::new(BlobContent::new_data(bytes))
1836    }
1837
1838    /// Creates a new contract bytecode [`Blob`] from the provided bytes.
1839    pub fn new_contract_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1840        Blob::new(BlobContent::new_contract_bytecode(compressed_bytecode))
1841    }
1842
1843    /// Creates a new contract bytecode [`BlobContent`] from the provided bytes.
1844    pub fn new_evm_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1845        Blob::new(BlobContent::new_evm_bytecode(compressed_bytecode))
1846    }
1847
1848    /// Creates a new service bytecode [`Blob`] from the provided bytes.
1849    pub fn new_service_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1850        Blob::new(BlobContent::new_service_bytecode(compressed_bytecode))
1851    }
1852
1853    /// Creates a new application description [`Blob`] from the provided description.
1854    pub fn new_application_description(application_description: &ApplicationDescription) -> Self {
1855        Blob::new(BlobContent::new_application_description(
1856            application_description,
1857        ))
1858    }
1859
1860    /// Creates a new application formats [`Blob`] from the BCS-encoded
1861    /// `Formats` description bytes.
1862    pub fn new_application_formats(bytes: impl Into<Box<[u8]>>) -> Self {
1863        Blob::new(BlobContent::new_application_formats(bytes))
1864    }
1865
1866    /// Creates a new committee [`Blob`] from the provided bytes.
1867    pub fn new_committee(committee: impl Into<Box<[u8]>>) -> Self {
1868        Blob::new(BlobContent::new_committee(committee))
1869    }
1870
1871    /// Creates a new chain description [`Blob`] from a [`ChainDescription`].
1872    pub fn new_chain_description(chain_description: &ChainDescription) -> Self {
1873        Blob::new(BlobContent::new_chain_description(chain_description))
1874    }
1875
1876    /// A content-addressed blob ID i.e. the hash of the `Blob`.
1877    pub fn id(&self) -> BlobId {
1878        BlobId {
1879            hash: self.hash,
1880            blob_type: self.content.blob_type,
1881        }
1882    }
1883
1884    /// Returns a reference to the inner `BlobContent`, without the hash.
1885    pub fn content(&self) -> &BlobContent {
1886        &self.content
1887    }
1888
1889    /// Moves ownership of the blob of binary data
1890    pub fn into_content(self) -> BlobContent {
1891        self.content
1892    }
1893
1894    /// Gets a reference to the inner blob's bytes.
1895    pub fn bytes(&self) -> &[u8] {
1896        self.content.bytes()
1897    }
1898
1899    /// Returns whether the blob is of [`BlobType::Committee`] variant.
1900    pub fn is_committee_blob(&self) -> bool {
1901        self.content().blob_type().is_committee_blob()
1902    }
1903
1904    /// Returns whether the blob carries a chunk of a checkpoint's execution-state dump.
1905    pub fn is_checkpoint_blob(&self) -> bool {
1906        self.content().blob_type().is_checkpoint_blob()
1907    }
1908}
1909
1910impl Serialize for Blob {
1911    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1912    where
1913        S: Serializer,
1914    {
1915        if serializer.is_human_readable() {
1916            let blob_bytes = bcs::to_bytes(&self.content).map_err(serde::ser::Error::custom)?;
1917            serializer.serialize_str(&hex::encode(blob_bytes))
1918        } else {
1919            BlobContent::serialize(self.content(), serializer)
1920        }
1921    }
1922}
1923
1924impl<'a> Deserialize<'a> for Blob {
1925    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1926    where
1927        D: Deserializer<'a>,
1928    {
1929        if deserializer.is_human_readable() {
1930            let s = String::deserialize(deserializer)?;
1931            let content_bytes = hex::decode(s).map_err(serde::de::Error::custom)?;
1932            let content: BlobContent =
1933                bcs::from_bytes(&content_bytes).map_err(serde::de::Error::custom)?;
1934
1935            Ok(Blob::new(content))
1936        } else {
1937            let content = BlobContent::deserialize(deserializer)?;
1938            Ok(Blob::new(content))
1939        }
1940    }
1941}
1942
1943impl BcsHashable<'_> for Blob {}
1944
1945/// An event recorded in a block.
1946#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, SimpleObject, Allocative)]
1947pub struct Event {
1948    /// The ID of the stream this event belongs to.
1949    pub stream_id: StreamId,
1950    /// The event index, i.e. the number of events in the stream before this one.
1951    pub index: u32,
1952    /// The payload data.
1953    #[debug(with = "hex_debug")]
1954    #[serde(with = "serde_bytes")]
1955    pub value: Vec<u8>,
1956}
1957
1958impl Event {
1959    /// Returns the ID of this event record, given the publisher chain ID.
1960    pub fn id(&self, chain_id: ChainId) -> EventId {
1961        EventId {
1962            chain_id,
1963            stream_id: self.stream_id.clone(),
1964            index: self.index,
1965        }
1966    }
1967}
1968
1969/// An update for a stream with new events.
1970#[derive(Clone, Debug, Serialize, Deserialize, WitType, WitLoad, WitStore)]
1971pub struct StreamUpdate {
1972    /// The publishing chain.
1973    pub chain_id: ChainId,
1974    /// The stream ID.
1975    pub stream_id: StreamId,
1976    /// The lowest index of a new event. See [`StreamUpdate::new_indices`].
1977    pub previous_index: u32,
1978    /// The lowest index whose event is still guaranteed to be readable (if it exists): the
1979    /// index of the first event published since the publisher's most recent checkpoint. Reading
1980    /// an event below this index may fail, since checkpoints prune earlier events.
1981    pub first_index: u32,
1982    /// The index of the next event, i.e. the lowest for which no event is known yet.
1983    pub next_index: u32,
1984}
1985
1986impl StreamUpdate {
1987    /// Returns the indices of all new events in the stream.
1988    pub fn new_indices(&self) -> impl Iterator<Item = u32> {
1989        self.previous_index..self.next_index
1990    }
1991}
1992
1993impl BcsHashable<'_> for Event {}
1994
1995/// Policies for automatically handling incoming messages.
1996#[derive(
1997    Clone,
1998    Debug,
1999    Default,
2000    PartialEq,
2001    serde::Serialize,
2002    serde::Deserialize,
2003    async_graphql::SimpleObject,
2004)]
2005pub struct MessagePolicy {
2006    /// The blanket policy applied to all messages.
2007    pub blanket: BlanketMessagePolicy,
2008    /// A collection of chains which restrict the origin of messages to be
2009    /// accepted. `Option::None` means that messages from all chains are accepted. An empty
2010    /// `HashSet` denotes that messages from no chains are accepted.
2011    pub restrict_chain_ids_to: Option<HashSet<ChainId>>,
2012    /// A collection of chains whose incoming messages should be ignored.
2013    pub ignore_chain_ids: HashSet<ChainId>,
2014    /// A collection of applications: If `Some`, only bundles with at least one message by any
2015    /// of these applications will be accepted.
2016    pub reject_message_bundles_without_application_ids: Option<HashSet<GenericApplicationId>>,
2017    /// A collection of applications: If `Some`, only bundles all of whose messages are by these
2018    /// applications will be accepted.
2019    pub reject_message_bundles_with_other_application_ids: Option<HashSet<GenericApplicationId>>,
2020    /// A collection of applications: If `Some`, only event streams from those
2021    /// applications will be processed.
2022    pub process_events_from_application_ids: Option<HashSet<GenericApplicationId>>,
2023    /// A collection of applications whose messages must never be rejected. Bundles whose
2024    /// messages are all from one of these applications bypass the other rejection rules
2025    /// (except `restrict_chain_ids_to`), and on execution failure they are discarded for
2026    /// later retry instead of being rejected. A bundle that contains any message from an
2027    /// application not on this list can be rejected. An empty set disables this feature.
2028    pub never_reject_application_ids: HashSet<GenericApplicationId>,
2029}
2030
2031/// A blanket policy to apply to all messages by default.
2032#[derive(
2033    Default,
2034    Copy,
2035    Clone,
2036    Debug,
2037    PartialEq,
2038    Eq,
2039    serde::Serialize,
2040    serde::Deserialize,
2041    async_graphql::Enum,
2042)]
2043#[cfg_attr(web, derive(tsify::Tsify), tsify(from_wasm_abi, into_wasm_abi))]
2044#[cfg_attr(any(web, not(target_arch = "wasm32")), derive(clap::ValueEnum))]
2045pub enum BlanketMessagePolicy {
2046    /// Automatically accept all incoming messages. Reject them only if execution fails.
2047    #[default]
2048    Accept,
2049    /// Automatically reject tracked messages, ignore or skip untracked messages, but accept
2050    /// protected ones.
2051    Reject,
2052    /// Don't include any messages in blocks, and don't make any decision whether to accept or
2053    /// reject.
2054    Ignore,
2055}
2056
2057impl MessagePolicy {
2058    /// Returns `true` if the blanket policy is to ignore messages.
2059    #[instrument(level = "trace", skip(self))]
2060    pub fn is_ignore(&self) -> bool {
2061        matches!(self.blanket, BlanketMessagePolicy::Ignore)
2062    }
2063
2064    /// Returns `true` if the blanket policy is to reject messages.
2065    #[instrument(level = "trace", skip(self))]
2066    pub fn is_reject(&self) -> bool {
2067        matches!(self.blanket, BlanketMessagePolicy::Reject)
2068    }
2069
2070    /// Returns `true` if every message from `origin` would be unconditionally dropped:
2071    /// blanket policy is `Ignore`, the origin is in `ignore_chain_ids`, or
2072    /// `restrict_chain_ids_to` is `Some` and does not contain the origin.
2073    #[instrument(level = "trace", skip(self))]
2074    pub fn ignores_origin(&self, origin: &ChainId) -> bool {
2075        self.is_ignore()
2076            || self.ignore_chain_ids.contains(origin)
2077            || self
2078                .restrict_chain_ids_to
2079                .as_ref()
2080                .is_some_and(|set| !set.contains(origin))
2081    }
2082}
2083
2084doc_scalar!(Bytecode, "A module bytecode (WebAssembly or EVM)");
2085doc_scalar!(Amount, "A non-negative amount of tokens.");
2086doc_scalar!(U128, "A 128-bit unsigned integer.");
2087doc_scalar!(
2088    Epoch,
2089    "A number identifying the configuration of the chain (aka the committee)"
2090);
2091doc_scalar!(BlockHeight, "A block height to identify blocks in a chain");
2092doc_scalar!(
2093    Timestamp,
2094    "A timestamp, in microseconds since the Unix epoch"
2095);
2096doc_scalar!(TimeDelta, "A duration in microseconds");
2097doc_scalar!(
2098    Round,
2099    "A number to identify successive attempts to decide a value in a consensus protocol."
2100);
2101doc_scalar!(
2102    ChainDescription,
2103    "Initial chain configuration and chain origin."
2104);
2105doc_scalar!(OracleResponse, "A record of a single oracle response.");
2106doc_scalar!(BlobContent, "A blob of binary data.");
2107doc_scalar!(
2108    Blob,
2109    "A blob of binary data, with its content-addressed blob ID."
2110);
2111doc_scalar!(ApplicationDescription, "Description of a user application");
2112
2113#[cfg(with_metrics)]
2114pub(crate) mod metrics {
2115    use prometheus::HistogramVec;
2116
2117    use crate::prometheus_util::{
2118        exponential_bucket_interval, exponential_bucket_latencies, register_histogram_vec,
2119    };
2120
2121    crate::declare_metrics! {
2122        /// The time it takes to compress a bytecode.
2123        pub static BYTECODE_COMPRESSION_LATENCY: HistogramVec =
2124            register_histogram_vec(
2125                "bytecode_compression_latency",
2126                "Bytecode compression latency",
2127                &[],
2128                exponential_bucket_latencies(10.0),
2129            );
2130
2131        /// The time it takes to decompress a bytecode.
2132        pub static BYTECODE_DECOMPRESSION_LATENCY: HistogramVec =
2133            register_histogram_vec(
2134                "bytecode_decompression_latency",
2135                "Bytecode decompression latency",
2136                &[],
2137                exponential_bucket_latencies(10.0),
2138            );
2139
2140        pub static BYTECODE_DECOMPRESSED_SIZE_BYTES: HistogramVec =
2141            register_histogram_vec(
2142                "wasm_bytecode_decompressed_size_bytes",
2143                "Decompressed size in bytes of WASM bytecodes stored on-chain",
2144                &[],
2145                exponential_bucket_interval(10_000.0, 100_000_000.0),
2146            );
2147    }
2148}
2149
2150#[cfg(test)]
2151mod tests {
2152    use std::str::FromStr;
2153
2154    use alloy_primitives::U256;
2155
2156    use super::{Amount, ApplicationDescription, BlobContent};
2157    use crate::{
2158        crypto::CryptoHash,
2159        data_types::BlockHeight,
2160        identifiers::{BlobType, ChainId, ModuleId},
2161        vm::VmRuntime,
2162    };
2163
2164    #[test]
2165    fn non_canonical_btree_map_serializes_like_vec() {
2166        use std::collections::BTreeMap;
2167
2168        use super::NonCanonicalBTreeMap;
2169
2170        // `256u32` is chosen so that its little-endian BCS bytes sort *before* `1u32`'s,
2171        // i.e. the canonical (serialized-byte) order differs from the numeric `Ord` order.
2172        let map = NonCanonicalBTreeMap::from(BTreeMap::from([
2173            (1u32, 10u8),
2174            (256u32, 20u8),
2175            (2u32, 30u8),
2176        ]));
2177
2178        // It serializes as a plain `Vec<(K, V)>` in the map's `Ord` key order, with no canonical
2179        // re-sorting.
2180        let entries = map
2181            .iter()
2182            .map(|(k, v)| (*k, *v))
2183            .collect::<Vec<(u32, u8)>>();
2184        assert_eq!(
2185            bcs::to_bytes(&map).unwrap(),
2186            bcs::to_bytes(&entries).unwrap()
2187        );
2188
2189        // ... which differs from the canonical `BTreeMap` encoding that re-sorts by serialized key.
2190        let canonical = map
2191            .iter()
2192            .map(|(k, v)| (*k, *v))
2193            .collect::<BTreeMap<u32, u8>>();
2194        assert_ne!(
2195            bcs::to_bytes(&map).unwrap(),
2196            bcs::to_bytes(&canonical).unwrap()
2197        );
2198
2199        // It round-trips.
2200        let deserialized: NonCanonicalBTreeMap<u32, u8> =
2201            bcs::from_bytes(&bcs::to_bytes(&map).unwrap()).unwrap();
2202        assert_eq!(map, deserialized);
2203    }
2204
2205    #[test]
2206    fn canonical_btree_set_serializes_like_map() {
2207        use std::collections::{BTreeMap, BTreeSet};
2208
2209        use super::CanonicalBTreeSet;
2210
2211        let set = CanonicalBTreeSet::from(BTreeSet::from([1u32, 256u32, 2u32]));
2212
2213        // It serializes exactly like a `BTreeMap<T, ()>`, i.e. canonically sorted by serialized
2214        // bytes.
2215        let map = set.iter().map(|t| (*t, ())).collect::<BTreeMap<u32, ()>>();
2216        assert_eq!(bcs::to_bytes(&set).unwrap(), bcs::to_bytes(&map).unwrap());
2217
2218        // That canonical order differs from a plain `BTreeSet`'s sequence encoding, which keeps
2219        // the numeric `Ord` order.
2220        let plain = set.iter().copied().collect::<BTreeSet<u32>>();
2221        assert_ne!(bcs::to_bytes(&set).unwrap(), bcs::to_bytes(&plain).unwrap());
2222
2223        // It round-trips.
2224        let deserialized: CanonicalBTreeSet<u32> =
2225            bcs::from_bytes(&bcs::to_bytes(&set).unwrap()).unwrap();
2226        assert_eq!(set, deserialized);
2227    }
2228
2229    #[test]
2230    fn display_amount() {
2231        assert_eq!("1.", Amount::ONE.to_string());
2232        assert_eq!("1.", Amount::from_str("1.").unwrap().to_string());
2233        assert_eq!(
2234            Amount(10_000_000_000_000_000_000),
2235            Amount::from_str("10").unwrap()
2236        );
2237        assert_eq!("10.", Amount(10_000_000_000_000_000_000).to_string());
2238        assert_eq!(
2239            "1001.3",
2240            (Amount::from_str("1.1")
2241                .unwrap()
2242                .saturating_add(Amount::from_str("1_000.2").unwrap()))
2243            .to_string()
2244        );
2245        assert_eq!(
2246            "   1.00000000000000000000",
2247            format!("{:25.20}", Amount::ONE)
2248        );
2249        assert_eq!(
2250            "~+12.34~~",
2251            format!("{:~^+9.1}", Amount::from_str("12.34").unwrap())
2252        );
2253    }
2254
2255    #[test]
2256    fn blob_content_serialization_deserialization() {
2257        let test_data = b"Hello, world!".as_slice();
2258        let original_blob = BlobContent::new(BlobType::Data, test_data);
2259
2260        let serialized = bcs::to_bytes(&original_blob).expect("Failed to serialize BlobContent");
2261        let deserialized: BlobContent =
2262            bcs::from_bytes(&serialized).expect("Failed to deserialize BlobContent");
2263        assert_eq!(original_blob, deserialized);
2264
2265        let serialized =
2266            serde_json::to_vec(&original_blob).expect("Failed to serialize BlobContent");
2267        let deserialized: BlobContent =
2268            serde_json::from_slice(&serialized).expect("Failed to deserialize BlobContent");
2269        assert_eq!(original_blob, deserialized);
2270    }
2271
2272    #[test]
2273    fn blob_content_hash_consistency() {
2274        let test_data = b"Hello, world!";
2275        let blob1 = BlobContent::new(BlobType::Data, test_data.as_slice());
2276        let blob2 = BlobContent::new(BlobType::Data, Vec::from(test_data.as_slice()));
2277
2278        // Both should have same hash since they contain the same data
2279        let hash1 = crate::crypto::CryptoHash::new(&blob1);
2280        let hash2 = crate::crypto::CryptoHash::new(&blob2);
2281
2282        assert_eq!(hash1, hash2, "Hashes should be equal for same content");
2283        assert_eq!(blob1.bytes(), blob2.bytes(), "Byte content should be equal");
2284    }
2285
2286    #[test]
2287    fn test_conversion_amount_u256() {
2288        let value_amount = Amount::from_tokens(15656565652209004332);
2289        let value_u256: U256 = value_amount.into();
2290        let value_amount_rev = Amount::try_from(value_u256).expect("Failed conversion");
2291        assert_eq!(value_amount, value_amount_rev);
2292    }
2293
2294    /// `linera-explorer` running on `wasm32` does not have access to the
2295    /// strongly-typed `ApplicationDescription`: the GraphQL client substitutes
2296    /// it for `serde_json::Value`. The explorer therefore fetches the module ID
2297    /// for an application by indexing into the JSON object as
2298    /// `description["module_id"]`. This test pins that field name and the
2299    /// hex-string shape of the serialized `ModuleId` so a future rename or
2300    /// representation change immediately breaks here instead of silently in the
2301    /// browser.
2302    #[test]
2303    fn application_description_serializes_module_id_as_hex_string() {
2304        let module_id = ModuleId::new(
2305            CryptoHash::test_hash("contract-bytecode"),
2306            CryptoHash::test_hash("service-bytecode"),
2307            VmRuntime::Wasm,
2308        );
2309        let description = ApplicationDescription {
2310            module_id,
2311            creator_chain_id: ChainId(CryptoHash::test_hash("chain")),
2312            block_height: BlockHeight(0),
2313            application_index: 0,
2314            parameters: Vec::new(),
2315            required_application_ids: Vec::new(),
2316        };
2317
2318        let value = serde_json::to_value(&description).unwrap();
2319        let module_id_value = value
2320            .get("module_id")
2321            .expect("`module_id` is the field name the explorer indexes into");
2322        let hex = module_id_value
2323            .as_str()
2324            .expect("`module_id` must serialize as a hex string in human-readable form");
2325        let roundtrip: ModuleId =
2326            serde_json::from_value(serde_json::Value::String(hex.to_owned())).unwrap();
2327        assert_eq!(roundtrip, module_id);
2328    }
2329
2330    /// Tests for [`decompress_frames`], which is what `wasm32` targets decompress bytecodes
2331    /// with. They run everywhere else, where `zstd` is available to compress the inputs and to
2332    /// compare against.
2333    #[cfg(not(target_arch = "wasm32"))]
2334    mod compression {
2335        use std::{io, sync::Arc};
2336
2337        use super::super::{decompress_frames, Bytecode, CompressedBytecode};
2338        use crate::limited_writer::{LimitedWriter, LimitedWriterError};
2339
2340        /// Builds a bytecode made of two zstd frames followed by a skippable frame, together
2341        /// with the bytes it decompresses to.
2342        ///
2343        /// `zstd` accepts such a concatenation, so the decompressor used on `wasm32` has to
2344        /// accept it too, or the two disagree about which bytecodes are valid.
2345        fn multi_frame_bytecode() -> (CompressedBytecode, Vec<u8>) {
2346            let first = vec![b'a'; 100_000];
2347            let second = vec![b'b'; 50_000];
2348
2349            let mut compressed_bytes = Bytecode::new(first.clone())
2350                .compress()
2351                .compressed_bytes
2352                .to_vec();
2353            compressed_bytes
2354                .extend_from_slice(&Bytecode::new(second.clone()).compress().compressed_bytes);
2355            // Magic number 0x184d2a50 and a four-byte little-endian payload length.
2356            compressed_bytes.extend_from_slice(&[0x50, 0x2a, 0x4d, 0x18, 4, 0, 0, 0, 1, 2, 3, 4]);
2357
2358            let compressed_bytecode = CompressedBytecode {
2359                compressed_bytes: Arc::new(compressed_bytes.into_boxed_slice()),
2360            };
2361
2362            (compressed_bytecode, [first, second].concat())
2363        }
2364
2365        #[test]
2366        fn all_frames_are_decompressed() {
2367            let (compressed_bytecode, expected) = multi_frame_bytecode();
2368
2369            assert_eq!(compressed_bytecode.decompress().unwrap().bytes, expected);
2370
2371            let mut bytes = Vec::new();
2372            decompress_frames(&compressed_bytecode.compressed_bytes, &mut bytes).unwrap();
2373            assert_eq!(bytes, expected);
2374        }
2375
2376        #[test]
2377        fn all_frames_count_towards_the_size_limit() {
2378            let (compressed_bytecode, expected) = multi_frame_bytecode();
2379            let compressed_bytes = &**compressed_bytecode.compressed_bytes;
2380            let size = expected.len();
2381
2382            for limit in [size / 2, size - 1, size, size + 1] {
2383                let mut writer = LimitedWriter::new(io::sink(), limit);
2384                let within_limit = match decompress_frames(compressed_bytes, &mut writer) {
2385                    Ok(()) => true,
2386                    Err(error) => {
2387                        error.downcast::<LimitedWriterError>().unwrap();
2388                        false
2389                    }
2390                };
2391
2392                assert_eq!(within_limit, limit >= size);
2393                assert_eq!(
2394                    CompressedBytecode::decompressed_size_at_most(
2395                        compressed_bytes,
2396                        u64::try_from(limit).unwrap()
2397                    )
2398                    .unwrap(),
2399                    within_limit
2400                );
2401            }
2402        }
2403
2404        #[test]
2405        fn trailing_garbage_is_rejected() {
2406            let (compressed_bytecode, _) = multi_frame_bytecode();
2407            let mut compressed_bytes = compressed_bytecode.compressed_bytes.to_vec();
2408            compressed_bytes.extend_from_slice(b"not a zstd frame");
2409
2410            let mut bytes = Vec::new();
2411            assert!(decompress_frames(&compressed_bytes, &mut bytes).is_err());
2412
2413            let compressed_bytecode = CompressedBytecode {
2414                compressed_bytes: Arc::new(compressed_bytes.into_boxed_slice()),
2415            };
2416            assert!(compressed_bytecode.decompress().is_err());
2417        }
2418    }
2419}