Skip to main content

linera_base/
data_types.rs

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