linera_base/
identifiers.rs

1// Copyright (c) Zefchain Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Core identifiers used by the Linera protocol.
5
6use std::{
7    fmt::{self, Debug, Display},
8    hash::{Hash, Hasher},
9    marker::PhantomData,
10    str::FromStr,
11};
12
13use anyhow::{anyhow, Context};
14use async_graphql::SimpleObject;
15use linera_witty::{WitLoad, WitStore, WitType};
16use serde::{Deserialize, Deserializer, Serialize, Serializer};
17
18use crate::{
19    bcs_scalar,
20    crypto::{BcsHashable, CryptoError, CryptoHash, PublicKey},
21    data_types::{BlobContent, BlockHeight},
22    doc_scalar,
23};
24
25/// The owner of a chain. This is currently the hash of the owner's public key used to
26/// verify signatures.
27#[derive(
28    Eq,
29    PartialEq,
30    Ord,
31    PartialOrd,
32    Copy,
33    Clone,
34    Hash,
35    Debug,
36    Serialize,
37    Deserialize,
38    WitLoad,
39    WitStore,
40    WitType,
41)]
42#[cfg_attr(with_testing, derive(Default, test_strategy::Arbitrary))]
43pub struct Owner(pub CryptoHash);
44
45/// An account owner.
46#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
47pub enum AccountOwner {
48    /// An account owned by a user.
49    User(Owner),
50    /// An account for an application.
51    Application(ApplicationId),
52}
53
54/// A system account.
55#[derive(
56    Debug, PartialEq, Eq, Hash, Copy, Clone, Serialize, Deserialize, WitLoad, WitStore, WitType,
57)]
58pub struct Account {
59    /// The chain of the account.
60    pub chain_id: ChainId,
61    /// The owner of the account, or `None` for the chain balance.
62    pub owner: Option<Owner>,
63}
64
65impl Account {
66    /// Creates an Account with a ChainId
67    pub fn chain(chain_id: ChainId) -> Self {
68        Account {
69            chain_id,
70            owner: None,
71        }
72    }
73
74    /// Creates an Account with a ChainId and an Owner
75    pub fn owner(chain_id: ChainId, owner: Owner) -> Self {
76        Account {
77            chain_id,
78            owner: Some(owner),
79        }
80    }
81}
82
83impl Display for Account {
84    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85        match self.owner {
86            Some(owner) => write!(f, "{}:{}", self.chain_id, owner),
87            None => write!(f, "{}", self.chain_id),
88        }
89    }
90}
91
92impl FromStr for Account {
93    type Err = anyhow::Error;
94
95    fn from_str(s: &str) -> Result<Self, Self::Err> {
96        let parts = s.split(':').collect::<Vec<_>>();
97        anyhow::ensure!(
98            parts.len() <= 2,
99            "Expecting format `chain-id:address` or `chain-id`"
100        );
101        if parts.len() == 1 {
102            Ok(Account::chain(s.parse()?))
103        } else {
104            let chain_id = parts[0].parse()?;
105            let owner = parts[1].parse()?;
106            Ok(Account::owner(chain_id, owner))
107        }
108    }
109}
110
111/// How to create a chain.
112#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Hash, Debug, Serialize, Deserialize)]
113pub enum ChainDescription {
114    /// The chain was created by the genesis configuration.
115    Root(u32),
116    /// The chain was created by a message from another chain.
117    Child(MessageId),
118}
119
120impl ChainDescription {
121    /// Whether the chain was created by another chain.
122    pub fn is_child(&self) -> bool {
123        matches!(self, ChainDescription::Child(_))
124    }
125}
126
127/// The unique identifier (UID) of a chain. This is currently computed as the hash value
128/// of a [`ChainDescription`].
129#[derive(
130    Eq,
131    PartialEq,
132    Ord,
133    PartialOrd,
134    Copy,
135    Clone,
136    Hash,
137    Serialize,
138    Deserialize,
139    WitLoad,
140    WitStore,
141    WitType,
142)]
143#[cfg_attr(with_testing, derive(test_strategy::Arbitrary))]
144#[cfg_attr(with_testing, derive(Default))]
145pub struct ChainId(pub CryptoHash);
146
147/// The type of the blob.
148/// Should be a 1:1 mapping of the types in `Blob`.
149#[derive(
150    Eq,
151    PartialEq,
152    Ord,
153    PartialOrd,
154    Clone,
155    Copy,
156    Hash,
157    Debug,
158    Serialize,
159    Deserialize,
160    WitType,
161    WitStore,
162    WitLoad,
163    Default,
164)]
165#[cfg_attr(with_testing, derive(test_strategy::Arbitrary))]
166pub enum BlobType {
167    /// A generic data blob.
168    #[default]
169    Data,
170    /// A blob containing contract bytecode.
171    ContractBytecode,
172    /// A blob containing service bytecode.
173    ServiceBytecode,
174}
175
176impl Display for BlobType {
177    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
178        match serde_json::to_string(self) {
179            Ok(s) => write!(f, "{}", s),
180            Err(_) => Err(fmt::Error),
181        }
182    }
183}
184
185impl FromStr for BlobType {
186    type Err = anyhow::Error;
187
188    fn from_str(s: &str) -> Result<Self, Self::Err> {
189        serde_json::from_str(s).with_context(|| format!("Invalid BlobType: {}", s))
190    }
191}
192
193impl From<&BlobContent> for BlobType {
194    fn from(content: &BlobContent) -> Self {
195        match content {
196            BlobContent::Data(_) => BlobType::Data,
197            BlobContent::ContractBytecode(_) => BlobType::ContractBytecode,
198            BlobContent::ServiceBytecode(_) => BlobType::ServiceBytecode,
199        }
200    }
201}
202
203/// A content-addressed blob ID i.e. the hash of the `BlobContent`.
204#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash, Debug, WitType, WitStore, WitLoad)]
205#[cfg_attr(with_testing, derive(test_strategy::Arbitrary, Default))]
206pub struct BlobId {
207    /// The hash of the blob.
208    pub hash: CryptoHash,
209    /// The type of the blob.
210    pub blob_type: BlobType,
211}
212
213impl BlobId {
214    /// Creates a new `BlobId` from a `BlobContent`
215    pub fn from_content(content: &BlobContent) -> Self {
216        Self {
217            hash: CryptoHash::new(&content.blob_bytes()),
218            blob_type: content.into(),
219        }
220    }
221
222    /// Creates a new `BlobId` from a `CryptoHash`. This must be a hash of the blob's bytes!
223    pub fn new(hash: CryptoHash, blob_type: BlobType) -> Self {
224        Self { hash, blob_type }
225    }
226}
227
228impl Display for BlobId {
229    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
230        write!(f, "{}:{}", self.blob_type, self.hash)?;
231        Ok(())
232    }
233}
234
235impl FromStr for BlobId {
236    type Err = anyhow::Error;
237
238    fn from_str(s: &str) -> Result<Self, Self::Err> {
239        let parts = s.split(':').collect::<Vec<_>>();
240        if parts.len() == 2 {
241            let blob_type = BlobType::from_str(parts[0]).context("Invalid BlobType!")?;
242            Ok(BlobId {
243                hash: CryptoHash::from_str(parts[1]).context("Invalid hash!")?,
244                blob_type,
245            })
246        } else {
247            Err(anyhow!("Invalid blob ID: {}", s))
248        }
249    }
250}
251
252#[derive(Serialize, Deserialize)]
253#[serde(rename = "BlobId")]
254struct BlobIdHelper {
255    hash: CryptoHash,
256    blob_type: BlobType,
257}
258
259impl Serialize for BlobId {
260    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
261    where
262        S: Serializer,
263    {
264        if serializer.is_human_readable() {
265            serializer.serialize_str(&self.to_string())
266        } else {
267            let helper = BlobIdHelper {
268                hash: self.hash,
269                blob_type: self.blob_type,
270            };
271            helper.serialize(serializer)
272        }
273    }
274}
275
276impl<'a> Deserialize<'a> for BlobId {
277    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
278    where
279        D: Deserializer<'a>,
280    {
281        if deserializer.is_human_readable() {
282            let s = String::deserialize(deserializer)?;
283            Self::from_str(&s).map_err(serde::de::Error::custom)
284        } else {
285            let helper = BlobIdHelper::deserialize(deserializer)?;
286            Ok(BlobId::new(helper.hash, helper.blob_type))
287        }
288    }
289}
290
291/// The index of a message in a chain.
292#[derive(
293    Eq,
294    PartialEq,
295    Ord,
296    PartialOrd,
297    Copy,
298    Clone,
299    Hash,
300    Debug,
301    Serialize,
302    Deserialize,
303    WitLoad,
304    WitStore,
305    WitType,
306)]
307#[cfg_attr(with_testing, derive(Default))]
308pub struct MessageId {
309    /// The chain ID that created the message.
310    pub chain_id: ChainId,
311    /// The height of the block that created the message.
312    pub height: BlockHeight,
313    /// The index of the message inside the block.
314    pub index: u32,
315}
316
317/// A unique identifier for a user application.
318#[derive(WitLoad, WitStore, WitType)]
319#[cfg_attr(with_testing, derive(Default))]
320pub struct ApplicationId<A = ()> {
321    /// The bytecode to use for the application.
322    pub bytecode_id: BytecodeId<A>,
323    /// The unique ID of the application's creation.
324    pub creation: MessageId,
325}
326
327/// Alias for `ApplicationId`. Use this alias in the core
328/// protocol where the distinction with the more general enum `GenericApplicationId` matters.
329pub type UserApplicationId<A = ()> = ApplicationId<A>;
330
331/// A unique identifier for an application.
332#[derive(
333    Eq,
334    PartialEq,
335    Ord,
336    PartialOrd,
337    Copy,
338    Clone,
339    Hash,
340    Debug,
341    Serialize,
342    Deserialize,
343    WitLoad,
344    WitStore,
345    WitType,
346)]
347pub enum GenericApplicationId {
348    /// The system application.
349    System,
350    /// A user application.
351    User(ApplicationId),
352}
353
354impl GenericApplicationId {
355    /// Returns the `ApplicationId`, or `None` if it is `System`.
356    pub fn user_application_id(&self) -> Option<&ApplicationId> {
357        if let GenericApplicationId::User(app_id) = self {
358            Some(app_id)
359        } else {
360            None
361        }
362    }
363}
364
365impl From<ApplicationId> for GenericApplicationId {
366    fn from(user_application_id: ApplicationId) -> Self {
367        GenericApplicationId::User(user_application_id)
368    }
369}
370
371/// A unique identifier for an application bytecode.
372#[derive(WitLoad, WitStore, WitType)]
373#[cfg_attr(with_testing, derive(Default))]
374pub struct BytecodeId<Abi = (), Parameters = (), InstantiationArgument = ()> {
375    /// The hash of the blob containing the contract bytecode.
376    pub contract_blob_hash: CryptoHash,
377    /// The hash of the blob containing the service bytecode.
378    pub service_blob_hash: CryptoHash,
379    #[witty(skip)]
380    _phantom: PhantomData<(Abi, Parameters, InstantiationArgument)>,
381}
382
383/// The name of a subscription channel.
384#[derive(
385    Clone,
386    Debug,
387    Eq,
388    Hash,
389    Ord,
390    PartialEq,
391    PartialOrd,
392    Serialize,
393    Deserialize,
394    WitLoad,
395    WitStore,
396    WitType,
397)]
398pub struct ChannelName(#[serde(with = "serde_bytes")] Vec<u8>);
399
400/// The name of an event stream.
401#[derive(
402    Clone,
403    Debug,
404    Eq,
405    Hash,
406    Ord,
407    PartialEq,
408    PartialOrd,
409    Serialize,
410    Deserialize,
411    WitLoad,
412    WitStore,
413    WitType,
414)]
415pub struct StreamName(#[serde(with = "serde_bytes")] pub Vec<u8>);
416
417/// An event stream ID.
418#[derive(
419    Clone,
420    Debug,
421    Eq,
422    Hash,
423    Ord,
424    PartialEq,
425    PartialOrd,
426    Serialize,
427    Deserialize,
428    WitLoad,
429    WitStore,
430    WitType,
431    SimpleObject,
432)]
433pub struct StreamId {
434    /// The application that can add events to this stream.
435    pub application_id: GenericApplicationId,
436    /// The name of this stream: an application can have multiple streams with different names.
437    pub stream_name: StreamName,
438}
439
440/// The destination of a message, relative to a particular application.
441#[derive(
442    Clone,
443    Debug,
444    Eq,
445    Hash,
446    Ord,
447    PartialEq,
448    PartialOrd,
449    Serialize,
450    Deserialize,
451    WitLoad,
452    WitStore,
453    WitType,
454)]
455pub enum Destination {
456    /// Direct message to a chain.
457    Recipient(ChainId),
458    /// Broadcast to the current subscribers of our channel.
459    Subscribers(ChannelName),
460}
461
462impl Destination {
463    /// Whether the destination is a broadcast channel.
464    pub fn is_channel(&self) -> bool {
465        matches!(self, Destination::Subscribers(_))
466    }
467}
468
469impl From<ChainId> for Destination {
470    fn from(chain_id: ChainId) -> Self {
471        Destination::Recipient(chain_id)
472    }
473}
474
475impl From<ChannelName> for Destination {
476    fn from(channel_name: ChannelName) -> Self {
477        Destination::Subscribers(channel_name)
478    }
479}
480
481impl AsRef<[u8]> for ChannelName {
482    fn as_ref(&self) -> &[u8] {
483        &self.0
484    }
485}
486
487impl From<Vec<u8>> for ChannelName {
488    fn from(name: Vec<u8>) -> Self {
489        ChannelName(name)
490    }
491}
492
493impl ChannelName {
494    /// Turns the channel name into bytes.
495    pub fn into_bytes(self) -> Vec<u8> {
496        self.0
497    }
498}
499
500impl StreamName {
501    /// Turns the stream name into bytes.
502    pub fn into_bytes(self) -> Vec<u8> {
503        self.0
504    }
505}
506
507// Cannot use #[derive(Clone)] because it requires `A: Clone`.
508impl<Abi, Parameters, InstantiationArgument> Clone
509    for BytecodeId<Abi, Parameters, InstantiationArgument>
510{
511    fn clone(&self) -> Self {
512        *self
513    }
514}
515
516impl<Abi, Parameters, InstantiationArgument> Copy
517    for BytecodeId<Abi, Parameters, InstantiationArgument>
518{
519}
520
521impl<Abi, Parameters, InstantiationArgument> PartialEq
522    for BytecodeId<Abi, Parameters, InstantiationArgument>
523{
524    fn eq(&self, other: &Self) -> bool {
525        let BytecodeId {
526            contract_blob_hash,
527            service_blob_hash,
528            _phantom,
529        } = other;
530        self.contract_blob_hash == *contract_blob_hash
531            && self.service_blob_hash == *service_blob_hash
532    }
533}
534
535impl<Abi, Parameters, InstantiationArgument> Eq
536    for BytecodeId<Abi, Parameters, InstantiationArgument>
537{
538}
539
540impl<Abi, Parameters, InstantiationArgument> PartialOrd
541    for BytecodeId<Abi, Parameters, InstantiationArgument>
542{
543    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
544        Some(self.cmp(other))
545    }
546}
547
548impl<Abi, Parameters, InstantiationArgument> Ord
549    for BytecodeId<Abi, Parameters, InstantiationArgument>
550{
551    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
552        let BytecodeId {
553            contract_blob_hash,
554            service_blob_hash,
555            _phantom,
556        } = other;
557        (self.contract_blob_hash, self.service_blob_hash)
558            .cmp(&(*contract_blob_hash, *service_blob_hash))
559    }
560}
561
562impl<Abi, Parameters, InstantiationArgument> Hash
563    for BytecodeId<Abi, Parameters, InstantiationArgument>
564{
565    fn hash<H: Hasher>(&self, state: &mut H) {
566        let BytecodeId {
567            contract_blob_hash: contract_blob_id,
568            service_blob_hash: service_blob_id,
569            _phantom,
570        } = self;
571        contract_blob_id.hash(state);
572        service_blob_id.hash(state);
573    }
574}
575
576impl<Abi, Parameters, InstantiationArgument> Debug
577    for BytecodeId<Abi, Parameters, InstantiationArgument>
578{
579    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
580        let BytecodeId {
581            contract_blob_hash: contract_blob_id,
582            service_blob_hash: service_blob_id,
583            _phantom,
584        } = self;
585        f.debug_struct("BytecodeId")
586            .field("contract_blob_id", contract_blob_id)
587            .field("service_blob_id", service_blob_id)
588            .finish_non_exhaustive()
589    }
590}
591
592#[derive(Serialize, Deserialize)]
593#[serde(rename = "BytecodeId")]
594struct SerializableBytecodeId {
595    contract_blob_hash: CryptoHash,
596    service_blob_hash: CryptoHash,
597}
598
599impl<Abi, Parameters, InstantiationArgument> Serialize
600    for BytecodeId<Abi, Parameters, InstantiationArgument>
601{
602    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
603    where
604        S: serde::ser::Serializer,
605    {
606        let serializable_bytecode_id = SerializableBytecodeId {
607            contract_blob_hash: self.contract_blob_hash,
608            service_blob_hash: self.service_blob_hash,
609        };
610        if serializer.is_human_readable() {
611            let bytes =
612                bcs::to_bytes(&serializable_bytecode_id).map_err(serde::ser::Error::custom)?;
613            serializer.serialize_str(&hex::encode(bytes))
614        } else {
615            SerializableBytecodeId::serialize(&serializable_bytecode_id, serializer)
616        }
617    }
618}
619
620impl<'de, Abi, Parameters, InstantiationArgument> Deserialize<'de>
621    for BytecodeId<Abi, Parameters, InstantiationArgument>
622{
623    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
624    where
625        D: serde::de::Deserializer<'de>,
626    {
627        if deserializer.is_human_readable() {
628            let s = String::deserialize(deserializer)?;
629            let bytecode_id_bytes = hex::decode(s).map_err(serde::de::Error::custom)?;
630            let serializable_bytecode_id: SerializableBytecodeId =
631                bcs::from_bytes(&bytecode_id_bytes).map_err(serde::de::Error::custom)?;
632            Ok(BytecodeId {
633                contract_blob_hash: serializable_bytecode_id.contract_blob_hash,
634                service_blob_hash: serializable_bytecode_id.service_blob_hash,
635                _phantom: PhantomData,
636            })
637        } else {
638            let serializable_bytecode_id = SerializableBytecodeId::deserialize(deserializer)?;
639            Ok(BytecodeId {
640                contract_blob_hash: serializable_bytecode_id.contract_blob_hash,
641                service_blob_hash: serializable_bytecode_id.service_blob_hash,
642                _phantom: PhantomData,
643            })
644        }
645    }
646}
647
648impl BytecodeId {
649    /// Creates a bytecode ID from contract/service hashes.
650    pub fn new(contract_blob_hash: CryptoHash, service_blob_hash: CryptoHash) -> Self {
651        BytecodeId {
652            contract_blob_hash,
653            service_blob_hash,
654            _phantom: PhantomData,
655        }
656    }
657
658    /// Specializes a bytecode ID for a given ABI.
659    pub fn with_abi<Abi, Parameters, InstantiationArgument>(
660        self,
661    ) -> BytecodeId<Abi, Parameters, InstantiationArgument> {
662        BytecodeId {
663            contract_blob_hash: self.contract_blob_hash,
664            service_blob_hash: self.service_blob_hash,
665            _phantom: PhantomData,
666        }
667    }
668}
669
670impl<Abi, Parameters, InstantiationArgument> BytecodeId<Abi, Parameters, InstantiationArgument> {
671    /// Forgets the ABI of a bytecode ID (if any).
672    pub fn forget_abi(self) -> BytecodeId {
673        BytecodeId {
674            contract_blob_hash: self.contract_blob_hash,
675            service_blob_hash: self.service_blob_hash,
676            _phantom: PhantomData,
677        }
678    }
679
680    /// Leaves just the ABI of a bytecode ID (if any).
681    pub fn just_abi(self) -> BytecodeId<Abi> {
682        BytecodeId {
683            contract_blob_hash: self.contract_blob_hash,
684            service_blob_hash: self.service_blob_hash,
685            _phantom: PhantomData,
686        }
687    }
688}
689
690// Cannot use #[derive(Clone)] because it requires `A: Clone`.
691impl<A> Clone for ApplicationId<A> {
692    fn clone(&self) -> Self {
693        *self
694    }
695}
696
697impl<A> Copy for ApplicationId<A> {}
698
699impl<A: PartialEq> PartialEq for ApplicationId<A> {
700    fn eq(&self, other: &Self) -> bool {
701        let ApplicationId {
702            bytecode_id,
703            creation,
704        } = other;
705        self.bytecode_id == *bytecode_id && self.creation == *creation
706    }
707}
708
709impl<A: Eq> Eq for ApplicationId<A> {}
710
711impl<A: PartialOrd> PartialOrd for ApplicationId<A> {
712    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
713        let ApplicationId {
714            bytecode_id,
715            creation,
716        } = other;
717        match self.bytecode_id.partial_cmp(bytecode_id) {
718            Some(std::cmp::Ordering::Equal) => self.creation.partial_cmp(creation),
719            result => result,
720        }
721    }
722}
723
724impl<A: Ord> Ord for ApplicationId<A> {
725    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
726        let ApplicationId {
727            bytecode_id,
728            creation,
729        } = other;
730        match self.bytecode_id.cmp(bytecode_id) {
731            std::cmp::Ordering::Equal => self.creation.cmp(creation),
732            result => result,
733        }
734    }
735}
736
737impl<A> Hash for ApplicationId<A> {
738    fn hash<H: Hasher>(&self, state: &mut H) {
739        let ApplicationId {
740            bytecode_id,
741            creation,
742        } = self;
743        bytecode_id.hash(state);
744        creation.hash(state);
745    }
746}
747
748impl<A> Debug for ApplicationId<A> {
749    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
750        let ApplicationId {
751            bytecode_id,
752            creation,
753        } = self;
754        f.debug_struct("ApplicationId")
755            .field("bytecode_id", bytecode_id)
756            .field("creation", creation)
757            .finish()
758    }
759}
760
761#[derive(Serialize, Deserialize)]
762#[serde(rename = "ApplicationId")]
763struct SerializableApplicationId {
764    pub bytecode_id: BytecodeId,
765    pub creation: MessageId,
766}
767
768impl<A> Serialize for ApplicationId<A> {
769    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
770    where
771        S: serde::ser::Serializer,
772    {
773        if serializer.is_human_readable() {
774            let bytes = bcs::to_bytes(&SerializableApplicationId {
775                bytecode_id: self.bytecode_id.forget_abi(),
776                creation: self.creation,
777            })
778            .map_err(serde::ser::Error::custom)?;
779            serializer.serialize_str(&hex::encode(bytes))
780        } else {
781            SerializableApplicationId::serialize(
782                &SerializableApplicationId {
783                    bytecode_id: self.bytecode_id.forget_abi(),
784                    creation: self.creation,
785                },
786                serializer,
787            )
788        }
789    }
790}
791
792impl<'de, A> Deserialize<'de> for ApplicationId<A> {
793    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
794    where
795        D: serde::de::Deserializer<'de>,
796    {
797        if deserializer.is_human_readable() {
798            let s = String::deserialize(deserializer)?;
799            let application_id_bytes = hex::decode(s).map_err(serde::de::Error::custom)?;
800            let application_id: SerializableApplicationId =
801                bcs::from_bytes(&application_id_bytes).map_err(serde::de::Error::custom)?;
802            Ok(ApplicationId {
803                bytecode_id: application_id.bytecode_id.with_abi(),
804                creation: application_id.creation,
805            })
806        } else {
807            let value = SerializableApplicationId::deserialize(deserializer)?;
808            Ok(ApplicationId {
809                bytecode_id: value.bytecode_id.with_abi(),
810                creation: value.creation,
811            })
812        }
813    }
814}
815
816impl ApplicationId {
817    /// Specializes an application ID for a given ABI.
818    pub fn with_abi<A>(self) -> ApplicationId<A> {
819        ApplicationId {
820            bytecode_id: self.bytecode_id.with_abi(),
821            creation: self.creation,
822        }
823    }
824}
825
826impl<A> ApplicationId<A> {
827    /// Forgets the ABI of a bytecode ID (if any).
828    pub fn forget_abi(self) -> ApplicationId {
829        ApplicationId {
830            bytecode_id: self.bytecode_id.forget_abi(),
831            creation: self.creation,
832        }
833    }
834}
835
836impl Display for Owner {
837    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
838        Display::fmt(&self.0, f)
839    }
840}
841
842impl From<PublicKey> for Owner {
843    fn from(value: PublicKey) -> Self {
844        Self(CryptoHash::new(&value))
845    }
846}
847
848impl From<&PublicKey> for Owner {
849    fn from(value: &PublicKey) -> Self {
850        Self(CryptoHash::new(value))
851    }
852}
853
854impl std::str::FromStr for Owner {
855    type Err = CryptoError;
856
857    fn from_str(s: &str) -> Result<Self, Self::Err> {
858        Ok(Owner(CryptoHash::from_str(s)?))
859    }
860}
861
862#[derive(Serialize, Deserialize)]
863#[serde(rename = "AccountOwner")]
864enum SerializableAccountOwner {
865    User(Owner),
866    Application(ApplicationId),
867}
868
869impl Serialize for AccountOwner {
870    fn serialize<S: serde::ser::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
871        if serializer.is_human_readable() {
872            serializer.serialize_str(&self.to_string())
873        } else {
874            match self {
875                AccountOwner::Application(app_id) => SerializableAccountOwner::Application(*app_id),
876                AccountOwner::User(owner) => SerializableAccountOwner::User(*owner),
877            }
878            .serialize(serializer)
879        }
880    }
881}
882
883impl<'de> Deserialize<'de> for AccountOwner {
884    fn deserialize<D: serde::de::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
885        if deserializer.is_human_readable() {
886            let s = String::deserialize(deserializer)?;
887            let value = Self::from_str(&s).map_err(serde::de::Error::custom)?;
888            Ok(value)
889        } else {
890            let value = SerializableAccountOwner::deserialize(deserializer)?;
891            match value {
892                SerializableAccountOwner::Application(app_id) => {
893                    Ok(AccountOwner::Application(app_id))
894                }
895                SerializableAccountOwner::User(owner) => Ok(AccountOwner::User(owner)),
896            }
897        }
898    }
899}
900
901impl Display for AccountOwner {
902    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
903        match self {
904            AccountOwner::User(owner) => write!(f, "User:{}", owner)?,
905            AccountOwner::Application(app_id) => write!(f, "Application:{}", app_id)?,
906        };
907
908        Ok(())
909    }
910}
911
912impl FromStr for AccountOwner {
913    type Err = anyhow::Error;
914
915    fn from_str(s: &str) -> Result<Self, Self::Err> {
916        if let Some(owner) = s.strip_prefix("User:") {
917            Ok(AccountOwner::User(
918                Owner::from_str(owner).context("Getting Owner should not fail")?,
919            ))
920        } else if let Some(app_id) = s.strip_prefix("Application:") {
921            Ok(AccountOwner::Application(
922                ApplicationId::from_str(app_id).context("Getting ApplicationId should not fail")?,
923            ))
924        } else {
925            Err(anyhow!("Invalid enum! Enum: {}", s))
926        }
927    }
928}
929
930impl<T> From<T> for AccountOwner
931where
932    T: Into<Owner>,
933{
934    fn from(owner: T) -> Self {
935        AccountOwner::User(owner.into())
936    }
937}
938
939impl Display for ChainId {
940    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
941        Display::fmt(&self.0, f)
942    }
943}
944
945impl FromStr for ChainId {
946    type Err = CryptoError;
947
948    fn from_str(s: &str) -> Result<Self, Self::Err> {
949        Ok(ChainId(CryptoHash::from_str(s)?))
950    }
951}
952
953impl TryFrom<&[u8]> for ChainId {
954    type Error = CryptoError;
955
956    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
957        Ok(ChainId(CryptoHash::try_from(value)?))
958    }
959}
960
961impl fmt::Debug for ChainId {
962    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
963        write!(f, "{:?}", self.0)
964    }
965}
966
967impl From<ChainDescription> for ChainId {
968    fn from(description: ChainDescription) -> Self {
969        Self(CryptoHash::new(&description))
970    }
971}
972
973impl ChainId {
974    /// The chain ID representing the N-th chain created at genesis time.
975    pub fn root(index: u32) -> Self {
976        Self(CryptoHash::new(&ChainDescription::Root(index)))
977    }
978
979    /// The chain ID representing the chain created by the given message.
980    pub fn child(id: MessageId) -> Self {
981        Self(CryptoHash::new(&ChainDescription::Child(id)))
982    }
983}
984
985impl BcsHashable for ChainDescription {}
986
987bcs_scalar!(ApplicationId, "A unique identifier for a user application");
988doc_scalar!(
989    GenericApplicationId,
990    "A unique identifier for a user application or for the system application"
991);
992bcs_scalar!(
993    BytecodeId,
994    "A unique identifier for an application bytecode"
995);
996doc_scalar!(ChainDescription, "How to create a chain");
997doc_scalar!(
998    ChainId,
999    "The unique identifier (UID) of a chain. This is currently computed as the hash value of a \
1000    ChainDescription."
1001);
1002doc_scalar!(ChannelName, "The name of a subscription channel");
1003doc_scalar!(StreamName, "The name of an event stream");
1004bcs_scalar!(MessageId, "The index of a message in a chain");
1005doc_scalar!(
1006    Owner,
1007    "The owner of a chain. This is currently the hash of the owner's public key used to verify \
1008    signatures."
1009);
1010doc_scalar!(
1011    Destination,
1012    "The destination of a message, relative to a particular application."
1013);
1014doc_scalar!(AccountOwner, "An owner of an account.");
1015doc_scalar!(Account, "An account");
1016doc_scalar!(
1017    BlobId,
1018    "A content-addressed blob ID i.e. the hash of the `BlobContent`"
1019);
1020
1021#[cfg(test)]
1022mod tests {
1023    use super::ChainId;
1024
1025    /// Verifies that chain IDs that are explicitly used in some example and test scripts don't
1026    /// change.
1027    #[test]
1028    fn chain_ids() {
1029        assert_eq!(
1030            &ChainId::root(0).to_string(),
1031            "e476187f6ddfeb9d588c7b45d3df334d5501d6499b3f9ad5595cae86cce16a65"
1032        );
1033        assert_eq!(
1034            &ChainId::root(9).to_string(),
1035            "256e1dbc00482ddd619c293cc0df94d366afe7980022bb22d99e33036fd465dd"
1036        );
1037        assert_eq!(
1038            &ChainId::root(999).to_string(),
1039            "9c8a838e8f7b63194f6c7585455667a8379d2b5db19a3300e9961f0b1e9091ea"
1040        );
1041    }
1042}