Skip to main content

linera_base/
data_types.rs

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