1#![cfg_attr(not(feature = "std"), no_std)]
6#![deny(missing_docs)]
7
8pub mod byte_string;
9pub mod crypto;
10pub mod mainchain_epoch;
11
12extern crate alloc;
13extern crate core;
14extern crate num_derive;
15
16pub use alloc::collections::btree_map::BTreeMap;
17#[cfg(feature = "std")]
18use alloc::format;
19pub use alloc::vec::Vec;
20use alloc::{str::FromStr, string::String, string::ToString, vec};
21use byte_string_derive::byte_string;
22use core::{
23 fmt::{Display, Formatter},
24 ops::Deref,
25};
26use crypto::blake2b;
27use derive_more::{From, Into};
28use num_derive::*;
29use parity_scale_codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen, WrapperTypeEncode};
30use plutus_datum_derive::*;
31use scale_info::TypeInfo;
32use sp_core::{ConstU32, bounded::BoundedVec, ecdsa, ed25519, sr25519};
33#[cfg(feature = "serde")]
34use {
35 derive_more::FromStr,
36 serde::{Deserialize, Deserializer, Serialize, Serializer},
37};
38
39const DATA_MC_EPOCH_OFFSET: u32 = 2;
42
43pub fn offset_data_epoch(epoch: &McEpochNumber) -> Result<McEpochNumber, u32> {
45 Ok(McEpochNumber(epoch.0.checked_sub(DATA_MC_EPOCH_OFFSET).ok_or(DATA_MC_EPOCH_OFFSET)?))
46}
47
48#[derive(
49 Default,
50 Debug,
51 Copy,
52 Clone,
53 PartialEq,
54 Eq,
55 Encode,
56 Decode,
57 DecodeWithMemTracking,
58 Hash,
59 TypeInfo,
60 Ord,
61 PartialOrd,
62)]
63#[cfg_attr(feature = "serde", derive(Serialize, Deserialize, FromStr))]
64pub struct McEpochNumber(pub u32);
66
67impl McEpochNumber {
68 pub fn next(&self) -> Self {
70 Self(&self.0 + 1)
71 }
72}
73
74impl Display for McEpochNumber {
75 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
76 u32::fmt(&self.0, f)
77 }
78}
79#[derive(
80 Default,
81 Clone,
82 Copy,
83 Debug,
84 Encode,
85 Decode,
86 DecodeWithMemTracking,
87 TypeInfo,
88 PartialEq,
89 Eq,
90 PartialOrd,
91 Ord,
92)]
93#[cfg_attr(feature = "serde", derive(Serialize))]
94pub struct StakeDelegation(pub u64);
96
97impl StakeDelegation {
98 pub fn is_zero(&self) -> bool {
100 self.0 == 0
101 }
102}
103
104#[derive(
105 Default,
106 Clone,
107 Copy,
108 Debug,
109 Encode,
110 Decode,
111 DecodeWithMemTracking,
112 TypeInfo,
113 PartialEq,
114 Eq,
115 From,
116 MaxEncodedLen,
117)]
118#[cfg_attr(feature = "serde", derive(Serialize))]
119pub struct NativeTokenAmount(pub u128);
121
122impl Display for NativeTokenAmount {
123 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
124 u128::fmt(&self.0, f)
125 }
126}
127
128#[derive(
129 Default,
130 Clone,
131 Copy,
132 Debug,
133 Encode,
134 Decode,
135 DecodeWithMemTracking,
136 PartialEq,
137 Eq,
138 PartialOrd,
139 Ord,
140 scale_info::TypeInfo,
141)]
142#[cfg_attr(feature = "serde", derive(Serialize, Deserialize, FromStr))]
143pub struct McBlockNumber(pub u32);
145
146impl Display for McBlockNumber {
147 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
148 u32::fmt(&self.0, f)
149 }
150}
151
152#[derive(
153 Default,
154 Debug,
155 Copy,
156 Clone,
157 PartialEq,
158 Eq,
159 PartialOrd,
160 Encode,
161 Decode,
162 DecodeWithMemTracking,
163 TypeInfo,
164 Hash,
165)]
166#[cfg_attr(feature = "serde", derive(Serialize, Deserialize, FromStr))]
167pub struct McSlotNumber(pub u64);
169
170impl Display for McSlotNumber {
171 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
172 u64::fmt(&self.0, f)
173 }
174}
175
176#[derive(
177 Default,
178 Debug,
179 Copy,
180 Clone,
181 PartialEq,
182 Eq,
183 Encode,
184 Decode,
185 DecodeWithMemTracking,
186 TypeInfo,
187 Hash,
188 MaxEncodedLen,
189)]
190#[cfg_attr(feature = "serde", derive(Serialize, Deserialize, FromStr))]
191pub struct ScSlotNumber(pub u64);
193
194#[derive(Debug, Clone, PartialEq, Default)]
196#[cfg_attr(feature = "serde", derive(serde::Serialize))]
197pub struct MainchainBlock {
198 pub number: McBlockNumber,
200 pub hash: McBlockHash,
202 pub epoch: McEpochNumber,
204 pub slot: McSlotNumber,
206 pub timestamp: u64, }
209
210#[derive(
211 Default,
212 Debug,
213 Copy,
214 Clone,
215 PartialEq,
216 Eq,
217 Encode,
218 Decode,
219 DecodeWithMemTracking,
220 PartialOrd,
221 Ord,
222 TypeInfo,
223 MaxEncodedLen,
224)]
225#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
226pub struct McTxIndexInBlock(pub u32);
228
229#[cfg(feature = "serde")]
230impl FromStr for McTxIndexInBlock {
231 type Err = sp_std::num::ParseIntError;
232 fn from_str(s: &str) -> Result<Self, Self::Err> {
233 let parsed = u32::from_str(s)?;
234 let _check_overflow = i32::from_str(s)?;
235 Ok(Self(parsed))
236 }
237}
238
239const MAX_MAINCHAIN_ADDRESS_BYTES: u32 = 120;
241
242#[derive(
246 Clone, Default, PartialEq, Eq, Encode, Decode, DecodeWithMemTracking, TypeInfo, MaxEncodedLen,
247)]
248#[byte_string(debug)]
249#[cfg_attr(feature = "serde", byte_string(hex_serialize, hex_deserialize))]
250pub struct MainchainAddress(BoundedVec<u8, ConstU32<MAX_MAINCHAIN_ADDRESS_BYTES>>);
251
252impl MainchainAddress {
253 pub fn bytes(&self) -> Vec<u8> {
255 self.0.to_vec()
256 }
257}
258
259#[cfg(feature = "serde")]
260impl FromStr for MainchainAddress {
261 type Err = &'static str;
262
263 fn from_str(s: &str) -> Result<Self, Self::Err> {
264 let bytes: Vec<u8> = s.as_bytes().to_vec();
265 let bounded = BoundedVec::try_from(bytes).map_err(|_| "Invalid length")?;
266 Ok(MainchainAddress(bounded))
267 }
268}
269
270impl Display for MainchainAddress {
271 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
272 let s = String::from_utf8(self.0.to_vec())
273 .expect("MainchainAddressString is always properly encoded UTF-8");
274 write!(f, "{}", s)
275 }
276}
277
278const POLICY_ID_LEN: usize = 28;
280#[derive(
281 Clone,
282 Default,
283 PartialEq,
284 Eq,
285 Encode,
286 Decode,
287 DecodeWithMemTracking,
288 ToDatum,
289 TypeInfo,
290 MaxEncodedLen,
291 Hash,
292)]
293#[byte_string(debug, decode_hex, hex_serialize, hex_deserialize)]
294#[cfg_attr(feature = "std", byte_string(to_hex_string))]
295pub struct PolicyId(pub [u8; POLICY_ID_LEN]);
297
298pub type ScriptHash = PolicyId;
300
301pub const MAX_ASSET_NAME_LEN: u32 = 32;
303
304#[derive(
306 Clone, Default, PartialEq, Eq, Encode, Decode, DecodeWithMemTracking, TypeInfo, MaxEncodedLen,
307)]
308#[byte_string(debug, hex_serialize, hex_deserialize, decode_hex)]
309pub struct AssetName(pub BoundedVec<u8, ConstU32<MAX_ASSET_NAME_LEN>>);
310
311impl AssetName {
312 pub fn empty() -> Self {
314 Self(BoundedVec::new())
315 }
316}
317
318#[derive(
319 Clone,
320 Debug,
321 PartialEq,
322 Eq,
323 Encode,
324 Decode,
325 DecodeWithMemTracking,
326 TypeInfo,
327 MaxEncodedLen,
328 Default,
329)]
330#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
331pub struct AssetId {
333 pub policy_id: PolicyId,
335 pub asset_name: AssetName,
337}
338
339#[cfg(feature = "std")]
340impl FromStr for AssetId {
341 type Err = String;
342
343 fn from_str(s: &str) -> Result<Self, Self::Err> {
344 match s.split_once(".") {
345 Some((policy_id, asset_name)) => {
346 let policy_id = PolicyId::from_str(policy_id)
347 .map_err(|e| format!("{} is invalid Policy ID: {}", policy_id, e))?;
348 let asset_name = AssetName::from_str(asset_name)
349 .map_err(|e| format!("{} is invalid Asset Name: {}", asset_name, e))?;
350 Ok(Self { policy_id, asset_name })
351 },
352 None => {
353 Err("AssetId should be <hex encoded Policy ID>.<hex encoded Asset Name>"
354 .to_string())
355 },
356 }
357 }
358}
359
360const STAKE_POOL_PUBLIC_KEY_LEN: usize = 32;
362
363#[derive(
364 Clone,
365 PartialEq,
366 Eq,
367 Encode,
368 Decode,
369 DecodeWithMemTracking,
370 TypeInfo,
371 MaxEncodedLen,
372 Hash,
373 Ord,
374 PartialOrd,
375)]
376#[cfg_attr(feature = "std", byte_string(to_hex_string))]
377#[byte_string(debug, hex_serialize, hex_deserialize, decode_hex)]
378pub struct StakePoolPublicKey(pub [u8; STAKE_POOL_PUBLIC_KEY_LEN]);
380
381impl StakePoolPublicKey {
382 pub fn hash(&self) -> MainchainKeyHash {
384 MainchainKeyHash::from_vkey(&self.0)
385 }
386}
387
388impl TryFrom<Vec<u8>> for StakePoolPublicKey {
389 type Error = &'static str;
390
391 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
392 <[u8; 32]>::try_from(value)
393 .map_err(|_| "Mainchain public key must be 32 bytes long")
394 .map(StakePoolPublicKey)
395 }
396}
397
398const STAKE_PUBLIC_KEY_LEN: usize = 32;
400
401#[derive(
403 Clone, PartialEq, Eq, Encode, Decode, DecodeWithMemTracking, TypeInfo, MaxEncodedLen, Hash,
404)]
405#[cfg_attr(feature = "std", byte_string(to_hex_string))]
406#[byte_string(debug, hex_serialize, hex_deserialize, decode_hex)]
407pub struct StakePublicKey(pub [u8; STAKE_PUBLIC_KEY_LEN]);
408
409impl StakePublicKey {
410 pub fn hash(&self) -> MainchainKeyHash {
412 MainchainKeyHash(blake2b(&self.0))
413 }
414}
415
416const MAINCHAIN_KEY_HASH_LEN: usize = 28;
418
419#[derive(
420 Clone,
421 Copy,
422 Decode,
423 DecodeWithMemTracking,
424 Default,
425 Encode,
426 Hash,
427 MaxEncodedLen,
428 Eq,
429 PartialEq,
430 Ord,
431 PartialOrd,
432 TypeInfo,
433)]
434#[byte_string(debug)]
435#[cfg_attr(feature = "std", byte_string(to_hex_string, decode_hex))]
436#[cfg_attr(feature = "serde", byte_string(hex_serialize, hex_deserialize))]
437pub struct MainchainKeyHash(pub [u8; MAINCHAIN_KEY_HASH_LEN]);
440
441impl Display for MainchainKeyHash {
442 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
443 let hash = sp_core::hexdisplay::HexDisplay::from(&self.0);
444 write!(f, "0x{}", hash)
445 }
446}
447
448impl MainchainKeyHash {
449 pub fn from_vkey(vkey: &[u8; 32]) -> Self {
451 Self(blake2b(vkey))
452 }
453}
454
455pub const MAINCHAIN_SIGNATURE_LEN: usize = 64;
457
458#[derive(Clone, DecodeWithMemTracking, TypeInfo, PartialEq, Eq, Hash)]
459#[cfg_attr(feature = "std", byte_string(to_hex_string))]
460#[byte_string(debug, hex_serialize, decode_hex)]
461pub struct MainchainSignature(pub [u8; MAINCHAIN_SIGNATURE_LEN]);
467
468impl From<[u8; MAINCHAIN_SIGNATURE_LEN]> for MainchainSignature {
469 fn from(raw: [u8; MAINCHAIN_SIGNATURE_LEN]) -> Self {
470 Self(raw)
471 }
472}
473
474impl WrapperTypeEncode for MainchainSignature {}
475impl Deref for MainchainSignature {
476 type Target = [u8];
477
478 fn deref(&self) -> &Self::Target {
479 &self.0
480 }
481}
482impl Decode for MainchainSignature {
483 fn decode<I: parity_scale_codec::Input>(
484 input: &mut I,
485 ) -> Result<Self, parity_scale_codec::Error> {
486 let vec: Vec<u8> = Decode::decode(input)?;
487 let arr = vec.try_into().map_err(|_| "Incorrect MainchainSignature size")?;
488 Ok(MainchainSignature(arr))
489 }
490}
491
492impl MainchainSignature {
493 pub fn verify(&self, public_key: &StakePoolPublicKey, signed_message: &[u8]) -> bool {
495 let mainchain_signature = ed25519::Signature::from(self.0);
496
497 sp_io::crypto::ed25519_verify(
498 &mainchain_signature,
499 signed_message,
500 &ed25519::Public::from(public_key.0),
501 )
502 }
503}
504
505pub const STAKE_KEY_SIGNATURE_LEN: usize = 64;
507
508#[derive(Clone, Encode, Decode, DecodeWithMemTracking, PartialEq, Eq, Hash, TypeInfo)]
509#[byte_string(debug, hex_serialize, decode_hex)]
510pub struct StakeKeySignature(pub [u8; STAKE_KEY_SIGNATURE_LEN]);
512
513impl From<[u8; STAKE_KEY_SIGNATURE_LEN]> for StakeKeySignature {
514 fn from(raw: [u8; STAKE_KEY_SIGNATURE_LEN]) -> Self {
515 Self(raw)
516 }
517}
518
519impl StakeKeySignature {
520 pub fn verify(&self, public_key: &StakePublicKey, message: &[u8]) -> bool {
522 let signature = ed25519::Signature::from(self.0);
523 sp_io::crypto::ed25519_verify(&signature, message, &ed25519::Public::from(public_key.0))
524 }
525}
526
527#[derive(
528 Clone,
529 Copy,
530 Debug,
531 Encode,
532 Decode,
533 DecodeWithMemTracking,
534 PartialEq,
535 TypeInfo,
536 ToDatum,
537 MaxEncodedLen,
538 Default,
539 PartialOrd,
540 Ord,
541 Eq,
542 Zero,
543 One,
544 NumOps,
545 Num,
546 From,
547 Into,
548)]
549#[cfg_attr(feature = "serde", derive(Serialize))]
550pub struct ScEpochNumber(pub u64);
552
553impl Display for ScEpochNumber {
554 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
555 u64::fmt(&self.0, f)
556 }
557}
558
559impl ScEpochNumber {
560 pub fn next(&self) -> Self {
562 Self(self.0 + 1)
563 }
564 pub fn prev(&self) -> Option<Self> {
566 self.0.checked_sub(1).map(Self)
567 }
568}
569
570#[derive(
571 Clone,
572 PartialEq,
573 Eq,
574 Encode,
575 Decode,
576 DecodeWithMemTracking,
577 ToDatum,
578 TypeInfo,
579 PartialOrd,
580 Ord,
581 Hash,
582)]
583#[byte_string(debug, hex_serialize, hex_deserialize, decode_hex, as_ref)]
584pub struct SidechainPublicKey(pub Vec<u8>);
590
591impl From<ecdsa::Public> for SidechainPublicKey {
592 fn from(value: ecdsa::Public) -> Self {
593 Self(value.0.to_vec())
594 }
595}
596
597#[derive(Clone, Encode, Decode, DecodeWithMemTracking, TypeInfo, PartialEq, Eq, Hash)]
599#[byte_string(debug, hex_serialize, hex_deserialize, decode_hex)]
600pub struct TransactionCbor(pub Vec<u8>);
601
602#[derive(Clone, Encode, Decode, DecodeWithMemTracking, TypeInfo, PartialEq, Eq, Hash)]
604#[byte_string(debug, hex_serialize, hex_deserialize, decode_hex)]
605pub struct VKeyWitnessCbor(pub Vec<u8>);
606
607#[derive(Clone, Encode, Decode, DecodeWithMemTracking, TypeInfo, PartialEq, Eq, Hash)]
609#[byte_string(debug, hex_serialize, hex_deserialize, decode_hex)]
610pub struct SidechainSignature(pub Vec<u8>);
611
612#[derive(Clone, Encode, Decode, DecodeWithMemTracking, PartialEq, Eq, TypeInfo)]
616#[byte_string(debug, hex_serialize, hex_deserialize)]
617pub struct CrossChainPublicKey(pub Vec<u8>);
618
619impl CrossChainPublicKey {
620 pub fn hash(&self) -> CrossChainKeyHash {
622 CrossChainKeyHash(blake2b(&self.0))
623 }
624}
625
626impl From<k256::PublicKey> for CrossChainPublicKey {
627 fn from(value: k256::PublicKey) -> Self {
628 Self(value.to_sec1_bytes().to_vec())
629 }
630}
631
632impl From<CrossChainPublicKey> for k256::PublicKey {
633 fn from(value: CrossChainPublicKey) -> Self {
634 k256::PublicKey::from_sec1_bytes(&value.0)
635 .expect("CrossChainPublicKey converts to valid secp256k1::PublicKey")
636 }
637}
638
639const CROSS_CHAIN_KEY_HASH_LEN: usize = 28;
641
642#[derive(
643 Clone,
644 Copy,
645 Decode,
646 DecodeWithMemTracking,
647 Default,
648 Encode,
649 Hash,
650 MaxEncodedLen,
651 Eq,
652 PartialEq,
653 Ord,
654 PartialOrd,
655 TypeInfo,
656)]
657#[byte_string(debug, to_hex_string)]
658#[cfg_attr(feature = "std", byte_string(decode_hex))]
659#[cfg_attr(feature = "serde", byte_string(hex_serialize, hex_deserialize))]
660pub struct CrossChainKeyHash(pub [u8; CROSS_CHAIN_KEY_HASH_LEN]);
662
663impl Display for CrossChainKeyHash {
664 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
665 f.write_str(&self.to_hex_string())
666 }
667}
668
669#[derive(Clone, Encode, Decode, DecodeWithMemTracking, PartialEq, Eq, TypeInfo)]
671#[byte_string(debug, hex_serialize)]
672pub struct CrossChainSignature(pub Vec<u8>);
673
674impl CrossChainSignature {
675 pub fn verify(
677 &self,
678 cross_chain_pubkey: &CrossChainPublicKey,
679 data: &[u8],
680 ) -> Result<(), k256::ecdsa::signature::Error> {
681 use k256::ecdsa::signature::Verifier;
682
683 let vkey = k256::ecdsa::VerifyingKey::from_sec1_bytes(&cross_chain_pubkey.0[..])?;
684 let signature = k256::ecdsa::Signature::from_slice(&self.0[..])?;
685 vkey.verify(data, &signature)
686 }
687}
688
689const EPOCH_NONCE_LEN: usize = 32;
691
692#[derive(Default, Clone, Encode, Decode, DecodeWithMemTracking, PartialEq, Eq, TypeInfo)]
699#[byte_string(debug, hex_serialize)]
700pub struct EpochNonce(pub Vec<u8>);
701
702impl EpochNonce {
703 pub fn as_array(&self) -> [u8; EPOCH_NONCE_LEN] {
705 let mut epoch_nonce = self.0.clone();
706 epoch_nonce.resize_with(32, || 0);
707 epoch_nonce.try_into().expect("Should never fail after being resized")
708 }
709}
710
711#[derive(
712 Default,
713 Debug,
714 Copy,
715 Clone,
716 PartialEq,
717 Eq,
718 Encode,
719 Decode,
720 DecodeWithMemTracking,
721 ToDatum,
722 TypeInfo,
723 MaxEncodedLen,
724 Hash,
725)]
726pub struct UtxoId {
734 pub tx_hash: McTxHash,
736 pub index: UtxoIndex,
738}
739
740impl UtxoId {
741 pub const fn new(hash: [u8; TX_HASH_SIZE], index: u16) -> UtxoId {
743 UtxoId { tx_hash: McTxHash(hash), index: UtxoIndex(index) }
744 }
745}
746
747#[cfg(feature = "serde")]
748impl Serialize for UtxoId {
749 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
750 where
751 S: Serializer,
752 {
753 serializer.serialize_str(&self.to_string())
754 }
755}
756
757#[cfg(feature = "serde")]
758impl<'de> Deserialize<'de> for UtxoId {
759 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
760 where
761 D: Deserializer<'de>,
762 {
763 alloc::string::String::deserialize(deserializer).and_then(|string| {
764 Self::from_str(&string).map_err(|err| serde::de::Error::custom(err.to_string()))
765 })
766 }
767}
768
769#[cfg(feature = "serde")]
770impl FromStr for UtxoId {
771 type Err = &'static str;
772
773 fn from_str(s: &str) -> Result<Self, Self::Err> {
774 let split: Vec<&str> = s.split('#').collect();
775 let &[hash_str, index_str] = split.as_slice() else {
776 return Err("UtxoId string must conform to format: '<hash>#<index>'");
777 };
778
779 Ok(UtxoId {
780 tx_hash: McTxHash::from_str(hash_str)
781 .map_err(|_| "invalid string input for McTxHash")?,
782 index: UtxoIndex::from_str(index_str)
783 .map_err(|_| "invalid string input for OutputIndex")?,
784 })
785 }
786}
787
788impl Display for UtxoId {
789 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
790 let hash = sp_core::hexdisplay::HexDisplay::from(&self.tx_hash.0);
791 write!(f, "{}#{}", hash, self.index.0)
792 }
793}
794
795#[derive(
796 Default,
797 Debug,
798 Copy,
799 Clone,
800 PartialEq,
801 Eq,
802 Encode,
803 Decode,
804 DecodeWithMemTracking,
805 PartialOrd,
806 Ord,
807 ToDatum,
808 TypeInfo,
809 MaxEncodedLen,
810 Hash,
811)]
812#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
813pub struct UtxoIndex(pub u16);
815
816#[cfg(feature = "serde")]
817impl FromStr for UtxoIndex {
818 type Err = sp_std::num::ParseIntError;
819 fn from_str(s: &str) -> Result<Self, Self::Err> {
820 let parsed = u16::from_str(s)?;
821 let _check_overflow = i16::from_str(s)?;
822 Ok(Self(parsed))
823 }
824}
825
826pub const TX_HASH_SIZE: usize = 32;
828
829#[derive(
830 Default,
831 Copy,
832 Clone,
833 Hash,
834 PartialEq,
835 Eq,
836 Encode,
837 Decode,
838 DecodeWithMemTracking,
839 ToDatum,
840 TypeInfo,
841 MaxEncodedLen,
842)]
843#[byte_string(debug, from_bytes, decode_hex, hex_serialize, hex_deserialize)]
844#[constructor_datum]
845pub struct McTxHash(pub [u8; TX_HASH_SIZE]);
849
850impl TryFrom<Vec<u8>> for McTxHash {
851 type Error = &'static str;
852
853 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
854 <[u8; 32]>::try_from(value)
855 .map_err(|_| "McTxHash must be 32 bytes long")
856 .map(McTxHash)
857 }
858}
859
860#[derive(
861 Default,
862 Clone,
863 Decode,
864 DecodeWithMemTracking,
865 Encode,
866 PartialEq,
867 Eq,
868 TypeInfo,
869 MaxEncodedLen,
870 Hash,
871)]
872#[byte_string(debug, decode_hex, hex_serialize, hex_deserialize)]
873pub struct McBlockHash(pub [u8; 32]);
877
878impl Display for McBlockHash {
879 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
880 let hash = sp_core::hexdisplay::HexDisplay::from(&self.0);
881 write!(f, "{}", hash)
882 }
883}
884
885#[derive(
887 Default, Debug, Copy, Clone, PartialEq, Eq, Encode, Decode, DecodeWithMemTracking, TypeInfo,
888)]
889#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
890#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
891pub struct UtxoInfo {
892 pub utxo_id: UtxoId,
894 pub epoch_number: McEpochNumber,
896 pub block_number: McBlockNumber,
898 pub slot_number: McSlotNumber,
900 pub tx_index_within_block: McTxIndexInBlock,
902}
903
904#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
909pub struct UtxoInfoOrderingKey {
910 pub block_number: McBlockNumber,
912 pub tx_index_within_block: McTxIndexInBlock,
914 pub utxo_id_index: UtxoIndex,
916}
917
918impl UtxoInfo {
919 pub fn ordering_key(&self) -> UtxoInfoOrderingKey {
921 UtxoInfoOrderingKey {
922 block_number: self.block_number,
923 tx_index_within_block: self.tx_index_within_block,
924 utxo_id_index: self.utxo_id.index,
925 }
926 }
927}
928
929#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
936#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
937#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
938pub enum NetworkType {
939 Mainnet,
941 #[default]
943 Testnet,
944}
945
946#[cfg(feature = "std")]
947impl std::fmt::Display for NetworkType {
948 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
949 let str = match self {
950 Self::Mainnet => "mainnet",
951 Self::Testnet => "testnet",
952 };
953 write!(f, "{}", str)
954 }
955}
956
957#[derive(Debug, Clone, Encode, Decode, DecodeWithMemTracking, PartialEq, Eq, TypeInfo)]
966#[cfg_attr(feature = "serde", derive(Serialize))]
967pub struct RegistrationData {
968 pub registration_utxo: UtxoId,
970 pub sidechain_signature: SidechainSignature,
972 pub mainchain_signature: MainchainSignature,
974 pub cross_chain_signature: CrossChainSignature,
976 pub sidechain_pub_key: SidechainPublicKey,
978 pub cross_chain_pub_key: CrossChainPublicKey,
980 pub utxo_info: UtxoInfo,
982 pub tx_inputs: Vec<UtxoId>,
984 pub aura_pub_key: AuraPublicKey,
986 pub grandpa_pub_key: GrandpaPublicKey,
988}
989
990#[derive(Debug, Clone, Encode, Decode, DecodeWithMemTracking, PartialEq, Eq, TypeInfo)]
992#[cfg_attr(feature = "serde", derive(Serialize))]
993pub struct CandidateRegistrations {
994 pub stake_pool_public_key: StakePoolPublicKey,
996 pub registrations: Vec<RegistrationData>,
998 pub stake_delegation: Option<StakeDelegation>,
1000}
1001
1002impl CandidateRegistrations {
1003 pub fn new(
1005 stake_pool_public_key: StakePoolPublicKey,
1006 stake_delegation: Option<StakeDelegation>,
1007 registrations: Vec<RegistrationData>,
1008 ) -> Self {
1009 Self { stake_pool_public_key, registrations, stake_delegation }
1010 }
1011
1012 pub fn mainchain_pub_key(&self) -> &StakePoolPublicKey {
1014 &self.stake_pool_public_key
1015 }
1016
1017 pub fn registrations(&self) -> &[RegistrationData] {
1019 &self.registrations
1020 }
1021}
1022
1023#[derive(
1025 Clone, PartialEq, Eq, Encode, Decode, DecodeWithMemTracking, TypeInfo, PartialOrd, Ord, Hash,
1026)]
1027#[byte_string(debug, hex_serialize, hex_deserialize, decode_hex)]
1028pub struct AuraPublicKey(pub Vec<u8>);
1029impl AuraPublicKey {
1030 pub fn try_into_sr25519(&self) -> Option<sr25519::Public> {
1032 Some(sr25519::Public::from_raw(self.0.clone().try_into().ok()?))
1033 }
1034}
1035
1036impl From<sr25519::Public> for AuraPublicKey {
1037 fn from(value: sr25519::Public) -> Self {
1038 Self(value.0.to_vec())
1039 }
1040}
1041
1042#[derive(
1044 Clone, PartialEq, Eq, Encode, Decode, DecodeWithMemTracking, TypeInfo, PartialOrd, Ord, Hash,
1045)]
1046#[byte_string(debug, hex_serialize, hex_deserialize, decode_hex)]
1047pub struct GrandpaPublicKey(pub Vec<u8>);
1048impl GrandpaPublicKey {
1049 pub fn try_into_ed25519(&self) -> Option<ed25519::Public> {
1051 Some(ed25519::Public::from_raw(self.0.clone().try_into().ok()?))
1052 }
1053}
1054
1055impl From<ed25519::Public> for GrandpaPublicKey {
1056 fn from(value: ed25519::Public) -> Self {
1057 Self(value.0.to_vec())
1058 }
1059}
1060
1061#[derive(
1062 Debug,
1063 Clone,
1064 PartialEq,
1065 Decode,
1066 DecodeWithMemTracking,
1067 Encode,
1068 MaxEncodedLen,
1069 TypeInfo,
1070 Eq,
1071 Hash,
1072)]
1073#[cfg_attr(feature = "serde", derive(Serialize))]
1074pub struct DParameter {
1082 pub num_permissioned_candidates: u16,
1084 pub num_registered_candidates: u16,
1086}
1087
1088impl DParameter {
1089 pub fn new(num_permissioned_candidates: u16, num_registered_candidates: u16) -> Self {
1091 Self { num_permissioned_candidates, num_registered_candidates }
1092 }
1093}
1094
1095#[derive(
1096 Debug,
1097 Clone,
1098 PartialEq,
1099 Eq,
1100 Decode,
1101 DecodeWithMemTracking,
1102 Encode,
1103 TypeInfo,
1104 PartialOrd,
1105 Ord,
1106 Hash,
1107)]
1108pub struct PermissionedCandidateData {
1114 pub sidechain_public_key: SidechainPublicKey,
1116 pub aura_public_key: AuraPublicKey,
1118 pub grandpa_public_key: GrandpaPublicKey,
1120}
1121
1122#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1124pub struct CandidateRegistration {
1125 pub stake_ownership: AdaBasedStaking,
1127 pub partner_chain_pub_key: SidechainPublicKey,
1129 pub partner_chain_signature: SidechainSignature,
1131 pub own_pkh: MainchainKeyHash,
1133 pub registration_utxo: UtxoId,
1135 pub aura_pub_key: AuraPublicKey,
1137 pub grandpa_pub_key: GrandpaPublicKey,
1139}
1140
1141impl CandidateRegistration {
1142 pub fn matches_keys(&self, other: &Self) -> bool {
1144 self.stake_ownership == other.stake_ownership
1145 && self.partner_chain_pub_key == other.partner_chain_pub_key
1146 && self.partner_chain_signature == other.partner_chain_signature
1147 && self.aura_pub_key == other.aura_pub_key
1148 && self.grandpa_pub_key == other.grandpa_pub_key
1149 }
1150}
1151
1152#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1156pub struct AdaBasedStaking {
1157 pub pub_key: StakePoolPublicKey,
1159 pub signature: MainchainSignature,
1161}
1162
1163#[cfg(test)]
1164mod tests {
1165 use super::*;
1166 use core::str::FromStr;
1167 use hex_literal::hex;
1168
1169 #[test]
1170 fn main_chain_address_string_serialize_deserialize_round_trip() {
1171 let address = MainchainAddress::from_str(
1172 "addr_test1wz5qc7fk2pat0058w4zwvkw35ytptej3nuc3je2kgtan5dq3rt4sc",
1173 )
1174 .unwrap();
1175 let serialized = serde_json::to_value(&address).unwrap();
1176 assert_eq!(
1177 serialized,
1178 serde_json::json!(
1179 "0x616464725f7465737431777a35716337666b327061743030353877347a77766b77333579747074656a336e7563336a65326b6774616e356471337274347363"
1180 )
1181 );
1182 let deserialized = serde_json::from_value(serialized).unwrap();
1183 assert_eq!(address, deserialized);
1184 }
1185
1186 #[test]
1187 fn main_chain_address_string_from_str_to_string_round_trip() {
1188 let address = MainchainAddress::from_str(
1189 "addr_test1wz5qc7fk2pat0058w4zwvkw35ytptej3nuc3je2kgtan5dq3rt4sc",
1190 )
1191 .unwrap();
1192 let str = address.to_string();
1193 let from_str = MainchainAddress::from_str(&str).unwrap();
1194 assert_eq!(address, from_str);
1195 }
1196
1197 #[test]
1198 fn main_chain_signature_should_be_backward_compatible_with_vec() {
1199 #[derive(Clone, Encode, Decode, DecodeWithMemTracking, TypeInfo, PartialEq, Eq, Hash)]
1200 #[byte_string(debug, hex_serialize, decode_hex)]
1201 struct LegacyMCSignature(pub Vec<u8>);
1202
1203 let legacy_encoded = LegacyMCSignature(vec![10; 64]).encode();
1204
1205 let legacy_decoded = MainchainSignature::decode(&mut legacy_encoded.as_slice())
1206 .expect("Encoded legacy should decode to current type");
1207
1208 assert_eq!(legacy_decoded.0, [10; MAINCHAIN_SIGNATURE_LEN]);
1209
1210 let current_encoded = MainchainSignature([9; MAINCHAIN_SIGNATURE_LEN]).encode();
1211
1212 let current_decoded = LegacyMCSignature::decode(&mut current_encoded.as_slice())
1213 .expect("Encoded current should decode to legacy");
1214
1215 assert_eq!(current_decoded.0, vec![9; 64]);
1216 }
1217
1218 #[test]
1219 fn cross_chain_signature_verify_works() {
1220 let signature = CrossChainSignature(
1221 hex!("d1e02e4a5484c3b7202ce6b844577048e7578dc62901cf8f51e6d74bbd3adb091688feacedd8343d0b04a0f5862b2e06148934a75e678e42051fde5431eca33d").to_vec()
1222 );
1223 let pubkey = CrossChainPublicKey(
1224 hex!("020a1091341fe5664bfa1782d5e04779689068c916b04cb365ec3153755684d9a1").to_vec(),
1225 );
1226 let signed_data = hex!(
1227 "84020a1091341fe5664bfa1782d5e04779689068c916b04cb365ec3153755684d9a16c68747470733a2f2f636f6f6c2e73747566662f73706f2e6a736f6e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
1228 );
1229
1230 assert!(signature.verify(&pubkey, &signed_data).is_ok())
1231 }
1232}
1233
1234#[derive(
1235 Clone,
1236 PartialEq,
1237 Eq,
1238 Ord,
1239 PartialOrd,
1240 TypeInfo,
1241 MaxEncodedLen,
1242 Encode,
1243 Decode,
1244 DecodeWithMemTracking,
1245)]
1246pub enum DelegatorKey {
1248 StakeKeyHash([u8; 28]),
1250 ScriptKeyHash {
1252 hash_raw: [u8; 28],
1254 script_hash: [u8; 28],
1256 },
1257}
1258
1259impl alloc::fmt::Debug for DelegatorKey {
1260 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
1261 let s = match self {
1262 Self::ScriptKeyHash { hash_raw, script_hash } => alloc::format!(
1263 "ScriptKeyHash{{ hash_raw: {}, script_hash: {} }}",
1264 hex::encode(hash_raw),
1265 hex::encode(script_hash)
1266 ),
1267 Self::StakeKeyHash(hash) => alloc::format!("StakeKeyHash({})", hex::encode(hash)),
1268 };
1269
1270 f.write_str(&s)
1271 }
1272}
1273
1274#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
1276pub struct DelegatorStakeAmount(pub u64);
1277
1278impl<T: Into<u64>> From<T> for DelegatorStakeAmount {
1279 fn from(value: T) -> Self {
1280 Self(value.into())
1281 }
1282}
1283
1284#[derive(Debug, Clone, Default)]
1289pub struct StakeDistribution(pub BTreeMap<MainchainKeyHash, PoolDelegation>);
1290
1291#[derive(Debug, Clone, Default, PartialEq)]
1293pub struct PoolDelegation {
1294 pub total_stake: StakeDelegation,
1296 pub delegators: BTreeMap<DelegatorKey, DelegatorStakeAmount>,
1298}