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#[cfg(target_arch = "wasm32")]
1618impl CompressedBytecode {
1619    /// Returns `true` if the decompressed size does not exceed the limit.
1620    pub fn decompressed_size_at_most(
1621        compressed_bytes: &[u8],
1622        limit: u64,
1623    ) -> Result<bool, DecompressionError> {
1624        use ruzstd::decoding::StreamingDecoder;
1625        let limit = usize::try_from(limit).unwrap_or(usize::MAX);
1626        let mut writer = LimitedWriter::new(io::sink(), limit);
1627        let mut decoder = StreamingDecoder::new(compressed_bytes).map_err(io::Error::other)?;
1628
1629        // TODO(#2710): Decode multiple frames, if present
1630        match io::copy(&mut decoder, &mut writer) {
1631            Ok(_) => Ok(true),
1632            Err(error) => {
1633                error.downcast::<LimitedWriterError>()?;
1634                Ok(false)
1635            }
1636        }
1637    }
1638
1639    /// Decompresses a [`CompressedBytecode`] into a [`Bytecode`].
1640    pub fn decompress(&self) -> Result<Bytecode, DecompressionError> {
1641        use ruzstd::{decoding::StreamingDecoder, io::Read};
1642
1643        #[cfg(with_metrics)]
1644        let _decompression_latency = BYTECODE_DECOMPRESSION_LATENCY.measure_latency();
1645
1646        let compressed_bytes = &*self.compressed_bytes;
1647        let mut bytes = Vec::new();
1648        let mut decoder = StreamingDecoder::new(&**compressed_bytes).map_err(io::Error::other)?;
1649
1650        // TODO(#2710): Decode multiple frames, if present
1651        while !decoder.get_ref().is_empty() {
1652            decoder
1653                .read_to_end(&mut bytes)
1654                .expect("Reading from a slice in memory should not result in I/O errors");
1655        }
1656
1657        #[cfg(with_metrics)]
1658        BYTECODE_DECOMPRESSED_SIZE_BYTES
1659            .with_label_values(&[])
1660            .observe(bytes.len() as f64);
1661
1662        Ok(Bytecode { bytes })
1663    }
1664}
1665
1666impl BcsHashable<'_> for BlobContent {}
1667
1668/// A blob of binary data.
1669#[serde_as]
1670#[derive(Hash, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Allocative)]
1671pub struct BlobContent {
1672    /// The type of data represented by the bytes.
1673    blob_type: BlobType,
1674    /// The binary data.
1675    #[debug(skip)]
1676    #[serde_as(as = "Arc<Bytes>")]
1677    bytes: Arc<Box<[u8]>>,
1678}
1679
1680impl BlobContent {
1681    /// Creates a new [`BlobContent`] from the provided bytes and [`BlobId`].
1682    pub fn new(blob_type: BlobType, bytes: impl Into<Box<[u8]>>) -> Self {
1683        let bytes = bytes.into();
1684        BlobContent {
1685            blob_type,
1686            bytes: Arc::new(bytes),
1687        }
1688    }
1689
1690    /// Creates a new data [`BlobContent`] from the provided bytes.
1691    pub fn new_data(bytes: impl Into<Box<[u8]>>) -> Self {
1692        BlobContent::new(BlobType::Data, bytes)
1693    }
1694
1695    /// Creates a new contract bytecode [`BlobContent`] from the provided bytes.
1696    pub fn new_contract_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1697        BlobContent {
1698            blob_type: BlobType::ContractBytecode,
1699            bytes: compressed_bytecode.compressed_bytes,
1700        }
1701    }
1702
1703    /// Creates a new contract bytecode [`BlobContent`] from the provided bytes.
1704    pub fn new_evm_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1705        BlobContent {
1706            blob_type: BlobType::EvmBytecode,
1707            bytes: compressed_bytecode.compressed_bytes,
1708        }
1709    }
1710
1711    /// Creates a new service bytecode [`BlobContent`] from the provided bytes.
1712    pub fn new_service_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1713        BlobContent {
1714            blob_type: BlobType::ServiceBytecode,
1715            bytes: compressed_bytecode.compressed_bytes,
1716        }
1717    }
1718
1719    /// Creates a new application description [`BlobContent`] from a [`ApplicationDescription`].
1720    pub fn new_application_description(application_description: &ApplicationDescription) -> Self {
1721        let bytes = application_description.to_bytes();
1722        BlobContent::new(BlobType::ApplicationDescription, bytes)
1723    }
1724
1725    /// Creates a new application formats [`BlobContent`] from the BCS-encoded
1726    /// `Formats` description bytes.
1727    pub fn new_application_formats(bytes: impl Into<Box<[u8]>>) -> Self {
1728        BlobContent::new(BlobType::ApplicationFormats, bytes)
1729    }
1730
1731    /// Creates a new committee [`BlobContent`] from the provided serialized committee.
1732    pub fn new_committee(committee: impl Into<Box<[u8]>>) -> Self {
1733        BlobContent::new(BlobType::Committee, committee)
1734    }
1735
1736    /// Creates a new chain description [`BlobContent`] from a [`ChainDescription`].
1737    pub fn new_chain_description(chain_description: &ChainDescription) -> Self {
1738        let bytes = bcs::to_bytes(&chain_description)
1739            .expect("Serializing a ChainDescription should not fail!");
1740        BlobContent::new(BlobType::ChainDescription, bytes)
1741    }
1742
1743    /// Gets a reference to the blob's bytes.
1744    pub fn bytes(&self) -> &[u8] {
1745        &self.bytes
1746    }
1747
1748    /// Converts a `BlobContent` into `Vec<u8>` without cloning if possible.
1749    pub fn into_vec_or_clone(self) -> Vec<u8> {
1750        let bytes = Arc::unwrap_or_clone(self.bytes);
1751        bytes.into_vec()
1752    }
1753
1754    /// Gets the `Arc<Box<[u8]>>` directly without cloning.
1755    pub fn into_arc_bytes(self) -> Arc<Box<[u8]>> {
1756        self.bytes
1757    }
1758
1759    /// Returns the type of data represented by this blob's bytes.
1760    pub fn blob_type(&self) -> BlobType {
1761        self.blob_type
1762    }
1763}
1764
1765impl From<Blob> for BlobContent {
1766    fn from(blob: Blob) -> BlobContent {
1767        blob.content
1768    }
1769}
1770
1771impl From<Arc<Blob>> for BlobContent {
1772    fn from(blob: Arc<Blob>) -> BlobContent {
1773        blob.content().clone()
1774    }
1775}
1776
1777/// A blob of binary data, with its hash.
1778#[derive(Debug, Hash, PartialEq, Eq, Clone, Allocative)]
1779pub struct Blob {
1780    /// ID of the blob.
1781    hash: CryptoHash,
1782    /// A blob of binary data.
1783    content: BlobContent,
1784}
1785
1786impl Blob {
1787    /// Computes the hash and returns the hashed blob for the given content.
1788    pub fn new(content: BlobContent) -> Self {
1789        let mut hash = CryptoHash::new(&content);
1790        if matches!(content.blob_type, BlobType::ApplicationDescription) {
1791            let application_description = bcs::from_bytes::<ApplicationDescription>(&content.bytes)
1792                .expect("to obtain an application description");
1793            if matches!(application_description.module_id.vm_runtime, VmRuntime::Evm) {
1794                hash.make_evm_compatible();
1795            }
1796        }
1797        Blob { hash, content }
1798    }
1799
1800    /// Creates a blob from ud and content without checks
1801    pub fn new_with_hash_unchecked(blob_id: BlobId, content: BlobContent) -> Self {
1802        Blob {
1803            hash: blob_id.hash,
1804            content,
1805        }
1806    }
1807
1808    /// Creates a blob without checking that the hash actually matches the content.
1809    pub fn new_with_id_unchecked(blob_id: BlobId, bytes: impl Into<Box<[u8]>>) -> Self {
1810        let bytes = bytes.into();
1811        Blob {
1812            hash: blob_id.hash,
1813            content: BlobContent {
1814                blob_type: blob_id.blob_type,
1815                bytes: Arc::new(bytes),
1816            },
1817        }
1818    }
1819
1820    /// Creates a new data [`Blob`] from the provided bytes.
1821    pub fn new_data(bytes: impl Into<Box<[u8]>>) -> Self {
1822        Blob::new(BlobContent::new_data(bytes))
1823    }
1824
1825    /// Creates a new contract bytecode [`Blob`] from the provided bytes.
1826    pub fn new_contract_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1827        Blob::new(BlobContent::new_contract_bytecode(compressed_bytecode))
1828    }
1829
1830    /// Creates a new contract bytecode [`BlobContent`] from the provided bytes.
1831    pub fn new_evm_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1832        Blob::new(BlobContent::new_evm_bytecode(compressed_bytecode))
1833    }
1834
1835    /// Creates a new service bytecode [`Blob`] from the provided bytes.
1836    pub fn new_service_bytecode(compressed_bytecode: CompressedBytecode) -> Self {
1837        Blob::new(BlobContent::new_service_bytecode(compressed_bytecode))
1838    }
1839
1840    /// Creates a new application description [`Blob`] from the provided description.
1841    pub fn new_application_description(application_description: &ApplicationDescription) -> Self {
1842        Blob::new(BlobContent::new_application_description(
1843            application_description,
1844        ))
1845    }
1846
1847    /// Creates a new application formats [`Blob`] from the BCS-encoded
1848    /// `Formats` description bytes.
1849    pub fn new_application_formats(bytes: impl Into<Box<[u8]>>) -> Self {
1850        Blob::new(BlobContent::new_application_formats(bytes))
1851    }
1852
1853    /// Creates a new committee [`Blob`] from the provided bytes.
1854    pub fn new_committee(committee: impl Into<Box<[u8]>>) -> Self {
1855        Blob::new(BlobContent::new_committee(committee))
1856    }
1857
1858    /// Creates a new chain description [`Blob`] from a [`ChainDescription`].
1859    pub fn new_chain_description(chain_description: &ChainDescription) -> Self {
1860        Blob::new(BlobContent::new_chain_description(chain_description))
1861    }
1862
1863    /// A content-addressed blob ID i.e. the hash of the `Blob`.
1864    pub fn id(&self) -> BlobId {
1865        BlobId {
1866            hash: self.hash,
1867            blob_type: self.content.blob_type,
1868        }
1869    }
1870
1871    /// Returns a reference to the inner `BlobContent`, without the hash.
1872    pub fn content(&self) -> &BlobContent {
1873        &self.content
1874    }
1875
1876    /// Moves ownership of the blob of binary data
1877    pub fn into_content(self) -> BlobContent {
1878        self.content
1879    }
1880
1881    /// Gets a reference to the inner blob's bytes.
1882    pub fn bytes(&self) -> &[u8] {
1883        self.content.bytes()
1884    }
1885
1886    /// Returns whether the blob is of [`BlobType::Committee`] variant.
1887    pub fn is_committee_blob(&self) -> bool {
1888        self.content().blob_type().is_committee_blob()
1889    }
1890
1891    /// Returns whether the blob carries a chunk of a checkpoint's execution-state dump.
1892    pub fn is_checkpoint_blob(&self) -> bool {
1893        self.content().blob_type().is_checkpoint_blob()
1894    }
1895}
1896
1897impl Serialize for Blob {
1898    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1899    where
1900        S: Serializer,
1901    {
1902        if serializer.is_human_readable() {
1903            let blob_bytes = bcs::to_bytes(&self.content).map_err(serde::ser::Error::custom)?;
1904            serializer.serialize_str(&hex::encode(blob_bytes))
1905        } else {
1906            BlobContent::serialize(self.content(), serializer)
1907        }
1908    }
1909}
1910
1911impl<'a> Deserialize<'a> for Blob {
1912    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1913    where
1914        D: Deserializer<'a>,
1915    {
1916        if deserializer.is_human_readable() {
1917            let s = String::deserialize(deserializer)?;
1918            let content_bytes = hex::decode(s).map_err(serde::de::Error::custom)?;
1919            let content: BlobContent =
1920                bcs::from_bytes(&content_bytes).map_err(serde::de::Error::custom)?;
1921
1922            Ok(Blob::new(content))
1923        } else {
1924            let content = BlobContent::deserialize(deserializer)?;
1925            Ok(Blob::new(content))
1926        }
1927    }
1928}
1929
1930impl BcsHashable<'_> for Blob {}
1931
1932/// An event recorded in a block.
1933#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, SimpleObject, Allocative)]
1934pub struct Event {
1935    /// The ID of the stream this event belongs to.
1936    pub stream_id: StreamId,
1937    /// The event index, i.e. the number of events in the stream before this one.
1938    pub index: u32,
1939    /// The payload data.
1940    #[debug(with = "hex_debug")]
1941    #[serde(with = "serde_bytes")]
1942    pub value: Vec<u8>,
1943}
1944
1945impl Event {
1946    /// Returns the ID of this event record, given the publisher chain ID.
1947    pub fn id(&self, chain_id: ChainId) -> EventId {
1948        EventId {
1949            chain_id,
1950            stream_id: self.stream_id.clone(),
1951            index: self.index,
1952        }
1953    }
1954}
1955
1956/// An update for a stream with new events.
1957#[derive(Clone, Debug, Serialize, Deserialize, WitType, WitLoad, WitStore)]
1958pub struct StreamUpdate {
1959    /// The publishing chain.
1960    pub chain_id: ChainId,
1961    /// The stream ID.
1962    pub stream_id: StreamId,
1963    /// The lowest index of a new event. See [`StreamUpdate::new_indices`].
1964    pub previous_index: u32,
1965    /// The lowest index whose event is still guaranteed to be readable (if it exists): the
1966    /// index of the first event published since the publisher's most recent checkpoint. Reading
1967    /// an event below this index may fail, since checkpoints prune earlier events.
1968    pub first_index: u32,
1969    /// The index of the next event, i.e. the lowest for which no event is known yet.
1970    pub next_index: u32,
1971}
1972
1973impl StreamUpdate {
1974    /// Returns the indices of all new events in the stream.
1975    pub fn new_indices(&self) -> impl Iterator<Item = u32> {
1976        self.previous_index..self.next_index
1977    }
1978}
1979
1980impl BcsHashable<'_> for Event {}
1981
1982/// Policies for automatically handling incoming messages.
1983#[derive(
1984    Clone,
1985    Debug,
1986    Default,
1987    PartialEq,
1988    serde::Serialize,
1989    serde::Deserialize,
1990    async_graphql::SimpleObject,
1991)]
1992pub struct MessagePolicy {
1993    /// The blanket policy applied to all messages.
1994    pub blanket: BlanketMessagePolicy,
1995    /// A collection of chains which restrict the origin of messages to be
1996    /// accepted. `Option::None` means that messages from all chains are accepted. An empty
1997    /// `HashSet` denotes that messages from no chains are accepted.
1998    pub restrict_chain_ids_to: Option<HashSet<ChainId>>,
1999    /// A collection of chains whose incoming messages should be ignored.
2000    pub ignore_chain_ids: HashSet<ChainId>,
2001    /// A collection of applications: If `Some`, only bundles with at least one message by any
2002    /// of these applications will be accepted.
2003    pub reject_message_bundles_without_application_ids: Option<HashSet<GenericApplicationId>>,
2004    /// A collection of applications: If `Some`, only bundles all of whose messages are by these
2005    /// applications will be accepted.
2006    pub reject_message_bundles_with_other_application_ids: Option<HashSet<GenericApplicationId>>,
2007    /// A collection of applications: If `Some`, only event streams from those
2008    /// applications will be processed.
2009    pub process_events_from_application_ids: Option<HashSet<GenericApplicationId>>,
2010    /// A collection of applications whose messages must never be rejected. Bundles whose
2011    /// messages are all from one of these applications bypass the other rejection rules
2012    /// (except `restrict_chain_ids_to`), and on execution failure they are discarded for
2013    /// later retry instead of being rejected. A bundle that contains any message from an
2014    /// application not on this list can be rejected. An empty set disables this feature.
2015    pub never_reject_application_ids: HashSet<GenericApplicationId>,
2016}
2017
2018/// A blanket policy to apply to all messages by default.
2019#[derive(
2020    Default,
2021    Copy,
2022    Clone,
2023    Debug,
2024    PartialEq,
2025    Eq,
2026    serde::Serialize,
2027    serde::Deserialize,
2028    async_graphql::Enum,
2029)]
2030#[cfg_attr(web, derive(tsify::Tsify), tsify(from_wasm_abi, into_wasm_abi))]
2031#[cfg_attr(any(web, not(target_arch = "wasm32")), derive(clap::ValueEnum))]
2032pub enum BlanketMessagePolicy {
2033    /// Automatically accept all incoming messages. Reject them only if execution fails.
2034    #[default]
2035    Accept,
2036    /// Automatically reject tracked messages, ignore or skip untracked messages, but accept
2037    /// protected ones.
2038    Reject,
2039    /// Don't include any messages in blocks, and don't make any decision whether to accept or
2040    /// reject.
2041    Ignore,
2042}
2043
2044impl MessagePolicy {
2045    /// Returns `true` if the blanket policy is to ignore messages.
2046    #[instrument(level = "trace", skip(self))]
2047    pub fn is_ignore(&self) -> bool {
2048        matches!(self.blanket, BlanketMessagePolicy::Ignore)
2049    }
2050
2051    /// Returns `true` if the blanket policy is to reject messages.
2052    #[instrument(level = "trace", skip(self))]
2053    pub fn is_reject(&self) -> bool {
2054        matches!(self.blanket, BlanketMessagePolicy::Reject)
2055    }
2056
2057    /// Returns `true` if every message from `origin` would be unconditionally dropped:
2058    /// blanket policy is `Ignore`, the origin is in `ignore_chain_ids`, or
2059    /// `restrict_chain_ids_to` is `Some` and does not contain the origin.
2060    #[instrument(level = "trace", skip(self))]
2061    pub fn ignores_origin(&self, origin: &ChainId) -> bool {
2062        self.is_ignore()
2063            || self.ignore_chain_ids.contains(origin)
2064            || self
2065                .restrict_chain_ids_to
2066                .as_ref()
2067                .is_some_and(|set| !set.contains(origin))
2068    }
2069}
2070
2071doc_scalar!(Bytecode, "A module bytecode (WebAssembly or EVM)");
2072doc_scalar!(Amount, "A non-negative amount of tokens.");
2073doc_scalar!(U128, "A 128-bit unsigned integer.");
2074doc_scalar!(
2075    Epoch,
2076    "A number identifying the configuration of the chain (aka the committee)"
2077);
2078doc_scalar!(BlockHeight, "A block height to identify blocks in a chain");
2079doc_scalar!(
2080    Timestamp,
2081    "A timestamp, in microseconds since the Unix epoch"
2082);
2083doc_scalar!(TimeDelta, "A duration in microseconds");
2084doc_scalar!(
2085    Round,
2086    "A number to identify successive attempts to decide a value in a consensus protocol."
2087);
2088doc_scalar!(
2089    ChainDescription,
2090    "Initial chain configuration and chain origin."
2091);
2092doc_scalar!(OracleResponse, "A record of a single oracle response.");
2093doc_scalar!(BlobContent, "A blob of binary data.");
2094doc_scalar!(
2095    Blob,
2096    "A blob of binary data, with its content-addressed blob ID."
2097);
2098doc_scalar!(ApplicationDescription, "Description of a user application");
2099
2100#[cfg(with_metrics)]
2101pub(crate) mod metrics {
2102    use prometheus::HistogramVec;
2103
2104    use crate::prometheus_util::{
2105        exponential_bucket_interval, exponential_bucket_latencies, register_histogram_vec,
2106    };
2107
2108    crate::declare_metrics! {
2109        /// The time it takes to compress a bytecode.
2110        pub static BYTECODE_COMPRESSION_LATENCY: HistogramVec =
2111            register_histogram_vec(
2112                "bytecode_compression_latency",
2113                "Bytecode compression latency",
2114                &[],
2115                exponential_bucket_latencies(10.0),
2116            );
2117
2118        /// The time it takes to decompress a bytecode.
2119        pub static BYTECODE_DECOMPRESSION_LATENCY: HistogramVec =
2120            register_histogram_vec(
2121                "bytecode_decompression_latency",
2122                "Bytecode decompression latency",
2123                &[],
2124                exponential_bucket_latencies(10.0),
2125            );
2126
2127        pub static BYTECODE_DECOMPRESSED_SIZE_BYTES: HistogramVec =
2128            register_histogram_vec(
2129                "wasm_bytecode_decompressed_size_bytes",
2130                "Decompressed size in bytes of WASM bytecodes stored on-chain",
2131                &[],
2132                exponential_bucket_interval(10_000.0, 100_000_000.0),
2133            );
2134    }
2135}
2136
2137#[cfg(test)]
2138mod tests {
2139    use std::str::FromStr;
2140
2141    use alloy_primitives::U256;
2142
2143    use super::{Amount, ApplicationDescription, BlobContent};
2144    use crate::{
2145        crypto::CryptoHash,
2146        data_types::BlockHeight,
2147        identifiers::{BlobType, ChainId, ModuleId},
2148        vm::VmRuntime,
2149    };
2150
2151    #[test]
2152    fn non_canonical_btree_map_serializes_like_vec() {
2153        use std::collections::BTreeMap;
2154
2155        use super::NonCanonicalBTreeMap;
2156
2157        // `256u32` is chosen so that its little-endian BCS bytes sort *before* `1u32`'s,
2158        // i.e. the canonical (serialized-byte) order differs from the numeric `Ord` order.
2159        let map = NonCanonicalBTreeMap::from(BTreeMap::from([
2160            (1u32, 10u8),
2161            (256u32, 20u8),
2162            (2u32, 30u8),
2163        ]));
2164
2165        // It serializes as a plain `Vec<(K, V)>` in the map's `Ord` key order, with no canonical
2166        // re-sorting.
2167        let entries = map
2168            .iter()
2169            .map(|(k, v)| (*k, *v))
2170            .collect::<Vec<(u32, u8)>>();
2171        assert_eq!(
2172            bcs::to_bytes(&map).unwrap(),
2173            bcs::to_bytes(&entries).unwrap()
2174        );
2175
2176        // ... which differs from the canonical `BTreeMap` encoding that re-sorts by serialized key.
2177        let canonical = map
2178            .iter()
2179            .map(|(k, v)| (*k, *v))
2180            .collect::<BTreeMap<u32, u8>>();
2181        assert_ne!(
2182            bcs::to_bytes(&map).unwrap(),
2183            bcs::to_bytes(&canonical).unwrap()
2184        );
2185
2186        // It round-trips.
2187        let deserialized: NonCanonicalBTreeMap<u32, u8> =
2188            bcs::from_bytes(&bcs::to_bytes(&map).unwrap()).unwrap();
2189        assert_eq!(map, deserialized);
2190    }
2191
2192    #[test]
2193    fn canonical_btree_set_serializes_like_map() {
2194        use std::collections::{BTreeMap, BTreeSet};
2195
2196        use super::CanonicalBTreeSet;
2197
2198        let set = CanonicalBTreeSet::from(BTreeSet::from([1u32, 256u32, 2u32]));
2199
2200        // It serializes exactly like a `BTreeMap<T, ()>`, i.e. canonically sorted by serialized
2201        // bytes.
2202        let map = set.iter().map(|t| (*t, ())).collect::<BTreeMap<u32, ()>>();
2203        assert_eq!(bcs::to_bytes(&set).unwrap(), bcs::to_bytes(&map).unwrap());
2204
2205        // That canonical order differs from a plain `BTreeSet`'s sequence encoding, which keeps
2206        // the numeric `Ord` order.
2207        let plain = set.iter().copied().collect::<BTreeSet<u32>>();
2208        assert_ne!(bcs::to_bytes(&set).unwrap(), bcs::to_bytes(&plain).unwrap());
2209
2210        // It round-trips.
2211        let deserialized: CanonicalBTreeSet<u32> =
2212            bcs::from_bytes(&bcs::to_bytes(&set).unwrap()).unwrap();
2213        assert_eq!(set, deserialized);
2214    }
2215
2216    #[test]
2217    fn display_amount() {
2218        assert_eq!("1.", Amount::ONE.to_string());
2219        assert_eq!("1.", Amount::from_str("1.").unwrap().to_string());
2220        assert_eq!(
2221            Amount(10_000_000_000_000_000_000),
2222            Amount::from_str("10").unwrap()
2223        );
2224        assert_eq!("10.", Amount(10_000_000_000_000_000_000).to_string());
2225        assert_eq!(
2226            "1001.3",
2227            (Amount::from_str("1.1")
2228                .unwrap()
2229                .saturating_add(Amount::from_str("1_000.2").unwrap()))
2230            .to_string()
2231        );
2232        assert_eq!(
2233            "   1.00000000000000000000",
2234            format!("{:25.20}", Amount::ONE)
2235        );
2236        assert_eq!(
2237            "~+12.34~~",
2238            format!("{:~^+9.1}", Amount::from_str("12.34").unwrap())
2239        );
2240    }
2241
2242    #[test]
2243    fn blob_content_serialization_deserialization() {
2244        let test_data = b"Hello, world!".as_slice();
2245        let original_blob = BlobContent::new(BlobType::Data, test_data);
2246
2247        let serialized = bcs::to_bytes(&original_blob).expect("Failed to serialize BlobContent");
2248        let deserialized: BlobContent =
2249            bcs::from_bytes(&serialized).expect("Failed to deserialize BlobContent");
2250        assert_eq!(original_blob, deserialized);
2251
2252        let serialized =
2253            serde_json::to_vec(&original_blob).expect("Failed to serialize BlobContent");
2254        let deserialized: BlobContent =
2255            serde_json::from_slice(&serialized).expect("Failed to deserialize BlobContent");
2256        assert_eq!(original_blob, deserialized);
2257    }
2258
2259    #[test]
2260    fn blob_content_hash_consistency() {
2261        let test_data = b"Hello, world!";
2262        let blob1 = BlobContent::new(BlobType::Data, test_data.as_slice());
2263        let blob2 = BlobContent::new(BlobType::Data, Vec::from(test_data.as_slice()));
2264
2265        // Both should have same hash since they contain the same data
2266        let hash1 = crate::crypto::CryptoHash::new(&blob1);
2267        let hash2 = crate::crypto::CryptoHash::new(&blob2);
2268
2269        assert_eq!(hash1, hash2, "Hashes should be equal for same content");
2270        assert_eq!(blob1.bytes(), blob2.bytes(), "Byte content should be equal");
2271    }
2272
2273    #[test]
2274    fn test_conversion_amount_u256() {
2275        let value_amount = Amount::from_tokens(15656565652209004332);
2276        let value_u256: U256 = value_amount.into();
2277        let value_amount_rev = Amount::try_from(value_u256).expect("Failed conversion");
2278        assert_eq!(value_amount, value_amount_rev);
2279    }
2280
2281    /// `linera-explorer` running on `wasm32` does not have access to the
2282    /// strongly-typed `ApplicationDescription`: the GraphQL client substitutes
2283    /// it for `serde_json::Value`. The explorer therefore fetches the module ID
2284    /// for an application by indexing into the JSON object as
2285    /// `description["module_id"]`. This test pins that field name and the
2286    /// hex-string shape of the serialized `ModuleId` so a future rename or
2287    /// representation change immediately breaks here instead of silently in the
2288    /// browser.
2289    #[test]
2290    fn application_description_serializes_module_id_as_hex_string() {
2291        let module_id = ModuleId::new(
2292            CryptoHash::test_hash("contract-bytecode"),
2293            CryptoHash::test_hash("service-bytecode"),
2294            VmRuntime::Wasm,
2295        );
2296        let description = ApplicationDescription {
2297            module_id,
2298            creator_chain_id: ChainId(CryptoHash::test_hash("chain")),
2299            block_height: BlockHeight(0),
2300            application_index: 0,
2301            parameters: Vec::new(),
2302            required_application_ids: Vec::new(),
2303        };
2304
2305        let value = serde_json::to_value(&description).unwrap();
2306        let module_id_value = value
2307            .get("module_id")
2308            .expect("`module_id` is the field name the explorer indexes into");
2309        let hex = module_id_value
2310            .as_str()
2311            .expect("`module_id` must serialize as a hex string in human-readable form");
2312        let roundtrip: ModuleId =
2313            serde_json::from_value(serde_json::Value::String(hex.to_owned())).unwrap();
2314        assert_eq!(roundtrip, module_id);
2315    }
2316}