diff --git a/catalyst-gateway/bin/src/cardano/registration/cip36.cddl b/catalyst-gateway/bin/src/cardano/cip36_registration/cip36.cddl similarity index 100% rename from catalyst-gateway/bin/src/cardano/registration/cip36.cddl rename to catalyst-gateway/bin/src/cardano/cip36_registration/cip36.cddl diff --git a/catalyst-gateway/bin/src/cardano/cip36_registration/cip36_registration.cddl b/catalyst-gateway/bin/src/cardano/cip36_registration/cip36_registration.cddl new file mode 100644 index 00000000000..8d4f949e2de --- /dev/null +++ b/catalyst-gateway/bin/src/cardano/cip36_registration/cip36_registration.cddl @@ -0,0 +1,17 @@ + +registration = { + 1 : [+delegation] / legacy_key_registration, + 2 : stake_credential, + 3 : payment_address, + 4 : nonce, + ? 5 : voting_purpose .default 0 +} + +cip36_vote_pub_key /= bytes .size 32 +payment_address /= bytes +nonce /= uint +weight /= uint .size 4 +voting_purpose /= uint +legacy_key_registration = cip36_vote_pub_key +delegation = [cip36_vote_pub_key, weight] +stake_credential /= staking_pub_key \ No newline at end of file diff --git a/catalyst-gateway/bin/src/cardano/cip36_registration/cip36_witness.cddl b/catalyst-gateway/bin/src/cardano/cip36_registration/cip36_witness.cddl new file mode 100644 index 00000000000..ec51d57e120 --- /dev/null +++ b/catalyst-gateway/bin/src/cardano/cip36_registration/cip36_witness.cddl @@ -0,0 +1,5 @@ +registration_witness = { + 1 : stake_witness +} + +stake_witness /= ed25519_signature \ No newline at end of file diff --git a/catalyst-gateway/bin/src/cardano/cip36_registration/mod.rs b/catalyst-gateway/bin/src/cardano/cip36_registration/mod.rs new file mode 100644 index 00000000000..180a067435e --- /dev/null +++ b/catalyst-gateway/bin/src/cardano/cip36_registration/mod.rs @@ -0,0 +1,490 @@ +//! Verify registration TXs + +use cardano_chain_follower::Network; +use ciborium::Value; +use cryptoxide::{blake2b::Blake2b, digest::Digest}; +use pallas::ledger::{ + primitives::{conway::Metadatum, Fragment}, + traverse::MultiEraMeta, +}; +use serde::{Deserialize, Serialize}; + +/// Pub key +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub(crate) struct PubKey(Vec); + +/// Nonce +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub(crate) struct Nonce(pub i64); + +/// Voting purpose +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)] +pub(crate) struct VotingPurpose(u64); + +/// Rewards address +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub(crate) struct RewardsAddress(pub Vec); + +/// Error report for serializing +pub(crate) type ErrorReport = Vec; + +impl PubKey { + /// Get credentials, a blake2b 28 bytes hash of the pub key + pub(crate) fn get_credentials(&self) -> [u8; 28] { + let mut digest = [0u8; 28]; + let mut context = Blake2b::new(28); + context.input(&self.0); + context.result(&mut digest); + digest + } + + /// Get bytes + pub(crate) fn bytes(&self) -> &[u8] { + &self.0 + } +} + +/// Ed25519 signature. +/// +/// This type represents a container for the byte serialization of an Ed25519 +/// signature, and does not necessarily represent well-formed field or curve +/// elements. +/// +/// Signature verification libraries are expected to reject invalid field +/// elements at the time a signature is verified. +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +#[repr(C)] +pub struct Signature { + /// Component of an Ed25519 signature when serialized as bytes + r: [u8; Self::COMPONENT_SIZE], + /// Component of an Ed25519 signature when serialized as bytes + s: [u8; Self::COMPONENT_SIZE], +} + +impl Signature { + /// Size of an encoded Ed25519 signature in bytes. + const BYTE_SIZE: usize = Self::COMPONENT_SIZE * 2; + /// Size of a single component of an Ed25519 signature. + const COMPONENT_SIZE: usize = 32; + + /// Parse an Ed25519 signature from a byte slice. + fn from_bytes(bytes: &[u8; Self::BYTE_SIZE]) -> Self { + let mut r = <[u8; Self::COMPONENT_SIZE]>::default(); + let mut s = <[u8; Self::COMPONENT_SIZE]>::default(); + + let components = bytes.split_at(Self::COMPONENT_SIZE); + r.copy_from_slice(components.0); + s.copy_from_slice(components.1); + + Self { r, s } + } +} + +/// The source of voting power for a given registration +/// +/// The voting power can either come from: +/// - a single wallet, OR +/// - a set of delegations +#[derive(Serialize, Deserialize)] +#[serde(untagged)] +#[derive(Debug, Clone, PartialEq)] +pub(crate) enum VotingInfo { + /// Direct voting + /// + /// Voting power is based on the staked ada of the given key + Direct(PubKey), + + /// Delegated voting + /// + /// Voting power is based on the staked ada of the delegated keys + /// order of elements is important and must be preserved. + Delegated(Vec<(PubKey, i64)>), +} + +/// A catalyst CIP-36 registration on Cardano +#[derive(Debug, Clone, PartialEq)] +pub(crate) struct Cip36Registration { + /// Voting info + pub voting_info: Option, + /// Stake key + pub stake_key: Option, + /// Rewards address + pub rewards_address: Option, + /// Nonce + pub nonce: Option, + /// Optional voting purpose + pub voting_purpose: Option, + /// Raw tx metadata + pub raw_metadata: Option>, + /// Witness signature 61285 + pub signature: Option, + /// Errors report + pub errors_report: ErrorReport, +} + +impl Cip36Registration { + /// Create new `Cip36Registration` from tx metadata + /// Collect secondary errors for granular json error report + #[allow(clippy::too_many_lines)] + pub(crate) fn generate_from_tx_metadata( + tx_metadata: &MultiEraMeta, network: Network, + ) -> Option { + if tx_metadata.is_empty() { + return None; + } + + let mut voting_info: Option = None; + let mut stake_key: Option = None; + let mut voting_purpose: Option = None; + let mut rewards_address: Option = None; + let mut nonce: Option = None; + let mut raw_metadata: Option> = None; + let mut signature: Option = None; + let mut errors_report = Vec::new(); + + if let pallas::ledger::traverse::MultiEraMeta::AlonzoCompatible(tx_metadata) = tx_metadata { + /// + const CIP36_REGISTRATION_CBOR_KEY: u64 = 61284; + /// + const CIP36_WITNESS_CBOR_KEY: u64 = 61285; + + raw_metadata = tx_metadata.encode_fragment().map_or_else( + |err| { + errors_report.push(format!("cannot encode tx metadata into bytes {err}")); + None + }, + Some, + ); + for (key, metadata) in tx_metadata.iter() { + match *key { + CIP36_REGISTRATION_CBOR_KEY => { + let cbor_value = match convert_pallas_metadatum_to_cbor_value(metadata) { + Ok(raw_cbor) => raw_cbor, + Err(err) => { + errors_report.push(err.to_string()); + continue; + }, + }; + + let Some(cbor_map) = cbor_value.as_map() else { + errors_report.push( + "Not a valid cbor cip36 registration, should be a cbor map" + .to_string(), + ); + continue; + }; + + // voting key: simply an ED25519 public key. This is the spending credential + // in the side chain that will receive voting power + // from this delegation. For direct voting it's + // necessary to have the corresponding private key + // to cast votes in the side chain + voting_info = inspect_voting_info(cbor_map).map_or_else( + |err| { + errors_report.push(format!("Invalid voting key, err: {err}",)); + None + }, + Some, + ); + + // A stake address for the network that this transaction is submitted to (to + // point to the Ada that is being delegated); + stake_key = inspect_stake_key(cbor_map).map_or_else( + |err| { + errors_report.push(format!("Invalid stake key, err: {err}",)); + None + }, + Some, + ); + + // A Shelley payment address (see CIP-0019) discriminated for the same + // network this transaction is submitted to, to + // receive rewards. + rewards_address = inspect_rewards_addr(cbor_map, network).map_or_else( + |err| { + errors_report.push(format!("Invalid rewards address, err: {err}",)); + None + }, + |val| Some(RewardsAddress(val.clone())), + ); + + nonce = inspect_nonce(cbor_map).map_or_else( + |err| { + errors_report.push(format!("Invalid nonce, err: {err}",)); + None + }, + Some, + ); + + voting_purpose = inspect_voting_purpose(cbor_map).map_or_else( + |err| { + errors_report.push(format!("Invalid voting purpose, err: {err}",)); + None + }, + Some, + ); + }, + CIP36_WITNESS_CBOR_KEY => { + let cbor_value = match convert_pallas_metadatum_to_cbor_value(metadata) { + Ok(raw_cbor) => raw_cbor, + Err(err) => { + errors_report.push(err.to_string()); + continue; + }, + }; + + signature = inspect_signature(cbor_value).map_or_else( + |err| { + errors_report.push(format!("Invalid signature, err: {err}",)); + None + }, + Some, + ); + }, + _ => continue, + }; + } + }; + + Some(Self { + voting_info, + stake_key, + rewards_address, + nonce, + voting_purpose, + raw_metadata, + signature, + errors_report, + }) + } +} + +/// Convert Pallas Metadatum to Cbor Value +fn convert_pallas_metadatum_to_cbor_value(metadata: &Metadatum) -> anyhow::Result { + let metadata_bytes = metadata + .encode_fragment() + .map_err(|err| anyhow::anyhow!("cannot encode metadata into bytes {err}"))?; + + ciborium::de::from_reader(metadata_bytes.as_slice()) + .map_err(|err| anyhow::anyhow!("Cannot decode cbor object from bytes, err: {err}")) +} + +/// Validate binary data against CIP-36 registration CDDL spec +#[allow(dead_code)] +fn validate_cip36_registration(data: &[u8]) -> anyhow::Result<()> { + /// Cip36 registration CDDL definition + const CIP36_REGISTRATION_CDDL: &str = include_str!("cip36_registration.cddl"); + + cddl::validate_cbor_from_slice(CIP36_REGISTRATION_CDDL, data, None)?; + Ok(()) +} + +/// Validate binary data against CIP-36 registration CDDL spec +#[allow(dead_code)] +fn validate_cip36_witness(data: &[u8]) -> anyhow::Result<()> { + /// Cip36 witness CDDL definition + const CIP36_WITNESS_CDDL: &str = include_str!("cip36_witness.cddl"); + + cddl::validate_cbor_from_slice(CIP36_WITNESS_CDDL, data, None)?; + Ok(()) +} + +/// Reward addresses start with a single header byte identifying their type and the +/// network, followed by 28 bytes of payload identifying either a stake key hash or a +/// script hash. Function accepts this first header prefix byte. +/// Validates first nibble is within the address range: 0x0? - 0x7? + 0xE? , 0xF? +/// Validates second nibble matches network id: 0/1 +fn is_valid_rewards_address(rewards_address_prefix: u8, network: Network) -> bool { + let addr_type = rewards_address_prefix >> 4 & 0xF; + let addr_net = rewards_address_prefix & 0xF; + + // 0 or 1 are valid addrs in the following cases: + // type = 0x0 - Testnet network + // type = 0x1 - Mainnet network + match network { + Network::Mainnet => { + if addr_net != 1 { + return false; + } + }, + Network::Testnet => { + if addr_net != 0 { + return false; + } + }, + _ => (), + } + + // Valid addrs: 0x0?, 0x1?, 0x2?, 0x3?, 0x4?, 0x5?, 0x6?, 0x7?, 0xE?, 0xF?. + let valid_addrs = [0, 1, 2, 3, 4, 5, 6, 7, 14, 15]; + valid_addrs.contains(&addr_type) +} + +/// Extract signature +fn inspect_signature(cbor_value: ciborium::value::Value) -> anyhow::Result { + let cbor_map = cbor_value + .into_map() + .map_err(|_| anyhow::anyhow!("Invalid cip36 witness cbor, should be a map"))?; + + let (_, cbor_signature) = cbor_map.into_iter().next().ok_or(anyhow::anyhow!( + "Invalid cip36 witness cbor, should have at least one entry" + ))?; + + let signature = cbor_signature + .into_bytes() + .map_err(|_| anyhow::anyhow!("Invalid cip36 witness cbor, signature should be bytes"))? + .try_into() + .map_err(|vec: Vec<_>| { + anyhow::anyhow!( + "Invalid signature length, expected: {}, got {}", + Signature::BYTE_SIZE, + vec.len() + ) + })?; + + Ok(Signature::from_bytes(&signature)) +} + +/// Extract voting info +fn inspect_voting_info(cbor_map: &[(Value, Value)]) -> anyhow::Result { + /// Voting info cbor key + const VOTING_INFO_CBOR_KEY: usize = 0; + /// Voting key cbor key + const VOTE_KEY_CBOR_KEY: usize = 0; + /// Weight cbor key + const WEIGHT_CBOR_KEY: usize = 1; + + let voting_key = match cbor_map.get(VOTING_INFO_CBOR_KEY).ok_or(anyhow::anyhow!( + "Issue with registration voting info cbor parsing" + ))? { + (Value::Integer(_), Value::Bytes(direct)) => VotingInfo::Direct(PubKey(direct.clone())), + (Value::Integer(_), Value::Array(cbor_array)) => { + let mut delegations = Vec::new(); + for cbor_value in cbor_array { + let delegation_info = cbor_value.as_array().ok_or(anyhow::anyhow!( + "Invalid delegations, should be a cbor array" + ))?; + + let voting_key = delegation_info + .get(VOTE_KEY_CBOR_KEY) + .ok_or(anyhow::anyhow!("Issue parsing delegation key"))? + .as_bytes() + .ok_or(anyhow::anyhow!("Issue parsing delegation key"))?; + + let weight = delegation_info + .get(WEIGHT_CBOR_KEY) + .ok_or(anyhow::anyhow!("Issue parsing delegation weight"))? + .as_integer() + .ok_or(anyhow::anyhow!("Issue parsing delegation weight"))? + .try_into()?; + + delegations.push(((PubKey(voting_key.clone())), weight)); + } + + VotingInfo::Delegated(delegations) + }, + + _ => return Err(anyhow::anyhow!("Missing voting info")), + }; + Ok(voting_key) +} + +/// Extract stake key +fn inspect_stake_key(cbor_map: &[(Value, Value)]) -> anyhow::Result { + /// Stake key cbor key + const STAKE_ADDRESS_CBOR_KEY: usize = 1; + + let stake_key = match cbor_map + .get(STAKE_ADDRESS_CBOR_KEY) + .ok_or(anyhow::anyhow!("Issue with stake key parsing"))? + { + (Value::Integer(_two), Value::Bytes(stake_addr)) => PubKey(stake_addr.clone()), + _ => return Err(anyhow::anyhow!("Missing stake key")), + }; + Ok(stake_key) +} + +/// Extract and validate rewards address +fn inspect_rewards_addr( + cbor_map: &[(Value, Value)], network_id: Network, +) -> anyhow::Result<&Vec> { + /// Payment address cbor key + const PAYMENT_ADDRESS_CBOR_KEY: usize = 2; + + let (Value::Integer(_three), Value::Bytes(rewards_address)) = &cbor_map + .get(PAYMENT_ADDRESS_CBOR_KEY) + .ok_or(anyhow::anyhow!("Issue with rewards address parsing"))? + else { + return Err(anyhow::anyhow!("Invalid rewards address")); + }; + + let network_prefix = rewards_address.first().ok_or(anyhow::anyhow!( + "Invalid rewards address, missing network prefix" + ))?; + if !is_valid_rewards_address(*network_prefix, network_id) { + return Err(anyhow::anyhow!("Invalid reward address")); + } + Ok(rewards_address) +} + +/// Extract Nonce +fn inspect_nonce(cbor_map: &[(Value, Value)]) -> anyhow::Result { + /// Nonce cbor key + const NONCE_CBOR_KEY: usize = 3; + + match cbor_map + .get(NONCE_CBOR_KEY) + .ok_or(anyhow::anyhow!("Issue with nonce parsing"))? + { + (Value::Integer(_four), Value::Integer(nonce)) => Ok(Nonce(i128::from(*nonce).try_into()?)), + _ => Err(anyhow::anyhow!("Missing nonce")), + } +} + +/// Extract optional voting purpose +fn inspect_voting_purpose(metamap: &[(Value, Value)]) -> anyhow::Result { + /// Voting purpose cbor key + const VOTING_PURPOSE_CBOR_KEY: usize = 4; + + // A non-negative integer that indicates the purpose of the vote. + // This is an optional field to allow for compatibility with CIP-15 + // 4 entries inside metadata map with one optional entry for the voting + // purpose + match metamap.get(VOTING_PURPOSE_CBOR_KEY) { + Some((Value::Integer(_five), Value::Integer(purpose))) => { + Ok(VotingPurpose(i128::from(*purpose).try_into()?)) + }, + Some(_) => Err(anyhow::anyhow!("Missing voting purpose")), + None => Ok(VotingPurpose::default()), + } +} + +#[cfg(test)] +#[test] +fn test_rewards_addr_permutations() { + // Valid addrs: 0x0?, 0x1?, 0x2?, 0x3?, 0x4?, 0x5?, 0x6?, 0x7?, 0xE?, 0xF?. + + let valid_addr_types = vec![0, 1, 2, 3, 4, 5, 6, 7, 14, 15]; + + for addr_type in valid_addr_types { + let test_addr = addr_type << 4; + assert!(is_valid_rewards_address(test_addr, Network::Testnet)); + assert!(!is_valid_rewards_address(test_addr, Network::Mainnet)); + + let test_addr = addr_type << 4 | 1; + assert!(!is_valid_rewards_address(test_addr, Network::Testnet)); + assert!(is_valid_rewards_address(test_addr, Network::Mainnet)); + } + + let invalid_addr_types = vec![8, 9, 10, 11, 12, 13]; + + for addr_type in invalid_addr_types { + let test_addr = addr_type << 4; + assert!(!is_valid_rewards_address(test_addr, Network::Testnet)); + assert!(!is_valid_rewards_address(test_addr, Network::Mainnet)); + + let test_addr = addr_type << 4 | 1; + assert!(!is_valid_rewards_address(test_addr, Network::Testnet)); + assert!(!is_valid_rewards_address(test_addr, Network::Mainnet)); + } +} diff --git a/catalyst-gateway/bin/src/cardano/mod.rs b/catalyst-gateway/bin/src/cardano/mod.rs index d35fc0d3941..16ec9603d71 100644 --- a/catalyst-gateway/bin/src/cardano/mod.rs +++ b/catalyst-gateway/bin/src/cardano/mod.rs @@ -14,13 +14,13 @@ use tracing::{debug, error, info}; use crate::{ cardano::util::valid_era, event_db::{ - cardano::{config::FollowerConfig, follower::MachineId}, + cardano::{chain_state::MachineId, config::FollowerConfig}, error::NotFoundError, EventDB, }, }; -pub(crate) mod registration; +pub(crate) mod cip36_registration; pub(crate) mod util; /// Returns a follower configs, waits until they present inside the db diff --git a/catalyst-gateway/bin/src/cardano/registration/61284.cddl b/catalyst-gateway/bin/src/cardano/registration/61284.cddl deleted file mode 100644 index f883f55cd13..00000000000 --- a/catalyst-gateway/bin/src/cardano/registration/61284.cddl +++ /dev/null @@ -1,33 +0,0 @@ -registration_cbor = { - 61284: key_registration, -} - -$cip36_vote_pub_key /= bytes .size 32 -$payment_address /= bytes -$nonce /= uint -$weight /= uint .size 4 -$voting_purpose /= uint -legacy_key_registration = $cip36_vote_pub_key -delegation = [$cip36_vote_pub_key, $weight] - - -$stake_credential /= $staking_pub_key -$stake_witness /= $ed25519_signature -; A stake key credential, not tagged for backward compatibility -$staking_pub_key /= bytes .size 32 -; Witness for a stake key credential, not tagged for backward compatibility -$ed25519_signature /= bytes .size 64 - - -key_registration = { - 1 : [+delegation] / legacy_key_registration, - 2 : $stake_credential, - 3 : $payment_address, - 4 : $nonce, - ? 5 : $voting_purpose .default 0 -} - - -registration_witness = { - 1 : $stake_witness -} \ No newline at end of file diff --git a/catalyst-gateway/bin/src/cardano/registration/61285.cddl b/catalyst-gateway/bin/src/cardano/registration/61285.cddl deleted file mode 100644 index 67f0d0d5f96..00000000000 --- a/catalyst-gateway/bin/src/cardano/registration/61285.cddl +++ /dev/null @@ -1,12 +0,0 @@ -registration_cbor = { - 61285: registration_witness -} - -$stake_witness /= $ed25519_signature - -; Witness for a stake key credential, not tagged for backward compatibility -$ed25519_signature /= bytes .size 64 - -registration_witness = { - 1 : $stake_witness -} \ No newline at end of file diff --git a/catalyst-gateway/bin/src/cardano/registration/mod.rs b/catalyst-gateway/bin/src/cardano/registration/mod.rs deleted file mode 100644 index 1ff5a817482..00000000000 --- a/catalyst-gateway/bin/src/cardano/registration/mod.rs +++ /dev/null @@ -1,552 +0,0 @@ -//! Verify registration TXs - -use std::io::Cursor; - -use cardano_chain_follower::Network; -use ciborium::Value; -use cryptoxide::{blake2b::Blake2b, digest::Digest}; -use pallas::ledger::{primitives::Fragment, traverse::MultiEraMeta}; -use serde::{Deserialize, Serialize}; - -/// Networks -const NETWORK_ID: usize = 0; - -/// Cip36 - 61284 entries -const KEY_61284: usize = 0; - -/// Cip36 -const STAKE_ADDRESS: usize = 1; -/// Cip36 -const PAYMENT_ADDRESS: usize = 2; -/// Cip36 -const NONCE: usize = 3; -/// Cip36 -const VOTE_PURPOSE: usize = 4; -/// Cip36 -const DELEGATIONS_OR_DIRECT: usize = 0; -/// Cip36 -const VOTE_KEY: usize = 0; -/// Cip36 -const WEIGHT: usize = 1; - -/// -const CIP36_61284: usize = 61284; -/// -const CIP36_61285: usize = 61285; - -/// Pub key -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)] -pub struct PubKey(Vec); - -/// Nonce -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)] -pub struct Nonce(pub u64); - -/// Voting purpose -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)] -pub struct VotingPurpose(u64); - -/// Rewards address -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)] -pub struct RewardsAddress(pub Vec); - -/// Error report for serializing -pub type ErrorReport = Vec; - -/// Size of a single component of an Ed25519 signature. -const COMPONENT_SIZE: usize = 32; - -/// Size of an `R` or `s` component of an Ed25519 signature when serialized -/// as bytes. -pub type ComponentBytes = [u8; COMPONENT_SIZE]; - -/// Ed25519 signature serialized as a byte array. -pub type SignatureBytes = [u8; Signature::BYTE_SIZE]; - -impl PubKey { - /// Get credentials, a blake2b 28 bytes hash of the pub key - pub(crate) fn get_credentials(&self) -> [u8; 28] { - let mut digest = [0u8; 28]; - let mut context = Blake2b::new(28); - context.input(&self.0); - context.result(&mut digest); - digest - } - - /// Get bytes - pub(crate) fn bytes(&self) -> &[u8] { - &self.0 - } -} - -/// Ed25519 signature. -/// -/// This type represents a container for the byte serialization of an Ed25519 -/// signature, and does not necessarily represent well-formed field or curve -/// elements. -/// -/// Signature verification libraries are expected to reject invalid field -/// elements at the time a signature is verified. -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -#[repr(C)] -pub struct Signature { - /// Component of an Ed25519 signature when serialized as bytes - r: ComponentBytes, - /// Component of an Ed25519 signature when serialized as bytes - s: ComponentBytes, -} - -impl Signature { - /// Size of an encoded Ed25519 signature in bytes. - pub const BYTE_SIZE: usize = COMPONENT_SIZE * 2; - - /// Parse an Ed25519 signature from a byte slice. - pub fn from_bytes(bytes: &SignatureBytes) -> Self { - let mut r = ComponentBytes::default(); - let mut s = ComponentBytes::default(); - - let components = bytes.split_at(COMPONENT_SIZE); - r.copy_from_slice(components.0); - s.copy_from_slice(components.1); - - Self { r, s } - } -} - -/// Cddl schema: -/// -pub struct CddlConfig { - /// Cip36 cddl representation - cip_36: String, -} - -impl CddlConfig { - #[must_use] - /// Create cddl config - pub fn new() -> Self { - let cip_36: String = include_str!("cip36.cddl").to_string(); - - CddlConfig { cip_36 } - } -} - -impl Default for CddlConfig { - fn default() -> Self { - Self::new() - } -} - -/// A catalyst registration on Cardano in either CIP-15 or CIP-36 format -#[derive(Debug, Clone, PartialEq)] -pub struct Registration { - /// Voting key - pub voting_key: Option, - /// Stake key - pub stake_key: Option, - /// Rewards address - pub rewards_address: Option, - /// Nonce - pub nonce: Option, - /// Optional voting purpose - pub voting_purpose: Option, - /// Raw cbor - pub raw_cbor_cip36: Option>, - /// Witness signature 61285 - pub signature: Option, -} - -/// The source of voting power for a given registration -/// -/// The voting power can either come from: -/// - a single wallet, OR -/// - a set of delegations -#[derive(Serialize, Deserialize)] -#[serde(untagged)] -#[derive(Debug, Clone, PartialEq)] -pub enum VotingInfo { - /// Direct voting - /// - /// Voting power is based on the staked ada of the given key - Direct(PubKey), - - /// Delegated voting - /// - /// Voting power is based on the staked ada of the delegated keys - /// order of elements is important and must be preserved. - Delegated(Vec<(PubKey, i64)>), -} - -impl Default for VotingInfo { - fn default() -> Self { - VotingInfo::Direct(PubKey(Vec::new())) - } -} - -/// Validate raw registration binary against 61284 CDDL spec -/// -/// # Errors -/// -/// Failure will occur if parsed keys do not match CDDL spec -pub fn validate_reg_cddl(bin_reg: &[u8], cddl_config: &CddlConfig) -> anyhow::Result<()> { - cddl::validate_cbor_from_slice(&cddl_config.cip_36, bin_reg, None)?; - - Ok(()) -} - -/// Reward addresses start with a single header byte identifying their type and the -/// network, followed by 28 bytes of payload identifying either a stake key hash or a -/// script hash. Function accepts this first header prefix byte. -/// Validates first nibble is within the address range: 0x0? - 0x7? + 0xE? , 0xF? -/// Validates second nibble matches network id: 0/1 -#[must_use] -pub fn is_valid_rewards_address(rewards_address_prefix: u8, network: Network) -> bool { - let addr_type = rewards_address_prefix >> 4 & 0xF; - let addr_net = rewards_address_prefix & 0xF; - - // 0 or 1 are valid addrs in the following cases: - // type = 0x0 - Testnet network - // type = 0x1 - Mainnet network - match network { - Network::Mainnet => { - if addr_net != 1 { - return false; - } - }, - Network::Testnet => { - if addr_net != 0 { - return false; - } - }, - _ => (), - } - - // Valid addrs: 0x0?, 0x1?, 0x2?, 0x3?, 0x4?, 0x5?, 0x6?, 0x7?, 0xE?, 0xF?. - let valid_addrs = [0, 1, 2, 3, 4, 5, 6, 7, 14, 15]; - valid_addrs.contains(&addr_type) -} - -/// Convert raw 61285 cbor to witness signature -pub fn raw_sig_conversion(raw_cbor: &[u8]) -> anyhow::Result { - let decoded: ciborium::value::Value = ciborium::de::from_reader(Cursor::new(&raw_cbor))?; - - let signature_61285 = match decoded { - Value::Map(m) => m.iter().map(|entry| entry.1.clone()).collect::>(), - _ => return Err(anyhow::anyhow!("Invalid signature {decoded:?}")), - }; - - let sig = signature_61285 - .first() - .ok_or(anyhow::anyhow!("no 61285 key"))? - .clone(); - let sig_bytes: [u8; 64] = match sig.into_bytes() { - Ok(s) => { - match s.try_into() { - Ok(sig) => sig, - Err(err) => return Err(anyhow::anyhow!("Invalid signature length {err:?}")), - } - }, - Err(err) => return Err(anyhow::anyhow!("Invalid signature parsing {err:?}")), - }; - - Ok(Signature::from_bytes(&sig_bytes)) -} - -#[allow(clippy::manual_let_else)] -/// Parse cip36 registration tx -pub fn inspect_metamap_reg(spec_61284: &[Value]) -> anyhow::Result<&Vec<(Value, Value)>> { - let metamap = match &spec_61284 - .get(KEY_61284) - .ok_or(anyhow::anyhow!("Issue parsing 61284 parent key"))? - { - Value::Map(metamap) => metamap, - _ => { - return Err(anyhow::anyhow!( - "Invalid metamap {:?}", - spec_61284 - .get(KEY_61284) - .ok_or(anyhow::anyhow!("Issue parsing metamap"))? - )) - }, - }; - Ok(metamap) -} - -#[allow(clippy::manual_let_else)] -/// Extract voting key -pub fn inspect_voting_key(metamap: &[(Value, Value)]) -> anyhow::Result { - let voting_key = match &metamap - .get(DELEGATIONS_OR_DIRECT) - .ok_or(anyhow::anyhow!("Issue with voting key 61284 cbor parsing"))? - { - (Value::Integer(_one), Value::Bytes(direct)) => VotingInfo::Direct(PubKey(direct.clone())), - (Value::Integer(_one), Value::Array(delegations)) => { - let mut delegations_map: Vec<(PubKey, i64)> = Vec::new(); - for d in delegations { - match d { - Value::Array(delegations) => { - let voting_key = match delegations - .get(VOTE_KEY) - .ok_or(anyhow::anyhow!("Issue parsing delegations"))? - .as_bytes() - { - Some(key) => key, - None => return Err(anyhow::anyhow!("Invalid voting key")), - }; - - let weight = match delegations - .get(WEIGHT) - .ok_or(anyhow::anyhow!("Issue parsing weight"))? - .as_integer() - { - Some(weight) => { - match weight.try_into() { - Ok(weight) => weight, - Err(_err) => { - return Err(anyhow::anyhow!("Invalid weight in delegation")) - }, - } - }, - None => return Err(anyhow::anyhow!("Invalid delegation")), - }; - - delegations_map.push(((PubKey(voting_key.clone())), weight)); - }, - - _ => return Err(anyhow::anyhow!("Invalid voting key")), - } - } - - VotingInfo::Delegated(delegations_map) - }, - - _ => return Err(anyhow::anyhow!("Invalid signature")), - }; - Ok(voting_key) -} - -/// Extract stake key -pub fn inspect_stake_key(metamap: &[(Value, Value)]) -> anyhow::Result { - let stake_key = match &metamap - .get(STAKE_ADDRESS) - .ok_or(anyhow::anyhow!("Issue with stake key parsing"))? - { - (Value::Integer(_two), Value::Bytes(stake_addr)) => PubKey(stake_addr.clone()), - _ => return Err(anyhow::anyhow!("Invalid stake key")), - }; - Ok(stake_key) -} - -/// Extract and validate rewards address -pub fn inspect_rewards_addr( - metamap: &[(Value, Value)], network_id: Network, -) -> anyhow::Result<&Vec> { - let (Value::Integer(_three), Value::Bytes(rewards_address)) = &metamap - .get(PAYMENT_ADDRESS) - .ok_or(anyhow::anyhow!("Issue with rewards address parsing"))? - else { - return Err(anyhow::anyhow!("Invalid rewards address")); - }; - - if !is_valid_rewards_address( - *rewards_address - .get(NETWORK_ID) - .ok_or(anyhow::anyhow!("Cannot get network id byte"))?, - network_id, - ) { - return Err(anyhow::anyhow!("Invalid reward address")); - } - Ok(rewards_address) -} - -/// Extract Nonce -pub fn inspect_nonce(metamap: &[(Value, Value)]) -> anyhow::Result { - let nonce: i128 = match metamap - .get(NONCE) - .ok_or(anyhow::anyhow!("Issue with nonce parsing"))? - { - (Value::Integer(_four), Value::Integer(nonce)) => i128::from(*nonce), - _ => return Err(anyhow::anyhow!("Invalid nonce")), - }; - - Ok(Nonce(nonce.try_into()?)) -} - -/// Extract optional voting purpose -pub fn inspect_voting_purpose(metamap: &[(Value, Value)]) -> anyhow::Result> { - if metamap.len() == 5 { - match metamap - .get(VOTE_PURPOSE) - .ok_or(anyhow::anyhow!("Issue with voting purpose parsing"))? - { - (Value::Integer(_five), Value::Integer(purpose)) => { - Ok(Some(VotingPurpose(i128::from(*purpose).try_into()?))) - }, - _ => Ok(None), - } - } else { - Ok(None) - } -} - -/// Extract registrations information for TX metadata -/// Collect secondary errors for granular json error report -pub fn parse_registrations_from_metadata( - meta: &MultiEraMeta, network: Network, -) -> anyhow::Result<(Registration, ErrorReport)> { - let mut voting_key: Option = None; - let mut stake_key: Option = None; - let mut voting_purpose: Option = None; - let mut rewards_address: Option = None; - let mut nonce: Option = None; - let mut raw_cbor_cip36: Option> = None; - let mut sig: Option = None; - - let mut errors_report = Vec::new(); - - if let pallas::ledger::traverse::MultiEraMeta::AlonzoCompatible(meta) = meta { - for (key, cip36_registration) in meta.iter() { - if *key == u64::try_from(CIP36_61284)? { - let raw_cbor = meta.encode_fragment().map_err(|e| anyhow::anyhow!("{e}"))?; - raw_cbor_cip36 = Some(raw_cbor.clone()); - - let decoded: ciborium::value::Value = - ciborium::de::from_reader(Cursor::new(&raw_cbor))?; - - let meta_61284 = if let Value::Map(m) = decoded { - m.iter().map(|entry| entry.1.clone()).collect::>() - } else { - errors_report.push(format!("61284 parent cddl invalid {decoded:?}")); - continue; - }; - - // 4 entries inside metadata map with one optional entry for the voting purpose - let metamap = match inspect_metamap_reg(&meta_61284) { - Ok(value) => value, - Err(err) => { - errors_report - .push(format!("61284 child cddl invalid {raw_cbor:?} {err:?}")); - continue; - }, - }; - - // voting key: simply an ED25519 public key. This is the spending credential in the - // side chain that will receive voting power from this delegation. - // For direct voting it's necessary to have the corresponding private key to cast - // votes in the side chain - voting_key = inspect_voting_key(metamap).map_or_else( - |err| { - errors_report.push(format!("Invalid voting key {raw_cbor:?} {err:?}")); - None - }, - Some, - ); - - // A stake address for the network that this transaction is submitted to (to point - // to the Ada that is being delegated); - stake_key = inspect_stake_key(metamap).map_or_else( - |err| { - errors_report.push(format!("Invalid stake key {raw_cbor:?} {err:?}")); - None - }, - Some, - ); - - // A Shelley payment address (see CIP-0019) discriminated for the same network - // this transaction is submitted to, to receive rewards. - rewards_address = inspect_rewards_addr(metamap, network).map_or_else( - |err| { - errors_report.push(format!("Invalid rewards address {raw_cbor:?} {err:?}")); - None - }, - |val| Some(RewardsAddress(val.clone())), - ); - - // A nonce that identifies that most recent delegation - nonce = inspect_nonce(metamap).map_or_else( - |err| { - errors_report.push(format!("Invalid nonce {raw_cbor:?} {err:?}")); - None - }, - Some, - ); - - // A non-negative integer that indicates the purpose of the vote. - // This is an optional field to allow for compatibility with CIP-15 - // 4 entries inside metadata map with one optional entry for the voting purpose - match inspect_voting_purpose(metamap) { - Ok(Some(value)) => voting_purpose = Some(value), - Ok(None) => voting_purpose = None, - Err(err) => { - voting_purpose = None; - errors_report.push(format!("Invalid voting purpose {raw_cbor:?} {err:?}")); - }, - }; - } else if *key == u64::try_from(CIP36_61285)? { - // Validate 61285 signature - let raw_cbor = cip36_registration - .encode_fragment() - .map_err(|e| anyhow::anyhow!("{e}"))?; - - match raw_sig_conversion( - &cip36_registration - .encode_fragment() - .map_err(|e| anyhow::anyhow!("{e}"))?, - ) { - Ok(signature) => { - sig = Some(signature); - }, - Err(err) => { - errors_report.push(format!( - "Invalid signature. cbor: {:?} {:?}", - hex::encode(raw_cbor), - err - )); - sig = None; - }, - }; - } - } - }; - - let r = Registration { - voting_key, - stake_key, - rewards_address, - nonce, - voting_purpose, - raw_cbor_cip36, - signature: sig, - }; - - Ok((r, errors_report)) -} - -#[cfg(test)] -#[test] -pub fn test_rewards_addr_permutations() { - // Valid addrs: 0x0?, 0x1?, 0x2?, 0x3?, 0x4?, 0x5?, 0x6?, 0x7?, 0xE?, 0xF?. - - let valid_addr_types = vec![0, 1, 2, 3, 4, 5, 6, 7, 14, 15]; - - for addr_type in valid_addr_types { - let test_addr = addr_type << 4; - assert!(is_valid_rewards_address(test_addr, Network::Testnet)); - assert!(!is_valid_rewards_address(test_addr, Network::Mainnet)); - - let test_addr = addr_type << 4 | 1; - assert!(!is_valid_rewards_address(test_addr, Network::Testnet)); - assert!(is_valid_rewards_address(test_addr, Network::Mainnet)); - } - - let invalid_addr_types = vec![8, 9, 10, 11, 12, 13]; - - for addr_type in invalid_addr_types { - let test_addr = addr_type << 4; - assert!(!is_valid_rewards_address(test_addr, Network::Testnet)); - assert!(!is_valid_rewards_address(test_addr, Network::Mainnet)); - - let test_addr = addr_type << 4 | 1; - assert!(!is_valid_rewards_address(test_addr, Network::Testnet)); - assert!(!is_valid_rewards_address(test_addr, Network::Mainnet)); - } -} diff --git a/catalyst-gateway/bin/src/event_db/cardano/follower/insert_slot_index.sql b/catalyst-gateway/bin/src/event_db/cardano/chain_state/insert_slot_index.sql similarity index 100% rename from catalyst-gateway/bin/src/event_db/cardano/follower/insert_slot_index.sql rename to catalyst-gateway/bin/src/event_db/cardano/chain_state/insert_slot_index.sql diff --git a/catalyst-gateway/bin/src/event_db/cardano/follower/insert_update_state.sql b/catalyst-gateway/bin/src/event_db/cardano/chain_state/insert_update_state.sql similarity index 100% rename from catalyst-gateway/bin/src/event_db/cardano/follower/insert_update_state.sql rename to catalyst-gateway/bin/src/event_db/cardano/chain_state/insert_update_state.sql diff --git a/catalyst-gateway/bin/src/event_db/cardano/follower/mod.rs b/catalyst-gateway/bin/src/event_db/cardano/chain_state/mod.rs similarity index 100% rename from catalyst-gateway/bin/src/event_db/cardano/follower/mod.rs rename to catalyst-gateway/bin/src/event_db/cardano/chain_state/mod.rs diff --git a/catalyst-gateway/bin/src/event_db/cardano/follower/select_slot_info_by_datetime.sql.hbs b/catalyst-gateway/bin/src/event_db/cardano/chain_state/select_slot_info_by_datetime.sql.hbs similarity index 100% rename from catalyst-gateway/bin/src/event_db/cardano/follower/select_slot_info_by_datetime.sql.hbs rename to catalyst-gateway/bin/src/event_db/cardano/chain_state/select_slot_info_by_datetime.sql.hbs diff --git a/catalyst-gateway/bin/src/event_db/cardano/follower/select_update_state.sql b/catalyst-gateway/bin/src/event_db/cardano/chain_state/select_update_state.sql similarity index 100% rename from catalyst-gateway/bin/src/event_db/cardano/follower/select_update_state.sql rename to catalyst-gateway/bin/src/event_db/cardano/chain_state/select_update_state.sql diff --git a/catalyst-gateway/bin/src/event_db/cardano/voter_registration/insert_voter_registration.sql b/catalyst-gateway/bin/src/event_db/cardano/cip36_registration/insert_cip36_registration.sql similarity index 100% rename from catalyst-gateway/bin/src/event_db/cardano/voter_registration/insert_voter_registration.sql rename to catalyst-gateway/bin/src/event_db/cardano/cip36_registration/insert_cip36_registration.sql diff --git a/catalyst-gateway/bin/src/event_db/cardano/voter_registration/mod.rs b/catalyst-gateway/bin/src/event_db/cardano/cip36_registration/mod.rs similarity index 61% rename from catalyst-gateway/bin/src/event_db/cardano/voter_registration/mod.rs rename to catalyst-gateway/bin/src/event_db/cardano/cip36_registration/mod.rs index 70fef492d2b..7e11da03a32 100644 --- a/catalyst-gateway/bin/src/event_db/cardano/voter_registration/mod.rs +++ b/catalyst-gateway/bin/src/event_db/cardano/cip36_registration/mod.rs @@ -5,10 +5,8 @@ use pallas::ledger::traverse::MultiEraTx; use serde_json::json; use crate::{ - cardano::registration::{ - parse_registrations_from_metadata, validate_reg_cddl, CddlConfig, ErrorReport, VotingInfo, - }, - event_db::{cardano::follower::SlotNumber, error::NotFoundError, EventDB}, + cardano::cip36_registration::{Cip36Registration, ErrorReport, VotingInfo}, + event_db::{cardano::chain_state::SlotNumber, error::NotFoundError, EventDB}, }; /// Transaction id @@ -36,22 +34,22 @@ const PUBLIC_VOTING_KEY_COLUMN: &str = "public_voting_key"; const NONCE_COLUMN: &str = "nonce"; /// `insert_voter_registration.sql` -const INSERT_VOTER_REGISTRATION_SQL: &str = include_str!("insert_voter_registration.sql"); +const INSERT_VOTER_REGISTRATION_SQL: &str = include_str!("insert_cip36_registration.sql"); /// `select_voter_registration.sql` -const SELECT_VOTER_REGISTRATION_SQL: &str = include_str!("select_voter_registration.sql"); +const SELECT_VOTER_REGISTRATION_SQL: &str = include_str!("select_cip36_registration.sql"); impl EventDB { /// Inserts voter registration data, replacing any existing data. #[allow(clippy::too_many_arguments)] async fn insert_voter_registration( &self, tx_id: TxId, stake_credential: Option, - public_voting_key: Option, payment_address: Option, + voting_info: Option, payment_address: Option, metadata_cip36: Option, nonce: Option, errors_report: ErrorReport, ) -> anyhow::Result<()> { let conn = self.pool.get().await?; // for the catalyst we dont support multiple delegations - let multiple_delegations = public_voting_key.as_ref().is_some_and(|voting_info| { + let multiple_delegations = voting_info.as_ref().is_some_and(|voting_info| { if let PublicVotingInfo::Delegated(delegations) = voting_info { delegations.len() > 1 } else { @@ -59,9 +57,9 @@ impl EventDB { } }); - let encoded_voting_key = if let Some(voting_key) = public_voting_key { + let encoded_voting_info = if let Some(voting_info) = voting_info { Some( - serde_json::to_string(&voting_key) + serde_json::to_string(&voting_info) .map_err(|_| anyhow::anyhow!("Cannot encode voting key".to_string()))? .as_bytes() .to_vec(), @@ -72,7 +70,7 @@ impl EventDB { let is_valid = !multiple_delegations && stake_credential.is_some() - && encoded_voting_key.is_some() + && encoded_voting_info.is_some() && payment_address.is_some() && metadata_cip36.is_some() && nonce.is_some() @@ -82,7 +80,7 @@ impl EventDB { .query(INSERT_VOTER_REGISTRATION_SQL, &[ &tx_id, &stake_credential, - &encoded_voting_key, + &encoded_voting_info, &payment_address, &nonce, &metadata_cip36, @@ -98,52 +96,24 @@ impl EventDB { pub(crate) async fn index_registration_data( &self, tx: &MultiEraTx<'_>, network: Network, ) -> anyhow::Result<()> { - let cddl = CddlConfig::new(); - - if !tx.metadata().is_empty() { - let (registration, errors_report) = - match parse_registrations_from_metadata(&tx.metadata(), network) { - Ok(registration) => registration, - Err(_err) => { - // fatal error parsing registration tx, unable to extract meaningful - // errors assume corrupted tx - return Ok(()); - }, - }; - - // cddl verification - if let Some(cip36) = registration.clone().raw_cbor_cip36 { - match validate_reg_cddl(&cip36, &cddl) { - Ok(()) => (), - Err(_err) => { - // did not pass cddl verification, not a valid registration - return Ok(()); - }, - }; - } else { - // registration does not contain cip36 61284 or 61285 keys - // not a valid registration tx - return Ok(()); - } + let Some(registration) = + Cip36Registration::generate_from_tx_metadata(&tx.metadata(), network) + else { + return Ok(()); + }; - let nonce = if let Some(nonce) = registration.nonce { - Some(nonce.0.try_into()?) - } else { - None - }; - self.insert_voter_registration( - tx.hash().to_vec(), - registration - .stake_key - .map(|val| val.get_credentials().to_vec()), - registration.voting_key, - registration.rewards_address.map(|val| val.0), - registration.raw_cbor_cip36, - nonce, - errors_report, - ) - .await?; - } + self.insert_voter_registration( + tx.hash().to_vec(), + registration + .stake_key + .map(|val| val.get_credentials().to_vec()), + registration.voting_info, + registration.rewards_address.map(|val| val.0), + registration.raw_metadata, + registration.nonce.map(|nonce| nonce.0), + registration.errors_report, + ) + .await?; Ok(()) } diff --git a/catalyst-gateway/bin/src/event_db/cardano/voter_registration/select_voter_registration.sql b/catalyst-gateway/bin/src/event_db/cardano/cip36_registration/select_cip36_registration.sql similarity index 100% rename from catalyst-gateway/bin/src/event_db/cardano/voter_registration/select_voter_registration.sql rename to catalyst-gateway/bin/src/event_db/cardano/cip36_registration/select_cip36_registration.sql diff --git a/catalyst-gateway/bin/src/event_db/cardano/mod.rs b/catalyst-gateway/bin/src/event_db/cardano/mod.rs index 350e100acfc..26511bbf432 100644 --- a/catalyst-gateway/bin/src/event_db/cardano/mod.rs +++ b/catalyst-gateway/bin/src/event_db/cardano/mod.rs @@ -1,6 +1,6 @@ //! Cardano db functionality +pub(crate) mod chain_state; +pub(crate) mod cip36_registration; pub(crate) mod config; -pub(crate) mod follower; pub(crate) mod utxo; -pub(crate) mod voter_registration; diff --git a/catalyst-gateway/bin/src/event_db/cardano/utxo/mod.rs b/catalyst-gateway/bin/src/event_db/cardano/utxo/mod.rs index b93df978c43..54284a1d20c 100644 --- a/catalyst-gateway/bin/src/event_db/cardano/utxo/mod.rs +++ b/catalyst-gateway/bin/src/event_db/cardano/utxo/mod.rs @@ -3,7 +3,7 @@ use cardano_chain_follower::Network; use pallas::ledger::{addresses::Address, traverse::MultiEraTx}; -use super::{follower::SlotNumber, voter_registration::StakeCredential}; +use super::{chain_state::SlotNumber, cip36_registration::StakeCredential}; use crate::{ cardano::util::parse_policy_assets, event_db::{error::NotFoundError, EventDB}, diff --git a/catalyst-gateway/bin/src/service/api/cardano/date_time_to_slot_number_get.rs b/catalyst-gateway/bin/src/service/api/cardano/date_time_to_slot_number_get.rs index 1bd4957ec62..fb053fd812e 100644 --- a/catalyst-gateway/bin/src/service/api/cardano/date_time_to_slot_number_get.rs +++ b/catalyst-gateway/bin/src/service/api/cardano/date_time_to_slot_number_get.rs @@ -5,7 +5,7 @@ use poem_openapi::payload::Json; use crate::{ event_db::{ - cardano::follower::{BlockHash, DateTime, SlotInfoQueryType, SlotNumber}, + cardano::chain_state::{BlockHash, DateTime, SlotInfoQueryType, SlotNumber}, error::NotFoundError, }, service::common::{ diff --git a/catalyst-gateway/bin/src/service/api/cardano/mod.rs b/catalyst-gateway/bin/src/service/api/cardano/mod.rs index a7fd8569de1..680a67c328a 100644 --- a/catalyst-gateway/bin/src/service/api/cardano/mod.rs +++ b/catalyst-gateway/bin/src/service/api/cardano/mod.rs @@ -9,7 +9,7 @@ use poem_openapi::{ }; use crate::{ - event_db::cardano::follower::{DateTime, SlotNumber}, + event_db::cardano::chain_state::{DateTime, SlotNumber}, service::{ common::{ objects::cardano::{network::Network, stake_address::StakeAddress}, diff --git a/catalyst-gateway/bin/src/service/api/cardano/registration_get.rs b/catalyst-gateway/bin/src/service/api/cardano/registration_get.rs index 08f83490975..a6d3e0f11f7 100644 --- a/catalyst-gateway/bin/src/service/api/cardano/registration_get.rs +++ b/catalyst-gateway/bin/src/service/api/cardano/registration_get.rs @@ -7,7 +7,7 @@ use poem_extensions::{ use poem_openapi::payload::Json; use crate::{ - event_db::{cardano::follower::SlotNumber, error::NotFoundError}, + event_db::{cardano::chain_state::SlotNumber, error::NotFoundError}, service::{ common::{ objects::cardano::{ diff --git a/catalyst-gateway/bin/src/service/api/cardano/staked_ada_get.rs b/catalyst-gateway/bin/src/service/api/cardano/staked_ada_get.rs index b75e1d0ac4e..c06fca9d924 100644 --- a/catalyst-gateway/bin/src/service/api/cardano/staked_ada_get.rs +++ b/catalyst-gateway/bin/src/service/api/cardano/staked_ada_get.rs @@ -7,7 +7,7 @@ use poem_extensions::{ use poem_openapi::payload::Json; use crate::{ - event_db::{cardano::follower::SlotNumber, error::NotFoundError}, + event_db::{cardano::chain_state::SlotNumber, error::NotFoundError}, service::{ common::{ objects::cardano::{ diff --git a/catalyst-gateway/bin/src/service/common/objects/cardano/registration_info.rs b/catalyst-gateway/bin/src/service/common/objects/cardano/registration_info.rs index a6161769483..581b0fe7506 100644 --- a/catalyst-gateway/bin/src/service/common/objects/cardano/registration_info.rs +++ b/catalyst-gateway/bin/src/service/common/objects/cardano/registration_info.rs @@ -3,7 +3,7 @@ use poem_openapi::{types::Example, Object, Union}; use crate::{ - event_db::cardano::voter_registration::{Nonce, PaymentAddress, PublicVotingInfo, TxId}, + event_db::cardano::cip36_registration::{Nonce, PaymentAddress, PublicVotingInfo, TxId}, service::{common::objects::cardano::hash::Hash, utilities::to_hex_with_prefix}, }; diff --git a/catalyst-gateway/bin/src/service/common/objects/cardano/slot_info.rs b/catalyst-gateway/bin/src/service/common/objects/cardano/slot_info.rs index 13f668b9b1a..2578d8e38a8 100644 --- a/catalyst-gateway/bin/src/service/common/objects/cardano/slot_info.rs +++ b/catalyst-gateway/bin/src/service/common/objects/cardano/slot_info.rs @@ -3,7 +3,7 @@ use poem_openapi::{types::Example, Object}; use crate::{ - event_db::cardano::follower::{DateTime, SlotNumber}, + event_db::cardano::chain_state::{DateTime, SlotNumber}, service::common::objects::cardano::hash::Hash, }; diff --git a/catalyst-gateway/bin/src/service/common/objects/cardano/stake_info.rs b/catalyst-gateway/bin/src/service/common/objects/cardano/stake_info.rs index ff9460de3fb..bff2f734896 100644 --- a/catalyst-gateway/bin/src/service/common/objects/cardano/stake_info.rs +++ b/catalyst-gateway/bin/src/service/common/objects/cardano/stake_info.rs @@ -2,7 +2,7 @@ use poem_openapi::{types::Example, Object}; -use crate::event_db::cardano::{follower::SlotNumber, utxo::StakeAmount}; +use crate::event_db::cardano::{chain_state::SlotNumber, utxo::StakeAmount}; /// User's cardano stake info. #[derive(Object)] diff --git a/catalyst-gateway/bin/src/service/common/objects/cardano/sync_state.rs b/catalyst-gateway/bin/src/service/common/objects/cardano/sync_state.rs index 512d2586cc3..d736775dc2a 100644 --- a/catalyst-gateway/bin/src/service/common/objects/cardano/sync_state.rs +++ b/catalyst-gateway/bin/src/service/common/objects/cardano/sync_state.rs @@ -3,7 +3,7 @@ use poem_openapi::{types::Example, Object}; use crate::{ - event_db::cardano::follower::{DateTime, SlotNumber}, + event_db::cardano::chain_state::{DateTime, SlotNumber}, service::common::objects::cardano::hash::Hash, };