1use 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#[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#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
47pub enum AccountOwner {
48 User(Owner),
50 Application(ApplicationId),
52}
53
54#[derive(
56 Debug, PartialEq, Eq, Hash, Copy, Clone, Serialize, Deserialize, WitLoad, WitStore, WitType,
57)]
58pub struct Account {
59 pub chain_id: ChainId,
61 pub owner: Option<Owner>,
63}
64
65impl Account {
66 pub fn chain(chain_id: ChainId) -> Self {
68 Account {
69 chain_id,
70 owner: None,
71 }
72 }
73
74 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#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Hash, Debug, Serialize, Deserialize)]
113pub enum ChainDescription {
114 Root(u32),
116 Child(MessageId),
118}
119
120impl ChainDescription {
121 pub fn is_child(&self) -> bool {
123 matches!(self, ChainDescription::Child(_))
124 }
125}
126
127#[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#[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 #[default]
169 Data,
170 ContractBytecode,
172 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#[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 pub hash: CryptoHash,
209 pub blob_type: BlobType,
211}
212
213impl BlobId {
214 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 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#[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 pub chain_id: ChainId,
311 pub height: BlockHeight,
313 pub index: u32,
315}
316
317#[derive(WitLoad, WitStore, WitType)]
319#[cfg_attr(with_testing, derive(Default))]
320pub struct ApplicationId<A = ()> {
321 pub bytecode_id: BytecodeId<A>,
323 pub creation: MessageId,
325}
326
327pub type UserApplicationId<A = ()> = ApplicationId<A>;
330
331#[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 System,
350 User(ApplicationId),
352}
353
354impl GenericApplicationId {
355 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#[derive(WitLoad, WitStore, WitType)]
373#[cfg_attr(with_testing, derive(Default))]
374pub struct BytecodeId<Abi = (), Parameters = (), InstantiationArgument = ()> {
375 pub contract_blob_hash: CryptoHash,
377 pub service_blob_hash: CryptoHash,
379 #[witty(skip)]
380 _phantom: PhantomData<(Abi, Parameters, InstantiationArgument)>,
381}
382
383#[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#[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#[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 pub application_id: GenericApplicationId,
436 pub stream_name: StreamName,
438}
439
440#[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 Recipient(ChainId),
458 Subscribers(ChannelName),
460}
461
462impl Destination {
463 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 pub fn into_bytes(self) -> Vec<u8> {
496 self.0
497 }
498}
499
500impl StreamName {
501 pub fn into_bytes(self) -> Vec<u8> {
503 self.0
504 }
505}
506
507impl<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 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 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 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 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
690impl<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 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 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 pub fn root(index: u32) -> Self {
976 Self(CryptoHash::new(&ChainDescription::Root(index)))
977 }
978
979 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 #[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}