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