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