sidechain_domain/
lib.rs

1//! # Partner Chains domain types
2//!
3//! This crate defines common domain and utility types used in the Partner Chain Toolkit.
4
5#![cfg_attr(not(feature = "std"), no_std)]
6#![deny(missing_docs)]
7
8pub mod byte_string;
9#[cfg(feature = "app-crypto")]
10pub mod cross_chain_app;
11pub mod crypto;
12pub mod mainchain_epoch;
13
14extern crate alloc;
15extern crate core;
16extern crate num_derive;
17
18pub use alloc::collections::btree_map::BTreeMap;
19#[cfg(feature = "std")]
20use alloc::format;
21pub use alloc::vec::Vec;
22use alloc::{str::FromStr, string::String, string::ToString, vec};
23use byte_string_derive::byte_string;
24use core::{
25	fmt::{Display, Formatter},
26	ops::Deref,
27	u32,
28};
29use crypto::blake2b;
30use derive_more::{From, Into};
31use num_derive::*;
32use parity_scale_codec::{
33	Compact, Decode, DecodeWithMemTracking, Encode, MaxEncodedLen, WrapperTypeEncode,
34	decode_vec_with_len,
35};
36use plutus_datum_derive::*;
37use scale_info::TypeInfo;
38use sp_core::{
39	ConstU32,
40	bounded::BoundedVec,
41	crypto::{
42		KeyTypeId,
43		key_types::{AURA, GRANDPA},
44	},
45	ecdsa, ed25519, sr25519,
46};
47#[cfg(feature = "serde")]
48use {
49	derive_more::FromStr,
50	serde::{Deserialize, Deserializer, Serialize, Serializer},
51};
52
53/// The number of main chain epochs back a Partner Chain queries for committee selection inputs.
54/// This offset is necessary to ensure that data is present and stable.
55pub const DATA_MC_EPOCH_OFFSET: u32 = 2;
56
57/// Shifts given epoch back by [DATA_MC_EPOCH_OFFSET] accounting for underflow.
58pub fn offset_data_epoch(epoch: &McEpochNumber) -> Result<McEpochNumber, u32> {
59	Ok(McEpochNumber(epoch.0.checked_sub(DATA_MC_EPOCH_OFFSET).ok_or(DATA_MC_EPOCH_OFFSET)?))
60}
61
62#[derive(
63	Default,
64	Debug,
65	Copy,
66	Clone,
67	PartialEq,
68	Eq,
69	Encode,
70	Decode,
71	DecodeWithMemTracking,
72	Hash,
73	TypeInfo,
74	Ord,
75	PartialOrd,
76)]
77#[cfg_attr(feature = "serde", derive(Serialize, Deserialize, FromStr))]
78/// Cardano epoch number. In range [0, 2^31-1].
79pub struct McEpochNumber(pub u32);
80
81impl McEpochNumber {
82	/// Returns next Cardano epoch number
83	pub fn next(&self) -> Self {
84		Self(&self.0 + 1)
85	}
86}
87
88impl Display for McEpochNumber {
89	fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
90		u32::fmt(&self.0, f)
91	}
92}
93#[derive(
94	Default,
95	Clone,
96	Copy,
97	Debug,
98	Encode,
99	Decode,
100	DecodeWithMemTracking,
101	TypeInfo,
102	PartialEq,
103	Eq,
104	PartialOrd,
105	Ord,
106)]
107#[cfg_attr(feature = "serde", derive(Serialize))]
108/// Amount of Lovelace (which is a fraction of 1 ADA) staked/locked on Cardano
109pub struct StakeDelegation(pub u64);
110
111impl StakeDelegation {
112	/// Checks if stake delegation is zero
113	pub fn is_zero(&self) -> bool {
114		self.0 == 0
115	}
116}
117
118#[derive(
119	Default,
120	Clone,
121	Copy,
122	Debug,
123	Encode,
124	Decode,
125	DecodeWithMemTracking,
126	TypeInfo,
127	PartialEq,
128	Eq,
129	From,
130	MaxEncodedLen,
131)]
132#[cfg_attr(feature = "serde", derive(Serialize))]
133/// The amount of a Cardano native token
134pub struct NativeTokenAmount(pub u128);
135
136impl Display for NativeTokenAmount {
137	fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
138		u128::fmt(&self.0, f)
139	}
140}
141
142#[derive(
143	Default,
144	Clone,
145	Copy,
146	Debug,
147	Encode,
148	Decode,
149	DecodeWithMemTracking,
150	PartialEq,
151	Eq,
152	PartialOrd,
153	Ord,
154	scale_info::TypeInfo,
155	MaxEncodedLen,
156)]
157#[cfg_attr(feature = "serde", derive(Serialize, Deserialize, FromStr))]
158/// Cardano block number. In range [0, 2^31-1].
159pub struct McBlockNumber(pub u32);
160
161impl Display for McBlockNumber {
162	fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
163		u32::fmt(&self.0, f)
164	}
165}
166
167impl McBlockNumber {
168	/// Adds `rhs` to the block number without overflow
169	pub fn saturating_add<Rhs: Into<u32>>(self, rhs: Rhs) -> Self {
170		Self(self.0.saturating_add(rhs.into()))
171	}
172
173	/// Subtracts `rhs` from the block number without overflow
174	pub fn saturating_sub<Rhs: Into<u32>>(self, rhs: Rhs) -> Self {
175		Self(self.0.saturating_sub(rhs.into()))
176	}
177}
178
179#[derive(
180	Default,
181	Debug,
182	Copy,
183	Clone,
184	PartialEq,
185	Eq,
186	PartialOrd,
187	Encode,
188	Decode,
189	DecodeWithMemTracking,
190	TypeInfo,
191	Hash,
192)]
193#[cfg_attr(feature = "serde", derive(Serialize, Deserialize, FromStr))]
194/// Cardano slot number. In range [0, 2^63-1].
195pub struct McSlotNumber(pub u64);
196
197impl Display for McSlotNumber {
198	fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
199		u64::fmt(&self.0, f)
200	}
201}
202
203/// Data describing a Cardano block
204#[derive(Debug, Clone, PartialEq, Default)]
205#[cfg_attr(feature = "serde", derive(serde::Serialize))]
206pub struct MainchainBlock {
207	/// Block number
208	pub number: McBlockNumber,
209	/// Block hash
210	pub hash: McBlockHash,
211	/// Block's epoch number
212	pub epoch: McEpochNumber,
213	/// Block's slot number
214	pub slot: McSlotNumber,
215	/// Block timestamp
216	pub timestamp: u64, // seconds since UNIX_EPOCH
217}
218
219#[derive(
220	Default,
221	Debug,
222	Copy,
223	Clone,
224	PartialEq,
225	Eq,
226	Encode,
227	Decode,
228	DecodeWithMemTracking,
229	PartialOrd,
230	Ord,
231	TypeInfo,
232	MaxEncodedLen,
233)]
234#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
235/// An index of transaction in a block. In range [0, 2^31-1].
236pub struct McTxIndexInBlock(pub u32);
237
238#[cfg(feature = "serde")]
239impl FromStr for McTxIndexInBlock {
240	type Err = sp_std::num::ParseIntError;
241	fn from_str(s: &str) -> Result<Self, Self::Err> {
242		let parsed = u32::from_str(s)?;
243		let _check_overflow = i32::from_str(s)?;
244		Ok(Self(parsed))
245	}
246}
247
248/// Maximum length of a Cardano address in UTF-8 bytes
249const MAX_MAINCHAIN_ADDRESS_BYTES: u32 = 120;
250
251/// Wraps UTF-8 bytes of Mainchain Address in bech32 format.
252/// Example: utf-8 bytes of "addr_test1wz5qc7fk2pat0058w4zwvkw35ytptej3nuc3je2kgtan5dq3rt4sc" are
253/// "0x616464725f7465737431777a35716337666b327061743030353877347a77766b77333579747074656a336e7563336a65326b6774616e356471337274347363"
254#[derive(
255	Clone, Default, PartialEq, Eq, Encode, Decode, DecodeWithMemTracking, TypeInfo, MaxEncodedLen,
256)]
257#[byte_string(debug)]
258pub struct MainchainAddress(BoundedVec<u8, ConstU32<MAX_MAINCHAIN_ADDRESS_BYTES>>);
259
260impl MainchainAddress {
261	/// Returns raw bytes of this Cardano address
262	pub fn bytes(&self) -> Vec<u8> {
263		self.0.to_vec()
264	}
265}
266
267#[cfg(feature = "serde")]
268impl FromStr for MainchainAddress {
269	type Err = &'static str;
270
271	fn from_str(s: &str) -> Result<Self, Self::Err> {
272		let bytes: Vec<u8> = s.as_bytes().to_vec();
273		let bounded = BoundedVec::try_from(bytes).map_err(|_| "Invalid length")?;
274		Ok(MainchainAddress(bounded))
275	}
276}
277
278impl Display for MainchainAddress {
279	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
280		let s = String::from_utf8(self.0.to_vec())
281			.expect("MainchainAddressString is always properly encoded UTF-8");
282		write!(f, "{}", s)
283	}
284}
285
286#[cfg(feature = "serde")]
287impl serde::Serialize for MainchainAddress {
288	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
289	where
290		S: serde::Serializer,
291	{
292		let s = String::from_utf8(self.0.to_vec()).expect("MainchainAddress is always valid UTF-8");
293		serializer.serialize_str(&s)
294	}
295}
296
297#[cfg(feature = "serde")]
298impl<'de> serde::Deserialize<'de> for MainchainAddress {
299	/// Deserialized MainchainAddress from both hexstring of ASCII bytes and plain String
300	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
301	where
302		D: serde::Deserializer<'de>,
303	{
304		let s = String::deserialize(deserializer)?;
305		let bytes = sp_core::bytes::from_hex(&s).unwrap_or_else(|_| s.as_bytes().to_vec());
306		let bounded = BoundedVec::try_from(bytes)
307			.map_err(|_| serde::de::Error::custom("MainchainAddress is too long"))?;
308		Ok(MainchainAddress(bounded))
309	}
310}
311
312/// Cardano Policy Id is a 224 bits blake2b hash.
313const POLICY_ID_LEN: usize = 28;
314#[derive(
315	Clone,
316	Default,
317	PartialEq,
318	Eq,
319	Encode,
320	Decode,
321	DecodeWithMemTracking,
322	ToDatum,
323	TypeInfo,
324	MaxEncodedLen,
325	Hash,
326)]
327#[byte_string(debug, decode_hex, hex_serialize, hex_deserialize)]
328#[cfg_attr(feature = "std", byte_string(to_hex_string))]
329/// Cardano Policy Id
330pub struct PolicyId(pub [u8; POLICY_ID_LEN]);
331
332#[cfg(feature = "std")]
333impl Display for PolicyId {
334	fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
335		write!(f, "{}", self.to_hex_string())
336	}
337}
338
339/// Cardano script hash
340pub type ScriptHash = PolicyId;
341
342/// Maximum length of a Cardano native asset's name in UTF-8 bytes
343pub const MAX_ASSET_NAME_LEN: u32 = 32;
344
345/// Cardano native asset name
346#[derive(
347	Clone, Default, PartialEq, Eq, Encode, Decode, DecodeWithMemTracking, TypeInfo, MaxEncodedLen,
348)]
349#[byte_string(debug, hex_serialize, hex_deserialize, decode_hex)]
350#[cfg_attr(feature = "std", byte_string(to_hex_string))]
351pub struct AssetName(pub BoundedVec<u8, ConstU32<MAX_ASSET_NAME_LEN>>);
352
353impl AssetName {
354	/// Constructs an empty [AssetName]
355	pub fn empty() -> Self {
356		Self(BoundedVec::new())
357	}
358}
359
360#[cfg(feature = "std")]
361impl Display for AssetName {
362	fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
363		write!(f, "{}", self.to_hex_string())
364	}
365}
366
367#[derive(
368	Clone,
369	Debug,
370	PartialEq,
371	Eq,
372	Encode,
373	Decode,
374	DecodeWithMemTracking,
375	TypeInfo,
376	MaxEncodedLen,
377	Default,
378)]
379#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
380/// Full data identifying a Cardano native asset
381pub struct AssetId {
382	/// Policy ID
383	pub policy_id: PolicyId,
384	/// Asset name
385	pub asset_name: AssetName,
386}
387
388#[cfg(feature = "std")]
389impl FromStr for AssetId {
390	type Err = String;
391
392	fn from_str(s: &str) -> Result<Self, Self::Err> {
393		match s.split_once(".") {
394			Some((policy_id, asset_name)) => {
395				let policy_id = PolicyId::from_str(policy_id)
396					.map_err(|e| format!("{} is invalid Policy ID: {}", policy_id, e))?;
397				let asset_name = AssetName::from_str(asset_name)
398					.map_err(|e| format!("{} is invalid Asset Name: {}", asset_name, e))?;
399				Ok(Self { policy_id, asset_name })
400			},
401			None => {
402				Err("AssetId should be <hex encoded Policy ID>.<hex encoded Asset Name>"
403					.to_string())
404			},
405		}
406	}
407}
408
409/// Length of Cardano stake pool key
410const STAKE_POOL_PUBLIC_KEY_LEN: usize = 32;
411
412#[derive(
413	Clone,
414	PartialEq,
415	Eq,
416	Encode,
417	Decode,
418	DecodeWithMemTracking,
419	TypeInfo,
420	MaxEncodedLen,
421	Hash,
422	Ord,
423	PartialOrd,
424)]
425#[cfg_attr(feature = "std", byte_string(to_hex_string))]
426#[byte_string(debug, hex_serialize, hex_deserialize, decode_hex)]
427/// Cardano stake pool public key (ed25519)
428pub struct StakePoolPublicKey(pub [u8; STAKE_POOL_PUBLIC_KEY_LEN]);
429
430impl StakePoolPublicKey {
431	/// Computes the blake2b_224 hash of this Cardano stake pool public key
432	pub fn hash(&self) -> MainchainKeyHash {
433		MainchainKeyHash::from_vkey(&self.0)
434	}
435}
436
437impl TryFrom<Vec<u8>> for StakePoolPublicKey {
438	type Error = &'static str;
439
440	fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
441		<[u8; 32]>::try_from(value)
442			.map_err(|_| "Mainchain public key must be 32 bytes long")
443			.map(StakePoolPublicKey)
444	}
445}
446
447/// Length of Cardano staking public key
448const STAKE_PUBLIC_KEY_LEN: usize = 32;
449
450/// Cardano staking public key (ed25519)
451#[derive(
452	Clone, PartialEq, Eq, Encode, Decode, DecodeWithMemTracking, TypeInfo, MaxEncodedLen, Hash,
453)]
454#[cfg_attr(feature = "std", byte_string(to_hex_string))]
455#[byte_string(debug, hex_serialize, hex_deserialize, decode_hex)]
456pub struct StakePublicKey(pub [u8; STAKE_PUBLIC_KEY_LEN]);
457
458impl StakePublicKey {
459	/// Computes the blake2b_224 hash of this Cardano staking public key
460	pub fn hash(&self) -> MainchainKeyHash {
461		MainchainKeyHash(blake2b(&self.0))
462	}
463}
464
465/// Length of Cardano key hash
466const MAINCHAIN_KEY_HASH_LEN: usize = 28;
467
468#[derive(
469	Clone,
470	Copy,
471	Decode,
472	DecodeWithMemTracking,
473	Default,
474	Encode,
475	Hash,
476	MaxEncodedLen,
477	Eq,
478	PartialEq,
479	Ord,
480	PartialOrd,
481	TypeInfo,
482)]
483#[byte_string(debug)]
484#[cfg_attr(feature = "std", byte_string(to_hex_string, decode_hex))]
485#[cfg_attr(feature = "serde", byte_string(hex_serialize, hex_deserialize))]
486/// blake2b_224 hash of a Cardano Verification (Public) Key.
487/// It can be a hash of Payment Verification, Payment Extended Verification, Stake Pool Verification Key or Staking Verification Key.
488pub struct MainchainKeyHash(pub [u8; MAINCHAIN_KEY_HASH_LEN]);
489
490impl Display for MainchainKeyHash {
491	fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
492		let hash = sp_core::hexdisplay::HexDisplay::from(&self.0);
493		write!(f, "0x{}", hash)
494	}
495}
496
497impl MainchainKeyHash {
498	/// Computes the blake2b_224 hash of the given ed25519 public key bytes
499	pub fn from_vkey(vkey: &[u8; 32]) -> Self {
500		Self(blake2b(vkey))
501	}
502}
503
504/// Length of Cardano signature (EDDSA)
505pub const MAINCHAIN_SIGNATURE_LEN: usize = 64;
506
507#[derive(Clone, DecodeWithMemTracking, TypeInfo, PartialEq, Eq, Hash)]
508#[cfg_attr(feature = "std", byte_string(to_hex_string))]
509#[byte_string(debug, hex_serialize, decode_hex)]
510/// Cardano signature type (EDDSA)
511///
512/// WARNING: This type needs to be backwards compatible with a legacy schema wrapping `Vec<u8>`.
513///          Because of this, it is not handled correctly by PolkadotJS. If you need to accept
514///          this type as extrinsic argument, use raw `[u8; MAINCHAIN_SIGNATURE_LEN]` instead.
515pub struct MainchainSignature(pub [u8; MAINCHAIN_SIGNATURE_LEN]);
516
517impl From<[u8; MAINCHAIN_SIGNATURE_LEN]> for MainchainSignature {
518	fn from(raw: [u8; MAINCHAIN_SIGNATURE_LEN]) -> Self {
519		Self(raw)
520	}
521}
522
523impl WrapperTypeEncode for MainchainSignature {}
524impl Deref for MainchainSignature {
525	type Target = [u8];
526
527	fn deref(&self) -> &Self::Target {
528		&self.0
529	}
530}
531impl Decode for MainchainSignature {
532	fn decode<I: parity_scale_codec::Input>(
533		input: &mut I,
534	) -> Result<Self, parity_scale_codec::Error> {
535		let vec: Vec<u8> = Decode::decode(input)?;
536		let arr = vec.try_into().map_err(|_| "Incorrect MainchainSignature size")?;
537		Ok(MainchainSignature(arr))
538	}
539}
540
541impl MainchainSignature {
542	/// Verifies whether `self` is a valid signature of `signed_message` for `public_key`
543	pub fn verify(&self, public_key: &StakePoolPublicKey, signed_message: &[u8]) -> bool {
544		let mainchain_signature = ed25519::Signature::from(self.0);
545
546		sp_io::crypto::ed25519_verify(
547			&mainchain_signature,
548			signed_message,
549			&ed25519::Public::from(public_key.0),
550		)
551	}
552}
553
554/// Length of Cardano staking key signature (EDDSA)
555pub const STAKE_KEY_SIGNATURE_LEN: usize = 64;
556
557#[derive(Clone, Encode, Decode, DecodeWithMemTracking, PartialEq, Eq, Hash, TypeInfo)]
558#[byte_string(debug, hex_serialize, decode_hex)]
559/// Cardano staking key signature type (EDDSA)
560pub struct StakeKeySignature(pub [u8; STAKE_KEY_SIGNATURE_LEN]);
561
562impl From<[u8; STAKE_KEY_SIGNATURE_LEN]> for StakeKeySignature {
563	fn from(raw: [u8; STAKE_KEY_SIGNATURE_LEN]) -> Self {
564		Self(raw)
565	}
566}
567
568impl StakeKeySignature {
569	/// Verifies whether `self` is a valid signature of `message` for `public_key`
570	pub fn verify(&self, public_key: &StakePublicKey, message: &[u8]) -> bool {
571		let signature = ed25519::Signature::from(self.0);
572		sp_io::crypto::ed25519_verify(&signature, message, &ed25519::Public::from(public_key.0))
573	}
574}
575
576#[derive(
577	Clone,
578	Copy,
579	Debug,
580	Encode,
581	Decode,
582	DecodeWithMemTracking,
583	PartialEq,
584	TypeInfo,
585	ToDatum,
586	MaxEncodedLen,
587	Default,
588	PartialOrd,
589	Ord,
590	Eq,
591	Zero,
592	One,
593	NumOps,
594	Num,
595	From,
596	Into,
597)]
598#[cfg_attr(feature = "serde", derive(Serialize))]
599/// Partner Chain epoch number
600pub struct ScEpochNumber(pub u64);
601
602impl Display for ScEpochNumber {
603	fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
604		u64::fmt(&self.0, f)
605	}
606}
607
608impl ScEpochNumber {
609	/// Returns next epoch number
610	pub fn next(&self) -> Self {
611		Self(self.0 + 1)
612	}
613	/// Returns previous epoch number accounting for underflow
614	pub fn prev(&self) -> Option<Self> {
615		self.0.checked_sub(1).map(Self)
616	}
617	/// Subtracts `other` from the epoch number, saturating at lower bound
618	pub fn saturating_sub(&self, other: u64) -> Self {
619		Self(self.0.saturating_sub(other.into()))
620	}
621}
622
623#[derive(
624	Clone,
625	Copy,
626	Debug,
627	Encode,
628	Decode,
629	DecodeWithMemTracking,
630	TypeInfo,
631	MaxEncodedLen,
632	PartialEq,
633	Eq,
634	Serialize,
635	Deserialize,
636)]
637/// Partner Chain epoch duration in milliseconds
638pub struct ScEpochDuration(u64);
639
640impl ScEpochDuration {
641	/// Creates epoch duration from number of milliseconds
642	pub fn from_millis(millis: u64) -> Self {
643		Self(millis)
644	}
645
646	/// Returns epoch duration in milliseconds
647	pub fn millis(&self) -> u64 {
648		self.0
649	}
650}
651
652impl Default for ScEpochDuration {
653	fn default() -> Self {
654		Self(60_000)
655	}
656}
657
658#[derive(
659	Clone,
660	PartialEq,
661	Eq,
662	Encode,
663	Decode,
664	DecodeWithMemTracking,
665	ToDatum,
666	TypeInfo,
667	PartialOrd,
668	Ord,
669	Hash,
670)]
671#[byte_string(debug, hex_serialize, hex_deserialize, decode_hex, as_ref)]
672/// Partner Chain public key
673///
674/// This public key is used as the identity of a Partner Chain network participant on a specific Partner Chain,
675/// ie. a network participant can use different [SidechainPublicKey] for each Partner Chain they are active on
676/// as opposed to [CrossChainPublicKey].
677pub struct SidechainPublicKey(pub Vec<u8>);
678
679impl From<ecdsa::Public> for SidechainPublicKey {
680	fn from(value: ecdsa::Public) -> Self {
681		Self(value.0.to_vec())
682	}
683}
684
685/// CBOR bytes of Plutus smart contract.
686#[derive(Clone, Encode, Decode, DecodeWithMemTracking, TypeInfo, PartialEq, Eq, Hash)]
687#[byte_string(debug, hex_serialize, hex_deserialize, decode_hex)]
688pub struct PlutusScriptCbor(pub Vec<u8>);
689
690/// CBOR bytes of Cardano Transaction.
691#[derive(Clone, Encode, Decode, DecodeWithMemTracking, TypeInfo, PartialEq, Eq, Hash)]
692#[byte_string(debug, hex_serialize, hex_deserialize, decode_hex)]
693pub struct TransactionCbor(pub Vec<u8>);
694
695/// CBOR bytes of Cardano VKeyWitness.
696#[derive(Clone, Encode, Decode, DecodeWithMemTracking, TypeInfo, PartialEq, Eq, Hash)]
697#[byte_string(debug, hex_serialize, hex_deserialize, decode_hex)]
698pub struct VKeyWitnessCbor(pub Vec<u8>);
699
700/// Cross-chain signature type (ECDSA) created using [SidechainPublicKey]
701#[derive(Clone, Encode, Decode, DecodeWithMemTracking, TypeInfo, PartialEq, Eq, Hash)]
702#[byte_string(debug, hex_serialize, hex_deserialize, decode_hex)]
703pub struct SidechainSignature(pub Vec<u8>);
704
705/// Cross-chain public key (ECDSA)
706///
707/// This public key is used as the universal identity of Partner Chain network participants across all Partner Chains.
708#[derive(Clone, Encode, Decode, DecodeWithMemTracking, PartialEq, Eq, TypeInfo)]
709#[byte_string(debug, hex_serialize, hex_deserialize)]
710pub struct CrossChainPublicKey(pub Vec<u8>);
711
712impl CrossChainPublicKey {
713	/// Computes the blake2b_224 hash of this cross-chain public key
714	pub fn hash(&self) -> CrossChainKeyHash {
715		CrossChainKeyHash(blake2b(&self.0))
716	}
717}
718
719impl From<k256::PublicKey> for CrossChainPublicKey {
720	fn from(value: k256::PublicKey) -> Self {
721		Self(value.to_sec1_bytes().to_vec())
722	}
723}
724
725impl From<CrossChainPublicKey> for k256::PublicKey {
726	fn from(value: CrossChainPublicKey) -> Self {
727		k256::PublicKey::from_sec1_bytes(&value.0)
728			.expect("CrossChainPublicKey converts to valid secp256k1::PublicKey")
729	}
730}
731
732/// Length of the cross-chain public key hash
733const CROSS_CHAIN_KEY_HASH_LEN: usize = 28;
734
735#[derive(
736	Clone,
737	Copy,
738	Decode,
739	DecodeWithMemTracking,
740	Default,
741	Encode,
742	Hash,
743	MaxEncodedLen,
744	Eq,
745	PartialEq,
746	Ord,
747	PartialOrd,
748	TypeInfo,
749)]
750#[byte_string(debug, to_hex_string)]
751#[cfg_attr(feature = "std", byte_string(decode_hex))]
752#[cfg_attr(feature = "serde", byte_string(hex_serialize, hex_deserialize))]
753/// blake2b_224 hash of a cross-chain public key
754pub struct CrossChainKeyHash(pub [u8; CROSS_CHAIN_KEY_HASH_LEN]);
755
756impl Display for CrossChainKeyHash {
757	fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
758		f.write_str(&self.to_hex_string())
759	}
760}
761
762/// Cross-chain signature created using [CrossChainPublicKey]
763#[derive(Clone, Encode, Decode, DecodeWithMemTracking, PartialEq, Eq, TypeInfo)]
764#[byte_string(debug, hex_serialize)]
765pub struct CrossChainSignature(pub Vec<u8>);
766
767impl CrossChainSignature {
768	/// Verifies that `self` is a valid signature of `data` for `cross_chain_pubkey`
769	pub fn verify(
770		&self,
771		cross_chain_pubkey: &CrossChainPublicKey,
772		data: &[u8],
773	) -> Result<(), k256::ecdsa::signature::Error> {
774		use k256::ecdsa::signature::Verifier;
775
776		let vkey = k256::ecdsa::VerifyingKey::from_sec1_bytes(&cross_chain_pubkey.0[..])?;
777		let signature = k256::ecdsa::Signature::from_slice(&self.0[..])?;
778		vkey.verify(data, &signature)
779	}
780}
781
782/// Length of Cardano epoch nonce
783const EPOCH_NONCE_LEN: usize = 32;
784
785/// Cardano epoch nonce
786///
787/// This value is a 32-byte hash generated at the start of each epoch on Cardano using
788/// a verifiable random function as part of normal chain operation by Cardano block producers.
789/// Because it is subject to Cardano's consensus mechanism and has strong cryptographic guarantees,
790/// this value can be used as a tamper-proof shared randomness seed by Partner Chain Toolkit components.
791#[derive(Default, Clone, Encode, Decode, DecodeWithMemTracking, PartialEq, Eq, TypeInfo)]
792#[byte_string(debug, hex_serialize, decode_hex)]
793pub struct EpochNonce(pub Vec<u8>);
794
795impl EpochNonce {
796	/// Returns epoch nonce as byte array.
797	pub fn as_array(&self) -> [u8; EPOCH_NONCE_LEN] {
798		let mut epoch_nonce = self.0.clone();
799		epoch_nonce.resize_with(32, || 0);
800		epoch_nonce.try_into().expect("Should never fail after being resized")
801	}
802}
803
804#[derive(
805	Default,
806	Debug,
807	Copy,
808	Clone,
809	PartialEq,
810	Eq,
811	Encode,
812	Decode,
813	DecodeWithMemTracking,
814	ToDatum,
815	TypeInfo,
816	MaxEncodedLen,
817	Hash,
818)]
819/// Identifies a Cardano UTxO (unspent transaction output)
820///
821/// A UTxO is uniquely identified by the hash of the transaction that produced it and its (zero-based)
822/// index in the transaction's output.
823///
824/// Standard semi-human-readable encoding of a UTxO id uses a hash sign to divide the two components:
825/// `0000000000000000000000000000000000000000000000000000000000000000#0`
826pub struct UtxoId {
827	/// Transaction hash
828	pub tx_hash: McTxHash,
829	/// Output index
830	pub index: UtxoIndex,
831}
832
833impl UtxoId {
834	/// Creates new [UtxoId] from primitive type arguments
835	pub const fn new(hash: [u8; TX_HASH_SIZE], index: u16) -> UtxoId {
836		UtxoId { tx_hash: McTxHash(hash), index: UtxoIndex(index) }
837	}
838}
839
840#[cfg(feature = "serde")]
841impl Serialize for UtxoId {
842	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
843	where
844		S: Serializer,
845	{
846		serializer.serialize_str(&self.to_string())
847	}
848}
849
850#[cfg(feature = "serde")]
851impl<'de> Deserialize<'de> for UtxoId {
852	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
853	where
854		D: Deserializer<'de>,
855	{
856		alloc::string::String::deserialize(deserializer).and_then(|string| {
857			Self::from_str(&string).map_err(|err| serde::de::Error::custom(err.to_string()))
858		})
859	}
860}
861
862#[cfg(feature = "serde")]
863impl FromStr for UtxoId {
864	type Err = &'static str;
865
866	fn from_str(s: &str) -> Result<Self, Self::Err> {
867		let split: Vec<&str> = s.split('#').collect();
868		let &[hash_str, index_str] = split.as_slice() else {
869			return Err("UtxoId string must conform to format: '<hash>#<index>'");
870		};
871
872		Ok(UtxoId {
873			tx_hash: McTxHash::from_str(hash_str)
874				.map_err(|_| "invalid string input for McTxHash")?,
875			index: UtxoIndex::from_str(index_str)
876				.map_err(|_| "invalid string input for OutputIndex")?,
877		})
878	}
879}
880
881impl Display for UtxoId {
882	fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
883		let hash = sp_core::hexdisplay::HexDisplay::from(&self.tx_hash.0);
884		write!(f, "{}#{}", hash, self.index.0)
885	}
886}
887
888#[derive(
889	Default,
890	Debug,
891	Copy,
892	Clone,
893	PartialEq,
894	Eq,
895	Encode,
896	Decode,
897	DecodeWithMemTracking,
898	PartialOrd,
899	Ord,
900	ToDatum,
901	TypeInfo,
902	MaxEncodedLen,
903	Hash,
904)]
905#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
906/// An index of output of a transaction. In range [0, 2^15-1].
907pub struct UtxoIndex(pub u16);
908
909#[cfg(feature = "serde")]
910impl FromStr for UtxoIndex {
911	type Err = sp_std::num::ParseIntError;
912	fn from_str(s: &str) -> Result<Self, Self::Err> {
913		let parsed = u16::from_str(s)?;
914		let _check_overflow = i16::from_str(s)?;
915		Ok(Self(parsed))
916	}
917}
918
919/// Size of a Cardano transaction hash
920pub const TX_HASH_SIZE: usize = 32;
921
922#[derive(
923	Default,
924	Copy,
925	Clone,
926	Hash,
927	PartialEq,
928	Eq,
929	Encode,
930	Decode,
931	DecodeWithMemTracking,
932	ToDatum,
933	TypeInfo,
934	MaxEncodedLen,
935)]
936#[byte_string(debug, from_bytes, decode_hex, hex_serialize, hex_deserialize)]
937#[constructor_datum]
938/// Cardano transaction hash
939///
940/// This hash uniquely identifies a transaction in the Cardano ledger.
941pub struct McTxHash(pub [u8; TX_HASH_SIZE]);
942
943impl TryFrom<Vec<u8>> for McTxHash {
944	type Error = &'static str;
945
946	fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
947		<[u8; 32]>::try_from(value)
948			.map_err(|_| "McTxHash must be 32 bytes long")
949			.map(McTxHash)
950	}
951}
952
953impl Display for McTxHash {
954	fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
955		let hash = sp_core::hexdisplay::HexDisplay::from(&self.0);
956		write!(f, "{}", hash)
957	}
958}
959
960#[derive(
961	Default,
962	Clone,
963	Decode,
964	DecodeWithMemTracking,
965	Encode,
966	PartialEq,
967	Eq,
968	TypeInfo,
969	MaxEncodedLen,
970	Hash,
971)]
972#[byte_string(debug, decode_hex, hex_serialize, hex_deserialize)]
973/// Cardano block hash
974///
975/// This hash uniquely identifies a Cardano block
976pub struct McBlockHash(pub [u8; 32]);
977
978impl Display for McBlockHash {
979	fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
980		let hash = sp_core::hexdisplay::HexDisplay::from(&self.0);
981		write!(f, "{}", hash)
982	}
983}
984
985/// Extended information about a UTxO in Cardano ledger
986#[derive(
987	Default, Debug, Copy, Clone, PartialEq, Eq, Encode, Decode, DecodeWithMemTracking, TypeInfo,
988)]
989#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
990#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
991pub struct UtxoInfo {
992	/// Output ID
993	pub utxo_id: UtxoId,
994	/// Epoch number in which the output was produced
995	pub epoch_number: McEpochNumber,
996	/// Block number in which the output was produced
997	pub block_number: McBlockNumber,
998	/// Slot number in which the output was produced
999	pub slot_number: McSlotNumber,
1000	/// Index in block of the transaction that produced the output
1001	pub tx_index_within_block: McTxIndexInBlock,
1002}
1003
1004/// Key type used for ordering transaction outputs
1005///
1006/// This ordering key is used in contexts where a common ordering of the data must be used
1007/// by all nodes participating in a Partner Chain due to it being subject to consensus.
1008#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
1009pub struct UtxoInfoOrderingKey {
1010	/// Block number on which the output was created
1011	pub block_number: McBlockNumber,
1012	/// Index within the block of the transaction that created the output
1013	pub tx_index_within_block: McTxIndexInBlock,
1014	/// Index of the output in the transaction outputs
1015	pub utxo_id_index: UtxoIndex,
1016}
1017
1018impl UtxoInfo {
1019	/// Returns the ordering key for this UTxO
1020	pub fn ordering_key(&self) -> UtxoInfoOrderingKey {
1021		UtxoInfoOrderingKey {
1022			block_number: self.block_number,
1023			tx_index_within_block: self.tx_index_within_block,
1024			utxo_id_index: self.utxo_id.index,
1025		}
1026	}
1027}
1028
1029/// Type of Cardano network
1030///
1031/// Cardano defines two network types:
1032/// - mainnet: the unique, production Cardano network
1033/// - testnet: various public and private testnets. These testnets are further differentiated
1034///            by their respective "testnet magic" numbers.
1035#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
1036#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1037#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
1038pub enum NetworkType {
1039	/// The Cardano mainnet (unique network)
1040	Mainnet,
1041	/// A Cardano testnet
1042	#[default]
1043	Testnet,
1044}
1045
1046#[cfg(feature = "std")]
1047impl std::fmt::Display for NetworkType {
1048	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1049		let str = match self {
1050			Self::Mainnet => "mainnet",
1051			Self::Testnet => "testnet",
1052		};
1053		write!(f, "{}", str)
1054	}
1055}
1056
1057/// Cardano SPO registration data
1058///
1059/// This data describes a single registration done by a Cardano SPO for the sake of being considered
1060/// for selection to the block producing committee on a given Partner Chain.
1061///
1062/// This registration is represented as a UTxO in the Cardano ledger containing a Plutus datum with
1063/// public keys that are being registered, together with signatures that prove the registrant's
1064/// control of these keys.
1065#[derive(Debug, Clone, Encode, Decode, DecodeWithMemTracking, PartialEq, Eq, TypeInfo)]
1066#[cfg_attr(feature = "serde", derive(Serialize))]
1067pub struct RegistrationData {
1068	/// UTXO that is an input parameter to the registration transaction
1069	pub registration_utxo: UtxoId,
1070	/// Signature confirming the registrant's ownership of `sidechain_pub_key`
1071	pub sidechain_signature: SidechainSignature,
1072	/// Signature confirming the registrant's ownership of the main chain public key used in the registration
1073	pub mainchain_signature: MainchainSignature,
1074	/// Signature confirming the registrant's ownership of `cross_chain_pub_key`
1075	pub cross_chain_signature: CrossChainSignature,
1076	/// Registering SPO's sidechain public key
1077	pub sidechain_pub_key: SidechainPublicKey,
1078	/// Registering SPO's cross-chain public key
1079	pub cross_chain_pub_key: CrossChainPublicKey,
1080	/// Information about the UTxO containing the registration data
1081	pub utxo_info: UtxoInfo,
1082	/// List of inputs to the registration transaction
1083	pub tx_inputs: Vec<UtxoId>,
1084	/// Registering SPO's additional keys
1085	pub keys: CandidateKeys,
1086}
1087
1088/// Information about an Authority Candidate's Registrations at some block.
1089#[derive(Debug, Clone, Encode, Decode, DecodeWithMemTracking, PartialEq, Eq, TypeInfo)]
1090#[cfg_attr(feature = "serde", derive(Serialize))]
1091pub struct CandidateRegistrations {
1092	/// Stake pool public key of the registering Cardano SPO
1093	pub stake_pool_public_key: StakePoolPublicKey,
1094	/// List of registrations done by the registering Cardano SPO
1095	pub registrations: Vec<RegistrationData>,
1096	/// Stake delegation of the registering Cardano SPO
1097	pub stake_delegation: Option<StakeDelegation>,
1098}
1099
1100impl CandidateRegistrations {
1101	/// Creates a new [CandidateRegistrations] from its members
1102	pub fn new(
1103		stake_pool_public_key: StakePoolPublicKey,
1104		stake_delegation: Option<StakeDelegation>,
1105		registrations: Vec<RegistrationData>,
1106	) -> Self {
1107		Self { stake_pool_public_key, registrations, stake_delegation }
1108	}
1109
1110	/// Return the stake pool public key of the registering SPO
1111	pub fn mainchain_pub_key(&self) -> &StakePoolPublicKey {
1112		&self.stake_pool_public_key
1113	}
1114
1115	/// Return the list of registrations of the SPO
1116	pub fn registrations(&self) -> &[RegistrationData] {
1117		&self.registrations
1118	}
1119}
1120
1121/// Sr25519 public key used by Aura consensus algorithm. Not validated
1122#[derive(
1123	Clone, PartialEq, Eq, Encode, Decode, DecodeWithMemTracking, TypeInfo, PartialOrd, Ord, Hash,
1124)]
1125#[byte_string(debug, hex_serialize, hex_deserialize, decode_hex)]
1126pub struct AuraPublicKey(pub Vec<u8>);
1127impl AuraPublicKey {
1128	/// Attempts to cast this public key to a valid [sr25519::Public]
1129	pub fn try_into_sr25519(&self) -> Option<sr25519::Public> {
1130		Some(sr25519::Public::from_raw(self.0.clone().try_into().ok()?))
1131	}
1132}
1133
1134impl From<sr25519::Public> for AuraPublicKey {
1135	fn from(value: sr25519::Public) -> Self {
1136		Self(value.0.to_vec())
1137	}
1138}
1139
1140impl From<AuraPublicKey> for CandidateKey {
1141	fn from(value: AuraPublicKey) -> Self {
1142		Self { id: AURA.0, bytes: value.0 }
1143	}
1144}
1145
1146/// Ed25519 public key used by the Grandpa finality gadget. Not validated
1147#[derive(
1148	Clone, PartialEq, Eq, Encode, Decode, DecodeWithMemTracking, TypeInfo, PartialOrd, Ord, Hash,
1149)]
1150#[byte_string(debug, hex_serialize, hex_deserialize, decode_hex)]
1151pub struct GrandpaPublicKey(pub Vec<u8>);
1152impl GrandpaPublicKey {
1153	/// Attempts to cast this public key to a valid [ed25519::Public]
1154	pub fn try_into_ed25519(&self) -> Option<ed25519::Public> {
1155		Some(ed25519::Public::from_raw(self.0.clone().try_into().ok()?))
1156	}
1157}
1158
1159impl From<ed25519::Public> for GrandpaPublicKey {
1160	fn from(value: ed25519::Public) -> Self {
1161		Self(value.0.to_vec())
1162	}
1163}
1164
1165impl From<GrandpaPublicKey> for CandidateKey {
1166	fn from(value: GrandpaPublicKey) -> Self {
1167		Self { id: GRANDPA.0, bytes: value.0 }
1168	}
1169}
1170
1171#[derive(
1172	Debug,
1173	Clone,
1174	PartialEq,
1175	Decode,
1176	DecodeWithMemTracking,
1177	Encode,
1178	MaxEncodedLen,
1179	TypeInfo,
1180	Eq,
1181	Hash,
1182)]
1183#[cfg_attr(feature = "serde", derive(Serialize))]
1184/// Parameter controlling the number and proportion of registered and permissioned candidates
1185/// selected into a Partner Chain committee, used by the Ariadne family of selection algorithms.
1186///
1187/// The core idea behind the D-Param is to enable a Partner Chain to bootstrap its operation by
1188/// relying on a hand-picked set of trusted block producers for security, and to later incrementally
1189/// shift block production onto trustless network participants as the chain grows and it becomes
1190/// harder for malicious actors to manipulate the chain.
1191pub struct DParameter {
1192	/// Expected number of permissioned candidates selected for a committee
1193	pub num_permissioned_candidates: u16,
1194	/// Expected number of registered candidates selected for a committee
1195	pub num_registered_candidates: u16,
1196}
1197
1198impl DParameter {
1199	/// Creates a new [DParameter] from member values
1200	pub fn new(num_permissioned_candidates: u16, num_registered_candidates: u16) -> Self {
1201		Self { num_permissioned_candidates, num_registered_candidates }
1202	}
1203}
1204
1205/// Opaque key bytes with a 4 bytes identifier
1206#[derive(
1207	Clone, PartialEq, Eq, Decode, DecodeWithMemTracking, Encode, TypeInfo, PartialOrd, Ord, Hash,
1208)]
1209#[cfg_attr(feature = "serde", derive(Serialize))]
1210pub struct CandidateKey {
1211	/// Key type id
1212	pub id: [u8; 4],
1213	/// Bytes of the key
1214	pub bytes: Vec<u8>,
1215}
1216
1217impl alloc::fmt::Debug for CandidateKey {
1218	fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
1219		let id = hex::encode(self.id);
1220		let id_text = String::from_utf8_lossy(&self.id);
1221		let bytes = hex::encode(&self.bytes);
1222		f.write_str(&alloc::format!("CandidateKey {{ id: {id}({id_text}), bytes: {bytes} }}"))
1223	}
1224}
1225
1226impl FromStr for CandidateKey {
1227	type Err = &'static str;
1228
1229	fn from_str(s: &str) -> Result<Self, Self::Err> {
1230		if let Some((id, bytes)) = s.split_once(':') {
1231			let id: [u8; 4] = id.as_bytes().try_into().map_err(|_| "invalid key type id")?;
1232			let bytes = bytes.trim_start_matches("0x");
1233			let bytes = hex::decode(bytes).map_err(|_| "key bytes are not in hex format")?;
1234			Ok(CandidateKey { id, bytes })
1235		} else {
1236			Err("invalid format of CandidateKey, expected '<key type>:<key>'")
1237		}
1238	}
1239}
1240
1241/// Key type id of Partner Chains cross-chain key, used with ECDSA cryptography
1242pub const CROSS_CHAIN_KEY_TYPE_ID: KeyTypeId = KeyTypeId(*b"crch");
1243
1244impl CandidateKey {
1245	/// Constructor
1246	pub fn new(id: KeyTypeId, bytes: Vec<u8>) -> Self {
1247		Self { id: id.0, bytes }
1248	}
1249}
1250
1251#[derive(Debug, Clone, PartialEq, Eq, DecodeWithMemTracking, TypeInfo, PartialOrd, Ord, Hash)]
1252#[cfg_attr(feature = "serde", derive(Serialize))]
1253/// Bytes of CandidateKeys that come from Cardano or other input.
1254pub struct CandidateKeys(pub Vec<CandidateKey>);
1255
1256impl CandidateKeys {
1257	/// Gets copy of key bytes identified by given id
1258	pub fn find(&self, id: KeyTypeId) -> Option<Vec<u8>> {
1259		self.0
1260			.iter()
1261			.find_map(|e| if e.id == id.0 { Some(e.bytes.clone()) } else { None })
1262	}
1263
1264	/// Gets copy of key bytes identified by given id or empty bytes if key is not present
1265	pub fn find_or_empty(&self, id: KeyTypeId) -> Vec<u8> {
1266		self.find(id).unwrap_or_default()
1267	}
1268
1269	/// True for keys that are only AURA and Grandpa
1270	pub fn has_only_aura_and_grandpa_keys(&self) -> bool {
1271		self.0.len() == 2 && self.find(AURA).is_some() && self.find(GRANDPA).is_some()
1272	}
1273}
1274
1275impl From<Vec<([u8; 4], Vec<u8>)>> for CandidateKeys {
1276	fn from(value: Vec<([u8; 4], Vec<u8>)>) -> Self {
1277		Self(value.into_iter().map(|(id, bytes)| CandidateKey { id, bytes }).collect())
1278	}
1279}
1280
1281/// Backward compatible [Encode] for [CandidateKeys].
1282/// After node update InherentData would be encoded with this version but runtime would still know [PermissionedCandidateData] and [CandidateRegistration]
1283/// that have [AuraPublicKey] and [GrandpaPublicKey] fields instead of [CandidateKeys] field.
1284/// To support existing chains, when keys are AURA and Grandpa, [CandidateKeys] is encoded exactly like in previous version.
1285/// If other key set is used in the place where AURA vector lenght is encoded, Compact(u32::MAX) is encoded to enable discrimination between the types that
1286/// has to be decoded.
1287/// The represtation is either:
1288/// Legacy: AuraKeySize, AuraKeyBytes, GrandpaKeySize, GrandpaKeyBytes
1289/// Generic: u32::MAX, CandidateKeysVector
1290/// AuraKeySize cannot be u32::MAX (won't fit on Cardano), so when it is encountered, we know that the generic representation is used.
1291impl Encode for CandidateKeys {
1292	fn size_hint(&self) -> usize {
1293		if self.has_only_aura_and_grandpa_keys() {
1294			Encode::size_hint(&AuraPublicKey(self.find_or_empty(AURA)))
1295				.saturating_add(Encode::size_hint(&GrandpaPublicKey(self.find_or_empty(GRANDPA))))
1296		} else {
1297			Encode::size_hint(&Compact(u32::MAX)).saturating_add(Encode::size_hint(&self.0))
1298		}
1299	}
1300
1301	fn encode_to<T: parity_scale_codec::Output + ?Sized>(&self, dest: &mut T) {
1302		if self.has_only_aura_and_grandpa_keys() {
1303			Encode::encode_to(&AuraPublicKey(self.find_or_empty(AURA)), dest);
1304			Encode::encode_to(&GrandpaPublicKey(self.find_or_empty(GRANDPA)), dest)
1305		} else {
1306			// Compact(u32::MAX) is used to signal that a vector of CandidateKey should be decoded
1307			// It has to be this type, be it is the item that AuraPublicKey::decode expects.
1308			Encode::encode_to(&Compact(u32::MAX), dest);
1309			Encode::encode_to(&self.0, dest)
1310		}
1311	}
1312}
1313
1314/// Custom backward compatibile Decode. See comment on the Encode implementation.
1315impl Decode for CandidateKeys {
1316	fn decode<I: parity_scale_codec::Input>(
1317		input: &mut I,
1318	) -> Result<Self, parity_scale_codec::Error> {
1319		// See Encode instance
1320		let marker_or_aura_size: u32 = <Compact<u32>>::decode(input)?.0;
1321		if marker_or_aura_size == u32::MAX {
1322			let keys = Vec::<CandidateKey>::decode(input)?;
1323			Ok(Self(keys))
1324		} else {
1325			let aura_bytes: Vec<u8> = decode_vec_with_len(input, marker_or_aura_size as usize)?;
1326			let grandpa = GrandpaPublicKey::decode(input)?;
1327			Ok(Self(vec![AuraPublicKey(aura_bytes).into(), grandpa.into()]))
1328		}
1329	}
1330}
1331
1332#[derive(
1333	Debug,
1334	Clone,
1335	PartialEq,
1336	Eq,
1337	Decode,
1338	DecodeWithMemTracking,
1339	Encode,
1340	TypeInfo,
1341	PartialOrd,
1342	Ord,
1343	Hash,
1344)]
1345#[cfg_attr(feature = "serde", derive(Serialize))]
1346/// Information about a permissioned committee member candidate
1347///
1348/// Permissioned candidates are nominated by the Partner Chain's governance authority to be
1349/// eligible for participation in block producer committee without controlling any ADA stake
1350/// on Cardano and registering as SPOs.
1351pub struct PermissionedCandidateData {
1352	/// Sidechain public key of the permissioned candidate
1353	pub sidechain_public_key: SidechainPublicKey,
1354	/// Additional keys of the permissioned candidate
1355	pub keys: CandidateKeys,
1356}
1357
1358/// Parses public keys formatted as PARTNER_CHAINS_KEY:AURA_KEY:GRANDPA_KEY or PARTNER_CHAINS_KEY,KEY_ID_1:KEY_1,...,KEY_ID_N:KEY_N
1359#[cfg(feature = "std")]
1360impl FromStr for PermissionedCandidateData {
1361	type Err = alloc::boxed::Box<dyn core::error::Error + Send + Sync>;
1362
1363	fn from_str(partner_chain_public_keys: &str) -> Result<Self, Self::Err> {
1364		fn is_legacy_format(line: &str) -> bool {
1365			line.contains(':') && !line.contains(',')
1366		}
1367
1368		fn parse_legacy_format(
1369			line: &str,
1370		) -> Result<
1371			PermissionedCandidateData,
1372			alloc::boxed::Box<dyn core::error::Error + Send + Sync>,
1373		> {
1374			let line = line.replace("0x", "");
1375			if let [sidechain_pub_key, aura_pub_key, grandpa_pub_key] =
1376				line.split(":").collect::<Vec<_>>()[..]
1377			{
1378				Ok(PermissionedCandidateData {
1379					sidechain_public_key: SidechainPublicKey(
1380						hex::decode(sidechain_pub_key).map_err(|e| e.to_string())?,
1381					),
1382					keys: CandidateKeys(vec![
1383						AuraPublicKey(hex::decode(aura_pub_key).map_err(|e| e.to_string())?).into(),
1384						GrandpaPublicKey(hex::decode(grandpa_pub_key).map_err(|e| e.to_string())?)
1385							.into(),
1386					]),
1387				})
1388			} else {
1389				Err(format!("Failed to parse partner chain public keys (legacy) from '{line}'")
1390					.into())
1391			}
1392		}
1393
1394		fn parse_generic_format(
1395			line: &str,
1396		) -> Result<
1397			PermissionedCandidateData,
1398			alloc::boxed::Box<dyn core::error::Error + Send + Sync>,
1399		> {
1400			let mut columns = line.split(",");
1401			if let Some(partner_chains_key) = columns.next() {
1402				let partner_chains_key = SidechainPublicKey(
1403					hex::decode(partner_chains_key.trim_start_matches("0x"))
1404						.map_err(|e| e.to_string())?,
1405				);
1406				let mut keys = vec![];
1407				for column in columns {
1408					let key = CandidateKey::from_str(column)?;
1409					keys.push(key);
1410				}
1411				Ok(PermissionedCandidateData {
1412					sidechain_public_key: partner_chains_key,
1413					keys: CandidateKeys(keys),
1414				})
1415			} else {
1416				Err("Failed to parse partner chain public keys (generic) from '{line}'.".into())
1417			}
1418		}
1419
1420		if is_legacy_format(&partner_chain_public_keys) {
1421			parse_legacy_format(&partner_chain_public_keys)
1422		} else {
1423			parse_generic_format(&partner_chain_public_keys)
1424		}
1425	}
1426}
1427
1428/// Cardano SPO registration. This is a stripped-down version of [RegistrationData].
1429#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1430pub struct CandidateRegistration {
1431	/// Information on ADA stake pool ownership
1432	pub stake_ownership: AdaBasedStaking,
1433	/// Registering SPO's sidechain public key
1434	pub partner_chain_pub_key: SidechainPublicKey,
1435	/// Signature confirming registering SPO's ownership of `partner_chain_pub_key`
1436	pub partner_chain_signature: SidechainSignature,
1437	/// Hash of the registering SPO's Cardano public key
1438	pub own_pkh: MainchainKeyHash,
1439	/// UTxO containing the registration data
1440	pub registration_utxo: UtxoId,
1441	/// Additional keys of the registered candidate
1442	pub keys: CandidateKeys,
1443}
1444
1445impl CandidateRegistration {
1446	/// Checks whether `self` and `other` contain the same keys
1447	pub fn matches_keys(&self, other: &Self) -> bool {
1448		self.stake_ownership == other.stake_ownership
1449			&& self.partner_chain_pub_key == other.partner_chain_pub_key
1450			&& self.partner_chain_signature == other.partner_chain_signature
1451			&& self.keys.0.iter().all(|key| other.keys.0.contains(key))
1452	}
1453}
1454
1455/// Information on ADA stake pool ownership
1456///
1457/// AdaBasedStaking is a variant of Plutus type StakeOwnership. The other variant, TokenBasedStaking, is not supported.
1458#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1459pub struct AdaBasedStaking {
1460	/// Public key of the stake pool operator
1461	pub pub_key: StakePoolPublicKey,
1462	/// Signature confirming ownership of `pub_key`
1463	pub signature: MainchainSignature,
1464}
1465
1466#[derive(
1467	Clone,
1468	PartialEq,
1469	Eq,
1470	Ord,
1471	PartialOrd,
1472	TypeInfo,
1473	MaxEncodedLen,
1474	Encode,
1475	Decode,
1476	DecodeWithMemTracking,
1477)]
1478/// Represents a Cardano ADA delegator
1479pub enum DelegatorKey {
1480	/// Represents a staking address that is controlled by a user delegator
1481	StakeKeyHash([u8; 28]),
1482	/// Represents a staking address that is locked by a Plutus script
1483	ScriptKeyHash {
1484		/// Raw stake address hash
1485		hash_raw: [u8; 28],
1486		/// Hash of the Plutus script controlling the staking address
1487		script_hash: [u8; 28],
1488	},
1489}
1490
1491impl alloc::fmt::Debug for DelegatorKey {
1492	fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
1493		let s = match self {
1494			Self::ScriptKeyHash { hash_raw, script_hash } => alloc::format!(
1495				"ScriptKeyHash{{ hash_raw: {}, script_hash: {} }}",
1496				hex::encode(hash_raw),
1497				hex::encode(script_hash)
1498			),
1499			Self::StakeKeyHash(hash) => alloc::format!("StakeKeyHash({})", hex::encode(hash)),
1500		};
1501
1502		f.write_str(&s)
1503	}
1504}
1505
1506/// Amount of Lovelace staked by a Cardano delegator to a single stake pool
1507#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
1508pub struct DelegatorStakeAmount(pub u64);
1509
1510impl<T: Into<u64>> From<T> for DelegatorStakeAmount {
1511	fn from(value: T) -> Self {
1512		Self(value.into())
1513	}
1514}
1515
1516/// A mapping between Cardano SPOs and the information about ADA delegation of their stake pools
1517///
1518/// This mapping can be used to calculate relative share of the total delegation for the
1519/// purpose of weighing during block producer selection.
1520#[derive(Debug, Clone, Default)]
1521pub struct StakeDistribution(pub BTreeMap<MainchainKeyHash, PoolDelegation>);
1522
1523/// ADA delegation data for a single Cardano SPO
1524#[derive(Debug, Clone, Default, PartialEq)]
1525pub struct PoolDelegation {
1526	/// Total amount delegated to the stake pool
1527	pub total_stake: StakeDelegation,
1528	/// Delegated amount for each delegator of the stake pool
1529	pub delegators: BTreeMap<DelegatorKey, DelegatorStakeAmount>,
1530}
1531
1532/// [FromStr] trait with [FromStr::Err] fixed to a type compatible with `clap`'s `value_parser` macro.
1533pub trait FromStrStdErr:
1534	FromStr<Err: Into<alloc::boxed::Box<dyn core::error::Error + Send + Sync + 'static>>>
1535{
1536}
1537impl<T: FromStr<Err: Into<alloc::boxed::Box<dyn core::error::Error + Send + Sync + 'static>>>>
1538	FromStrStdErr for T
1539{
1540}
1541
1542#[cfg(test)]
1543mod tests {
1544	use super::*;
1545	use core::str::FromStr;
1546	use hex_literal::hex;
1547	use parity_scale_codec::{Decode, Encode};
1548
1549	#[test]
1550	fn main_chain_address_string_serialize_deserialize_round_trip() {
1551		let address = MainchainAddress::from_str(
1552			"addr_test1wz5qc7fk2pat0058w4zwvkw35ytptej3nuc3je2kgtan5dq3rt4sc",
1553		)
1554		.unwrap();
1555		let serialized = serde_json::to_value(&address).unwrap();
1556		assert_eq!(
1557			serialized,
1558			serde_json::json!("addr_test1wz5qc7fk2pat0058w4zwvkw35ytptej3nuc3je2kgtan5dq3rt4sc")
1559		);
1560		let deserialized = serde_json::from_value(serialized).unwrap();
1561		assert_eq!(address, deserialized);
1562	}
1563
1564	#[test]
1565	fn main_chain_address_deserialization_of_hex_encoded_bytes() {
1566		let address = MainchainAddress::from_str("addr_test1wz5q").unwrap();
1567		let serialized = serde_json::json!("0x616464725f7465737431777a3571");
1568		assert_eq!(address, serde_json::from_value(serialized).unwrap());
1569		let serialized = serde_json::json!("616464725f7465737431777a3571");
1570		assert_eq!(address, serde_json::from_value(serialized).unwrap());
1571	}
1572
1573	#[test]
1574	fn main_chain_address_string_from_str_to_string_round_trip() {
1575		let address = MainchainAddress::from_str(
1576			"addr_test1wz5qc7fk2pat0058w4zwvkw35ytptej3nuc3je2kgtan5dq3rt4sc",
1577		)
1578		.unwrap();
1579		let str = address.to_string();
1580		let from_str = MainchainAddress::from_str(&str).unwrap();
1581		assert_eq!(address, from_str);
1582	}
1583
1584	#[test]
1585	fn main_chain_signature_should_be_backward_compatible_with_vec() {
1586		#[derive(Clone, Encode, Decode, DecodeWithMemTracking, TypeInfo, PartialEq, Eq, Hash)]
1587		#[byte_string(debug, hex_serialize, decode_hex)]
1588		struct LegacyMCSignature(pub Vec<u8>);
1589
1590		let legacy_encoded = LegacyMCSignature(vec![10; 64]).encode();
1591
1592		let legacy_decoded = MainchainSignature::decode(&mut legacy_encoded.as_slice())
1593			.expect("Encoded legacy should decode to current type");
1594
1595		assert_eq!(legacy_decoded.0, [10; MAINCHAIN_SIGNATURE_LEN]);
1596
1597		let current_encoded = MainchainSignature([9; MAINCHAIN_SIGNATURE_LEN]).encode();
1598
1599		let current_decoded = LegacyMCSignature::decode(&mut current_encoded.as_slice())
1600			.expect("Encoded current should decode to legacy");
1601
1602		assert_eq!(current_decoded.0, vec![9; 64]);
1603	}
1604
1605	#[test]
1606	fn cross_chain_signature_verify_works() {
1607		let signature =	CrossChainSignature(
1608			hex!("d1e02e4a5484c3b7202ce6b844577048e7578dc62901cf8f51e6d74bbd3adb091688feacedd8343d0b04a0f5862b2e06148934a75e678e42051fde5431eca33d").to_vec()
1609		);
1610		let pubkey = CrossChainPublicKey(
1611			hex!("020a1091341fe5664bfa1782d5e04779689068c916b04cb365ec3153755684d9a1").to_vec(),
1612		);
1613		let signed_data = hex!(
1614			"84020a1091341fe5664bfa1782d5e04779689068c916b04cb365ec3153755684d9a16c68747470733a2f2f636f6f6c2e73747566662f73706f2e6a736f6e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
1615		);
1616
1617		assert!(signature.verify(&pubkey, &signed_data).is_ok())
1618	}
1619
1620	#[derive(Decode, Encode, PartialEq, Eq, Debug)]
1621	struct TestCandidateKeys {
1622		field_before: Option<u32>,
1623		keys: CandidateKeys,
1624		// ensures that Decode of CandidateKeys does not consume the whole input
1625		field_after: Option<u32>,
1626	}
1627
1628	#[test]
1629	fn encode_decode_round_trip_for_generic_candidate_keys() {
1630		let keys = TestCandidateKeys {
1631			field_before: Some(42),
1632			keys: CandidateKeys(vec![
1633				CandidateKey { id: *b"abcd", bytes: [7u8; 32].to_vec() },
1634				CandidateKey { id: *b"efgh", bytes: [9u8; 32].to_vec() },
1635			]),
1636			field_after: Some(15),
1637		};
1638		let bytes: Vec<u8> = Encode::encode(&keys);
1639		let mut bytes: &[u8] = &bytes;
1640		let decoded = TestCandidateKeys::decode(&mut bytes).unwrap();
1641		assert_eq!(keys, decoded)
1642	}
1643
1644	#[test]
1645	fn encode_decode_round_trip_for_aura_and_grandpa_candidate_keys() {
1646		let keys = TestCandidateKeys {
1647			field_before: Some(42),
1648			keys: CandidateKeys(vec![
1649				AuraPublicKey([7u8; 32].to_vec()).into(),
1650				GrandpaPublicKey([9u8; 32].to_vec()).into(),
1651			]),
1652			field_after: Some(15),
1653		};
1654		let bytes: Vec<u8> = Encode::encode(&keys);
1655		let mut bytes: &[u8] = &bytes;
1656		let decoded = TestCandidateKeys::decode(&mut bytes).unwrap();
1657		assert_eq!(keys, decoded)
1658	}
1659}