From bc4bfff0ca1893e1d727996e5219b1be532d7aa1 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Thu, 19 Dec 2024 10:10:46 +0700 Subject: [PATCH 01/40] fix(cardano-chain-follower): use Network, MultiEraBlock, Point from cardano-blockchain-types Signed-off-by: bkioshn --- rust/cardano-chain-follower/Cargo.toml | 1 + rust/cardano-chain-follower/src/chain_sync.rs | 58 +- .../src/chain_sync_config.rs | 2 +- .../src/chain_sync_live_chains.rs | 36 +- .../src/chain_sync_ready.rs | 3 +- .../src/chain_update.rs | 3 +- rust/cardano-chain-follower/src/error.rs | 3 +- rust/cardano-chain-follower/src/follow.rs | 57 +- rust/cardano-chain-follower/src/lib.rs | 6 - .../src/mithril_query.rs | 6 +- .../src/mithril_snapshot.rs | 3 +- .../src/mithril_snapshot_config.rs | 6 +- .../src/mithril_snapshot_data.rs | 3 +- .../src/mithril_snapshot_iterator.rs | 20 +- .../src/mithril_snapshot_sync.rs | 3 +- .../src/multi_era_block_data.rs | 744 ------------------ rust/cardano-chain-follower/src/network.rs | 396 ---------- rust/cardano-chain-follower/src/point.rs | 590 -------------- .../cardano-chain-follower/src/snapshot_id.rs | 24 +- rust/cardano-chain-follower/src/stats.rs | 3 +- 20 files changed, 114 insertions(+), 1853 deletions(-) delete mode 100644 rust/cardano-chain-follower/src/multi_era_block_data.rs delete mode 100644 rust/cardano-chain-follower/src/network.rs delete mode 100644 rust/cardano-chain-follower/src/point.rs diff --git a/rust/cardano-chain-follower/Cargo.toml b/rust/cardano-chain-follower/Cargo.toml index 5114ea2ff..9e112b64c 100644 --- a/rust/cardano-chain-follower/Cargo.toml +++ b/rust/cardano-chain-follower/Cargo.toml @@ -21,6 +21,7 @@ mithril-client = { version = "0.10.4", default-features = false, features = [ ] } rbac-registration = { version = "0.0.2", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "v0.0.8" } +cardano-blockchain-types = { git = "https://github.com/input-output-hk/catalyst-libs.git", branch = "feat/cardano-blockchain-types" } thiserror = "1.0.64" tokio = { version = "1.40.0", features = [ diff --git a/rust/cardano-chain-follower/src/chain_sync.rs b/rust/cardano-chain-follower/src/chain_sync.rs index 779efcc0f..fef5fe334 100644 --- a/rust/cardano-chain-follower/src/chain_sync.rs +++ b/rust/cardano-chain-follower/src/chain_sync.rs @@ -6,6 +6,7 @@ use std::time::Duration; use anyhow::Context; +use cardano_blockchain_types::{Fork, MultiEraBlock, Network, Point}; use pallas::{ ledger::traverse::MultiEraHeader, network::{ @@ -32,8 +33,7 @@ use crate::{ error::{Error, Result}, mithril_snapshot_config::MithrilUpdateMessage, mithril_snapshot_data::latest_mithril_snapshot_id, - point::{TIP_POINT, UNKNOWN_POINT}, - stats, ChainSyncConfig, MultiEraBlock, Network, Point, ORIGIN_POINT, + stats, ChainSyncConfig, }; /// The maximum number of seconds we wait for a node to connect. @@ -88,7 +88,7 @@ async fn retry_connect( /// Purge the live chain, and intersect with TIP. async fn purge_and_intersect_tip(client: &mut PeerClient, chain: Network) -> Result { - if let Err(error) = purge_live_chain(chain, &TIP_POINT) { + if let Err(error) = purge_live_chain(chain, &Point::TIP) { // Shouldn't happen. error!("failed to purge live chain: {error}"); } @@ -122,7 +122,7 @@ async fn resync_live_tip(client: &mut PeerClient, chain: Network) -> Result anyhow::Result { let block_data = peer .blockfetch() @@ -130,8 +130,8 @@ async fn fetch_block_from_peer( .await .with_context(|| "Fetching block data")?; - debug!("{chain}, {previous_point}, {fork_count}"); - let live_block_data = MultiEraBlock::new(chain, block_data, &previous_point, fork_count)?; + debug!("{chain}, {previous_point}, {fork:?}"); + let live_block_data = MultiEraBlock::new(chain, block_data, &previous_point, fork)?; Ok(live_block_data) } @@ -141,7 +141,7 @@ async fn fetch_block_from_peer( /// Fetch the rollback block, and try and insert it into the live-chain. /// If its a real rollback, it will purge the chain ahead of the block automatically. async fn process_rollback_actual( - peer: &mut PeerClient, chain: Network, point: Point, tip: &Tip, fork_count: &mut u64, + peer: &mut PeerClient, chain: Network, point: Point, tip: &Tip, fork: &mut Fork, ) -> anyhow::Result { debug!("RollBackward: {:?} {:?}", point, tip); @@ -149,8 +149,8 @@ async fn process_rollback_actual( // rest of live chain tip. And increments the fork count. if let Some(mut block) = get_live_block(chain, &point, 0, true) { // Even though we are re-adding the known block, increase the fork count. - block.set_fork(*fork_count); - live_chain_add_block_to_tip(chain, block, fork_count, tip.0.clone().into())?; + block.set_fork(*fork); + live_chain_add_block_to_tip(chain, block, fork, tip.0.clone().into())?; return Ok(point); } @@ -165,7 +165,7 @@ async fn process_rollback_actual( let previous_point = if let Some(previous_block) = previous_block { let previous = previous_block.previous(); debug!("Previous block: {:?}", previous); - if previous == ORIGIN_POINT { + if previous == Point::ORIGIN { latest_mithril_snapshot_id(chain).tip() } else { previous @@ -175,9 +175,8 @@ async fn process_rollback_actual( latest_mithril_snapshot_id(chain).tip() }; debug!("Previous point: {:?}", previous_point); - let block = - fetch_block_from_peer(peer, chain, point.clone(), previous_point, *fork_count).await?; - live_chain_add_block_to_tip(chain, block, fork_count, tip.0.clone().into())?; + let block = fetch_block_from_peer(peer, chain, point.clone(), previous_point, *fork).await?; + live_chain_add_block_to_tip(chain, block, fork, tip.0.clone().into())?; // Next block we receive is a rollback. Ok(point) @@ -186,7 +185,7 @@ async fn process_rollback_actual( /// Process a rollback detected from the peer. async fn process_rollback( peer: &mut PeerClient, chain: Network, point: Point, tip: &Tip, previous_point: &Point, - fork_count: &mut u64, + fork: &mut Fork, ) -> anyhow::Result { let rollback_slot = point.slot_or_default(); let head_slot = previous_point.slot_or_default(); @@ -199,7 +198,7 @@ async fn process_rollback( }; // We actually do the work here... - let response = process_rollback_actual(peer, chain, point, tip, fork_count).await?; + let response = process_rollback_actual(peer, chain, point, tip, fork).await?; // We never really know how many blocks are rolled back when advised by the peer, but we // can work out how many slots. This function wraps the real work, so we can properly @@ -212,7 +211,7 @@ async fn process_rollback( /// Process a rollback detected from the peer. async fn process_next_block( peer: &mut PeerClient, chain: Network, header: HeaderContent, tip: &Tip, - previous_point: &Point, fork_count: &mut u64, + previous_point: &Point, fork: &mut Fork, ) -> anyhow::Result { // Decode the Header of the block so we know what to fetch. let decoded_header = MultiEraHeader::decode( @@ -222,7 +221,7 @@ async fn process_next_block( ) .with_context(|| "Decoding Block Header")?; - let block_point = Point::new(decoded_header.slot(), decoded_header.hash().to_vec()); + let block_point = Point::new(decoded_header.slot().into(), decoded_header.hash().into()); debug!("RollForward: {block_point:?} {tip:?}"); @@ -231,7 +230,7 @@ async fn process_next_block( chain, block_point.clone(), previous_point.clone(), - *fork_count, + *fork, ) .await?; @@ -239,12 +238,12 @@ async fn process_next_block( // We can't store this block because we don't know the previous one so the chain // would break, so just use it for previous. - if *previous_point == UNKNOWN_POINT { + if *previous_point == Point::UNKNOWN { // Nothing else we can do with the first block when we don't know the previous // one. Just return it's point. debug!("Not storing the block, because we did not know the previous point."); } else { - live_chain_add_block_to_tip(chain, block, fork_count, tip.0.clone().into())?; + live_chain_add_block_to_tip(chain, block, fork, tip.0.clone().into())?; } Ok(block_point) @@ -255,10 +254,10 @@ async fn process_next_block( /// /// We take ownership of the client because of that. async fn follow_chain( - peer: &mut PeerClient, chain: Network, fork_count: &mut u64, + peer: &mut PeerClient, chain: Network, fork: &mut Fork, ) -> anyhow::Result<()> { let mut update_sender = get_chain_update_tx_queue(chain).await; - let mut previous_point = UNKNOWN_POINT; + let mut previous_point = Point::UNKNOWN; loop { // debug!("Waiting for data from Cardano Peer Node:"); @@ -286,8 +285,7 @@ async fn follow_chain( // subtracting current block height and the tip block height. // IF the TIP is <= the current block height THEN we are at tip. previous_point = - process_next_block(peer, chain, header, &tip, &previous_point, fork_count) - .await?; + process_next_block(peer, chain, header, &tip, &previous_point, fork).await?; // This update is just for followers to know to look again at their live chains for // new data. @@ -295,7 +293,7 @@ async fn follow_chain( }, chainsync::NextResponse::RollBackward(point, tip) => { previous_point = - process_rollback(peer, chain, point.into(), &tip, &previous_point, fork_count) + process_rollback(peer, chain, point.into(), &tip, &previous_point, fork) .await?; // This update is just for followers to know to look again at their live chains for // new data. @@ -367,8 +365,8 @@ async fn live_sync_backfill( while let Some(block_data) = peer.blockfetch().recv_while_streaming().await? { // Backfilled blocks get placed in the oldest fork currently on the live-chain. - let block = - MultiEraBlock::new(cfg.chain, block_data, &previous_point, 1).with_context(|| { + let block = MultiEraBlock::new(cfg.chain, block_data, &previous_point, 1.into()) + .with_context(|| { format!( "Failed to decode block data. previous: {previous_point:?}, range: {range_msg}" ) @@ -533,7 +531,7 @@ pub(crate) async fn chain_sync(cfg: ChainSyncConfig, rx: mpsc::Receiver> = La static PEER_TIP: LazyLock> = LazyLock::new(|| { let map = SkipMap::new(); for network in Network::iter() { - map.insert(network, UNKNOWN_POINT); + map.insert(network, Point::UNKNOWN); } map }); @@ -52,7 +52,7 @@ fn update_peer_tip(chain: Network, tip: Point) { /// Set the last TIP received from the peer. pub(crate) fn get_peer_tip(chain: Network) -> Point { - (*PEER_TIP.get_or_insert(chain, UNKNOWN_POINT).value()).clone() + (*PEER_TIP.get_or_insert(chain, Point::UNKNOWN).value()).clone() } /// Number of seconds to wait if we detect a `SyncReady` race condition. @@ -122,7 +122,7 @@ impl ProtectedLiveChainBlockList { let Some(check_last_live_entry) = live_chain.back() else { // Its not an error if we can't get a latest block because the chain is empty, // so report that we don't know... - return UNKNOWN_POINT; + return Point::UNKNOWN; }; let check_last_live_block = check_last_live_entry.value(); check_last_live_block.point() @@ -192,7 +192,7 @@ impl ProtectedLiveChainBlockList { /// would be lost due to rollback. Will REFUSE to add a block which does NOT have /// a proper "previous" point defined. fn add_block_to_tip( - &self, chain: Network, block: MultiEraBlock, fork_count: &mut u64, tip: Point, + &self, chain: Network, block: MultiEraBlock, fork: &mut Fork, tip: Point, ) -> Result<()> { let live_chain = self.0.write().map_err(|_| Error::Internal)?; @@ -202,11 +202,11 @@ impl ProtectedLiveChainBlockList { let last_live_point = Self::get_last_live_point(&live_chain); if !previous_point.strict_eq(&last_live_point) { // Detected a rollback, so increase the fork count. - *fork_count += 1; + fork.incr(); let mut rollback_size: u64 = 0; // We are NOT contiguous, so check if we can become contiguous with a rollback. - debug!("Detected non-contiguous block, rolling back. Fork: {fork_count}"); + debug!("Detected non-contiguous block, rolling back. Fork: {fork:?}"); // First check if the previous is >= the earliest block in the live chain. // This is because when we start syncing we could rollback earlier than our @@ -265,7 +265,7 @@ impl ProtectedLiveChainBlockList { // Ensures we are properly connected to the Mithril Chain. // But don't check this if we are about to purge the entire chain. // We do this before we bother locking the chain for update. - if *point != TIP_POINT { + if *point != Point::TIP { let latest_mithril_tip = latest_mithril_snapshot_id(chain).tip(); if !point.strict_eq(&latest_mithril_tip) { return Err(Error::LiveSync(format!( @@ -278,7 +278,7 @@ impl ProtectedLiveChainBlockList { // Special Case. // If the Purge Point == TIP_POINT, then we purge the entire chain. - if *point == TIP_POINT { + if *point == Point::TIP { live_chain.clear(); } else { // If the block we want to purge upto must be in the chain. @@ -345,7 +345,7 @@ impl ProtectedLiveChainBlockList { // Loop until we exhaust probe slots, OR we would step past genesis. while slot_age < reference_slot { - let ref_point = Point::fuzzy(reference_slot - slot_age); + let ref_point = Point::fuzzy((reference_slot - slot_age).into()); let Some(entry) = chain.lower_bound(Bound::Included(&ref_point)) else { break; }; @@ -363,7 +363,7 @@ impl ProtectedLiveChainBlockList { /// Given a known point on the live chain, and a fork count, find the best block we /// have. fn find_best_fork_block( - &self, point: &Point, previous_point: &Point, fork: u64, + &self, point: &Point, previous_point: &Point, fork: Fork, ) -> Option<(MultiEraBlock, u64)> { let mut rollback_depth: u64 = 0; let Ok(chain) = self.0.read() else { @@ -371,7 +371,7 @@ impl ProtectedLiveChainBlockList { }; // Get the block <= the current slot. - let ref_point = Point::fuzzy(point.slot_or_default()); + let ref_point = Point::fuzzy(point.slot_or_default().into()); let mut entry = chain.upper_bound(Bound::Included(&ref_point))?; let mut this_block = entry.value().clone(); @@ -400,7 +400,7 @@ impl ProtectedLiveChainBlockList { let live_chain = self.0.read().map_err(|_| Error::Internal).ok()?; let head_point = Self::get_last_live_point(&live_chain); - if head_point == UNKNOWN_POINT { + if head_point == Point::UNKNOWN { return None; } @@ -457,7 +457,7 @@ pub(crate) fn get_live_block( /// /// Note: It MAY change between calling this function and actually backfilling. /// This is expected and normal behavior. -pub(crate) async fn get_fill_to_point(chain: Network) -> (Point, u64) { +pub(crate) async fn get_fill_to_point(chain: Network) -> (Point, Fork) { let live_chain = get_live_chain(chain); loop { @@ -474,10 +474,10 @@ pub(crate) async fn get_fill_to_point(chain: Network) -> (Point, u64) { /// `rollback_count` should be set to 1 on the very first connection, after that, /// it is maintained by this function, and MUST not be modified elsewhere. pub(crate) fn live_chain_add_block_to_tip( - chain: Network, block: MultiEraBlock, fork_count: &mut u64, tip: Point, + chain: Network, block: MultiEraBlock, fork: &mut Fork, tip: Point, ) -> Result<()> { let live_chain = get_live_chain(chain); - live_chain.add_block_to_tip(chain, block, fork_count, tip) + live_chain.add_block_to_tip(chain, block, fork, tip) } /// Backfill the live chain with the block set provided. @@ -509,7 +509,7 @@ pub(crate) fn get_intersect_points(chain: Network) -> Vec Option<(MultiEraBlock, u64)> { let live_chain = get_live_chain(chain); live_chain.find_best_fork_block(point, previous_point, fork) diff --git a/rust/cardano-chain-follower/src/chain_sync_ready.rs b/rust/cardano-chain-follower/src/chain_sync_ready.rs index 4122a56d1..eb77a3edc 100644 --- a/rust/cardano-chain-follower/src/chain_sync_ready.rs +++ b/rust/cardano-chain-follower/src/chain_sync_ready.rs @@ -3,6 +3,7 @@ use std::{sync::LazyLock, time::Duration}; +use cardano_blockchain_types::Network; use dashmap::DashMap; use strum::IntoEnumIterator; use tokio::{ @@ -11,7 +12,7 @@ use tokio::{ }; use tracing::error; -use crate::{chain_update, Network}; +use crate::chain_update; /// Data we hold related to sync being ready or not. struct SyncReady { diff --git a/rust/cardano-chain-follower/src/chain_update.rs b/rust/cardano-chain-follower/src/chain_update.rs index 044982b96..50a94426f 100644 --- a/rust/cardano-chain-follower/src/chain_update.rs +++ b/rust/cardano-chain-follower/src/chain_update.rs @@ -2,10 +2,9 @@ use std::fmt::Display; +use cardano_blockchain_types::MultiEraBlock; use strum::Display; -use crate::multi_era_block_data::MultiEraBlock; - /// Enum of chain updates received by the follower. #[derive(Debug, Clone, Display, PartialEq)] pub enum Kind { diff --git a/rust/cardano-chain-follower/src/error.rs b/rust/cardano-chain-follower/src/error.rs index 27218bd82..862a5298d 100644 --- a/rust/cardano-chain-follower/src/error.rs +++ b/rust/cardano-chain-follower/src/error.rs @@ -2,11 +2,10 @@ use std::{io, path::PathBuf}; +use cardano_blockchain_types::Network; use pallas::network::miniprotocols::chainsync; use thiserror::Error; -use crate::network::Network; - /// Crate error type. #[derive(Debug, Error)] pub enum Error { diff --git a/rust/cardano-chain-follower/src/follow.rs b/rust/cardano-chain-follower/src/follow.rs index 95972ce23..9a17dfc82 100644 --- a/rust/cardano-chain-follower/src/follow.rs +++ b/rust/cardano-chain-follower/src/follow.rs @@ -1,5 +1,6 @@ //! Cardano chain follow module. +use cardano_blockchain_types::{Fork, MultiEraBlock, Network, Point}; use pallas::network::miniprotocols::txmonitor::{TxBody, TxId}; use tokio::sync::broadcast::{self}; use tracing::{debug, error}; @@ -12,10 +13,8 @@ use crate::{ mithril_snapshot::MithrilSnapshot, mithril_snapshot_data::latest_mithril_snapshot_id, mithril_snapshot_iterator::MithrilSnapshotIterator, - network::Network, - point::{TIP_POINT, UNKNOWN_POINT}, stats::{self, rollback}, - MultiEraBlock, Point, Statistics, + Statistics, }; /// The Chain Follower @@ -29,7 +28,7 @@ pub struct ChainFollower { /// Where we are currently in the following process. current: Point, /// What fork were we last on - fork: u64, + fork: Fork, /// Mithril Snapshot snapshot: MithrilSnapshot, /// Mithril Snapshot Follower @@ -74,9 +73,9 @@ impl ChainFollower { ChainFollower { chain, end, - previous: UNKNOWN_POINT, + previous: Point::UNKNOWN, current: start, - fork: 1, // This is correct, because Mithril is Fork 0. + fork: 1.into(), // This is correct, because Mithril is Fork 0. snapshot: MithrilSnapshot::new(chain), mithril_follower: None, mithril_tip: None, @@ -102,7 +101,7 @@ impl ChainFollower { self.previous = self.current.clone(); // debug!("Post Previous update 3 : {:?}", self.previous); self.current = next.point(); - self.fork = 0; // Mithril Immutable data is always Fork 0. + self.fork = 0.into(); // Mithril Immutable data is always Fork 0. let update = ChainUpdate::new(chain_update::Kind::Block, false, next); return Some(update); } @@ -142,7 +141,7 @@ impl ChainFollower { let mut rollback_depth: u64 = 0; // Special Case: point = TIP_POINT. Just return the latest block in the live chain. - if self.current == TIP_POINT { + if self.current == Point::TIP { next_block = { let block = get_live_block(self.chain, &self.current, -1, false)?; Some(block) @@ -213,7 +212,7 @@ impl ChainFollower { fn update_current(&mut self, update: &Option) -> bool { if let Some(update) = update { let decoded = update.block_data().decode(); - self.current = Point::new(decoded.slot(), decoded.hash().to_vec()); + self.current = Point::new(decoded.slot().into(), decoded.hash().into()); return true; } false @@ -279,7 +278,7 @@ impl ChainFollower { /// Returns NONE is there is no block left to return. pub async fn next(&mut self) -> Option { // If we aren't syncing TIP, and Current >= End, then return None - if self.end != TIP_POINT && self.current >= self.end { + if self.end != Point::TIP && self.current >= self.end { return None; } @@ -301,7 +300,7 @@ impl ChainFollower { // Get the block from the chain. // This function suppose to run only once, so the end point // can be set to `TIP_POINT` - let mut follower = Self::new(chain, point, TIP_POINT).await; + let mut follower = Self::new(chain, point, Point::TIP).await; follower.next().await } @@ -314,8 +313,8 @@ impl ChainFollower { let tips = Statistics::tips(chain); - let mithril_tip = Point::fuzzy(tips.0); - let live_tip = Point::fuzzy(tips.1); + let mithril_tip = Point::fuzzy(tips.0.into()); + let live_tip = Point::fuzzy(tips.1.into()); (mithril_tip, live_tip) } @@ -371,40 +370,47 @@ mod tests { .expect("cannot decode block"); let previous_point = Point::new( - pallas_block.slot() - 1, + (pallas_block.slot() - 1).into(), pallas_block .header() .previous_hash() .expect("cannot get previous hash") - .to_vec(), + .into(), ); - MultiEraBlock::new(Network::Preprod, raw_block.clone(), &previous_point, 1) - .expect("cannot create block") + MultiEraBlock::new( + Network::Preprod, + raw_block.clone(), + &previous_point, + 1.into(), + ) + .expect("cannot create block") } #[tokio::test] + // FIXME - This test should fail async fn test_chain_follower_new() { let chain = Network::Mainnet; - let start = Point::new(100u64, vec![]); - let end = Point::fuzzy(999u64); + let start = Point::new(100u64.into(), [0; 32].into()); + let end = Point::fuzzy(999u64.into()); let follower = ChainFollower::new(chain, start.clone(), end.clone()).await; assert_eq!(follower.chain, chain); assert_eq!(follower.end, end); - assert_eq!(follower.previous, UNKNOWN_POINT); + assert_eq!(follower.previous, Point::UNKNOWN); assert_eq!(follower.current, start); - assert_eq!(follower.fork, 1); + assert_eq!(follower.fork, 1.into()); assert!(follower.mithril_follower.is_none()); assert!(follower.mithril_tip.is_none()); } #[tokio::test] + // FIXME - This test should fail async fn test_chain_follower_update_current_none() { let chain = Network::Mainnet; - let start = Point::new(100u64, vec![]); - let end = Point::fuzzy(999u64); + let start = Point::new(100u64.into(), [0; 32].into()); + let end = Point::fuzzy(999u64.into()); let mut follower = ChainFollower::new(chain, start.clone(), end.clone()).await; @@ -414,10 +420,11 @@ mod tests { } #[tokio::test] + // FIXME - This test should fail async fn test_chain_follower_update_current() { let chain = Network::Mainnet; - let start = Point::new(100u64, vec![]); - let end = Point::fuzzy(999u64); + let start = Point::new(100u64.into(), [0; 32].into()); + let end = Point::fuzzy(999u64.into()); let mut follower = ChainFollower::new(chain, start.clone(), end.clone()).await; diff --git a/rust/cardano-chain-follower/src/lib.rs b/rust/cardano-chain-follower/src/lib.rs index 692ac6e34..6516685fd 100644 --- a/rust/cardano-chain-follower/src/lib.rs +++ b/rust/cardano-chain-follower/src/lib.rs @@ -15,9 +15,6 @@ mod mithril_snapshot_data; mod mithril_snapshot_iterator; mod mithril_snapshot_sync; mod mithril_turbo_downloader; -mod multi_era_block_data; -mod network; -mod point; mod snapshot_id; mod stats; pub mod turbo_downloader; @@ -29,7 +26,4 @@ pub use chain_update::{ChainUpdate, Kind}; pub use error::Result; pub use follow::ChainFollower; pub use metadata as Metadata; -pub use multi_era_block_data::MultiEraBlock; -pub use network::Network; -pub use point::{Point, ORIGIN_POINT, TIP_POINT}; pub use stats::Statistics; diff --git a/rust/cardano-chain-follower/src/mithril_query.rs b/rust/cardano-chain-follower/src/mithril_query.rs index 7c6e38a13..b67cf380b 100644 --- a/rust/cardano-chain-follower/src/mithril_query.rs +++ b/rust/cardano-chain-follower/src/mithril_query.rs @@ -2,13 +2,11 @@ use std::path::Path; +use cardano_blockchain_types::Point; use pallas_hardano::storage::immutable::FallibleBlock; use tokio::task; -use crate::{ - error::{Error, Result}, - Point, -}; +use crate::error::{Error, Result}; /// Synchronous Immutable block iterator. pub(crate) type ImmutableBlockIterator = Box + Send + Sync>; diff --git a/rust/cardano-chain-follower/src/mithril_snapshot.rs b/rust/cardano-chain-follower/src/mithril_snapshot.rs index 4c59cb51d..b98c2555d 100644 --- a/rust/cardano-chain-follower/src/mithril_snapshot.rs +++ b/rust/cardano-chain-follower/src/mithril_snapshot.rs @@ -1,11 +1,12 @@ //! Internal Mithril snapshot functions. +use cardano_blockchain_types::{MultiEraBlock, Network, Point}; use logcall::logcall; use tracing_log::log; use crate::{ mithril_snapshot_data::latest_mithril_snapshot_id, - mithril_snapshot_iterator::MithrilSnapshotIterator, network::Network, MultiEraBlock, Point, + mithril_snapshot_iterator::MithrilSnapshotIterator, }; // Any single program using this crate can have EXACTLY THREE Mithril snapshots. diff --git a/rust/cardano-chain-follower/src/mithril_snapshot_config.rs b/rust/cardano-chain-follower/src/mithril_snapshot_config.rs index 3eea1111c..099360f19 100644 --- a/rust/cardano-chain-follower/src/mithril_snapshot_config.rs +++ b/rust/cardano-chain-follower/src/mithril_snapshot_config.rs @@ -7,6 +7,7 @@ use std::{ }; use anyhow::bail; +use cardano_blockchain_types::{Network, Point}; use dashmap::DashMap; use futures::future::join_all; use strum::IntoEnumIterator; @@ -22,11 +23,8 @@ use crate::{ error::{Error, Result}, mithril_snapshot_data::{latest_mithril_snapshot_id, SnapshotData}, mithril_snapshot_sync::background_mithril_update, - network::Network, - point::ORIGIN_POINT, snapshot_id::SnapshotId, turbo_downloader::DlConfig, - Point, }; /// Type we use to manage the Sync Task handle map. @@ -200,7 +198,7 @@ impl MithrilSnapshotConfig { }; // If None, its not a snapshot path, so continue. - if let Some(this_snapshot) = SnapshotId::new(&entry.path(), ORIGIN_POINT) { + if let Some(this_snapshot) = SnapshotId::new(&entry.path(), Point::ORIGIN) { // Don't do anything with the latest snapshot. // Comparison does NOT use `tip` so we construct a temporary ID without it. if this_snapshot != latest_snapshot { diff --git a/rust/cardano-chain-follower/src/mithril_snapshot_data.rs b/rust/cardano-chain-follower/src/mithril_snapshot_data.rs index 8c3f146ac..697cf71b0 100644 --- a/rust/cardano-chain-follower/src/mithril_snapshot_data.rs +++ b/rust/cardano-chain-follower/src/mithril_snapshot_data.rs @@ -1,9 +1,10 @@ //! Data about the current Mithril Snapshot use std::{default, sync::LazyLock}; +use cardano_blockchain_types::Network; use dashmap::DashMap; -use crate::{network::Network, snapshot_id::SnapshotId}; +use crate::snapshot_id::SnapshotId; /// Current Mithril Snapshot Data for a network. #[derive(Debug, Clone)] diff --git a/rust/cardano-chain-follower/src/mithril_snapshot_iterator.rs b/rust/cardano-chain-follower/src/mithril_snapshot_iterator.rs index 3e1d4f079..233542320 100644 --- a/rust/cardano-chain-follower/src/mithril_snapshot_iterator.rs +++ b/rust/cardano-chain-follower/src/mithril_snapshot_iterator.rs @@ -6,6 +6,7 @@ use std::{ sync::{Arc, Mutex}, }; +use cardano_blockchain_types::{MultiEraBlock, Network, Point}; use logcall::logcall; use tokio::task; use tracing::{debug, error}; @@ -14,9 +15,6 @@ use tracing_log::log; use crate::{ error::{Error, Result}, mithril_query::{make_mithril_iterator, ImmutableBlockIterator}, - network::Network, - point::ORIGIN_POINT, - MultiEraBlock, Point, }; /// Search backwards by 60 slots (seconds) looking for a previous block. @@ -60,11 +58,11 @@ pub(crate) fn probe_point(point: &Point, distance: u64) -> Point { // We stepped back to the origin, so just return Origin if step_back_search == 0 { - return ORIGIN_POINT; + return Point::ORIGIN; } // Create a fuzzy search probe by making the hash zero length. - Point::fuzzy(step_back_search) + Point::fuzzy(step_back_search.into()) } impl MithrilSnapshotIterator { @@ -90,7 +88,7 @@ impl MithrilSnapshotIterator { return None; }; - let point = Point::new(block.slot(), block.hash().to_vec()); + let point = Point::new(block.slot().into(), block.hash().into()); previous = this; this = Some(point.clone()); @@ -166,7 +164,7 @@ impl MithrilSnapshotIterator { } let previous = if from.is_origin() { - ORIGIN_POINT + Point::ORIGIN } else { let Some(previous) = previous_point else { return Err(Error::Internal); @@ -212,7 +210,7 @@ impl Iterator for MithrilSnapshotIteratorInner { if let Ok(block) = maybe_block { if !self.previous.is_unknown() { // We can safely fully decode this block. - match MultiEraBlock::new(self.chain, block, &self.previous, 0) { + match MultiEraBlock::new(self.chain, block, &self.previous, 0.into()) { Ok(block_data) => { // Update the previous point // debug!("Pre Previous update 1 : {:?}", self.previous); @@ -241,8 +239,10 @@ impl Iterator for MithrilSnapshotIteratorInner { pallas::ledger::traverse::MultiEraBlock::decode(&block) { // debug!("Pre Previous update 2 : {:?}", self.previous); - self.previous = - Point::new(raw_decoded_block.slot(), raw_decoded_block.hash().to_vec()); + self.previous = Point::new( + raw_decoded_block.slot().into(), + raw_decoded_block.hash().into(), + ); // debug!("Post Previous update 2 : {:?}", self.previous); continue; } diff --git a/rust/cardano-chain-follower/src/mithril_snapshot_sync.rs b/rust/cardano-chain-follower/src/mithril_snapshot_sync.rs index 964d46cad..f619069ed 100644 --- a/rust/cardano-chain-follower/src/mithril_snapshot_sync.rs +++ b/rust/cardano-chain-follower/src/mithril_snapshot_sync.rs @@ -7,6 +7,7 @@ use std::{ sync::Arc, }; +use cardano_blockchain_types::{MultiEraBlock, Network}; use chrono::{TimeDelta, Utc}; use dashmap::DashSet; use humantime::format_duration; @@ -27,10 +28,8 @@ use crate::{ mithril_snapshot_data::update_latest_mithril_snapshot, mithril_snapshot_iterator::MithrilSnapshotIterator, mithril_turbo_downloader::MithrilTurboDownloader, - network::Network, snapshot_id::SnapshotId, stats::{self, mithril_sync_failure, mithril_validation_state}, - MultiEraBlock, }; /// The minimum duration between checks for a new Mithril Snapshot. (Must be same as diff --git a/rust/cardano-chain-follower/src/multi_era_block_data.rs b/rust/cardano-chain-follower/src/multi_era_block_data.rs deleted file mode 100644 index c5f1e85b6..000000000 --- a/rust/cardano-chain-follower/src/multi_era_block_data.rs +++ /dev/null @@ -1,744 +0,0 @@ -//! Multi Era CBOR Encoded Block Data -//! -//! Data about how the block/transactions can be encoded is found here: -//! -//! -//! DO NOT USE the documentation/cddl definitions from the head of this repo because it -//! currently lacks most of the documentation needed to understand the format and is also -//! incorrectly generated and contains errors that will be difficult to discern. - -use std::{cmp::Ordering, fmt::Display, sync::Arc}; - -use ouroboros::self_referencing; -use tracing::debug; - -use crate::{ - error::Error, metadata, stats::stats_invalid_block, witness::TxWitness, Network, Point, -}; - -/// Self-referencing CBOR encoded data of a multi-era block. -/// Note: The fields in the original struct can not be accessed directly -/// The builder creates accessor methods which are called -/// `borrow_raw_data()` and `borrow_block()` -#[self_referencing] -#[derive(Debug)] -pub(crate) struct SelfReferencedMultiEraBlock { - /// The CBOR encoded data of a multi-era block. - raw_data: Vec, - - /// The decoded multi-era block. - /// References the `raw_data` field. - #[borrows(raw_data)] - #[covariant] - block: pallas::ledger::traverse::MultiEraBlock<'this>, -} - -/// Multi-era block - inner. -#[derive(Debug)] -pub struct MultiEraBlockInner { - /// What blockchain was the block produced on. - //#[allow(dead_code)] - pub chain: Network, - /// The Point on the blockchain this block can be found. - point: Point, - /// The previous point on the blockchain before this block. - /// When the current point is Genesis, so is the previous. - previous: Point, - /// The decoded multi-era block. - data: SelfReferencedMultiEraBlock, - /// Decoded Metadata in the transactions in the block. - metadata: metadata::DecodedTransaction, - /// A map of public key hashes to the public key and transaction numbers they are in. - #[allow(dead_code)] - witness_map: Option, -} - -/// Multi-era block. -#[derive(Clone, Debug)] -pub struct MultiEraBlock { - /// What fork is the block on? - /// This is NOT part of the inner block, because it is not to be protected by the Arc. - /// It can change at any time due to rollbacks detected on the live-chain. - /// This means that any holder of a `MultiEraBlock` will have the actual fork their - /// block was on when they read it, the live-chain code can modify the actual fork - /// count at any time without that impacting consumers processing the data. - /// The fork count itself is used so an asynchronous follower can properly work out - /// how far to roll back on the live-chain in order to resynchronize, without - /// keeping a full state of processed blocks. - /// Followers, simply need to step backwards on the live chain until they find the - /// previous block they followed, or reach a fork that is <= the fork of the - /// previous block they followed. They can then safely re-follow from that earlier - /// point, with full integrity. fork is 0 on any immutable block. - /// It starts at 1 for live blocks, and is only incremented if the live-chain tip is - /// purged because of a detected fork based on data received from the peer node. - /// It does NOT count the strict number of forks reported by the peer node. - fork: u64, - /// The Immutable decoded data about the block itself. - inner: Arc, -} - -impl MultiEraBlock { - /// Creates a new `MultiEraBlockData` from the given bytes. - /// - /// # Errors - /// - /// If the given bytes cannot be decoded as a multi-era block, an error is returned. - fn new_block( - chain: Network, raw_data: Vec, previous: &Point, fork: u64, - ) -> anyhow::Result { - let builder = SelfReferencedMultiEraBlockTryBuilder { - raw_data, - block_builder: |raw_data| -> Result<_, Error> { - pallas::ledger::traverse::MultiEraBlock::decode(raw_data) - .map_err(|err| Error::Codec(err.to_string())) - }, - }; - let self_ref_block = builder.try_build()?; - let decoded_block = self_ref_block.borrow_block(); - - let witness_map = TxWitness::new(&decoded_block.txs()).ok(); - - let slot = decoded_block.slot(); - - let point = Point::new(slot, decoded_block.hash().to_vec()); - - let byron_block = matches!( - decoded_block, - pallas::ledger::traverse::MultiEraBlock::Byron(_) - ); - - // debug!("New Block: {slot} {point} {}", *previous); - - // Dump the early mainnet blocks because somethings funny in there. - // if slot == 0 || slot == 21600 { - // debug!("Block of interest {slot} {:?}", decoded_block); - //} - - // Validate that the Block point is valid. - if !previous.is_origin() { - // Every 21600 Blocks, Byron Era has duplicated sequential slot#'s. - // So this filters them out from the sequential point check. - // The Hash chain is still checked. - if (!byron_block || ((slot % 21600) != 0)) && *previous >= slot { - return Err(Error::Codec(format!( - "Previous slot is not less than current slot:{slot}" - ))); - } - - // Special case, when the previous block is actually UNKNOWN, we can't check it. - if !previous.is_unknown() - // Otherwise, we make sure the hash chain is intact - && !previous.cmp_hash(&decoded_block.header().previous_hash()) - { - debug!("{}, {:?}", previous, decoded_block.header().previous_hash()); - - return Err(Error::Codec( - "Previous Block Hash mismatch with block".to_string(), - )); - } - } - - let metadata = metadata::DecodedTransaction::new(chain, decoded_block); - - Ok(Self { - fork, - inner: Arc::new(MultiEraBlockInner { - chain, - point, - previous: previous.clone(), - data: self_ref_block, - metadata, - witness_map, - }), - }) - } - - /// Creates a new `MultiEraBlockData` from the given bytes. - /// - /// # Errors - /// - /// If the given bytes cannot be decoded as a multi-era block, an error is returned. - pub(crate) fn new( - chain: Network, raw_data: Vec, previous: &Point, fork: u64, - ) -> anyhow::Result { - // This lets us reliably count any bad block arising from deserialization. - let block = MultiEraBlock::new_block(chain, raw_data, previous, fork); - if block.is_err() { - stats_invalid_block(chain, fork == 0); - } - block - } - - /// Remake the block on a new fork. - pub(crate) fn set_fork(&mut self, fork: u64) { - self.fork = fork; - } - - /// Decodes the data into a multi-era block. - /// - /// # Returns - /// The decoded block data, which can easily be processed by a consumer. - #[must_use] - #[allow(clippy::missing_panics_doc)] - pub fn decode(&self) -> &pallas::ledger::traverse::MultiEraBlock { - self.inner.data.borrow_block() - } - - /// Decodes the data into a multi-era block. - /// - /// # Returns - /// The raw byte data of the block. - #[must_use] - #[allow(clippy::missing_panics_doc)] - pub fn raw(&self) -> &Vec { - self.inner.data.borrow_raw_data() - } - - /// Returns the block point of this block. - /// - /// # Returns - /// The block point of this block. - #[must_use] - pub fn point(&self) -> Point { - self.inner.point.clone() - } - - /// Returns the block point of the previous block. - /// - /// # Returns - /// The previous blocks `Point` - #[must_use] - pub fn previous(&self) -> Point { - self.inner.previous.clone() - } - - /// Is the block data immutable on-chain. - /// - /// Immutable blocks are by-definition those that exist in the Mithril Snapshot - /// (Immutable Database) of the Node. - /// - /// # Returns - /// `true` if the block is immutable, `false` otherwise. - #[must_use] - pub fn immutable(&self) -> bool { - self.fork == 0 - } - - /// What fork is the block from. - /// - /// The fork is a synthetic number that represents how many rollbacks have been - /// detected in the running chain. The fork is: - /// - 0 - for all immutable data; - /// - 1 - for any data read from the blockchain during a *backfill* on initial sync - /// - 2+ - for each subsequent rollback detected while reading live blocks. - /// - /// # Returns - /// The fork the block was found on. - #[must_use] - pub fn fork(&self) -> u64 { - self.fork - } - - /// What chain was the block from - /// - /// # Returns - /// - The chain that this block originated on. - #[must_use] - pub fn chain(&self) -> Network { - self.inner.chain - } - - /// Get The Decoded Metadata fora a transaction and known label from the block - /// - /// # Parameters - /// - `txn_idx` - Index of the Transaction in the Block - /// - `label` - The label of the transaction - /// - /// # Returns - /// - Metadata for the given label in the transaction. - /// - Or None if the label requested isn't present. - #[must_use] - pub fn txn_metadata( - &self, txn_idx: usize, label: u64, - ) -> Option> { - self.inner.metadata.get_metadata(txn_idx, label) - } - - /// Get The Raw Metadata fora a transaction and known label from the block - #[must_use] - pub fn txn_raw_metadata(&self, txn_idx: usize, label: u64) -> Option>> { - self.inner.metadata.get_raw_metadata(txn_idx, label) - } - - /// Returns the witness map for the block. - pub(crate) fn witness_map(&self) -> Option<&TxWitness> { - self.inner.witness_map.as_ref() - } - - /// If the Witness exists for a given transaction then return its public key. - #[must_use] - pub fn witness_for_tx(&self, vkey_hash: &[u8; 28], tx_num: u16) -> Option> { - if let Some(witnesses) = self.witness_map() { - if witnesses.check_witness_in_tx(vkey_hash, tx_num) { - if let Some(pub_key) = witnesses.get_witness_pk_addr(vkey_hash) { - return Some(pub_key.into()); - } - } - } - - None - } -} - -impl Display for MultiEraBlock { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let fork = self.fork; - let block_data = &self.inner.data; - let block = block_data.borrow_block(); - let block_number = block.number(); - let slot = block.slot(); - let size = block.size(); - let txns = block.tx_count(); - let aux_data = block.has_aux_data(); - - let fork = if self.immutable() { - "Immutable".to_string() - } else { - format!("Fork: {fork}") - }; - - let block_era = match block { - pallas::ledger::traverse::MultiEraBlock::EpochBoundary(_) => { - "Byron Epoch Boundary".to_string() - }, - pallas::ledger::traverse::MultiEraBlock::AlonzoCompatible(_, era) => { - format!("{era}") - }, - pallas::ledger::traverse::MultiEraBlock::Babbage(_) => "Babbage".to_string(), - pallas::ledger::traverse::MultiEraBlock::Byron(_) => "Byron".to_string(), - pallas::ledger::traverse::MultiEraBlock::Conway(_) => "Conway".to_string(), - _ => "Unknown".to_string(), - }; - write!(f, "{block_era} block : {}, Previous {} : Slot# {slot} : {fork} : Block# {block_number} : Size {size} : Txns {txns} : AuxData? {aux_data}", - self.point(), self.previous())?; - Ok(()) - } -} - -impl PartialEq for MultiEraBlock { - /// Compare two `MultiEraBlock` by their current points. - /// Ignores the Hash, we only check for equality of the Slot#. - fn eq(&self, other: &Self) -> bool { - self.partial_cmp(other) == Some(Ordering::Equal) - } -} - -impl Eq for MultiEraBlock {} - -impl PartialOrd for MultiEraBlock { - /// Compare two `MultiEraBlock` by their points. - /// Only checks the Slot#. - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for MultiEraBlock { - /// Compare two `LiveBlocks` by their points. - /// Only checks the Slot#. - fn cmp(&self, other: &Self) -> Ordering { - self.inner.point.cmp(&other.inner.point) - } -} - -// Allows us to compare a MultiEraBlock against a Point directly (Just the slot#). -impl PartialEq for MultiEraBlock { - // Equality ONLY checks the Slot# - fn eq(&self, other: &Point) -> bool { - Some(Ordering::Equal) == self.partial_cmp(other) - } -} - -impl PartialOrd for MultiEraBlock { - /// Compare a `MultiEraBlock` to a `Point` by their points. - /// Only checks the Slot#. - fn partial_cmp(&self, other: &Point) -> Option { - Some(self.inner.point.cmp(other)) - } -} - -#[cfg(test)] -pub(crate) mod tests { - use std::ops::Add; - - use anyhow::Ok; - - use crate::{point::ORIGIN_POINT, MultiEraBlock, Network, Point}; - - struct TestRecord { - raw: Vec, - previous: Point, - } - - /// Byron Test Block data - fn byron_block() -> Vec { - hex::decode(include_str!("./../test_data/byron.block")) - .expect("Failed to decode hex block.") - } - - /// Shelley Test Block data - fn shelley_block() -> Vec { - hex::decode(include_str!("./../test_data/shelley.block")) - .expect("Failed to decode hex block.") - } - - /// Mary Test Block data - fn mary_block() -> Vec { - hex::decode(include_str!("./../test_data/mary.block")).expect("Failed to decode hex block.") - } - - /// Allegra Test Block data - fn allegra_block() -> Vec { - hex::decode(include_str!("./../test_data/allegra.block")) - .expect("Failed to decode hex block.") - } - - /// Alonzo Test Block data - pub(crate) fn alonzo_block() -> Vec { - hex::decode(include_str!("./../test_data/allegra.block")) - .expect("Failed to decode hex block.") - } - - /// Babbage Test Block data - pub(crate) fn babbage_block() -> Vec { - hex::decode(include_str!("./../test_data/babbage.block")) - .expect("Failed to decode hex block.") - } - - /// An array of test blocks - fn test_blocks() -> Vec { - vec![ - TestRecord { - raw: byron_block(), - previous: ORIGIN_POINT, - }, - TestRecord { - raw: shelley_block(), - previous: ORIGIN_POINT, - }, - TestRecord { - raw: mary_block(), - previous: ORIGIN_POINT, - }, - TestRecord { - raw: allegra_block(), - previous: ORIGIN_POINT, - }, - TestRecord { - raw: alonzo_block(), - previous: ORIGIN_POINT, - }, - ] - } - - // Gets sorted by slot number from highest to lowest - fn sorted_test_blocks() -> Vec> { - vec![ - mary_block(), // 27388606 - allegra_block(), // 18748707 - alonzo_block(), // 18748707 - shelley_block(), // 7948610 - byron_block(), // 3241381 - ] - } - - /// Previous Point slot is >= blocks point, but hash is correct (should fail) - #[test] - fn test_multi_era_block_point_compare_1() -> anyhow::Result<()> { - for (i, test_block) in test_blocks().into_iter().enumerate() { - let pallas_block = - pallas::ledger::traverse::MultiEraBlock::decode(test_block.raw.as_slice())?; - - let previous_point = Point::new( - pallas_block.slot().add(i as u64), - pallas_block - .header() - .previous_hash() - .expect("cannot get previous hash") - .to_vec(), - ); - - let block = - MultiEraBlock::new(Network::Preprod, test_block.raw.clone(), &previous_point, 1); - - assert!(block.is_err()); - } - - Ok(()) - } - - /// Previous Point slot is < blocks point, but hash is different. (should fail). - #[test] - fn test_multi_era_block_point_compare_2() -> anyhow::Result<()> { - for test_block in test_blocks() { - let pallas_block = - pallas::ledger::traverse::MultiEraBlock::decode(test_block.raw.as_slice())?; - - let previous_point = Point::new(pallas_block.slot() - 1, vec![0; 32]); - - let block = - MultiEraBlock::new(Network::Preprod, test_block.raw.clone(), &previous_point, 1); - - assert!(block.is_err()); - } - - Ok(()) - } - - /// Previous Point slot is < blocks point, and hash is also correct. (should pass). - #[test] - fn test_multi_era_block_point_compare_3() -> anyhow::Result<()> { - for test_block in test_blocks() { - let pallas_block = - pallas::ledger::traverse::MultiEraBlock::decode(test_block.raw.as_slice())?; - - let previous_point = Point::new( - pallas_block.slot() - 1, - pallas_block - .header() - .previous_hash() - .expect("cannot get previous hash") - .to_vec(), - ); - - let block = - MultiEraBlock::new(Network::Preprod, test_block.raw.clone(), &previous_point, 1)?; - - assert_eq!(block.decode().hash(), pallas_block.hash()); - } - - Ok(()) - } - - fn mk_test_blocks() -> Vec { - let raw_blocks = sorted_test_blocks(); - raw_blocks - .iter() - .map(|block| { - let prev_point = pallas::ledger::traverse::MultiEraBlock::decode(block.as_slice()) - .map(|block| { - Point::new( - block.slot() - 1, - block - .header() - .previous_hash() - .expect("cannot get previous hash") - .to_vec(), - ) - }) - .expect("cannot create point"); - - MultiEraBlock::new(Network::Preprod, block.clone(), &prev_point, 1) - .expect("cannot create multi-era block") - }) - .collect() - } - - fn mk_test_points() -> Vec { - let raw_blocks = sorted_test_blocks(); - raw_blocks - .iter() - .map(|block| { - pallas::ledger::traverse::MultiEraBlock::decode(block.as_slice()) - .map(|block| { - Point::new( - block.slot(), - block - .header() - .previous_hash() - .expect("cannot get previous hash") - .to_vec(), - ) - }) - .expect("cannot create point") - }) - .collect() - } - - /// Compares between blocks using comparison operators - #[test] - fn test_multi_era_block_point_compare_4() -> anyhow::Result<()> { - let multi_era_blocks = mk_test_blocks(); - - let mary_block = multi_era_blocks.first().expect("cannot get block"); - let allegra_block = multi_era_blocks.get(1).expect("cannot get block"); - let alonzo_block = multi_era_blocks.get(2).expect("cannot get block"); - let shelley_block = multi_era_blocks.get(3).expect("cannot get block"); - let byron_block = multi_era_blocks.get(4).expect("cannot get block"); - - assert!(mary_block > allegra_block); - assert!(mary_block >= allegra_block); - assert!(mary_block != allegra_block); - assert!(mary_block > alonzo_block); - assert!(mary_block >= alonzo_block); - assert!(mary_block != alonzo_block); - assert!(mary_block > shelley_block); - assert!(mary_block >= shelley_block); - assert!(mary_block != shelley_block); - assert!(mary_block > byron_block); - assert!(mary_block >= byron_block); - - assert!(allegra_block < mary_block); - assert!(allegra_block <= mary_block); - assert!(allegra_block != mary_block); - assert!(allegra_block == alonzo_block); - assert!(allegra_block >= alonzo_block); - assert!(allegra_block <= alonzo_block); - assert!(allegra_block > shelley_block); - assert!(allegra_block >= shelley_block); - assert!(allegra_block != shelley_block); - assert!(allegra_block > byron_block); - assert!(allegra_block >= byron_block); - assert!(allegra_block != byron_block); - - assert!(alonzo_block < mary_block); - assert!(alonzo_block <= mary_block); - assert!(alonzo_block != mary_block); - assert!(alonzo_block == allegra_block); - assert!(alonzo_block >= allegra_block); - assert!(alonzo_block <= allegra_block); - assert!(alonzo_block > shelley_block); - assert!(alonzo_block >= shelley_block); - assert!(alonzo_block != shelley_block); - assert!(alonzo_block > byron_block); - assert!(alonzo_block >= byron_block); - assert!(alonzo_block != byron_block); - - assert!(shelley_block < mary_block); - assert!(shelley_block <= mary_block); - assert!(shelley_block != mary_block); - assert!(shelley_block < allegra_block); - assert!(shelley_block <= allegra_block); - assert!(shelley_block != allegra_block); - assert!(shelley_block < alonzo_block); - assert!(shelley_block <= alonzo_block); - assert!(shelley_block != alonzo_block); - assert!(shelley_block > byron_block); - assert!(shelley_block >= byron_block); - assert!(shelley_block != byron_block); - - assert!(byron_block < mary_block); - assert!(byron_block <= mary_block); - assert!(byron_block != mary_block); - assert!(byron_block < allegra_block); - assert!(byron_block <= allegra_block); - assert!(byron_block != allegra_block); - assert!(byron_block < alonzo_block); - assert!(byron_block <= alonzo_block); - assert!(byron_block != alonzo_block); - assert!(byron_block < shelley_block); - assert!(byron_block <= shelley_block); - assert!(byron_block != shelley_block); - - Ok(()) - } - - /// Compares between blocks and points using comparison operators - #[test] - fn test_multi_era_block_point_compare_5() -> anyhow::Result<()> { - let points = mk_test_points(); - let blocks = mk_test_blocks(); - - let mary_block = blocks.first().expect("cannot get block"); - let allegra_block = blocks.get(1).expect("cannot get block"); - let alonzo_block = blocks.get(2).expect("cannot get block"); - let shelley_block = blocks.get(3).expect("cannot get block"); - let byron_block = blocks.get(4).expect("cannot get block"); - - let mary_point = points.first().expect("cannot get point"); - let allegra_point = points.get(1).expect("cannot get point"); - let alonzo_point = points.get(2).expect("cannot get point"); - let shelley_point = points.get(3).expect("cannot get point"); - let byron_point = points.get(4).expect("cannot get point"); - - assert!(mary_block > allegra_point); - assert!(mary_block >= allegra_point); - assert!(mary_block != allegra_point); - assert!(mary_block > alonzo_point); - assert!(mary_block >= alonzo_point); - assert!(mary_block != alonzo_point); - assert!(mary_block > shelley_point); - assert!(mary_block >= shelley_point); - assert!(mary_block != shelley_point); - assert!(mary_block > byron_point); - assert!(mary_block >= byron_point); - - assert!(allegra_block < mary_point); - assert!(allegra_block <= mary_point); - assert!(allegra_block != mary_point); - assert!(allegra_block == alonzo_point); - assert!(allegra_block >= alonzo_point); - assert!(allegra_block <= alonzo_point); - assert!(allegra_block > shelley_point); - assert!(allegra_block >= shelley_point); - assert!(allegra_block != shelley_point); - assert!(allegra_block > byron_point); - assert!(allegra_block >= byron_point); - assert!(allegra_block != byron_point); - - assert!(alonzo_block < mary_point); - assert!(alonzo_block <= mary_point); - assert!(alonzo_block != mary_point); - assert!(alonzo_block == allegra_point); - assert!(alonzo_block >= allegra_point); - assert!(alonzo_block <= allegra_point); - assert!(alonzo_block > shelley_point); - assert!(alonzo_block >= shelley_point); - assert!(alonzo_block != shelley_point); - assert!(alonzo_block > byron_point); - assert!(alonzo_block >= byron_point); - assert!(alonzo_block != byron_point); - - assert!(shelley_block < mary_point); - assert!(shelley_block <= mary_point); - assert!(shelley_block != mary_point); - assert!(shelley_block < allegra_point); - assert!(shelley_block <= allegra_point); - assert!(shelley_block != allegra_point); - assert!(shelley_block < alonzo_point); - assert!(shelley_block <= alonzo_point); - assert!(shelley_block != alonzo_point); - assert!(shelley_block > byron_point); - assert!(shelley_block >= byron_point); - assert!(shelley_block != byron_point); - - assert!(byron_block < mary_point); - assert!(byron_block <= mary_point); - assert!(byron_block != mary_point); - assert!(byron_block < allegra_point); - assert!(byron_block <= allegra_point); - assert!(byron_block != allegra_point); - assert!(byron_block < alonzo_point); - assert!(byron_block <= alonzo_point); - assert!(byron_block != alonzo_point); - assert!(byron_block < shelley_point); - assert!(byron_block <= shelley_point); - assert!(byron_block != shelley_point); - - Ok(()) - } - - #[test] - fn test_multi_era_block_with_origin_point() { - for test_block in test_blocks() { - let block = MultiEraBlock::new( - Network::Preprod, - test_block.raw.clone(), - &test_block.previous, - 1, - ); - - assert!(block.is_ok()); - } - } -} diff --git a/rust/cardano-chain-follower/src/network.rs b/rust/cardano-chain-follower/src/network.rs deleted file mode 100644 index ddb0364b6..000000000 --- a/rust/cardano-chain-follower/src/network.rs +++ /dev/null @@ -1,396 +0,0 @@ -//! Enum of possible Cardano networks. - -use std::{ffi::OsStr, path::PathBuf}; - -use chrono::{DateTime, Utc}; -use pallas::{ - ledger::traverse::wellknown::GenesisValues, - network::miniprotocols::{MAINNET_MAGIC, PREVIEW_MAGIC, PRE_PRODUCTION_MAGIC}, -}; -// use strum::IntoEnumIterator; -// use strum_macros; -use tracing::debug; - -/// Default name of the executable if we can't derive it. -pub(crate) const DEFAULT_EXE_NAME: &str = "cardano_chain_follower"; -/// ENV VAR name for the data path. -pub(crate) const ENVVAR_MITHRIL_DATA_PATH: &str = "MITHRIL_DATA_PATH"; -/// ENV VAR name for the executable name. -pub(crate) const ENVVAR_MITHRIL_EXE_NAME: &str = "MITHRIL_EXE_NAME"; - -/// Enum of possible Cardano networks. -#[derive( - Debug, - Copy, - Clone, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - strum::EnumIter, - strum::VariantNames, - strum::EnumString, - strum::Display, -)] -#[strum(ascii_case_insensitive)] -pub enum Network { - /// Cardano mainnet network. - Mainnet, - /// Cardano pre-production network. - Preprod, - /// Cardano preview network. - Preview, -} - -// Mainnet Defaults. -/// Mainnet Default Public Cardano Relay. -const DEFAULT_MAINNET_RELAY: &str = "backbone.cardano.iog.io:3001"; -/// Main-net Mithril Signature genesis vkey. -const DEFAULT_MAINNET_MITHRIL_GENESIS_KEY: &str = include_str!("data/mainnet-genesis.vkey"); -/// Default Mithril Aggregator to use. -const DEFAULT_MAINNET_MITHRIL_AGGREGATOR: &str = - "https://aggregator.release-mainnet.api.mithril.network/aggregator"; - -// Preprod Defaults -/// Preprod Default Public Cardano Relay. -const DEFAULT_PREPROD_RELAY: &str = "preprod-node.play.dev.cardano.org:3001"; -/// Preprod network Mithril Signature genesis vkey. -const DEFAULT_PREPROD_MITHRIL_GENESIS_KEY: &str = include_str!("data/preprod-genesis.vkey"); -/// Default Mithril Aggregator to use. -const DEFAULT_PREPROD_MITHRIL_AGGREGATOR: &str = - "https://aggregator.release-preprod.api.mithril.network/aggregator"; - -// Preview Defaults -/// Preview Default Public Cardano Relay. -const DEFAULT_PREVIEW_RELAY: &str = "preview-node.play.dev.cardano.org:3001"; -/// Preview network Mithril Signature genesis vkey. -const DEFAULT_PREVIEW_MITHRIL_GENESIS_KEY: &str = include_str!("data/preview-genesis.vkey"); -/// Default Mithril Aggregator to use. -const DEFAULT_PREVIEW_MITHRIL_AGGREGATOR: &str = - "https://aggregator.pre-release-preview.api.mithril.network/aggregator"; - -impl Network { - /// Get the default Relay for a blockchain network. - #[must_use] - pub fn default_relay(self) -> String { - match self { - Network::Mainnet => DEFAULT_MAINNET_RELAY.to_string(), - Network::Preprod => DEFAULT_PREPROD_RELAY.to_string(), - Network::Preview => DEFAULT_PREVIEW_RELAY.to_string(), - } - } - - /// Get the default aggregator for a blockchain. - #[must_use] - pub fn default_mithril_aggregator(self) -> String { - match self { - Network::Mainnet => DEFAULT_MAINNET_MITHRIL_AGGREGATOR.to_string(), - Network::Preprod => DEFAULT_PREPROD_MITHRIL_AGGREGATOR.to_string(), - Network::Preview => DEFAULT_PREVIEW_MITHRIL_AGGREGATOR.to_string(), - } - } - - /// Get the default Mithril Signature genesis key for a blockchain. - #[must_use] - pub fn default_mithril_genesis_key(self) -> String { - match self { - Network::Mainnet => DEFAULT_MAINNET_MITHRIL_GENESIS_KEY.to_string(), - Network::Preprod => DEFAULT_PREPROD_MITHRIL_GENESIS_KEY.to_string(), - Network::Preview => DEFAULT_PREVIEW_MITHRIL_GENESIS_KEY.to_string(), - } - } - - /// Get the default storage location for mithril snapshots. - /// Defaults to: `//mithril/` - pub fn default_mithril_path(self) -> PathBuf { - // Get the base path for storing Data. - // IF the ENV var is set, use that. - // Otherwise use the system default data path for an application. - // All else fails default to "/var/lib" - let mut base_path = std::env::var(ENVVAR_MITHRIL_DATA_PATH).map_or_else( - |_| dirs::data_local_dir().unwrap_or("/var/lib".into()), - PathBuf::from, - ); - - // Get the Executable name for the data path. - // IF the ENV var is set, use it, otherwise try and get it from the exe itself. - // Fallback to using a default exe name if all else fails. - let exe_name = std::env::var(ENVVAR_MITHRIL_EXE_NAME).unwrap_or( - std::env::current_exe() - .unwrap_or(DEFAULT_EXE_NAME.into()) - .file_name() - .unwrap_or(OsStr::new(DEFAULT_EXE_NAME)) - .to_string_lossy() - .to_string(), - ); - - // / - base_path.push(exe_name); - - // Put everything in a `mithril` sub directory. - base_path.push("mithril"); - - // // - base_path.push(self.to_string()); - - debug!( - chain = self.to_string(), - path = base_path.to_string_lossy().to_string(), - "DEFAULT Mithril Data Path", - ); - - // Return the final path - base_path - } - - /// Return genesis values for given network - #[must_use] - pub fn genesis_values(self) -> GenesisValues { - match self { - Network::Mainnet => GenesisValues::mainnet(), - Network::Preprod => GenesisValues::preprod(), - Network::Preview => GenesisValues::preview(), - } - } - - /// Convert a given slot# to its Wall Time for a Blockchain network. - #[must_use] - pub fn slot_to_time(&self, slot: u64) -> DateTime { - let genesis = self.genesis_values(); - let wall_clock = genesis.slot_to_wallclock(slot); - - let raw_time: i64 = wall_clock.try_into().unwrap_or(i64::MAX); - DateTime::from_timestamp(raw_time, 0).unwrap_or(DateTime::::MAX_UTC) - } - - /// Convert an arbitrary time to a slot. - /// - /// If the given time predates the blockchain, will return None. - /// - /// The Slot does not have to be a valid slot present in the blockchain. - #[must_use] - pub fn time_to_slot(&self, time: DateTime) -> Option { - let genesis = self.genesis_values(); - - let byron_start_time = i64::try_from(genesis.byron_known_time) - .map(|time| DateTime::::from_timestamp(time, 0)) - .ok()??; - let shelley_start_time = i64::try_from(genesis.shelley_known_time) - .map(|time| DateTime::::from_timestamp(time, 0)) - .ok()??; - - // determine if the given time is in Byron or Shelley era. - if time < byron_start_time { - return None; - } - - if time < shelley_start_time { - // Byron era - let time_diff = time - byron_start_time; - let elapsed_slots = time_diff.num_seconds() / i64::from(genesis.byron_slot_length); - - u64::try_from(elapsed_slots) - .map(|elapsed_slots| Some(genesis.byron_known_slot + elapsed_slots)) - .ok()? - } else { - // Shelley era - let time_diff = time - shelley_start_time; - let elapsed_slots = time_diff.num_seconds() / i64::from(genesis.shelley_slot_length); - - u64::try_from(elapsed_slots) - .map(|elapsed_slots| Some(genesis.shelley_known_slot + elapsed_slots)) - .ok()? - } - } -} - -impl From for u64 { - fn from(network: Network) -> Self { - match network { - Network::Mainnet => MAINNET_MAGIC, - Network::Preprod => PRE_PRODUCTION_MAGIC, - Network::Preview => PREVIEW_MAGIC, - } - } -} - -#[cfg(test)] -mod tests { - use std::str::FromStr; - - use anyhow::Ok; - use chrono::{TimeZone, Utc}; - - use super::*; - - #[test] - fn test_from_str() -> anyhow::Result<()> { - let mainnet = Network::from_str("mainnet")?; - let preprod = Network::from_str("preprod")?; - let preview = Network::from_str("preview")?; - - assert_eq!(mainnet, Network::Mainnet); - assert_eq!(preprod, Network::Preprod); - assert_eq!(preview, Network::Preview); - - let mainnet = Network::from_str("Mainnet")?; - let preprod = Network::from_str("Preprod")?; - let preview = Network::from_str("Preview")?; - - assert_eq!(mainnet, Network::Mainnet); - assert_eq!(preprod, Network::Preprod); - assert_eq!(preview, Network::Preview); - - Ok(()) - } - - #[test] - fn test_time_to_slot_before_blockchain() { - let network = Network::Mainnet; - let genesis = network.genesis_values(); - - let before_blockchain = Utc - .timestamp_opt(i64::try_from(genesis.byron_known_time).unwrap() - 1, 0) - .unwrap(); - - assert_eq!(network.time_to_slot(before_blockchain), None); - } - - #[test] - fn test_time_to_slot_byron_era() { - let network = Network::Mainnet; - let genesis = network.genesis_values(); - - let byron_start_time = Utc - .timestamp_opt(i64::try_from(genesis.byron_known_time).unwrap(), 0) - .unwrap(); - let byron_slot_length = i64::from(genesis.byron_slot_length); - - // a time in the middle of the Byron era. - let time = byron_start_time + chrono::Duration::seconds(byron_slot_length * 100); - let expected_slot = genesis.byron_known_slot + 100; - - assert_eq!(network.time_to_slot(time), Some(expected_slot)); - } - - #[test] - fn test_time_to_slot_transition_to_shelley() { - let network = Network::Mainnet; - let genesis = network.genesis_values(); - - let shelley_start_time = Utc - .timestamp_opt(i64::try_from(genesis.shelley_known_time).unwrap(), 0) - .unwrap(); - let byron_slot_length = i64::from(genesis.byron_slot_length); - - // a time just before Shelley era starts. - let time = shelley_start_time - chrono::Duration::seconds(1); - let elapsed_slots = (time - - Utc - .timestamp_opt(i64::try_from(genesis.byron_known_time).unwrap(), 0) - .unwrap()) - .num_seconds() - / byron_slot_length; - let expected_slot = genesis.byron_known_slot + u64::try_from(elapsed_slots).unwrap(); - - assert_eq!(network.time_to_slot(time), Some(expected_slot)); - } - - #[test] - fn test_time_to_slot_shelley_era() { - let network = Network::Mainnet; - let genesis = network.genesis_values(); - - let shelley_start_time = Utc - .timestamp_opt(i64::try_from(genesis.shelley_known_time).unwrap(), 0) - .unwrap(); - let shelley_slot_length = i64::from(genesis.shelley_slot_length); - - // a time in the middle of the Shelley era. - let time = shelley_start_time + chrono::Duration::seconds(shelley_slot_length * 200); - let expected_slot = genesis.shelley_known_slot + 200; - - assert_eq!(network.time_to_slot(time), Some(expected_slot)); - } - - #[test] - fn test_slot_to_time_to_slot_consistency() { - let network = Network::Mainnet; - - // a few arbitrary slots in different ranges. - let slots_to_test = vec![0, 10_000, 1_000_000, 50_000_000]; - - for slot in slots_to_test { - let time = network.slot_to_time(slot); - let calculated_slot = network.time_to_slot(time); - - assert_eq!(calculated_slot, Some(slot), "Failed for slot: {slot}"); - } - } - - #[test] - #[allow(clippy::panic)] - fn test_time_to_slot_to_time_consistency() { - let network = Network::Mainnet; - let genesis = network.genesis_values(); - - // Byron, Shelley, and Conway. - let times_to_test = vec![ - Utc.timestamp_opt(i64::try_from(genesis.byron_known_time).unwrap() + 100, 0) - .unwrap(), - Utc.timestamp_opt( - i64::try_from(genesis.shelley_known_time).unwrap() + 1_000, - 0, - ) - .unwrap(), - Utc.timestamp_opt( - i64::try_from(genesis.shelley_known_time).unwrap() + 10_000_000, - 0, - ) - .unwrap(), - ]; - - for time in times_to_test { - if let Some(slot) = network.time_to_slot(time) { - let calculated_time = network.slot_to_time(slot); - - assert_eq!( - calculated_time.timestamp(), - time.timestamp(), - "Failed for time: {time}" - ); - } else { - panic!("time_to_slot returned None for a valid time: {time}"); - } - } - } - - #[test] - fn test_conway_era_time_to_slot_and_back() { - let network = Network::Mainnet; - let genesis = network.genesis_values(); - - // a very late time, far in the Conway era. - let conway_time = Utc - .timestamp_opt( - i64::try_from(genesis.shelley_known_time).unwrap() + 20_000_000, - 0, - ) - .unwrap(); - - let slot = network.time_to_slot(conway_time); - assert!( - slot.is_some(), - "Failed to calculate slot for Conway era time" - ); - - let calculated_time = network.slot_to_time(slot.unwrap()); - - assert_eq!( - calculated_time.timestamp(), - conway_time.timestamp(), - "Inconsistency for Conway era time" - ); - } -} diff --git a/rust/cardano-chain-follower/src/point.rs b/rust/cardano-chain-follower/src/point.rs deleted file mode 100644 index 21396144b..000000000 --- a/rust/cardano-chain-follower/src/point.rs +++ /dev/null @@ -1,590 +0,0 @@ -//! A Cardano Point on the Blockchain. -//! -//! Wrapped version of the Pallas primitive. -//! We only use this version unless talking to Pallas. - -use std::{ - cmp::Ordering, - fmt::{Debug, Display, Formatter}, -}; - -use pallas::crypto::hash::Hash; - -/// A specific point in the blockchain. It can be used to -/// identify a particular location within the blockchain, such as the tip (the -/// most recent block) or any other block. It has special kinds of `Point`, -/// available as constants: `TIP_POINT`, and `ORIGIN_POINT`. -/// -/// # Attributes -/// -/// * `Point` - The inner type is a `Point` from the `pallas::network::miniprotocols` -/// module. This inner `Point` type encapsulates the specific details required to -/// identify a point in the blockchain. -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub struct Point(pallas::network::miniprotocols::Point); - -/// A truly unknown point in the blockchain. It is used -/// when the previous point is completely unknown and does not correspond to the -/// origin of the blockchain. -/// -/// # Usage -/// -/// `UNKNOWN_POINT` can be used in scenarios where the previous point in the blockchain -/// is not known and should not be assumed to be the origin. It serves as a marker -/// for an indeterminate or unspecified point. -/// -/// The inner `Point` is created with `u64::MIN` and an empty `Vec`, indicating -/// that this is a special marker for an unknown point, rather than a specific -/// point in the blockchain. -pub(crate) const UNKNOWN_POINT: Point = Point(pallas::network::miniprotocols::Point::Specific( - u64::MIN, - Vec::new(), -)); - -/// The tip of the blockchain at the current moment. -/// It is used when the specific point in the blockchain is not known, but the -/// interest is in the most recent block (the tip). The tip is the point where -/// new blocks are being added. -/// -/// # Usage -/// -/// `TIP_POINT` can be used in scenarios where the most up-to-date point in the -/// blockchain is required. It signifies that the exact point is not important -/// as long as it is the latest available point in the chain. -/// -/// The inner `Point` is created with `u64::MAX` and an empty `Vec`, indicating -/// that this is a special marker rather than a specific point in the blockchain. -pub const TIP_POINT: Point = Point(pallas::network::miniprotocols::Point::Specific( - u64::MAX, - Vec::new(), -)); - -/// The origin of the blockchain. It is used when the -/// interest is in the very first point of the blockchain, regardless of its -/// specific details. -/// -/// # Usage -/// -/// `ORIGIN_POINT` can be used in scenarios where the starting point of the -/// blockchain is required. It signifies the genesis block or the initial state -/// of the blockchain. -/// -/// The inner `Point` is created with the `Origin` variant from -/// `pallas::network::miniprotocols::Point`, indicating that this is a marker -/// for the blockchain's origin. -pub const ORIGIN_POINT: Point = Point(pallas::network::miniprotocols::Point::Origin); - -impl Point { - /// Creates a new `Point` instance representing a specific - /// point in the blockchain, identified by a given slot and hash. - /// - /// # Parameters - /// - /// * `slot` - A `u64` value representing the slot number in the blockchain. - /// * `hash` - A `Vec` containing the hash of the block at the specified slot. - /// - /// # Returns - /// - /// A new `Point` instance encapsulating the given slot and hash. - /// - /// # Examples - /// - /// ```rs - /// use cardano_chain_follower::Point; - /// - /// let slot = 42; - /// let hash = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - /// let point = Point::new(slot, hash); - /// ``` - #[must_use] - pub fn new(slot: u64, hash: Vec) -> Self { - Self(pallas::network::miniprotocols::Point::Specific(slot, hash)) - } - - /// Creates a new `Point` instance representing a specific - /// point in the blockchain, identified by a given slot, but with an - /// unknown hash. This can be useful in scenarios where the slot is known - /// but the hash is either unavailable or irrelevant. - /// - /// # Parameters - /// - /// * `slot` - A `u64` value representing the slot number in the blockchain. - /// - /// # Returns - /// - /// A new `Point` instance encapsulating the given slot with an empty hash. - /// - /// # Examples - /// - /// ```rs - /// use cardano_chain_follower::Point; - /// - /// let slot = 42; - /// let point = Point::fuzzy(slot); - /// ``` - #[must_use] - pub fn fuzzy(slot: u64) -> Self { - Self(pallas::network::miniprotocols::Point::Specific( - slot, - Vec::new(), - )) - } - - /// Creates a new Fuzzy `Point` from a concrete point. - /// - /// Will not alter either TIP or ORIGIN points. - #[must_use] - pub fn as_fuzzy(&self) -> Self { - if *self == TIP_POINT { - TIP_POINT - } else { - match self.0 { - pallas::network::miniprotocols::Point::Specific(slot, _) => Self::fuzzy(slot), - pallas::network::miniprotocols::Point::Origin => ORIGIN_POINT, - } - } - } - - /// Check if a Point is Fuzzy. - /// - /// Even though we don't know the hash for TIP or Origin, neither of these points - /// are considered to be fuzzy. - /// - /// # Examples - /// - /// ```rs - /// use cardano_chain_follower::Point; - /// - /// let slot = 42; - /// let point = Point::fuzzy(slot); - /// - /// assert!(point.is_fuzzy()); - /// ``` - #[must_use] - pub fn is_fuzzy(&self) -> bool { - if *self == TIP_POINT { - false - } else { - match self.0 { - pallas::network::miniprotocols::Point::Specific(_, ref hash) => hash.is_empty(), - pallas::network::miniprotocols::Point::Origin => false, - } - } - } - - /// Check if a Point is the origin. - /// - /// Origin is the synthetic Origin point, and ALSO any point thats at slot zero with a - /// hash. - /// - /// # Examples - /// - /// ```rs - /// use cardano_chain_follower::Point; - /// - /// let slot = 42; - /// let point = Point::fuzzy(slot); - /// - /// assert!(!point.is_origin()); - /// ``` - #[must_use] - pub fn is_origin(&self) -> bool { - match self.0 { - pallas::network::miniprotocols::Point::Specific(slot, ref hash) => { - slot == 0 && !hash.is_empty() - }, - pallas::network::miniprotocols::Point::Origin => true, - } - } - - /// Check if a Point is actually unknown. - /// - /// # Examples - /// - /// ```rs - /// use cardano_chain_follower::Point; - /// - /// let point = Point::fuzzy(0); - /// - /// assert!(point.is_unknown()); - /// ``` - #[must_use] - pub fn is_unknown(&self) -> bool { - match self.0 { - pallas::network::miniprotocols::Point::Specific(slot, ref hash) => { - slot == 0 && hash.is_empty() - }, - pallas::network::miniprotocols::Point::Origin => false, - } - } - - /// Check if a Point is actually unknown. - /// - /// # Examples - /// - /// ```rs - /// use cardano_chain_follower::Point; - /// - /// let point = Point::fuzzy(0); - /// - /// assert!(point.is_unknown()); - /// ``` - #[must_use] - pub fn is_tip(&self) -> bool { - match self.0 { - pallas::network::miniprotocols::Point::Specific(slot, ref hash) => { - slot == u64::MAX && hash.is_empty() - }, - pallas::network::miniprotocols::Point::Origin => false, - } - } - - /// Compares the hash stored in the `Point` with a known hash. - /// It returns `true` if the hashes match and `false` otherwise. If the - /// provided hash is `None`, the function checks if the `Point` has an - /// empty hash. - /// - /// # Parameters - /// - /// * `hash` - An `Option>` containing the hash to compare against. If - /// `Some`, the contained hash is compared with the `Point`'s hash. If `None`, the - /// function checks if the `Point`'s hash is empty. - /// - /// # Returns - /// - /// A `bool` indicating whether the hashes match. - /// - /// # Examples - /// - /// ```rs - /// use cardano_chain_follower::Point; - /// - /// use pallas::crypto::hash::Hash; - /// - /// let point = Point::new(42, vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); - /// let hash = Some(Hash::new([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])); - /// assert!(point.cmp_hash(&hash)); - /// - /// let empty_point = Point::fuzzy(42); - /// assert!(empty_point.cmp_hash(&None)); - /// ``` - #[must_use] - pub fn cmp_hash(&self, hash: &Option>) -> bool { - match hash { - Some(cmp_hash) => { - match self.0 { - pallas::network::miniprotocols::Point::Specific(_, ref hash) => { - **hash == **cmp_hash - }, - pallas::network::miniprotocols::Point::Origin => false, - } - }, - None => { - match self.0 { - pallas::network::miniprotocols::Point::Specific(_, ref hash) => hash.is_empty(), - pallas::network::miniprotocols::Point::Origin => true, - } - }, - } - } - - /// Retrieves the slot number from the `Point`. If the `Point` - /// is the origin, it returns a default slot number. - /// - /// # Returns - /// - /// A `u64` representing the slot number. If the `Point` is the origin, - /// it returns a default slot value, typically `0`. - /// - /// # Examples - /// - /// ```rs - /// use cardano_chain_follower::{Point, ORIGIN_POINT}; - /// - /// let specific_point = Point::new(42, vec![1, 2, 3]); - /// assert_eq!(specific_point.slot_or_default(), 42); - /// - /// let origin_point = ORIGIN_POINT; - /// assert_eq!(origin_point.slot_or_default(), 0); // assuming 0 is the default - /// ``` - #[must_use] - pub fn slot_or_default(&self) -> u64 { - self.0.slot_or_default() - } - - /// Retrieves the hash from the `Point`. If the `Point` is - /// the origin, it returns a default hash value, which is an empty `Vec`. - /// - /// # Returns - /// - /// A `Vec` representing the hash. If the `Point` is the `Origin`, it - /// returns an empty vector. - /// - /// # Examples - /// - /// ```rs - /// use cardano_chain_follower::{Point, ORIGIN_POINT}; - /// - /// let specific_point = Point::new(42, vec![1, 2, 3]); - /// assert_eq!(specific_point.hash_or_default(), vec![1, 2, 3]); - /// - /// let origin_point = ORIGIN_POINT; - /// assert_eq!(origin_point.hash_or_default(), Vec::new()); - /// ``` - #[must_use] - pub fn hash_or_default(&self) -> Vec { - match &self.0 { - pallas::network::miniprotocols::Point::Specific(_, hash) => hash.clone(), - pallas::network::miniprotocols::Point::Origin => Vec::new(), - } - } - - /// Checks if two `Point` instances are strictly equal. - /// Strict equality means both the slot number and hash must be identical. - /// - /// # Parameters - /// - /// * `b` - Another `Point` instance to compare against. - /// - /// # Returns - /// - /// A `bool` indicating whether the two `Point` instances are strictly equal. - /// - /// # Examples - /// - /// ```rs - /// use cardano_chain_follower::Point; - /// - /// let point1 = Point::new(42, vec![1, 2, 3]); - /// let point2 = Point::new(42, vec![1, 2, 3]); - /// assert!(point1.strict_eq(&point2)); - /// - /// let point3 = Point::new(42, vec![1, 2, 3]); - /// let point4 = Point::new(43, vec![1, 2, 3]); - /// assert!(!point3.strict_eq(&point4)); - /// ``` - #[must_use] - pub fn strict_eq(&self, b: &Self) -> bool { - self.0 == b.0 - } -} - -impl Display for Point { - fn fmt(&self, f: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { - if *self == ORIGIN_POINT { - return write!(f, "Point @ Origin"); - } else if *self == TIP_POINT { - return write!(f, "Point @ Tip"); - } else if *self == UNKNOWN_POINT { - return write!(f, "Point @ Unknown"); - } - - let slot = self.slot_or_default(); - let hash = self.hash_or_default(); - if hash.is_empty() { - return write!(f, "Point @ Probe:{slot}"); - } - write!(f, "Point @ {slot}:{}", hex::encode(hash)) - } -} - -impl From for Point { - fn from(point: pallas::network::miniprotocols::Point) -> Self { - Self(point) - } -} - -impl From for pallas::network::miniprotocols::Point { - fn from(point: Point) -> pallas::network::miniprotocols::Point { - point.0 - } -} - -impl PartialOrd for Point { - /// Implements a partial ordering based on the slot number - /// of two `Point` instances. It only checks the slot number for ordering. - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Point { - /// Implements a total ordering based on the slot number - /// of two `Point` instances. It only checks the slot number for ordering. - fn cmp(&self, other: &Self) -> Ordering { - cmp_point(&self.0, &other.0) - } -} - -impl PartialEq for Point { - /// Allows to compare a `SnapshotID` against `u64` (Just the Immutable File Number). - /// - /// Equality ONLY checks the Immutable File Number, not the path. - /// This is because the Filename is already the Immutable File Number. - fn eq(&self, other: &u64) -> bool { - self.0.slot_or_default() == *other - } -} - -impl PartialOrd for Point { - /// Allows to compare a `Point` against a `u64` (Just the Immutable File Number). - /// - /// Equality ONLY checks the Immutable File Number, not the path. - /// This is because the Filename is already the Immutable File Number. - fn partial_cmp(&self, other: &u64) -> Option { - self.0.slot_or_default().partial_cmp(other) - } -} - -impl PartialEq> for Point { - /// Allows to compare a `SnapshotID` against `u64` (Just the Immutable File Number). - /// - /// Equality ONLY checks the Immutable File Number, not the path. - /// This is because the Filename is already the Immutable File Number. - fn eq(&self, other: &Option) -> bool { - if let Some(other) = other { - *self == *other - } else { - false - } - } -} - -impl PartialOrd> for Point { - /// Allows to compare a `Point` against a `u64` (Just the Immutable File Number). - /// - /// Equality ONLY checks the Immutable File Number, not the path. - /// This is because the Filename is already the Immutable File Number. - /// Any point is greater than None. - fn partial_cmp(&self, other: &Option) -> Option { - if let Some(other) = other { - self.partial_cmp(other) - } else { - Some(Ordering::Greater) - } - } -} - -impl Default for Point { - /// Returns the default value for `Point`, which is `UNKNOWN_POINT`. - fn default() -> Self { - UNKNOWN_POINT - } -} - -/// Compare Points, because Pallas does not impl `Ord` for Point. -pub(crate) fn cmp_point( - a: &pallas::network::miniprotocols::Point, b: &pallas::network::miniprotocols::Point, -) -> Ordering { - match a { - pallas::network::miniprotocols::Point::Origin => { - match b { - pallas::network::miniprotocols::Point::Origin => Ordering::Equal, - pallas::network::miniprotocols::Point::Specific(..) => Ordering::Less, - } - }, - pallas::network::miniprotocols::Point::Specific(slot, _) => { - match b { - pallas::network::miniprotocols::Point::Origin => Ordering::Greater, - pallas::network::miniprotocols::Point::Specific(other_slot, _) => { - slot.cmp(other_slot) - }, - } - }, - } -} - -#[cfg(test)] -mod tests { - use pallas::crypto::hash::Hash; - - use crate::*; - - #[test] - fn test_create_points() { - let point1 = Point::new(100u64, vec![]); - let fuzzy1 = Point::fuzzy(100u64); - - assert!(point1 == fuzzy1); - } - - #[test] - fn test_cmp_hash_simple() { - let origin1 = ORIGIN_POINT; - let point1 = Point::new(100u64, vec![8; 32]); - - assert!(!origin1.cmp_hash(&Some(Hash::new([0; 32])))); - assert!(origin1.cmp_hash(&None)); - - assert!(point1.cmp_hash(&Some(Hash::new([8; 32])))); - assert!(!point1.cmp_hash(&None)); - } - - #[test] - fn test_get_hash_simple() { - let point1 = Point::new(100u64, vec![8; 32]); - - assert_eq!(point1.hash_or_default(), vec![8; 32]); - } - - #[test] - fn test_identical_compare() { - let point1 = Point::new(100u64, vec![8; 32]); - let point2 = Point::new(100u64, vec![8; 32]); - let point3 = Point::new(999u64, vec![8; 32]); - - assert!(point1.strict_eq(&point2)); - assert!(!point1.strict_eq(&point3)); - } - - #[test] - fn test_comparisons() { - let origin1 = ORIGIN_POINT; - let origin2 = ORIGIN_POINT; - let tip1 = TIP_POINT; - let tip2 = TIP_POINT; - let early_block = Point::new(100u64, vec![]); - let late_block1 = Point::new(5000u64, vec![]); - let late_block2 = Point::new(5000u64, vec![]); - - assert!(origin1 == origin2); - assert!(origin1 < early_block); - assert!(origin1 <= early_block); - assert!(origin1 != early_block); - assert!(origin1 < late_block1); - assert!(origin1 <= late_block1); - assert!(origin1 != late_block1); - assert!(origin1 < tip1); - assert!(origin1 <= tip1); - assert!(origin1 != tip1); - - assert!(tip1 > origin1); - assert!(tip1 >= origin1); - assert!(tip1 != origin1); - assert!(tip1 > early_block); - assert!(tip1 >= late_block1); - assert!(tip1 != late_block1); - assert!(tip1 == tip2); - - assert!(early_block > origin1); - assert!(early_block >= origin1); - assert!(early_block != origin1); - assert!(early_block < late_block1); - assert!(early_block <= late_block1); - assert!(early_block != late_block1); - assert!(early_block < tip1); - assert!(early_block <= tip1); - assert!(early_block != tip1); - - assert!(late_block1 == late_block2); - assert!(late_block1 > origin1); - assert!(late_block1 >= origin1); - assert!(late_block1 != origin1); - assert!(late_block1 > early_block); - assert!(late_block1 >= early_block); - assert!(late_block1 != early_block); - assert!(late_block1 < tip1); - assert!(late_block1 <= tip1); - assert!(late_block1 != tip1); - } -} diff --git a/rust/cardano-chain-follower/src/snapshot_id.rs b/rust/cardano-chain-follower/src/snapshot_id.rs index 4a5489b2f..3b2bea10d 100644 --- a/rust/cardano-chain-follower/src/snapshot_id.rs +++ b/rust/cardano-chain-follower/src/snapshot_id.rs @@ -7,13 +7,10 @@ use std::{ path::{Path, PathBuf}, }; +use cardano_blockchain_types::{Network, Point}; use tracing::debug; -use crate::{ - mithril_snapshot_sync::{get_mithril_tip, MITHRIL_IMMUTABLE_SUB_DIRECTORY}, - point::UNKNOWN_POINT, - Network, Point, -}; +use crate::mithril_snapshot_sync::{get_mithril_tip, MITHRIL_IMMUTABLE_SUB_DIRECTORY}; /// A Representation of a Snapshot Path and its represented Immutable File Number. #[derive(Clone, Debug)] pub(crate) struct SnapshotId { @@ -101,7 +98,7 @@ impl default::Default for SnapshotId { SnapshotId { path: PathBuf::new(), file: 0, - tip: UNKNOWN_POINT, + tip: Point::UNKNOWN, } } } @@ -185,7 +182,6 @@ impl PartialOrd for SnapshotId { #[cfg(test)] mod tests { use super::*; - use crate::point::*; const TEST_DIR: &str = "test_data/test_snapshot_id"; @@ -219,9 +215,9 @@ mod tests { let dir_path_2 = &[TEST_DIR, "12346"].join("/"); let dir_path_3 = &[TEST_DIR, "12347"].join("/"); - let point_1 = Point::fuzzy(999); - let point_2 = Point::new(999, vec![0; 32]); - let point_3 = Point::new(12345, vec![8; 32]); + let point_1 = Point::fuzzy(999.into()); + let point_2 = Point::new(999.into(), [0; 32].into()); + let point_3 = Point::new(12345.into(), [8; 32].into()); assert!(SnapshotId::new(&PathBuf::from(dir_path_1), point_1).is_some()); assert!(SnapshotId::new(&PathBuf::from(dir_path_2), point_2).is_some()); @@ -245,7 +241,7 @@ mod tests { fn test_immutable_path() { let dir_path_1 = &[TEST_DIR, "12345"].join("/"); - let point_1 = Point::fuzzy(999); + let point_1 = Point::fuzzy(999.into()); let snapshot_id_1 = SnapshotId::new(&PathBuf::from(dir_path_1), point_1) .expect("cannot create snapshot id"); @@ -263,9 +259,9 @@ mod tests { let dir_path_3 = &[TEST_DIR, "12346"].join("/"); let dir_path_4 = &[TEST_DIR, "12347"].join("/"); - let point_1 = Point::fuzzy(999); - let point_2 = Point::new(999, vec![0; 32]); - let point_3 = Point::new(12345, vec![8; 32]); + let point_1 = Point::fuzzy(999.into()); + let point_2 = Point::new(999.into(), [0; 32].into()); + let point_3 = Point::new(12345.into(), [8; 32].into()); let snapshot_id_1 = SnapshotId::new(&PathBuf::from(dir_path_1), point_1.clone()); let snapshot_id_2 = SnapshotId::new(&PathBuf::from(dir_path_2), point_1); diff --git a/rust/cardano-chain-follower/src/stats.rs b/rust/cardano-chain-follower/src/stats.rs index fadd26f1b..7049cf7e7 100644 --- a/rust/cardano-chain-follower/src/stats.rs +++ b/rust/cardano-chain-follower/src/stats.rs @@ -2,14 +2,13 @@ use std::sync::{Arc, LazyLock, RwLock}; +use cardano_blockchain_types::Network; use chrono::{DateTime, Utc}; use dashmap::DashMap; use serde::Serialize; use strum::{EnumIter, IntoEnumIterator}; use tracing::error; -use crate::Network; - // -------- GENERAL STATISTIC TRACKING /// Statistics related to Mithril Snapshots From 1d370120ea9a27f69d6b7eb2181ef02d7fa4ed14 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Thu, 19 Dec 2024 13:09:22 +0700 Subject: [PATCH 02/40] fix(cardano-chain-follower): comments Signed-off-by: bkioshn --- rust/cardano-chain-follower/src/chain_sync.rs | 4 ++-- .../src/chain_sync_config.rs | 16 ++++++---------- .../src/chain_sync_live_chains.rs | 19 ++++++++++--------- .../src/chain_update.rs | 2 +- rust/cardano-chain-follower/src/error.rs | 4 ++-- rust/cardano-chain-follower/src/follow.rs | 10 +++++----- .../src/mithril_snapshot.rs | 2 +- .../src/mithril_snapshot_config.rs | 3 ++- 8 files changed, 29 insertions(+), 31 deletions(-) diff --git a/rust/cardano-chain-follower/src/chain_sync.rs b/rust/cardano-chain-follower/src/chain_sync.rs index fef5fe334..eb16f6d45 100644 --- a/rust/cardano-chain-follower/src/chain_sync.rs +++ b/rust/cardano-chain-follower/src/chain_sync.rs @@ -40,7 +40,7 @@ use crate::{ const MAX_NODE_CONNECT_TIME_SECS: u64 = 2; /// The maximum number of times we wait for a nodeChainUpdate to connect. -/// Currently set to never give up. +/// Currently set to maximum of 5 retries. const MAX_NODE_CONNECT_RETRIES: u64 = 5; /// Try and connect to a node, in a robust and quick way. @@ -120,7 +120,7 @@ async fn resync_live_tip(client: &mut PeerClient, chain: Network) -> Result anyhow::Result { diff --git a/rust/cardano-chain-follower/src/chain_sync_config.rs b/rust/cardano-chain-follower/src/chain_sync_config.rs index e0dcc7e0e..492b50afd 100644 --- a/rust/cardano-chain-follower/src/chain_sync_config.rs +++ b/rust/cardano-chain-follower/src/chain_sync_config.rs @@ -22,12 +22,13 @@ use crate::{ /// Default Follower block buffer size. const DEFAULT_CHAIN_UPDATE_BUFFER_SIZE: usize = 32; -/// How many slots back from TIP is considered Immutable in the absence of a mithril -/// snapshot. +/// How many window (in slot) back from TIP is considered Immutable in the +/// absence of a mithril snapshot. const DEFAULT_IMMUTABLE_SLOT_WINDOW: u64 = 12 * 60 * 60; /// Type we use to manage the Sync Task handle map. type SyncMap = DashMap>>>; + /// Handle to the mithril sync thread. One for each Network ONLY. static SYNC_JOIN_HANDLE_MAP: LazyLock = LazyLock::new(|| { let map = DashMap::new(); @@ -68,7 +69,7 @@ impl ChainSyncConfig { } } - /// Sets the relay to use for Chain Sync. + /// Sets the relay address to use for Chain Sync. /// /// # Arguments /// @@ -101,12 +102,11 @@ impl ChainSyncConfig { self } - /// Sets the the Mithril snapshot Config the `ChainSync` will use. + /// Sets the Mithril snapshot Config the `ChainSync` will use. /// /// # Arguments /// - /// * `path`: Mithril snapshot path. - /// * `update`: Auto-update this path with the latest mithril snapshot as it changes. + /// * `cfg`: Mithril snapshot configuration. #[must_use] pub fn mithril_cfg(mut self, cfg: MithrilSnapshotConfig) -> Self { self.mithril_cfg = cfg; @@ -117,10 +117,6 @@ impl ChainSyncConfig { /// /// Must be done BEFORE the chain can be followed. /// - /// # Arguments - /// - /// * `chain`: The chain to follow. - /// /// # Returns /// /// `Result<()>`: On success. diff --git a/rust/cardano-chain-follower/src/chain_sync_live_chains.rs b/rust/cardano-chain-follower/src/chain_sync_live_chains.rs index d3998c11d..0c5141ebd 100644 --- a/rust/cardano-chain-follower/src/chain_sync_live_chains.rs +++ b/rust/cardano-chain-follower/src/chain_sync_live_chains.rs @@ -21,7 +21,7 @@ use crate::{ /// Type we use to manage the Sync Task handle map. type LiveChainBlockList = SkipMap; -/// Because we have multi-entry relationships in the live-chain protect it with a +/// Because we have multi-entry relationships in the live-chain, it need to protect it with a /// `read/write lock`. The underlying `SkipMap` is still capable of multiple simultaneous /// reads from multiple threads which is the most common access. #[derive(Clone)] @@ -50,7 +50,8 @@ fn update_peer_tip(chain: Network, tip: Point) { PEER_TIP.insert(chain, tip); } -/// Set the last TIP received from the peer. +/// Get the last TIP received from the peer. +/// If the peer tip doesn't exist, get the UNKNOWN point. pub(crate) fn get_peer_tip(chain: Network) -> Point { (*PEER_TIP.get_or_insert(chain, Point::UNKNOWN).value()).clone() } @@ -117,7 +118,7 @@ impl ProtectedLiveChainBlockList { Ok(check_first_live_block.point()) } - /// Get the point of the first known block in the Live Chain. + /// Get the point of the last known block in the Live Chain. fn get_last_live_point(live_chain: &LiveChainBlockList) -> Point { let Some(check_last_live_entry) = live_chain.back() else { // Its not an error if we can't get a latest block because the chain is empty, @@ -151,7 +152,7 @@ impl ProtectedLiveChainBlockList { ))); } - // Get the current Oldest block in the live chain. + // Get the current oldest block in the live chain. let check_first_live_point = Self::get_first_live_point(&live_chain)?; let last_backfill_block = blocks @@ -160,7 +161,7 @@ impl ProtectedLiveChainBlockList { .clone(); let last_backfill_point = last_backfill_block.point(); - // Make sure the backfill will properly connect the partial Live chain to the Mithril + // Make sure the backfill will properly connect the partial live chain to the Mithril // chain. if !last_backfill_point.strict_eq(&check_first_live_point) { return Err(Error::LiveSync(format!( @@ -179,8 +180,8 @@ impl ProtectedLiveChainBlockList { Ok(()) } - /// Check if the given point is strictly in the live-chain. This means the slot and - /// Hash MUST be present. + /// Check if the given point is strictly in the live-chain. This means the slot and + /// block hash MUST be present. fn strict_block_lookup(live_chain: &LiveChainBlockList, point: &Point) -> bool { if let Some(found_block) = live_chain.get(point) { return found_block.value().point().strict_eq(point); @@ -451,7 +452,7 @@ pub(crate) fn get_live_block( live_chain.get_block(point, advance, strict) } -/// Get the fill tp point for a chain. +/// Get the fill to point for a chain. /// /// Returns the Point of the block we are filling up-to, and it's fork count. /// @@ -493,7 +494,7 @@ pub(crate) fn live_chain_length(chain: Network) -> usize { live_chain.len() } -/// On an immutable update, purge the live-chain up to the new immutable tip. +/// On an immutable update, purge the live chain up to the new immutable tip. /// Will error if the point is not in the Live chain. pub(crate) fn purge_live_chain(chain: Network, point: &Point) -> Result<()> { let live_chain = get_live_chain(chain); diff --git a/rust/cardano-chain-follower/src/chain_update.rs b/rust/cardano-chain-follower/src/chain_update.rs index 50a94426f..f9330e865 100644 --- a/rust/cardano-chain-follower/src/chain_update.rs +++ b/rust/cardano-chain-follower/src/chain_update.rs @@ -40,7 +40,7 @@ impl ChainUpdate { &self.data } - /// Gets the chain update's block data. + /// Is the chain update immutable? #[must_use] pub fn immutable(&self) -> bool { self.data.immutable() diff --git a/rust/cardano-chain-follower/src/error.rs b/rust/cardano-chain-follower/src/error.rs index 862a5298d..1f7fe748d 100644 --- a/rust/cardano-chain-follower/src/error.rs +++ b/rust/cardano-chain-follower/src/error.rs @@ -21,7 +21,7 @@ pub enum Error { /// Chainsync protocol error. #[error("Chainsync error: {0:?}")] Chainsync(chainsync::ClientError), - /// Backfill Synch error. + /// Backfill Sync error. #[error("Backfill Sync error: {0}")] BackfillSync(String), /// Live Sync error. @@ -48,7 +48,7 @@ pub enum Error { /// Mithril snapshot traversal error. #[error("Failed to traverse block(s) from Mithril snapshot")] MithrilSnapshotTraverse(pallas::ledger::traverse::Error), - /// Failed to parse + /// Failed to parse network error. #[error("Failed to parse network")] ParseNetwork, /// Mithril Snapshot path is not a directory diff --git a/rust/cardano-chain-follower/src/follow.rs b/rust/cardano-chain-follower/src/follow.rs index 9a17dfc82..91c3ea544 100644 --- a/rust/cardano-chain-follower/src/follow.rs +++ b/rust/cardano-chain-follower/src/follow.rs @@ -23,9 +23,9 @@ pub struct ChainFollower { chain: Network, /// Where we end following. end: Point, - /// Block we processed most recently. + /// Point we processed most recently. previous: Point, - /// Where we are currently in the following process. + /// Point we are currently in the following process. current: Point, /// What fork were we last on fork: Fork, @@ -134,7 +134,7 @@ impl ChainFollower { None } - /// If we can, get the next update from the mithril snapshot. + /// If we can, get the next update from the live chain. async fn next_from_live_chain(&mut self) -> Option { let mut next_block: Option = None; let mut update_type = chain_update::Kind::Block; @@ -208,7 +208,7 @@ impl ChainFollower { None } - /// Update the current Point, and return `false` if this fails. + /// Update the current Point, return `false` if this fails. fn update_current(&mut self, update: &Option) -> bool { if let Some(update) = update { let decoded = update.block_data().decode(); @@ -323,7 +323,7 @@ impl ChainFollower { /// /// # Arguments /// - /// * `chain` - The blockchain to post the transaction on. + /// * `chain` - The blockchain network to post the transaction on. /// * `txn` - The transaction to be posted. /// /// # Returns diff --git a/rust/cardano-chain-follower/src/mithril_snapshot.rs b/rust/cardano-chain-follower/src/mithril_snapshot.rs index b98c2555d..a635733a6 100644 --- a/rust/cardano-chain-follower/src/mithril_snapshot.rs +++ b/rust/cardano-chain-follower/src/mithril_snapshot.rs @@ -33,7 +33,7 @@ impl MithrilSnapshot { /// Checks if the snapshot contains a given point. /// /// # Arguments - /// * `network`: The network that this function should check against. + /// /// * `point`: The point to be checked for existence within the specified Mithril /// snapshot. /// diff --git a/rust/cardano-chain-follower/src/mithril_snapshot_config.rs b/rust/cardano-chain-follower/src/mithril_snapshot_config.rs index 099360f19..e4c95a091 100644 --- a/rust/cardano-chain-follower/src/mithril_snapshot_config.rs +++ b/rust/cardano-chain-follower/src/mithril_snapshot_config.rs @@ -29,6 +29,7 @@ use crate::{ /// Type we use to manage the Sync Task handle map. type SyncMap = DashMap>>>; + /// Handle to the mithril sync thread. One for each Network ONLY. static SYNC_JOIN_HANDLE_MAP: LazyLock = LazyLock::new(|| { let map = DashMap::new(); @@ -294,7 +295,7 @@ impl MithrilSnapshotConfig { snapshot_path } - /// Check if the Mithril Snapshot Path is valid an usable. + /// Check if the Mithril Snapshot Path is valid and usable. async fn validate_path(&self) -> Result<()> { let path = self.path.clone(); debug!( From e645601a1e73b065ba0429e17cb0e6e47b7c2bcf Mon Sep 17 00:00:00 2001 From: bkioshn Date: Thu, 19 Dec 2024 20:08:18 +0700 Subject: [PATCH 03/40] fix(cardano-chain-follower): comments Signed-off-by: bkioshn --- .../src/mithril_snapshot_data.rs | 3 +- .../src/mithril_snapshot_iterator.rs | 4 +- .../src/mithril_snapshot_sync.rs | 16 ++----- .../cardano-chain-follower/src/snapshot_id.rs | 46 ++++++++----------- 4 files changed, 28 insertions(+), 41 deletions(-) diff --git a/rust/cardano-chain-follower/src/mithril_snapshot_data.rs b/rust/cardano-chain-follower/src/mithril_snapshot_data.rs index 697cf71b0..2dcdf912c 100644 --- a/rust/cardano-chain-follower/src/mithril_snapshot_data.rs +++ b/rust/cardano-chain-follower/src/mithril_snapshot_data.rs @@ -26,7 +26,7 @@ impl SnapshotData { } impl default::Default for SnapshotData { - /// The default snapshot data represents there is no latest snapshot. + /// The default snapshot data represents, there is no latest snapshot. fn default() -> Self { SnapshotData { id: SnapshotId::default(), @@ -41,7 +41,6 @@ static CURRENT_MITHRIL_SNAPSHOT: LazyLock> = /// Get the current latest snapshot data we have recorded. pub(crate) fn latest_mithril_snapshot_data(chain: Network) -> SnapshotData { // There should ALWAYS be a snapshot for the chain if this is called. - match CURRENT_MITHRIL_SNAPSHOT.get(&chain) { Some(snapshot_data) => snapshot_data.value().clone(), None => SnapshotData::default(), diff --git a/rust/cardano-chain-follower/src/mithril_snapshot_iterator.rs b/rust/cardano-chain-follower/src/mithril_snapshot_iterator.rs index 233542320..9f6b883a5 100644 --- a/rust/cardano-chain-follower/src/mithril_snapshot_iterator.rs +++ b/rust/cardano-chain-follower/src/mithril_snapshot_iterator.rs @@ -23,9 +23,9 @@ const BACKWARD_SEARCH_SLOT_INTERVAL: u64 = 60; /// Synchronous Inner Iterator state struct MithrilSnapshotIteratorInner { - /// The chain being iterated + /// The blockchain network being iterated chain: Network, - /// Where we really want to start iterating from + /// Point we want to start iterating from start: Point, /// Previous iteration point. previous: Point, diff --git a/rust/cardano-chain-follower/src/mithril_snapshot_sync.rs b/rust/cardano-chain-follower/src/mithril_snapshot_sync.rs index f619069ed..3bd2dcef5 100644 --- a/rust/cardano-chain-follower/src/mithril_snapshot_sync.rs +++ b/rust/cardano-chain-follower/src/mithril_snapshot_sync.rs @@ -73,7 +73,7 @@ async fn get_latest_snapshots( Some((latest_snapshot.clone(), chronologically_previous.clone())) } -/// Given a particular snapshot ID, find the Actual Snapshot for it. +/// Given a particular snapshot ID, find the actual snapshot for it. async fn get_snapshot_by_id( client: &Client, network: Network, snapshot_id: &SnapshotId, ) -> Option { @@ -205,11 +205,7 @@ async fn download_and_verify_snapshot_certificate( /// /// # Arguments /// -/// * `network` - The network type for the client to connect to. -/// * `aggregator_url` - A reference to the URL of an aggregator that can be used to -/// create the client. -/// * `genesis_vkey` - The genesis verification key, which is needed to authenticate with -/// the server. +/// * `cfg` - Mithril snapshot configuration. /// /// # Returns /// @@ -238,6 +234,7 @@ pub(crate) const MITHRIL_IMMUTABLE_SUB_DIRECTORY: &str = "immutable"; /// /// # Arguments /// +/// * `chain` - The network chain to get the tip block from. /// * `path` - The path where the immutable chain is stored. /// /// # Returns @@ -676,11 +673,8 @@ macro_rules! next_iteration { /// networks. /// # Arguments /// -/// * `network` - The network type for the client to connect to. -/// * `aggregator_url` - A reference to the URL of an aggregator that can be used to -/// create the client. -/// * `genesis_vkey` - The genesis verification key, which is needed to authenticate with -/// the server. +/// * `cfg` - The configuration for the Mithril snapshot. +/// * `tx` - The message to be sent when Mithril Snapshot updates. /// /// # Returns /// diff --git a/rust/cardano-chain-follower/src/snapshot_id.rs b/rust/cardano-chain-follower/src/snapshot_id.rs index 3b2bea10d..08584daaf 100644 --- a/rust/cardano-chain-follower/src/snapshot_id.rs +++ b/rust/cardano-chain-follower/src/snapshot_id.rs @@ -11,19 +11,19 @@ use cardano_blockchain_types::{Network, Point}; use tracing::debug; use crate::mithril_snapshot_sync::{get_mithril_tip, MITHRIL_IMMUTABLE_SUB_DIRECTORY}; -/// A Representation of a Snapshot Path and its represented Immutable File Number. +/// A representation of a Snapshot Path and its represented immutable file number. #[derive(Clone, Debug)] pub(crate) struct SnapshotId { - /// The Snapshot Path + /// The snapshot path path: PathBuf, - /// The largest Immutable File Number + /// The largest immutable file number file: u64, - /// The Tip of the Snapshot + /// The tip of the Snapshot tip: Point, } impl SnapshotId { - /// See if we can Parse the path into an immutable file number. + /// See if we can parse the path into an immutable file number. pub(crate) fn parse_path(path: &Path) -> Option { // Path must actually exist, and be a directory. if !path.is_dir() { @@ -42,7 +42,7 @@ impl SnapshotId { } /// Try and create a new `SnapshotID` from a given path. - /// Immutable TIP must be provided. + /// Immutable tip must be provided. pub(crate) fn new(path: &Path, tip: Point) -> Option { debug!("Trying to Get SnapshotID of: {}", path.to_string_lossy()); let immutable_file = SnapshotId::parse_path(path)?; @@ -56,7 +56,7 @@ impl SnapshotId { } /// Try and create a new `SnapshotID` from a given path. - /// Includes properly getting the Immutable TIP. + /// Includes properly getting the immutable TIP. pub(crate) async fn try_new(chain: Network, path: &Path) -> Option { let Ok(tip) = get_mithril_tip(chain, path).await else { return None; @@ -65,7 +65,7 @@ impl SnapshotId { SnapshotId::new(path, tip.point()) } - /// Get the Immutable Blockchain path from this `SnapshotId` + /// Get the immutable blockchain path from this `SnapshotId` pub(crate) fn immutable_path(&self) -> PathBuf { let mut immutable = self.path.clone(); immutable.push(MITHRIL_IMMUTABLE_SUB_DIRECTORY); @@ -73,12 +73,12 @@ impl SnapshotId { immutable } - /// Get the Blockchain path from this `SnapshotId` + /// Get the blockchain path from this `SnapshotId` pub(crate) fn path(&self) -> PathBuf { self.path.clone() } - /// Get the Blockchain path from this `SnapshotId` only if it actually exists. + /// Get the blockchain path from this `SnapshotId` only if it actually exists. pub(crate) fn path_if_exists(&self) -> Option { if self.tip.is_unknown() { return None; @@ -86,7 +86,7 @@ impl SnapshotId { Some(self.path.clone()) } - /// Get the Tip of the Immutable Blockchain from this `SnapshotId` + /// Get the tip of the immutable blockchain from this `SnapshotId` pub(crate) fn tip(&self) -> Point { self.tip.clone() } @@ -122,27 +122,24 @@ impl Display for SnapshotId { } } -// Normal Comparisons to simplify code. +// Normal comparisons to simplify code. impl PartialEq for SnapshotId { - // Equality ONLY checks the Immutable File Number, not the path. - // This is because the Filename is already the ImmutableFileNumber + // Equality ONLY checks the `file` (immutable file number), not the path. fn eq(&self, other: &Self) -> bool { self.file == other.file } } impl PartialOrd for SnapshotId { - // Equality ONLY checks the Immutable File Number, not the path. - // This is because the Filename is already the ImmutableFileNumber + // Equality ONLY checks the `file` (immutable file number), not the path. fn partial_cmp(&self, other: &Self) -> Option { self.file.partial_cmp(&other.file) } } -// Allows us to compare a SnapshotID against Some(SnapshotID). +// Allows us to compare a `SnapshotID` against Some(`SnapshotID`). impl PartialEq> for SnapshotId { - // Equality ONLY checks the Immutable File Number, not the path. - // This is because the Filename is already the ImmutableFileNumber + // Equality ONLY checks the `file` (immutable file number), not the path. fn eq(&self, other: &Option) -> bool { match other { None => false, @@ -152,8 +149,7 @@ impl PartialEq> for SnapshotId { } impl PartialOrd> for SnapshotId { - // Equality ONLY checks the Immutable File Number, not the path. - // This is because the Filename is already the ImmutableFileNumber + // Equality ONLY checks the `file` (immutable file number), not the path. fn partial_cmp(&self, other: &Option) -> Option { match other { None => Some(Ordering::Greater), // Anything is always greater than None. @@ -162,18 +158,16 @@ impl PartialOrd> for SnapshotId { } } -// Allows us to compare a SnapshotID against u64 (Just the Immutable File Number). +// Allows us to compare a `SnapshotID` against u64 (just the immutable file number). impl PartialEq for SnapshotId { - // Equality ONLY checks the Immutable File Number, not the path. - // This is because the Filename is already the ImmutableFileNumber + // Equality ONLY checks the `file` (immutable file number), not the path. fn eq(&self, other: &u64) -> bool { self.file == *other } } impl PartialOrd for SnapshotId { - // Equality ONLY checks the Immutable File Number, not the path. - // This is because the Filename is already the ImmutableFileNumber + // Equality ONLY checks the `file` (immutable file number), not the path. fn partial_cmp(&self, other: &u64) -> Option { self.file.partial_cmp(other) } From 4d1aea00da5649085b7c80b6736fed3d5fc645e4 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Mon, 23 Dec 2024 16:16:42 +0700 Subject: [PATCH 04/40] fix(cardano-chain-follower): fix type --- rust/cardano-chain-follower/src/chain_sync.rs | 6 +- .../src/chain_sync_config.rs | 2 +- .../src/chain_sync_live_chains.rs | 6 +- .../src/chain_update.rs | 2 +- rust/cardano-chain-follower/src/lib.rs | 1 - .../src/mithril_snapshot.rs | 2 +- .../src/mithril_snapshot_iterator.rs | 6 +- rust/cardano-chain-follower/src/stats.rs | 8 +- rust/cardano-chain-follower/src/witness.rs | 135 ------------------ 9 files changed, 16 insertions(+), 152 deletions(-) delete mode 100644 rust/cardano-chain-follower/src/witness.rs diff --git a/rust/cardano-chain-follower/src/chain_sync.rs b/rust/cardano-chain-follower/src/chain_sync.rs index eb16f6d45..edd5a9839 100644 --- a/rust/cardano-chain-follower/src/chain_sync.rs +++ b/rust/cardano-chain-follower/src/chain_sync.rs @@ -189,8 +189,8 @@ async fn process_rollback( ) -> anyhow::Result { let rollback_slot = point.slot_or_default(); let head_slot = previous_point.slot_or_default(); - debug!("Head slot: {}", head_slot); - debug!("Rollback slot: {}", rollback_slot); + debug!("Head slot: {head_slot:?}"); + debug!("Rollback slot: {rollback_slot:?}"); let slot_rollback_size = if head_slot > rollback_slot { head_slot - rollback_slot } else { @@ -444,7 +444,7 @@ async fn live_sync_backfill_and_purge( stats::new_mithril_update( cfg.chain, update.tip.slot_or_default(), - live_chain_length(cfg.chain) as u64, + live_chain_length(cfg.chain), live_chain_head.slot_or_default(), ); diff --git a/rust/cardano-chain-follower/src/chain_sync_config.rs b/rust/cardano-chain-follower/src/chain_sync_config.rs index 492b50afd..db6699979 100644 --- a/rust/cardano-chain-follower/src/chain_sync_config.rs +++ b/rust/cardano-chain-follower/src/chain_sync_config.rs @@ -22,7 +22,7 @@ use crate::{ /// Default Follower block buffer size. const DEFAULT_CHAIN_UPDATE_BUFFER_SIZE: usize = 32; -/// How many window (in slot) back from TIP is considered Immutable in the +/// How many window (in slot) back from TIP is considered Immutable in the /// absence of a mithril snapshot. const DEFAULT_IMMUTABLE_SLOT_WINDOW: u64 = 12 * 60 * 60; diff --git a/rust/cardano-chain-follower/src/chain_sync_live_chains.rs b/rust/cardano-chain-follower/src/chain_sync_live_chains.rs index 0c5141ebd..8c49f8b09 100644 --- a/rust/cardano-chain-follower/src/chain_sync_live_chains.rs +++ b/rust/cardano-chain-follower/src/chain_sync_live_chains.rs @@ -21,9 +21,9 @@ use crate::{ /// Type we use to manage the Sync Task handle map. type LiveChainBlockList = SkipMap; -/// Because we have multi-entry relationships in the live-chain, it need to protect it with a -/// `read/write lock`. The underlying `SkipMap` is still capable of multiple simultaneous -/// reads from multiple threads which is the most common access. +/// Because we have multi-entry relationships in the live-chain, it need to protect it +/// with a `read/write lock`. The underlying `SkipMap` is still capable of multiple +/// simultaneous reads from multiple threads which is the most common access. #[derive(Clone)] struct ProtectedLiveChainBlockList(Arc>); diff --git a/rust/cardano-chain-follower/src/chain_update.rs b/rust/cardano-chain-follower/src/chain_update.rs index f9330e865..4835efab9 100644 --- a/rust/cardano-chain-follower/src/chain_update.rs +++ b/rust/cardano-chain-follower/src/chain_update.rs @@ -43,7 +43,7 @@ impl ChainUpdate { /// Is the chain update immutable? #[must_use] pub fn immutable(&self) -> bool { - self.data.immutable() + self.data.is_immutable() } } diff --git a/rust/cardano-chain-follower/src/lib.rs b/rust/cardano-chain-follower/src/lib.rs index 6516685fd..29f4f20d6 100644 --- a/rust/cardano-chain-follower/src/lib.rs +++ b/rust/cardano-chain-follower/src/lib.rs @@ -19,7 +19,6 @@ mod snapshot_id; mod stats; pub mod turbo_downloader; mod utils; -mod witness; pub use chain_sync_config::ChainSyncConfig; pub use chain_update::{ChainUpdate, Kind}; diff --git a/rust/cardano-chain-follower/src/mithril_snapshot.rs b/rust/cardano-chain-follower/src/mithril_snapshot.rs index a635733a6..2d8c9d31a 100644 --- a/rust/cardano-chain-follower/src/mithril_snapshot.rs +++ b/rust/cardano-chain-follower/src/mithril_snapshot.rs @@ -33,7 +33,7 @@ impl MithrilSnapshot { /// Checks if the snapshot contains a given point. /// /// # Arguments - /// + /// /// * `point`: The point to be checked for existence within the specified Mithril /// snapshot. /// diff --git a/rust/cardano-chain-follower/src/mithril_snapshot_iterator.rs b/rust/cardano-chain-follower/src/mithril_snapshot_iterator.rs index 9f6b883a5..c1662fb38 100644 --- a/rust/cardano-chain-follower/src/mithril_snapshot_iterator.rs +++ b/rust/cardano-chain-follower/src/mithril_snapshot_iterator.rs @@ -6,7 +6,7 @@ use std::{ sync::{Arc, Mutex}, }; -use cardano_blockchain_types::{MultiEraBlock, Network, Point}; +use cardano_blockchain_types::{MultiEraBlock, Network, Point, Slot}; use logcall::logcall; use tokio::task; use tracing::{debug, error}; @@ -54,10 +54,10 @@ pub(crate) struct MithrilSnapshotIterator { pub(crate) fn probe_point(point: &Point, distance: u64) -> Point { // Now that we have the tip, step back about 4 block intervals from tip, and do a fuzzy // iteration to find the exact two blocks at the end of the immutable chain. - let step_back_search = point.slot_or_default().saturating_sub(distance); + let step_back_search = Slot::from_saturating(point.slot_or_default().into() - distance); // We stepped back to the origin, so just return Origin - if step_back_search == 0 { + if step_back_search == 0.into() { return Point::ORIGIN; } diff --git a/rust/cardano-chain-follower/src/stats.rs b/rust/cardano-chain-follower/src/stats.rs index 7049cf7e7..7f98eff75 100644 --- a/rust/cardano-chain-follower/src/stats.rs +++ b/rust/cardano-chain-follower/src/stats.rs @@ -2,7 +2,7 @@ use std::sync::{Arc, LazyLock, RwLock}; -use cardano_blockchain_types::Network; +use cardano_blockchain_types::{Network, Slot}; use chrono::{DateTime, Utc}; use dashmap::DashMap; use serde::Serialize; @@ -142,9 +142,9 @@ pub struct Live { /// Current Number of Live Blocks pub blocks: u64, /// The current head of the live chain slot# - pub head_slot: u64, + pub head_slot: Slot, /// The current live tip slot# as reported by the peer. - pub tip: u64, + pub tip: Slot, /// Number of times we connected/re-connected to the Node. pub reconnects: u64, /// Last reconnect time, @@ -312,7 +312,7 @@ pub(crate) fn stats_invalid_block(chain: Network, immutable: bool) { /// Count the validly deserialized blocks pub(crate) fn new_live_block( - chain: Network, total_live_blocks: u64, head_slot: u64, tip_slot: u64, + chain: Network, total_live_blocks: u64, head_slot: Slot, tip_slot: Slot, ) { // This will actually always succeed. let Some(stats) = lookup_stats(chain) else { diff --git a/rust/cardano-chain-follower/src/witness.rs b/rust/cardano-chain-follower/src/witness.rs deleted file mode 100644 index f649d6b9f..000000000 --- a/rust/cardano-chain-follower/src/witness.rs +++ /dev/null @@ -1,135 +0,0 @@ -//! Transaction Witness -use std::fmt::{Display, Formatter}; - -use dashmap::DashMap; -use pallas::{codec::utils::Bytes, ledger::traverse::MultiEraTx}; - -use crate::utils::blake2b_244; - -/// `WitnessMap` type of `DashMap` with -/// key as [u8; 28] = (`blake2b_244` hash of the public key) -/// value as `(Bytes, Vec) = (public key, tx index within the block)` -pub(crate) type WitnessMap = DashMap<[u8; 28], (Bytes, Vec)>; - -#[derive(Debug)] -/// `TxWitness` struct to store the witness data. -pub(crate) struct TxWitness(WitnessMap); - -impl TxWitness { - /// Create a new `TxWitness` from a list of `MultiEraTx`. - pub(crate) fn new(txs: &[MultiEraTx]) -> anyhow::Result { - let map: WitnessMap = DashMap::new(); - for (i, tx) in txs.iter().enumerate() { - match tx { - MultiEraTx::AlonzoCompatible(tx, _) => { - let witness_set = &tx.transaction_witness_set; - if let Some(vkey_witness_set) = witness_set.vkeywitness.clone() { - for vkey_witness in vkey_witness_set { - let vkey_hash = blake2b_244(&vkey_witness.vkey)?; - let tx_num = u16::try_from(i)?; - map.entry(vkey_hash) - .and_modify(|entry: &mut (_, Vec)| entry.1.push(tx_num)) - .or_insert((vkey_witness.vkey.clone(), vec![tx_num])); - } - }; - }, - MultiEraTx::Babbage(tx) => { - let witness_set = &tx.transaction_witness_set; - if let Some(vkey_witness_set) = witness_set.vkeywitness.clone() { - for vkey_witness in vkey_witness_set { - let vkey_hash = blake2b_244(&vkey_witness.vkey)?; - let tx_num = u16::try_from(i)?; - map.entry(vkey_hash) - .and_modify(|entry: &mut (_, Vec)| entry.1.push(tx_num)) - .or_insert((vkey_witness.vkey.clone(), vec![tx_num])); - } - } - }, - MultiEraTx::Conway(tx) => { - let witness_set = &tx.transaction_witness_set; - if let Some(vkey_witness_set) = &witness_set.vkeywitness.clone() { - for vkey_witness in vkey_witness_set { - let vkey_hash = blake2b_244(&vkey_witness.vkey)?; - let tx_num = u16::try_from(i)?; - map.entry(vkey_hash) - .and_modify(|entry: &mut (_, Vec)| entry.1.push(tx_num)) - .or_insert((vkey_witness.vkey.clone(), vec![tx_num])); - } - } - }, - _ => { - return Err(anyhow::anyhow!("Unsupported transaction type")); - }, - }; - } - Ok(Self(map)) - } - - /// Check whether the public key hash is in the given transaction number. - pub(crate) fn check_witness_in_tx(&self, vkey_hash: &[u8; 28], tx_num: u16) -> bool { - self.0 - .get(vkey_hash) - .map_or(false, |entry| entry.1.contains(&tx_num)) - } - - /// Get the actual address from the given public key hash. - pub(crate) fn get_witness_pk_addr(&self, vkey_hash: &[u8; 28]) -> Option { - self.0.get(vkey_hash).map(|entry| entry.0.clone()) - } -} - -impl Display for TxWitness { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - for data in &self.0 { - let vkey_hash = hex::encode(data.key()); - let vkey: Vec = data.0.clone().into(); - let vkey_encoded = hex::encode(&vkey); - writeln!( - f, - "Key Hash: {}, PublicKey: {}, Tx: {:?}", - vkey_hash, vkey_encoded, data.1 - )?; - } - Ok(()) - } -} - -#[cfg(test)] -mod tests { - - use super::*; - use crate::multi_era_block_data::tests::{alonzo_block, babbage_block}; - - #[test] - fn tx_witness() { - let alonzo = alonzo_block(); - let alonzo_block = pallas::ledger::traverse::MultiEraBlock::decode(&alonzo) - .expect("Failed to decode MultiEraBlock"); - let txs_alonzo = alonzo_block.txs(); - let tx_witness_alonzo = TxWitness::new(&txs_alonzo).expect("Failed to create TxWitness"); - let vkey1_hash: [u8; 28] = - hex::decode("6082eb618d161a704207a0b3a9609e820111570d94d1e711b005386c") - .expect("Failed to decode vkey1_hash") - .try_into() - .expect("Invalid length of vkey1_hash"); - println!("{tx_witness_alonzo}"); - assert!(tx_witness_alonzo.get_witness_pk_addr(&vkey1_hash).is_some()); - assert!(tx_witness_alonzo.check_witness_in_tx(&vkey1_hash, 0)); - - let babbage = babbage_block(); - let babbage_block = pallas::ledger::traverse::MultiEraBlock::decode(&babbage) - .expect("Failed to decode MultiEraBlock"); - let txs_babbage = babbage_block.txs(); - let tx_witness_babbage = TxWitness::new(&txs_babbage).expect("Failed to create TxWitness"); - let vkey2_hash: [u8; 28] = - hex::decode("ba4ab50bdecca85162f3b8114739bc5ba3aaa6490e2b1d15ad0f9c66") - .expect("Failed to decode vkey2_hash") - .try_into() - .expect("Invalid length of vkey2_hash"); - println!("{tx_witness_babbage}"); - assert!(tx_witness_babbage - .get_witness_pk_addr(&vkey2_hash) - .is_some()); - assert!(tx_witness_babbage.check_witness_in_tx(&vkey2_hash, 0)); - } -} From 489a289d4870d8ebcd3467aa3c55a2f1ced680a9 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Mon, 23 Dec 2024 16:36:07 +0700 Subject: [PATCH 05/40] fix(cardano-chain-follower): fix type stat --- rust/cardano-chain-follower/src/stats.rs | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/rust/cardano-chain-follower/src/stats.rs b/rust/cardano-chain-follower/src/stats.rs index 7f98eff75..94dfe2ba9 100644 --- a/rust/cardano-chain-follower/src/stats.rs +++ b/rust/cardano-chain-follower/src/stats.rs @@ -17,7 +17,7 @@ pub struct Mithril { /// Number of Mithril Snapshots that have downloaded successfully. pub updates: u64, /// The Immutable TIP Slot# - Origin = No downloaded snapshot - pub tip: u64, + pub tip: Slot, /// Time we started downloading the current snapshot. 1/1/1970-00:00:00 UTC = Never /// downloaded. pub dl_start: DateTime, @@ -110,11 +110,11 @@ pub struct Follower { /// Synthetic follower connection ID pub id: u64, /// Starting slot for this follower (0 = Start at Genesis Block for the chain). - pub start: u64, + pub start: Slot, /// Current slot for this follower. - pub current: u64, + pub current: Slot, /// Target slot for this follower (MAX U64 == Follow Tip Forever). - pub end: u64, + pub end: Slot, /// Current Sync Time. pub sync_start: DateTime, /// When this follower reached TIP or its destination slot. @@ -238,13 +238,14 @@ impl Statistics { } /// Get the current tips of the immutable chain and live chain. - pub(crate) fn tips(chain: Network) -> (u64, u64) { + pub(crate) fn tips(chain: Network) -> (Slot, Slot) { + let zero_slot = Slot::from_saturating(0); let Some(stats) = lookup_stats(chain) else { - return (0, 0); + return (zero_slot, zero_slot); }; let Ok(chain_stats) = stats.read() else { - return (0, 0); + return (zero_slot, zero_slot); }; (chain_stats.mithril.tip, chain_stats.live.head_slot) @@ -333,7 +334,7 @@ pub(crate) fn new_live_block( /// Track the end of the current mithril update pub(crate) fn new_mithril_update( - chain: Network, mithril_tip: u64, total_live_blocks: u64, tip_slot: u64, + chain: Network, mithril_tip: Slot, total_live_blocks: u64, tip_slot: Slot, ) { // This will actually always succeed. let Some(stats) = lookup_stats(chain) else { @@ -790,12 +791,12 @@ mod tests { #[test] fn test_new_live_block() { let network = Network::Preprod; - new_live_block(network, 100, 50, 200); + new_live_block(network, 100, 50.into(), 200.into()); let stats = lookup_stats(network).unwrap(); let stats = stats.read().unwrap(); assert_eq!(stats.live.blocks, 100); - assert_eq!(stats.live.head_slot, 50); - assert_eq!(stats.live.tip, 200); + assert_eq!(stats.live.head_slot, 50.into()); + assert_eq!(stats.live.tip, 200.into()); } #[test] From d8542d19c407d2457982a33486302103b291727c Mon Sep 17 00:00:00 2001 From: bkioshn Date: Tue, 24 Dec 2024 13:18:22 +0700 Subject: [PATCH 06/40] fix(cardano-chain-follower): fix type --- rust/cardano-chain-follower/src/chain_sync.rs | 2 +- rust/cardano-chain-follower/src/chain_sync_live_chains.rs | 4 ++-- rust/cardano-chain-follower/src/metadata/mod.rs | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/rust/cardano-chain-follower/src/chain_sync.rs b/rust/cardano-chain-follower/src/chain_sync.rs index edd5a9839..e32e9839a 100644 --- a/rust/cardano-chain-follower/src/chain_sync.rs +++ b/rust/cardano-chain-follower/src/chain_sync.rs @@ -444,7 +444,7 @@ async fn live_sync_backfill_and_purge( stats::new_mithril_update( cfg.chain, update.tip.slot_or_default(), - live_chain_length(cfg.chain), + live_chain_length(cfg.chain) as u64, live_chain_head.slot_or_default(), ); diff --git a/rust/cardano-chain-follower/src/chain_sync_live_chains.rs b/rust/cardano-chain-follower/src/chain_sync_live_chains.rs index 8c49f8b09..0621230d2 100644 --- a/rust/cardano-chain-follower/src/chain_sync_live_chains.rs +++ b/rust/cardano-chain-follower/src/chain_sync_live_chains.rs @@ -6,7 +6,7 @@ use std::{ time::Duration, }; -use cardano_blockchain_types::{Fork, MultiEraBlock, Network, Point}; +use cardano_blockchain_types::{Fork, MultiEraBlock, Network, Point, Slot}; use crossbeam_skiplist::SkipMap; use rayon::prelude::*; use strum::IntoEnumIterator; @@ -340,7 +340,7 @@ impl ProtectedLiveChainBlockList { } // Now find points based on an every increasing Slot age. - let mut slot_age: u64 = 40; + let mut slot_age: Slot = 40.into(); let reference_slot = entry.value().point().slot_or_default(); let mut previous_point = entry.value().point(); diff --git a/rust/cardano-chain-follower/src/metadata/mod.rs b/rust/cardano-chain-follower/src/metadata/mod.rs index 1ed77c300..876319251 100644 --- a/rust/cardano-chain-follower/src/metadata/mod.rs +++ b/rust/cardano-chain-follower/src/metadata/mod.rs @@ -2,6 +2,7 @@ use std::{fmt::Debug, sync::Arc}; +use cardano_blockchain_types::Network; use cip36::Cip36; use cip509::Cip509; use dashmap::DashMap; @@ -9,7 +10,7 @@ use pallas::ledger::traverse::{MultiEraBlock, MultiEraTx}; use raw_aux_data::RawAuxData; use tracing::error; -use crate::{utils::usize_from_saturating, Network}; +use crate::utils::usize_from_saturating; pub mod cip36; pub mod cip509; From 1ce3a2066e779f821c83c5143e8406a486cdc136 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Wed, 25 Dec 2024 17:47:40 +0700 Subject: [PATCH 07/40] fix(cardano-chain-follower): remove raw_aux_data Signed-off-by: bkioshn --- .../src/metadata/raw_aux_data.rs | 269 ------------------ 1 file changed, 269 deletions(-) delete mode 100644 rust/cardano-chain-follower/src/metadata/raw_aux_data.rs diff --git a/rust/cardano-chain-follower/src/metadata/raw_aux_data.rs b/rust/cardano-chain-follower/src/metadata/raw_aux_data.rs deleted file mode 100644 index f8d39ed57..000000000 --- a/rust/cardano-chain-follower/src/metadata/raw_aux_data.rs +++ /dev/null @@ -1,269 +0,0 @@ -//! Raw Auxiliary Data Decoding - -use std::sync::Arc; - -use anyhow::bail; -use dashmap::DashMap; -use minicbor::{data::Type, Decoder}; -use tracing::{error, warn}; - -/// What type of smart contract is this list. -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, strum::Display, Hash)] -pub enum SmartContractType { - /// Native smart contracts - Native, - /// Plutus smart contracts (with version number 1-x) - Plutus(u64), -} - -// We CAN NOT use the Pallas library metadata decoding because it does not preserve raw -// metadata values which are critical for performing operations like signature checks on -// data. So we have a bespoke metadata decoder here. -#[derive(Debug)] -pub(crate) struct RawAuxData { - /// Metadata: key = label, value = raw metadata bytes - metadata: DashMap>>, - /// Scripts: 1 = Native, 2 = Plutus V1, 3 = Plutus V2, 4 = Plutus V3 - scripts: DashMap>>>, -} - -impl RawAuxData { - /// Create a new `RawDecodedMetadata`. - pub(crate) fn new(aux_data: &[u8]) -> Self { - let mut raw_decoded_data = Self { - metadata: DashMap::new(), - scripts: DashMap::new(), - }; - - let mut decoder = Decoder::new(aux_data); - - match decoder.datatype() { - Ok(minicbor::data::Type::Map) => { - if let Err(error) = Self::decode_shelley_map(&mut raw_decoded_data, &mut decoder) { - error!("Failed to Deserialize Shelley Metadata: {error}: {aux_data:02x?}"); - } - }, - Ok(minicbor::data::Type::Array) => { - if let Err(error) = - Self::decode_shelley_ma_array(&mut raw_decoded_data, &mut decoder) - { - error!("Failed to Deserialize Shelley-MA Metadata: {error}: {aux_data:02x?}"); - } - }, - Ok(minicbor::data::Type::Tag) => { - if let Err(error) = - Self::decode_alonzo_plus_map(&mut raw_decoded_data, &mut decoder) - { - error!("Failed to Deserialize Alonzo+ Metadata: {error}: {aux_data:02x?}"); - } - }, - Ok(unexpected) => { - error!("Unexpected datatype for Aux data: {unexpected}: {aux_data:02x?}"); - }, - Err(error) => { - error!("Error decoding metadata: {error}: {aux_data:02x?}"); - }, - } - - raw_decoded_data - } - - /// Decode the Shelley map of metadata. - fn decode_shelley_map( - raw_decoded_data: &mut Self, decoder: &mut minicbor::Decoder, - ) -> anyhow::Result<()> { - let entries = match decoder.map() { - Ok(Some(entries)) => entries, - Ok(None) => { - // Sadly... Indefinite Maps are allowed in Cardano CBOR Encoding. - u64::MAX - }, - Err(error) => { - bail!("Error decoding metadata: {error}"); - }, - }; - - // debug!("Decoding shelley metadata map with {} entries", entries); - - let raw_metadata = decoder.input(); - - for _ in 0..entries { - let key = match decoder.u64() { - Ok(key) => key, - Err(error) => { - bail!("Error decoding metadata key: {error}"); - }, - }; - let value_start = decoder.position(); - if let Err(error) = decoder.skip() { - bail!("Error decoding metadata value: {error}"); - } - let value_end = decoder.position(); - let Some(value_slice) = raw_metadata.get(value_start..value_end) else { - bail!("Invalid metadata value found. Unable to extract raw value slice."); - }; - let value = value_slice.to_vec(); - - // debug!("Decoded metadata key: {key}, value: {value:?}"); - - let _unused = raw_decoded_data.metadata.insert(key, Arc::new(value)); - - // Look for End Sentinel IF its an indefinite MAP (which we know because entries is - // u64::MAX). - if entries == u64::MAX { - match decoder.datatype() { - Ok(Type::Break) => { - // Skip over the break token. - let _unused = decoder.skip(); - break; - }, - Ok(_) => (), // Not break, so do next loop, should be the next key. - Err(error) => { - bail!("Error checking indefinite metadata map end sentinel: {error}"); - }, - } - } - } - - Ok(()) - } - - /// Decode a Shelley-MA Auxiliary Data Array - fn decode_shelley_ma_array( - raw_decoded_data: &mut Self, decoder: &mut minicbor::Decoder, - ) -> anyhow::Result<()> { - match decoder.array() { - Ok(Some(entries)) => { - if entries != 2 { - bail!( - "Invalid number of entries in Metadata Array. Expected 2, found {entries}." - ); - } - }, - Ok(None) => { - bail!("Indefinite Array found decoding Metadata. Invalid."); - }, - Err(error) => { - bail!("Error decoding metadata: {error}"); - }, - }; - - // First entry is the metadata map, so just decode that now. - Self::decode_shelley_map(raw_decoded_data, decoder)?; - // Second entry is an array of native scripts. - Self::decode_script_array(raw_decoded_data, decoder, SmartContractType::Native)?; - - Ok(()) - } - - /// Decode a Shelley-MA Auxiliary Data Array - fn decode_alonzo_plus_map( - raw_decoded_data: &mut Self, decoder: &mut minicbor::Decoder, - ) -> anyhow::Result<()> { - match decoder.tag() { - Ok(tag) => { - if tag.as_u64() != 259 { - bail!("Invalid tag for alonzo+ aux data. Expected 259, found {tag}."); - } - }, - Err(error) => { - bail!("Error decoding tag for alonzo+ aux data: {error}"); - }, - } - - let entries = match decoder.map() { - Ok(Some(entries)) => entries, - Ok(None) => bail!("Indefinite Map found decoding Alonzo+ Metadata. Invalid."), - Err(error) => bail!("Error decoding Alonzo+ Metadata: {error}"), - }; - - // iterate the map - for _ in 0..entries { - let aux_type_key = match decoder.u64() { - Ok(key) => key, - Err(error) => { - bail!("Error decoding Alonzo+ Metadata Aux Data Type Key: {error}"); - }, - }; - - let contract_type = match aux_type_key { - 0 => { - if raw_decoded_data.metadata.is_empty() { - Self::decode_shelley_map(raw_decoded_data, decoder)?; - continue; - } - bail!("Multiple Alonzo+ Metadata entries found. Invalid."); - }, - 1 => SmartContractType::Native, - _ => { - if aux_type_key > 4 { - warn!( - "Auxiliary Type Key > 4 detected, assuming its a plutus script > V3." - ); - } - SmartContractType::Plutus(aux_type_key - 1) - }, - }; - - if raw_decoded_data.scripts.contains_key(&contract_type) { - bail!("Multiple Alonzo+ Scripts of type {contract_type} found. Invalid."); - } - - Self::decode_script_array(raw_decoded_data, decoder, contract_type)?; - } - Ok(()) - } - - /// Decode an array of smart contract scripts - fn decode_script_array( - raw_decoded_data: &mut Self, decoder: &mut minicbor::Decoder, - contract_type: SmartContractType, - ) -> anyhow::Result<()> { - let mut scripts: Vec> = Vec::new(); - - let entries = match decoder.array() { - Ok(Some(entries)) => entries, - Ok(None) => { - bail!("Indefinite Script Array found decoding Metadata. Invalid."); - }, - Err(error) => { - bail!("Error decoding metadata: {error}"); - }, - }; - - let raw_metadata = decoder.input(); - - for _entry in 0..entries { - if contract_type == SmartContractType::Native { - // Native Scripts are actually CBOR arrays, so capture their data as bytes for - // later processing. - let value_start = decoder.position(); - if let Err(error) = decoder.skip() { - bail!("Error decoding native script value: {error}"); - } - let value_end = decoder.position(); - let Some(value_slice) = raw_metadata.get(value_start..value_end) else { - bail!("Invalid metadata value found. Unable to extract native script slice."); - }; - scripts.push(value_slice.to_vec()); - } else { - let script = match decoder.bytes() { - Ok(script) => script, - Err(error) => bail!("Error decoding script data from metadata: {error}"), - }; - scripts.push(script.to_vec()); - } - } - - let _unused = raw_decoded_data - .scripts - .insert(contract_type, Arc::new(scripts)); - - Ok(()) - } - - /// Get Raw metadata for a given metadata label, if it exists. - pub(crate) fn get_metadata(&self, label: u64) -> Option>> { - self.metadata.get(&label).map(|v| v.value().clone()) - } -} From 9f48bd0feb122acdc221a9bc9ac0352333faa7da Mon Sep 17 00:00:00 2001 From: bkioshn Date: Wed, 25 Dec 2024 17:48:13 +0700 Subject: [PATCH 08/40] fix(cardano-chain-follower): remove decoded_transaction Signed-off-by: bkioshn --- .../src/metadata/mod.rs | 108 +----------------- 1 file changed, 3 insertions(+), 105 deletions(-) diff --git a/rust/cardano-chain-follower/src/metadata/mod.rs b/rust/cardano-chain-follower/src/metadata/mod.rs index 876319251..ae9c29417 100644 --- a/rust/cardano-chain-follower/src/metadata/mod.rs +++ b/rust/cardano-chain-follower/src/metadata/mod.rs @@ -2,19 +2,14 @@ use std::{fmt::Debug, sync::Arc}; -use cardano_blockchain_types::Network; +use cardano_blockchain_types::{Network, TransactionAuxData}; use cip36::Cip36; use cip509::Cip509; use dashmap::DashMap; -use pallas::ledger::traverse::{MultiEraBlock, MultiEraTx}; -use raw_aux_data::RawAuxData; -use tracing::error; - -use crate::utils::usize_from_saturating; +use pallas::ledger::traverse::MultiEraTx; pub mod cip36; pub mod cip509; -mod raw_aux_data; /// List of all validation errors (as strings) Metadata is considered Valid if this list /// is empty. @@ -50,7 +45,7 @@ pub(crate) struct DecodedMetadata(DashMap>); impl DecodedMetadata { /// Create new decoded metadata for a transaction. - fn new(chain: Network, slot: u64, txn: &MultiEraTx, raw_aux_data: &RawAuxData) -> Self { + fn new(chain: Network, slot: u64, txn: &MultiEraTx, raw_aux_data: &TransactionAuxData) -> Self { let decoded_metadata = Self(DashMap::new()); // Process each known type of metadata here, and record the decoded result. @@ -82,100 +77,3 @@ impl Debug for DecodedMetadata { f.write_str("}") } } - -/// Decoded Metadata for a all transactions in a block. -/// The Key for both entries is the Transaction offset in the block. -#[derive(Debug)] -pub struct DecodedTransaction { - /// The Raw Auxiliary Data for each transaction in the block. - raw: DashMap, - /// The Decoded Metadata for each transaction in the block. - decoded: DashMap, -} - -impl DecodedTransaction { - /// Insert another transaction worth of data into the Decoded Aux Data - fn insert( - &mut self, chain: Network, slot: u64, txn_idx: u32, cbor_data: &[u8], - transactions: &[MultiEraTx], - ) { - let txn_idx = usize_from_saturating(txn_idx); - - let Some(txn) = transactions.get(txn_idx) else { - error!("No transaction at index {txn_idx} trying to decode metadata."); - return; - }; - - let txn_raw_aux_data = RawAuxData::new(cbor_data); - let txn_metadata = DecodedMetadata::new(chain, slot, txn, &txn_raw_aux_data); - - self.raw.insert(txn_idx, txn_raw_aux_data); - self.decoded.insert(txn_idx, txn_metadata); - } - - /// Create a new `DecodedTransaction`. - pub(crate) fn new(chain: Network, block: &MultiEraBlock) -> Self { - let mut decoded_aux_data = DecodedTransaction { - raw: DashMap::new(), - decoded: DashMap::new(), - }; - - if block.has_aux_data() { - let transactions = block.txs(); - let slot = block.slot(); - - if let Some(_metadata) = block.as_byron() { - // Nothing to do here. - } else if let Some(alonzo_block) = block.as_alonzo() { - for (txn_idx, metadata) in alonzo_block.auxiliary_data_set.iter() { - decoded_aux_data.insert( - chain, - slot, - *txn_idx, - metadata.raw_cbor(), - &transactions, - ); - } - } else if let Some(babbage_block) = block.as_babbage() { - for (txn_idx, metadata) in babbage_block.auxiliary_data_set.iter() { - decoded_aux_data.insert( - chain, - slot, - *txn_idx, - metadata.raw_cbor(), - &transactions, - ); - } - } else if let Some(conway_block) = block.as_conway() { - for (txn_idx, metadata) in conway_block.auxiliary_data_set.iter() { - decoded_aux_data.insert( - chain, - slot, - *txn_idx, - metadata.raw_cbor(), - &transactions, - ); - } - } else { - error!("Undecodable metadata, unknown Era"); - }; - } - decoded_aux_data - } - - /// Get metadata for a given label in a transaction if it exists. - #[must_use] - pub fn get_metadata(&self, txn_idx: usize, label: u64) -> Option> { - let txn_metadata = self.decoded.get(&txn_idx)?; - let txn_metadata = txn_metadata.value(); - txn_metadata.get(label) - } - - /// Get raw metadata for a given label in a transaction if it exists. - #[must_use] - pub fn get_raw_metadata(&self, txn_idx: usize, label: u64) -> Option>> { - let txn_metadata = self.raw.get(&txn_idx)?; - let txn_metadata = txn_metadata.value(); - txn_metadata.get_metadata(label) - } -} From b0b68f971148f8bc7afa828e699aa1de2791049a Mon Sep 17 00:00:00 2001 From: bkioshn Date: Wed, 25 Dec 2024 17:48:46 +0700 Subject: [PATCH 09/40] fix(cardano-chain-follower): update cip509 Signed-off-by: bkioshn --- rust/cardano-chain-follower/src/metadata/cip509.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/rust/cardano-chain-follower/src/metadata/cip509.rs b/rust/cardano-chain-follower/src/metadata/cip509.rs index a100887df..de98ea275 100644 --- a/rust/cardano-chain-follower/src/metadata/cip509.rs +++ b/rust/cardano-chain-follower/src/metadata/cip509.rs @@ -4,12 +4,13 @@ use std::sync::Arc; +use cardano_blockchain_types::{MetadatumLabel, TransactionAuxData}; use minicbor::{Decode, Decoder}; use pallas::ledger::traverse::MultiEraTx; use rbac_registration::cardano::cip509::{Cip509 as RbacRegCip509, Cip509Validation, LABEL}; use super::{ - DecodedMetadata, DecodedMetadataItem, DecodedMetadataValues, RawAuxData, ValidationReport, + DecodedMetadata, DecodedMetadataItem, DecodedMetadataValues, ValidationReport, }; /// CIP509 metadatum. @@ -28,15 +29,15 @@ impl Cip509 { /// /// Nothing. IF CIP509 Metadata is found it will be updated in `decoded_metadata`. pub(crate) fn decode_and_validate( - decoded_metadata: &DecodedMetadata, txn: &MultiEraTx, raw_aux_data: &RawAuxData, + decoded_metadata: &DecodedMetadata, txn: &MultiEraTx, raw_aux_data: &TransactionAuxData, ) { // Get the CIP509 metadata if possible - let Some(k509) = raw_aux_data.get_metadata(LABEL) else { + let Some(k509) = raw_aux_data.metadata(MetadatumLabel::CIP509_RBAC) else { return; }; let mut validation_report = ValidationReport::new(); - let mut decoder = Decoder::new(k509.as_slice()); + let mut decoder = Decoder::new(k509.as_ref()); let cip509 = match RbacRegCip509::decode(&mut decoder, &mut ()) { Ok(metadata) => metadata, From 980b1b38d3d339b62b1d85ebee919da05f3153c1 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Thu, 26 Dec 2024 08:12:37 +0700 Subject: [PATCH 10/40] fix(cardano-chain-follower): update cip36 Signed-off-by: bkioshn --- .../src/metadata/cip36.rs | 1398 +++++------------ 1 file changed, 357 insertions(+), 1041 deletions(-) diff --git a/rust/cardano-chain-follower/src/metadata/cip36.rs b/rust/cardano-chain-follower/src/metadata/cip36.rs index e277840a4..2f65b85c7 100644 --- a/rust/cardano-chain-follower/src/metadata/cip36.rs +++ b/rust/cardano-chain-follower/src/metadata/cip36.rs @@ -2,68 +2,20 @@ use std::sync::Arc; -use ed25519_dalek::Verifier; -use minicbor::Decoder; -use pallas::ledger::traverse::MultiEraTx; -use tracing::debug; - -use super::{ - DecodedMetadata, DecodedMetadataItem, DecodedMetadataValues, RawAuxData, ValidationReport, +use cardano_blockchain_types::{ + Cip36 as Cip36Registration, Cip36KeyRegistration, Cip36RegistrationWitness, Cip36Validation, + MetadatumLabel, Network, TransactionAuxData, }; -use crate::Network; - -/// CIP36 Metadata Label -pub const LABEL: u64 = 61284; -/// CIP36 Metadata Signature label -pub const SIG_LABEL: u64 = 61285; - -/// Project Catalyst Purpose -pub const PROJECT_CATALYST_PURPOSE: u64 = 0; - -/// Signdata Preamble = `{ 61284: ?? }` -/// CBOR Decoded = -/// A1 # map(1) -/// 19 EF64 # unsigned(61284) -pub const SIGNDATA_PREAMBLE: [u8; 4] = [0xA1, 0x19, 0xEF, 0x64]; - -/// Ed25519 Public Key -type Ed25519PubKey = ed25519_dalek::VerifyingKey; +use minicbor::{Decode, Decoder}; +use pallas::ledger::traverse::MultiEraTx; -/// Voting Public Key - Also known as Delegation in the CIP36 Specification -#[derive(Clone, Debug)] -pub struct VotingPubKey { - /// Ed25519 Public Key - pub voting_pk: Ed25519PubKey, - /// Weight of the Voting Public Key - pub weight: u32, -} +use super::{DecodedMetadata, DecodedMetadataItem, DecodedMetadataValues, ValidationReport}; /// CIP 36 Registration Data. #[derive(Clone, Debug, Default)] pub struct Cip36 { - /// Is this CIP36 or CIP15 format. - #[allow(clippy::struct_field_names)] - pub cip36: Option, - /// Voting Keys (Called Delegations in the CIP-36 Spec) - /// If No Voting Keys could be decoded, this will be an empty array. - pub voting_keys: Vec, - /// Stake Address to associate with the Voting Keys - pub stake_pk: Option, - /// Payment Address to associate with the Voting Keys - /// No Payment key decoded will be an empty vec. - pub payment_addr: Vec, - /// Is the address able to be paid to? (Can't be a script or Stake address) - pub payable: bool, - /// Raw Nonce (Nonce that has not had slot correction applied) - pub raw_nonce: u64, - /// Nonce (Nonce that has been slot corrected) - pub nonce: u64, - /// Registration Purpose (Always 0 for Catalyst) - pub purpose: u64, - /// Signature Validates - pub signed: bool, - /// Strict Catalyst Validated - pub strict_catalyst: bool, + pub cip36: Cip36Registration, + pub validation: Cip36Validation, } impl Cip36 { @@ -84,1020 +36,384 @@ impl Cip36 { /// * `raw_aux_data` - Raw Auxiliary Data for the transaction. /// * `catalyst_strict` - Strict Catalyst Validation - otherwise Catalyst Specific /// rules/workarounds are not applied. - /// * `chain` - Network Chain + /// * `network` - Network Chain /// /// # Returns /// /// Nothing. IF CIP36 Metadata is found it will be updated in `decoded_metadata`. #[allow(clippy::too_many_lines)] pub(crate) fn decode_and_validate( - decoded_metadata: &DecodedMetadata, slot: u64, txn: &MultiEraTx, raw_aux_data: &RawAuxData, - catalyst_strict: bool, chain: Network, + decoded_metadata: &DecodedMetadata, slot: u64, txn: &MultiEraTx, + raw_aux_data: &TransactionAuxData, catalyst_strict: bool, network: Network, ) { - let k61284 = raw_aux_data.get_metadata(LABEL); - let k61285 = raw_aux_data.get_metadata(SIG_LABEL); - - let mut cip36 = Cip36 { - strict_catalyst: catalyst_strict, - ..Default::default() - }; - - // If there is NO Cip36/Cip15 Metadata then nothing to decode or validate, so quickly - // exit. - if k61284.is_none() && k61285.is_none() { - return; - } - - // if let Some(reg) = k61284.as_ref() { - // debug!("CIP36 Metadata Detected: {slot}, {reg:02x?}"); - //} - // if let Some(sig) = k61285.as_ref() { - // debug!("CIP36 Signature Detected: {slot}, {sig:02x?}"); - //} - - // Any Decode/Validation errors go here. - let mut validation_report = ValidationReport::new(); - - // Check if we actually have metadata to decode for the CIP36 Registration. - let Some(raw_cip36) = k61284 else { - cip36.decoding_failed( - "No CIP36 Metadata found, but CIP36 Signature Metadata found.", - &mut validation_report, - decoded_metadata, - ); - debug!("decoded 1: {decoded_metadata:?}"); + let Some(k61284) = raw_aux_data.metadata(MetadatumLabel::CIP036_REGISTRATION) else { return; }; - - let cip36_slice = raw_cip36.as_slice(); - - let mut decoder = Decoder::new(cip36_slice); - - // It should be a definite map, get the number of entries in the map. - let Some(cip36_map_entries) = - cip36.decode_map_entries(&mut decoder, &mut validation_report, decoded_metadata) - else { - debug!("decoded 2: {decoded_metadata:?}"); + let Some(k61285) = raw_aux_data.metadata(MetadatumLabel::CIP036_WITNESS) else { return; }; - let mut found_keys: Vec = Vec::new(); - - for _entry in 0..cip36_map_entries { - let Some(key) = - cip36.decode_map_key(&mut decoder, &mut validation_report, decoded_metadata) - else { - debug!("decoded 3: {decoded_metadata:?} : {raw_cip36:02x?}"); - return; - }; - - if found_keys.contains(&key) { - validation_report.push(format!("Duplicate key found in CIP36 Metadata: {key}")); - } else { - found_keys.push(key); - match key { - 1 => { - if cip36 - .decode_voting_key( - &mut decoder, - &mut validation_report, - decoded_metadata, - ) - .is_none() - { - // debug!("decoded 4: {decoded_metadata:?} : {validation_report:?} : - // {raw_cip36:02x?}"); - return; - } - }, - 2 => { - if cip36 - .decode_stake_pub( - &mut decoder, - &mut validation_report, - decoded_metadata, - ) - .is_none() - { - // debug!("decoded 5: {decoded_metadata:?} : {validation_report:?} : - // {raw_cip36:02x?}"); - return; - } - }, - 3 => { - if cip36 - .decode_payment_address( - &mut decoder, - &mut validation_report, - decoded_metadata, - txn, - chain, - ) - .is_none() - { - debug!("decoded 6: {decoded_metadata:?} : {validation_report:?} : {raw_cip36:02x?}"); - return; - } - }, - 4 => { - if cip36 - .decode_nonce( - &mut decoder, - &mut validation_report, - decoded_metadata, - slot, - ) - .is_none() - { - debug!("decoded 7: {decoded_metadata:?} : {validation_report:?} : {raw_cip36:02x?}"); - return; - } - }, - 5 => { - if cip36 - .decode_purpose(&mut decoder, &mut validation_report, decoded_metadata) - .is_none() - { - debug!("decoded 8: {decoded_metadata:?} : {validation_report:?} : {raw_cip36:02x?}"); - return; - } - }, - _ => { - validation_report - .push(format!("Invalid key found in CIP36 Metadata: {key}")); - }, - } - } - } - - // Validate that all keys required to be present in the CIP36 Metadata are present. - if !found_keys.contains(&1) { - validation_report.push( - "The CIP36 Metadata Voting Key/Delegation is missing from the data.".to_string(), - ); - } - if !found_keys.contains(&2) { - validation_report - .push("The CIP36 Metadata Stake Address is missing from the data.".to_string()); - } - if !found_keys.contains(&3) { - validation_report - .push("The CIP36 Metadata Payment Address is missing from the data.".to_string()); - } - if !found_keys.contains(&4) { - validation_report - .push("The CIP36 Metadata Nonce is missing from the data.".to_string()); - } - - if !decoded_metadata.0.is_empty() { - debug!("decoded 9: {decoded_metadata:?}"); - } - // If we get this far, decode the signature, and verify it. - cip36.validate_signature(&raw_cip36, k61285, &mut validation_report, decoded_metadata); - } - - /// Decoding of the CIP36 metadata failed, and can not continue. - fn decoding_failed( - &self, reason: &str, validation_report: &mut ValidationReport, - decoded_metadata: &DecodedMetadata, - ) { - validation_report.push(reason.into()); - decoded_metadata.0.insert( - LABEL, - Arc::new(DecodedMetadataItem { - value: DecodedMetadataValues::Cip36(Arc::new(self.clone()).clone()), - report: validation_report.clone(), - }), - ); - } - - /// Decode number of entries in the CIP36 metadata map. - fn decode_map_entries( - &self, decoder: &mut Decoder, validation_report: &mut ValidationReport, - decoded_metadata: &DecodedMetadata, - ) -> Option { - let cip36_map_entries = match decoder.map() { - Ok(None) => { - self.decoding_failed( - "CIP36 Metadata was Indefinite Map, Invalid Encoding.", - validation_report, - decoded_metadata, - ); - return None; - }, - Ok(Some(entries)) => entries, - Err(error) => { - self.decoding_failed( - format!("CIP36 Metadata was error decoding Map: {error}").as_str(), - validation_report, - decoded_metadata, - ); - return None; - }, - }; - - Some(cip36_map_entries) - } - - /// Decode the Key of an entry in the CIP36 Metadata map. - fn decode_map_key( - &self, decoder: &mut Decoder, validation_report: &mut ValidationReport, - decoded_metadata: &DecodedMetadata, - ) -> Option { - let key = match decoder.u64() { - Ok(key) => key, - Err(err) => { - self.decoding_failed( - format!("CIP36 Metadata was error decoding Map Entry Key: {err}").as_str(), - validation_report, - decoded_metadata, - ); - return None; - }, - }; - - Some(key) - } - - /// Decode the Registration Purpose in the CIP36 Metadata map. - fn decode_purpose( - &mut self, decoder: &mut Decoder, validation_report: &mut ValidationReport, - decoded_metadata: &DecodedMetadata, - ) -> Option { - let purpose = match decoder.u64() { - Ok(key) => key, - Err(err) => { - self.decoding_failed( - format!("Error decoding Purpose Value: {err}").as_str(), - validation_report, - decoded_metadata, - ); - return None; - }, - }; - - if self.strict_catalyst && purpose != PROJECT_CATALYST_PURPOSE { - validation_report.push(format!("Registration contains unknown purpose: {purpose}")); - } - - self.purpose = purpose; - - Some(purpose) - } - - /// Decode the Registration Nonce in the CIP36 Metadata map. - fn decode_nonce( - &mut self, decoder: &mut Decoder, validation_report: &mut ValidationReport, - decoded_metadata: &DecodedMetadata, slot: u64, - ) -> Option { - let raw_nonce = match decoder.u64() { - Ok(key) => key, - Err(err) => { - self.decoding_failed( - format!("Error decoding Purpose Value: {err}").as_str(), - validation_report, - decoded_metadata, - ); - return None; - }, - }; - - let nonce = if self.strict_catalyst && raw_nonce > slot { - slot - } else { - raw_nonce - }; - - self.raw_nonce = raw_nonce; - self.nonce = nonce; - - Some(nonce) - } - - /// Decode the Payment Address Metadata in the CIP36 Metadata map. - fn decode_payment_address( - &mut self, decoder: &mut Decoder, validation_report: &mut ValidationReport, - decoded_metadata: &DecodedMetadata, _txn: &MultiEraTx, chain: Network, - ) -> Option { - let raw_address = match decoder.bytes() { - Ok(address) => address, - Err(err) => { - self.decoding_failed( - format!("Error decoding Payment Address: {err}").as_str(), - validation_report, - decoded_metadata, - ); - return None; - }, - }; - - let Some(header_byte) = raw_address.first() else { - self.decoding_failed( - "Error decoding Payment Address: Empty", - validation_report, - decoded_metadata, - ); - return None; - }; - - // See: https://cips.cardano.org/cip/CIP-19 for details on address decoding. - let network_tag = header_byte & 0x0F; - let header_type = header_byte >> 4; - match header_type { - 0..=3 => { - if raw_address.len() != 57 { - validation_report.push(format!("Address Length {} != 57", raw_address.len())); - } - }, - 4 | 5 => { - if raw_address.len() < 29 { - validation_report - .push(format!("Pointer Address Length {} < 29", raw_address.len())); - } - }, - 6 | 7 | 14 | 15 => { - if raw_address.len() != 29 { - validation_report.push(format!( - "Pointer Address Length {} != 29", - raw_address.len() - )); - } - }, - _ => { - validation_report.push(format!( - "Address Type {header_type} is invalid and unsupported" - )); - }, - } - - // Check address is for the correct network of the transaction. - if header_type == 8 { - validation_report.push("Byron Addresses are unsupported".to_string()); - } else { - let valid = match chain { - Network::Mainnet => network_tag == 1, - Network::Preprod | Network::Preview => network_tag == 0, - }; - if !valid { - validation_report.push(format!( - "Network Tag {network_tag} does not match transactions Network ID" - )); - } - } - - // Addresses are only payable if they are a normal payment address and not a script - // address. - self.payable = header_type <= 7 && (header_type & 0x1 == 0); - self.payment_addr = raw_address.to_vec(); - - Some(self.payment_addr.len()) - } - - /// Decode the Payment Address Metadata in the CIP36 Metadata map. - fn decode_ed25519_pub_key( - &mut self, decoder: &mut Decoder, validation_report: &mut ValidationReport, - decoded_metadata: &DecodedMetadata, key_type: &str, - ) -> Option { - let pub_key = match decoder.bytes() { - Ok(pub_key) => pub_key, - Err(err) => { - self.decoding_failed( - format!("Error decoding {key_type}: {err}").as_str(), - validation_report, + let mut validation_report = ValidationReport::new(); + let mut key_registration = Decoder::new(k61284.as_ref()); + let mut registration_witness = Decoder::new(k61285.as_ref()); + + let key_registration = match Cip36KeyRegistration::decode(&mut key_registration, &mut ()) { + Ok(metadata) => metadata, + Err(e) => { + Cip36::default().decoding_failed( + &format!("Failed to decode CIP36 Key Registration metadata: {e}"), + &mut validation_report, decoded_metadata, + MetadatumLabel::CIP036_REGISTRATION, ); - return None; + return; }, }; - if pub_key.len() == ed25519_dalek::PUBLIC_KEY_LENGTH { - // Safe to use `unwrap()` here because the length is fixed and we know it's 32 bytes - // long. - #[allow(clippy::unwrap_used)] - let pub_key: [u8; ed25519_dalek::PUBLIC_KEY_LENGTH] = pub_key.try_into().unwrap(); - match ed25519_dalek::VerifyingKey::from_bytes(&pub_key) { - Ok(pk) => return Some(pk), - Err(error) => { - validation_report.push(format!("{key_type} not valid Ed25519: {error}")); + let registration_witness = + match Cip36RegistrationWitness::decode(&mut registration_witness, &mut ()) { + Ok(metadata) => metadata, + Err(e) => { + Cip36::default().decoding_failed( + &format!("Failed to decode CIP36 Registration Witness metadata: {e}"), + &mut validation_report, + decoded_metadata, + MetadatumLabel::CIP036_WITNESS, + ); + return; }, - } - } else { - validation_report.push(format!( - "{key_type} Length {} != {}", - pub_key.len(), - ed25519_dalek::PUBLIC_KEY_LENGTH - )); - } - - None - } - - /// Decode the Staking Public Key in the CIP36 Metadata map. - fn decode_stake_pub( - &mut self, decoder: &mut Decoder, validation_report: &mut ValidationReport, - decoded_metadata: &DecodedMetadata, - ) -> Option { - let pk = self.decode_ed25519_pub_key( - decoder, - validation_report, - decoded_metadata, - "Stake Public Key", - )?; - self.stake_pk = Some(pk); - - Some(self.stake_pk.as_slice().len()) - } - - /// Decode an individual delegation entry from the CIP36 Metadata map. - fn decode_delegation( - &mut self, decoder: &mut Decoder, validation_report: &mut ValidationReport, - decoded_metadata: &DecodedMetadata, - ) -> Option { - match decoder.array() { - Ok(Some(2)) => { - let vk = self.decode_ed25519_pub_key( - decoder, - validation_report, - decoded_metadata, - "Delegation Public Key", - )?; - let weight = match decoder.u32() { - Ok(weight) => weight, - Err(err) => { - self.decoding_failed( - format!("Error Decoding CIP36 Delegations Entry Weight: {err}.") - .as_str(), - validation_report, - decoded_metadata, - ); - return None; - }, - }; - - self.voting_keys.push(VotingPubKey { - voting_pk: vk, - weight, - }); - }, - Ok(Some(entries)) => { - self.decoding_failed( - format!("Error Decoding CIP36 Delegations Entry Array: Must have exactly 2 elements, had {entries}.").as_str(), - validation_report, - decoded_metadata, - ); - return None; - }, - Ok(None) => { - self.decoding_failed( - "Error Decoding CIP36 Delegations Entry Array: Indefinite Array is invalid encoding.", - validation_report, - decoded_metadata, - ); - return None; - }, - Err(err) => { - self.decoding_failed( - format!("Error Decoding CIP36 Delegations Entry Array: {err}").as_str(), - validation_report, - decoded_metadata, - ); - return None; - }, - } - - Some(self.voting_keys.len()) - } - - /// Decode the Voting Key(s) in the CIP36 Metadata map. - fn decode_voting_key( - &mut self, decoder: &mut Decoder, validation_report: &mut ValidationReport, - decoded_metadata: &DecodedMetadata, - ) -> Option { - match decoder.datatype() { - Ok(key_type) => { - match key_type { - minicbor::data::Type::Bytes => { - // CIP 15 type registration (single voting key). - self.cip36 = Some(false); - let vk = self.decode_ed25519_pub_key( - decoder, - validation_report, - decoded_metadata, - "Voting Public Key", - )?; - self.voting_keys.push(VotingPubKey { - voting_pk: vk, - weight: 1, - }); - }, - minicbor::data::Type::Array => { - // CIP 36 type registration (multiple voting keys). - self.cip36 = Some(true); - match decoder.array() { - Ok(Some(entries)) => { - for _entry in 0..entries { - self.decode_delegation( - decoder, - validation_report, - decoded_metadata, - )?; - } - }, - Ok(None) => { - self.decoding_failed( - "Error Decoding CIP36 Delegations Array: Indefinite Array is invalid encoding.", - validation_report, - decoded_metadata, - ); - }, - Err(err) => { - self.decoding_failed( - format!("Error Decoding CIP36 Delegations Array: {err}") - .as_str(), - validation_report, - decoded_metadata, - ); - return None; - }, - } - }, - _ => { - self.decoding_failed( - format!( - "Error inspecting Voting Key type: Unexpected CBOR Type {key_type}" - ) - .as_str(), - validation_report, - decoded_metadata, - ); - }, - } - }, - Err(error) => { - self.decoding_failed( - format!("Error inspecting Voting Key type: {error}").as_str(), - validation_report, - decoded_metadata, - ); - return None; - }, - } - - if self.strict_catalyst && self.voting_keys.len() != 1 { - validation_report.push(format!( - "Catalyst Supports only a single Voting Key per registration. Found {}", - self.voting_keys.len() - )); - } - - Some(self.voting_keys.len()) - } - - /// Decode a signature from the Signature metadata in 61285 - /// Also checks that the signature is valid against the public key. - #[allow(clippy::too_many_lines)] - fn validate_signature( - &mut self, metadata: &Arc>, sig_metadata: Option>>, - validation_report: &mut ValidationReport, decoded_metadata: &DecodedMetadata, - ) -> Option { - // Check if we actually have metadata to decode for the CIP36 Registration. - let Some(raw_cip36) = sig_metadata else { - self.decoding_failed( - "No CIP36 Signature found, but CIP36 Metadata found.", - validation_report, - decoded_metadata, - ); - return None; - }; - - let cip36_slice = raw_cip36.as_slice(); - - let mut decoder = Decoder::new(cip36_slice); - - match decoder.map() { - Ok(Some(1)) => (), // Ok - Ok(Some(x)) => { - self.decoding_failed( - format!("CIP36 Signature Map decoding failed: Has {x} entries, should have 1.") - .as_str(), - validation_report, - decoded_metadata, - ); - return None; - }, - Ok(None) => { - self.decoding_failed( - "CIP36 Signature Map is Indefinite. Decoding failed.", - validation_report, - decoded_metadata, - ); - return None; - }, - Err(err) => { - self.decoding_failed( - format!("CIP36 Signature Map decoding failed: {err}").as_str(), - validation_report, - decoded_metadata, - ); - return None; - }, - } - - match decoder.u64() { - Ok(1) => (), // Ok - Ok(x) => { - self.decoding_failed( - format!("CIP36 Signature Map decoding failed: Map entry was {x} MUST BE 1.") - .as_str(), - validation_report, - decoded_metadata, - ); - return None; - }, - Err(err) => { - self.decoding_failed( - format!("CIP36 Signature Map Key decoding failed: {err}").as_str(), - validation_report, - decoded_metadata, - ); - return None; - }, - } - - let sig: ed25519_dalek::Signature = match decoder.bytes() { - Ok(sig) => { - match ed25519_dalek::Signature::from_slice(sig) { - Ok(sig) => sig, - Err(err) => { - self.decoding_failed( - format!("CIP36 Signature Decoding failed: {err}",).as_str(), - validation_report, - decoded_metadata, - ); - return None; - }, - } - }, - Err(error) => { - self.decoding_failed( - format!("CIP36 Signature Decode error: {error}.",).as_str(), - validation_report, - decoded_metadata, - ); - return None; - }, - }; - - // Ok, if we get this far then we have a valid CIP36 Signature. - let Some(pk) = self.stake_pk else { - self.decoding_failed( - "CIP36 Signature Verification Failed, no Staking Public Key.", - validation_report, - decoded_metadata, - ); - return None; - }; - - // Now we have both the Public Key and the signature. So calculate the hash of the - // metadata. - let hash = blake2b_simd::Params::new() - .hash_length(32) - .to_state() - .update(&SIGNDATA_PREAMBLE) - .update(metadata) - .finalize(); - - // debug!( - // "Hash = {:02x?}, pk = {:02x?}, sig = {:02x?}", - // hash.as_bytes(), - // pk.as_ref(), - // sig.to_bytes() - //); + }; - if let Err(error) = pk.verify(hash.as_bytes(), &sig) { - self.signed = false; - self.decoding_failed( - format!("CIP36 Signature Verification Failed: {error}").as_str(), - validation_report, - decoded_metadata, - ); - return None; + let cip36 = Cip36Registration { + key_registration, + registration_witness, + is_catalyst_strict: catalyst_strict, }; - // If we get this far then we have a valid CIP36 Signature (Doesn't mean there aren't - // other issues). - self.signed = true; + let validation = cip36.validate(network, &k61284, &mut validation_report); - // Record the fully validated Cip36 metadata + // Create a Cip509 struct and insert it into decoded_metadata decoded_metadata.0.insert( - LABEL, + MetadatumLabel::CIP036_REGISTRATION, Arc::new(DecodedMetadataItem { - value: DecodedMetadataValues::Cip36(Arc::new(self.clone()).clone()), + value: DecodedMetadataValues::Cip36(Arc::new(Cip36 { cip36, validation })), report: validation_report.clone(), }), ); - - Some(true) } -} - -#[cfg(test)] -mod tests { - use dashmap::DashMap; - use super::*; - - fn create_empty_cip36(strict: bool) -> Cip36 { - Cip36 { - cip36: None, - voting_keys: vec![], - stake_pk: None, - payment_addr: vec![], - payable: false, - raw_nonce: 0, - nonce: 0, - purpose: 0, - signed: false, - strict_catalyst: strict, - } - } - - #[test] - fn test_decode_purpose_1() { - let decoded_metadata = DecodedMetadata(DashMap::new()); - let mut cip36 = create_empty_cip36(true); - let mut decoder = Decoder::new(&[0x00]); - let mut report = ValidationReport::new(); - - let rc = cip36.decode_purpose(&mut decoder, &mut report, &decoded_metadata); - - assert_eq!(report.len(), 0); - assert_eq!(cip36.purpose, 0); - assert_eq!(rc, Some(0)); - } - - #[test] - fn test_decode_purpose_2() { - let decoded_metadata = DecodedMetadata(DashMap::new()); - let mut cip36 = create_empty_cip36(true); - let mut decoder = Decoder::new(&[0x19, 0x30, 0x39]); - let mut report = ValidationReport::new(); - - let rc = cip36.decode_purpose(&mut decoder, &mut report, &decoded_metadata); - - assert_eq!(report.len(), 1); - assert_eq!(cip36.purpose, 12345); - assert_eq!(rc, Some(12345)); - } - - #[test] - fn test_decode_purpose_3() { - let decoded_metadata = DecodedMetadata(DashMap::new()); - let mut cip36 = create_empty_cip36(false); - let mut decoder = Decoder::new(&[0x19, 0x30, 0x39]); - let mut report = ValidationReport::new(); - - let rc = cip36.decode_purpose(&mut decoder, &mut report, &decoded_metadata); - - assert_eq!(report.len(), 0); - assert_eq!(cip36.purpose, 12345); - assert_eq!(rc, Some(12345)); - } - - #[test] - fn test_decode_purpose_4() { - let bytes_cases: &[&[u8]] = &[ - &[0x80], // array(0) - &[0xA0], // map(0) - &[0x21], // negative(1) - &[0xF9, 0x3C, 0x00], // primitive(15360) - 1.0 - ]; - - for bytes in bytes_cases { - let decoded_metadata = DecodedMetadata(DashMap::new()); - let mut cip36 = create_empty_cip36(false); - let mut decoder = Decoder::new(bytes); - let mut report = ValidationReport::new(); - - let rc = cip36.decode_purpose(&mut decoder, &mut report, &decoded_metadata); - - assert_eq!(report.len(), 1); - assert_eq!(cip36.purpose, 0); - assert_eq!(rc, None); - } - } - - #[test] - // valid `nonce`, strict = false, raw_nonce > slot - fn test_decode_nonce_1() { - let decoded_metadata = DecodedMetadata(DashMap::new()); - let mut cip36 = create_empty_cip36(false); - let mut decoder = Decoder::new(&[0x1B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]); - let mut report = ValidationReport::new(); - - let rc = cip36.decode_nonce(&mut decoder, &mut report, &decoded_metadata, 0); - - assert_eq!(report.len(), 0); - assert_eq!(cip36.raw_nonce, u64::MAX); - assert_eq!(cip36.nonce, u64::MAX); - assert_eq!(rc, Some(u64::MAX)); - } - - #[test] - // valid `nonce`, strict = false, raw_nonce < slot - fn test_decode_nonce_2() { - let decoded_metadata = DecodedMetadata(DashMap::new()); - let mut cip36 = create_empty_cip36(false); - let mut decoder = Decoder::new(&[0x01]); - let mut report = ValidationReport::new(); - - let rc = cip36.decode_nonce(&mut decoder, &mut report, &decoded_metadata, 99); - - assert_eq!(report.len(), 0); - assert_eq!(cip36.raw_nonce, 1); - assert_eq!(cip36.nonce, 1); - assert_eq!(rc, Some(1)); - } - - #[test] - // valid `nonce`, strict = true, raw_nonce > slot - fn test_decode_nonce_3() { - let decoded_metadata = DecodedMetadata(DashMap::new()); - let mut cip36 = create_empty_cip36(true); - let mut decoder = Decoder::new(&[0x10]); - let mut report = ValidationReport::new(); - - let rc = cip36.decode_nonce(&mut decoder, &mut report, &decoded_metadata, 1); - - assert_eq!(report.len(), 0); - assert_eq!(cip36.raw_nonce, 16); - assert_eq!(cip36.nonce, 1); - assert_eq!(rc, Some(1)); - } - - #[test] - fn test_decode_nonce_4() { - let bytes_cases: &[&[u8]] = &[ - &[0x80], // array(0) - &[0xA0], // map(0) - &[0x21], // negative(1) - &[0xF9, 0x3C, 0x00], // primitive(15360) - 1.0 - ]; - - for bytes in bytes_cases { - let decoded_metadata = DecodedMetadata(DashMap::new()); - let mut cip36 = create_empty_cip36(false); - let mut decoder = Decoder::new(bytes); - let mut report = ValidationReport::new(); - - let rc = cip36.decode_nonce(&mut decoder, &mut report, &decoded_metadata, 0); - - assert_eq!(report.len(), 1); - assert_eq!(cip36.raw_nonce, 0); - assert_eq!(cip36.nonce, 0); - assert_eq!(rc, None); - } - } - - #[test] - fn test_decode_payment_address_1() { - let hex_data = hex::decode( - // 0x004777561e7d9ec112ec307572faec1aff61ff0cfed68df4cd5c847f1872b617657881e30ad17c46e4010c9cb3ebb2440653a34d32219c83e9 - "5839004777561E7D9EC112EC307572FAEC1AFF61FF0CFED68DF4CD5C847F1872B617657881E30AD17C46E4010C9CB3EBB2440653A34D32219C83E9" - ).expect("cannot decode hex"); - let decoded_metadata = DecodedMetadata(DashMap::new()); - let mut cip36 = create_empty_cip36(false); - let mut decoder = Decoder::new(&hex_data); - let mut report = ValidationReport::new(); - let multi_era_tx: *const MultiEraTx = std::ptr::null(); - let multi_era_tx = unsafe { &*multi_era_tx }; - - let rc = cip36.decode_payment_address( - &mut decoder, - &mut report, - &decoded_metadata, - multi_era_tx, - Network::Preprod, + /// Decoding of the CIP36 metadata failed, and can not continue. + fn decoding_failed( + &self, reason: &str, validation_report: &mut ValidationReport, + decoded_metadata: &DecodedMetadata, label: MetadatumLabel, + ) { + validation_report.push(reason.into()); + decoded_metadata.0.insert( + label, + Arc::new(DecodedMetadataItem { + value: DecodedMetadataValues::Cip36(Arc::new(self.clone()).clone()), + report: validation_report.clone(), + }), ); - - assert_eq!(report.len(), 0); - assert!(cip36.payable); - assert_eq!(cip36.payment_addr.len(), 57); - assert_eq!(rc, Some(57)); - } - - #[test] - fn test_decode_stake_pub_1() { - let hex_data = hex::decode( - // 0xe3cd2404c84de65f96918f18d5b445bcb933a7cda18eeded7945dd191e432369 - "5820E3CD2404C84DE65F96918F18D5B445BCB933A7CDA18EEDED7945DD191E432369", - ) - .expect("cannot decode hex"); - let decoded_metadata = DecodedMetadata(DashMap::new()); - let mut cip36 = create_empty_cip36(false); - let mut decoder = Decoder::new(&hex_data); - let mut report = ValidationReport::new(); - - let rc = cip36.decode_stake_pub(&mut decoder, &mut report, &decoded_metadata); - - assert_eq!(report.len(), 0); - assert!(cip36.stake_pk.is_some()); - assert_eq!(rc, Some(1)); - } - - #[test] - fn test_decode_stake_pub_2() { - let bytes_cases: &[Vec] = &[ - vec![], - hex::decode( - // 0xe3cd2404c84de65f96918f18d5b445bcb933a7cda18eeded7945dd19 (28 bytes) - "581CE3CD2404C84DE65F96918F18D5B445BCB933A7CDA18EEDED7945DD19", - ) - .expect("cannot decode hex"), - ]; - - for bytes in bytes_cases { - let decoded_metadata = DecodedMetadata(DashMap::new()); - let mut cip36 = create_empty_cip36(false); - let mut decoder = Decoder::new(bytes); - let mut report = ValidationReport::new(); - - let rc = cip36.decode_stake_pub(&mut decoder, &mut report, &decoded_metadata); - - assert_eq!(report.len(), 1); - assert_eq!(rc, None); - } - } - - #[test] - // cip-36 version - fn test_decode_voting_key_1() { - let hex_data = hex::decode( - // [["0x0036ef3e1f0d3f5989e2d155ea54bdb2a72c4c456ccb959af4c94868f473f5a0", 1]] - "818258200036EF3E1F0D3F5989E2D155EA54BDB2A72C4C456CCB959AF4C94868F473F5A001", - ) - .expect("cannot decode hex"); - let decoded_metadata = DecodedMetadata(DashMap::new()); - let mut cip36 = create_empty_cip36(false); - let mut decoder = Decoder::new(&hex_data); - let mut report = ValidationReport::new(); - - let rc = cip36.decode_voting_key(&mut decoder, &mut report, &decoded_metadata); - - assert_eq!(report.len(), 0); - assert_eq!(cip36.cip36, Some(true)); - assert_eq!(cip36.voting_keys.len(), 1); - assert_eq!(rc, Some(1)); - } - - #[test] - // cip-15 version - fn test_decode_voting_key_2() { - let hex_data = hex::decode( - // 0x0036ef3e1f0d3f5989e2d155ea54bdb2a72c4c456ccb959af4c94868f473f5a0 - "58200036EF3E1F0D3F5989E2D155EA54BDB2A72C4C456CCB959AF4C94868F473F5A0", - ) - .expect("cannot decode hex"); - let decoded_metadata = DecodedMetadata(DashMap::new()); - let mut cip36 = create_empty_cip36(false); - let mut decoder = Decoder::new(&hex_data); - let mut report = ValidationReport::new(); - - let rc = cip36.decode_voting_key(&mut decoder, &mut report, &decoded_metadata); - - assert_eq!(report.len(), 0); - assert_eq!(cip36.cip36, Some(false)); - assert_eq!(cip36.voting_keys.len(), 1); - assert_eq!(rc, Some(1)); - } - - #[test] - fn test_decode_voting_key_3() { - let bytes_cases: &[Vec] = &[ - vec![], - hex::decode( - // [[]] (empty) - "8180", - ) - .expect("cannot decode hex"), - hex::decode( - // [["0x0036ef3e1f0d3f5989e2d155ea54bdb2a72c4c456ccb959af4c94868f473f5a0"]] - // (without weight) - "818158200036EF3E1F0D3F5989E2D155EA54BDB2A72C4C456CCB959AF4C94868F473F5A0", - ) - .expect("cannot decode hex"), - ]; - - for bytes in bytes_cases { - let decoded_metadata = DecodedMetadata(DashMap::new()); - let mut cip36 = create_empty_cip36(false); - let mut decoder = Decoder::new(bytes); - let mut report = ValidationReport::new(); - - let rc = cip36.decode_voting_key(&mut decoder, &mut report, &decoded_metadata); - - assert_eq!(report.len(), 1); - assert_eq!(rc, None); - } } } +// #[cfg(test)] +// mod tests { +// use dashmap::DashMap; + +// use super::*; + +// fn create_empty_cip36(strict: bool) -> Cip36 { +// Cip36 { +// cip36: None, +// voting_keys: vec![], +// stake_pk: None, +// payment_addr: vec![], +// payable: false, +// raw_nonce: 0, +// nonce: 0, +// purpose: 0, +// signed: false, +// strict_catalyst: strict, +// } +// } + +// #[test] +// fn test_decode_purpose_1() { +// let decoded_metadata = DecodedMetadata(DashMap::new()); +// let mut cip36 = create_empty_cip36(true); +// let mut decoder = Decoder::new(&[0x00]); +// let mut report = ValidationReport::new(); + +// let rc = cip36.decode_purpose(&mut decoder, &mut report, &decoded_metadata); + +// assert_eq!(report.len(), 0); +// assert_eq!(cip36.purpose, 0); +// assert_eq!(rc, Some(0)); +// } + +// #[test] +// fn test_decode_purpose_2() { +// let decoded_metadata = DecodedMetadata(DashMap::new()); +// let mut cip36 = create_empty_cip36(true); +// let mut decoder = Decoder::new(&[0x19, 0x30, 0x39]); +// let mut report = ValidationReport::new(); + +// let rc = cip36.decode_purpose(&mut decoder, &mut report, &decoded_metadata); + +// assert_eq!(report.len(), 1); +// assert_eq!(cip36.purpose, 12345); +// assert_eq!(rc, Some(12345)); +// } + +// #[test] +// fn test_decode_purpose_3() { +// let decoded_metadata = DecodedMetadata(DashMap::new()); +// let mut cip36 = create_empty_cip36(false); +// let mut decoder = Decoder::new(&[0x19, 0x30, 0x39]); +// let mut report = ValidationReport::new(); + +// let rc = cip36.decode_purpose(&mut decoder, &mut report, &decoded_metadata); + +// assert_eq!(report.len(), 0); +// assert_eq!(cip36.purpose, 12345); +// assert_eq!(rc, Some(12345)); +// } + +// #[test] +// fn test_decode_purpose_4() { +// let bytes_cases: &[&[u8]] = &[ +// &[0x80], // array(0) +// &[0xA0], // map(0) +// &[0x21], // negative(1) +// &[0xF9, 0x3C, 0x00], // primitive(15360) - 1.0 +// ]; + +// for bytes in bytes_cases { +// let decoded_metadata = DecodedMetadata(DashMap::new()); +// let mut cip36 = create_empty_cip36(false); +// let mut decoder = Decoder::new(bytes); +// let mut report = ValidationReport::new(); + +// let rc = cip36.decode_purpose(&mut decoder, &mut report, &decoded_metadata); + +// assert_eq!(report.len(), 1); +// assert_eq!(cip36.purpose, 0); +// assert_eq!(rc, None); +// } +// } + +// #[test] +// // valid `nonce`, strict = false, raw_nonce > slot +// fn test_decode_nonce_1() { +// let decoded_metadata = DecodedMetadata(DashMap::new()); +// let mut cip36 = create_empty_cip36(false); +// let mut decoder = Decoder::new(&[0x1B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]); +// let mut report = ValidationReport::new(); + +// let rc = cip36.decode_nonce(&mut decoder, &mut report, &decoded_metadata, 0); + +// assert_eq!(report.len(), 0); +// assert_eq!(cip36.raw_nonce, u64::MAX); +// assert_eq!(cip36.nonce, u64::MAX); +// assert_eq!(rc, Some(u64::MAX)); +// } + +// #[test] +// // valid `nonce`, strict = false, raw_nonce < slot +// fn test_decode_nonce_2() { +// let decoded_metadata = DecodedMetadata(DashMap::new()); +// let mut cip36 = create_empty_cip36(false); +// let mut decoder = Decoder::new(&[0x01]); +// let mut report = ValidationReport::new(); + +// let rc = cip36.decode_nonce(&mut decoder, &mut report, &decoded_metadata, 99); + +// assert_eq!(report.len(), 0); +// assert_eq!(cip36.raw_nonce, 1); +// assert_eq!(cip36.nonce, 1); +// assert_eq!(rc, Some(1)); +// } + +// #[test] +// // valid `nonce`, strict = true, raw_nonce > slot +// fn test_decode_nonce_3() { +// let decoded_metadata = DecodedMetadata(DashMap::new()); +// let mut cip36 = create_empty_cip36(true); +// let mut decoder = Decoder::new(&[0x10]); +// let mut report = ValidationReport::new(); + +// let rc = cip36.decode_nonce(&mut decoder, &mut report, &decoded_metadata, 1); + +// assert_eq!(report.len(), 0); +// assert_eq!(cip36.raw_nonce, 16); +// assert_eq!(cip36.nonce, 1); +// assert_eq!(rc, Some(1)); +// } + +// #[test] +// fn test_decode_nonce_4() { +// let bytes_cases: &[&[u8]] = &[ +// &[0x80], // array(0) +// &[0xA0], // map(0) +// &[0x21], // negative(1) +// &[0xF9, 0x3C, 0x00], // primitive(15360) - 1.0 +// ]; + +// for bytes in bytes_cases { +// let decoded_metadata = DecodedMetadata(DashMap::new()); +// let mut cip36 = create_empty_cip36(false); +// let mut decoder = Decoder::new(bytes); +// let mut report = ValidationReport::new(); + +// let rc = cip36.decode_nonce(&mut decoder, &mut report, &decoded_metadata, 0); + +// assert_eq!(report.len(), 1); +// assert_eq!(cip36.raw_nonce, 0); +// assert_eq!(cip36.nonce, 0); +// assert_eq!(rc, None); +// } +// } + +// #[test] +// fn test_decode_payment_address_1() { +// let hex_data = hex::decode( +// // 0x004777561e7d9ec112ec307572faec1aff61ff0cfed68df4cd5c847f1872b617657881e30ad17c46e4010c9cb3ebb2440653a34d32219c83e9 +// "5839004777561E7D9EC112EC307572FAEC1AFF61FF0CFED68DF4CD5C847F1872B617657881E30AD17C46E4010C9CB3EBB2440653A34D32219C83E9" +// ).expect("cannot decode hex"); +// let decoded_metadata = DecodedMetadata(DashMap::new()); +// let mut cip36 = create_empty_cip36(false); +// let mut decoder = Decoder::new(&hex_data); +// let mut report = ValidationReport::new(); +// let multi_era_tx: *const MultiEraTx = std::ptr::null(); +// let multi_era_tx = unsafe { &*multi_era_tx }; + +// let rc = cip36.decode_payment_address( +// &mut decoder, +// &mut report, +// &decoded_metadata, +// multi_era_tx, +// Network::Preprod, +// ); + +// assert_eq!(report.len(), 0); +// assert!(cip36.payable); +// assert_eq!(cip36.payment_addr.len(), 57); +// assert_eq!(rc, Some(57)); +// } + +// #[test] +// fn test_decode_stake_pub_1() { +// let hex_data = hex::decode( +// // 0xe3cd2404c84de65f96918f18d5b445bcb933a7cda18eeded7945dd191e432369 +// "5820E3CD2404C84DE65F96918F18D5B445BCB933A7CDA18EEDED7945DD191E432369", +// ) +// .expect("cannot decode hex"); +// let decoded_metadata = DecodedMetadata(DashMap::new()); +// let mut cip36 = create_empty_cip36(false); +// let mut decoder = Decoder::new(&hex_data); +// let mut report = ValidationReport::new(); + +// let rc = cip36.decode_stake_pub(&mut decoder, &mut report, &decoded_metadata); + +// assert_eq!(report.len(), 0); +// assert!(cip36.stake_pk.is_some()); +// assert_eq!(rc, Some(1)); +// } + +// #[test] +// fn test_decode_stake_pub_2() { +// let bytes_cases: &[Vec] = &[ +// vec![], +// hex::decode( +// // 0xe3cd2404c84de65f96918f18d5b445bcb933a7cda18eeded7945dd19 (28 bytes) +// "581CE3CD2404C84DE65F96918F18D5B445BCB933A7CDA18EEDED7945DD19", +// ) +// .expect("cannot decode hex"), +// ]; + +// for bytes in bytes_cases { +// let decoded_metadata = DecodedMetadata(DashMap::new()); +// let mut cip36 = create_empty_cip36(false); +// let mut decoder = Decoder::new(bytes); +// let mut report = ValidationReport::new(); + +// let rc = cip36.decode_stake_pub(&mut decoder, &mut report, &decoded_metadata); + +// assert_eq!(report.len(), 1); +// assert_eq!(rc, None); +// } +// } + +// #[test] +// // cip-36 version +// fn test_decode_voting_key_1() { +// let hex_data = hex::decode( +// // [["0x0036ef3e1f0d3f5989e2d155ea54bdb2a72c4c456ccb959af4c94868f473f5a0", 1]] +// "818258200036EF3E1F0D3F5989E2D155EA54BDB2A72C4C456CCB959AF4C94868F473F5A001", +// ) +// .expect("cannot decode hex"); +// let decoded_metadata = DecodedMetadata(DashMap::new()); +// let mut cip36 = create_empty_cip36(false); +// let mut decoder = Decoder::new(&hex_data); +// let mut report = ValidationReport::new(); + +// let rc = cip36.decode_voting_key(&mut decoder, &mut report, &decoded_metadata); + +// assert_eq!(report.len(), 0); +// assert_eq!(cip36.cip36, Some(true)); +// assert_eq!(cip36.voting_keys.len(), 1); +// assert_eq!(rc, Some(1)); +// } + +// #[test] +// // cip-15 version +// fn test_decode_voting_key_2() { +// let hex_data = hex::decode( +// // 0x0036ef3e1f0d3f5989e2d155ea54bdb2a72c4c456ccb959af4c94868f473f5a0 +// "58200036EF3E1F0D3F5989E2D155EA54BDB2A72C4C456CCB959AF4C94868F473F5A0", +// ) +// .expect("cannot decode hex"); +// let decoded_metadata = DecodedMetadata(DashMap::new()); +// let mut cip36 = create_empty_cip36(false); +// let mut decoder = Decoder::new(&hex_data); +// let mut report = ValidationReport::new(); + +// let rc = cip36.decode_voting_key(&mut decoder, &mut report, &decoded_metadata); + +// assert_eq!(report.len(), 0); +// assert_eq!(cip36.cip36, Some(false)); +// assert_eq!(cip36.voting_keys.len(), 1); +// assert_eq!(rc, Some(1)); +// } + +// #[test] +// fn test_decode_voting_key_3() { +// let bytes_cases: &[Vec] = &[ +// vec![], +// hex::decode( +// // [[]] (empty) +// "8180", +// ) +// .expect("cannot decode hex"), +// hex::decode( +// // [["0x0036ef3e1f0d3f5989e2d155ea54bdb2a72c4c456ccb959af4c94868f473f5a0"]] +// // (without weight) +// "818158200036EF3E1F0D3F5989E2D155EA54BDB2A72C4C456CCB959AF4C94868F473F5A0", +// ) +// .expect("cannot decode hex"), +// ]; + +// for bytes in bytes_cases { +// let decoded_metadata = DecodedMetadata(DashMap::new()); +// let mut cip36 = create_empty_cip36(false); +// let mut decoder = Decoder::new(bytes); +// let mut report = ValidationReport::new(); + +// let rc = cip36.decode_voting_key(&mut decoder, &mut report, &decoded_metadata); + +// assert_eq!(report.len(), 1); +// assert_eq!(rc, None); +// } +// } +// } From 944a112659c76fbefed4ccc0c9c15e927a56ba58 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Thu, 26 Dec 2024 08:13:02 +0700 Subject: [PATCH 11/40] fix(cardano-chain-follower): update metadata Signed-off-by: bkioshn --- rust/cardano-chain-follower/src/metadata/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rust/cardano-chain-follower/src/metadata/mod.rs b/rust/cardano-chain-follower/src/metadata/mod.rs index ae9c29417..35fb88866 100644 --- a/rust/cardano-chain-follower/src/metadata/mod.rs +++ b/rust/cardano-chain-follower/src/metadata/mod.rs @@ -2,7 +2,7 @@ use std::{fmt::Debug, sync::Arc}; -use cardano_blockchain_types::{Network, TransactionAuxData}; +use cardano_blockchain_types::{MetadatumLabel, Network, TransactionAuxData}; use cip36::Cip36; use cip509::Cip509; use dashmap::DashMap; @@ -41,7 +41,7 @@ pub struct DecodedMetadataItem { /// For example, CIP15/36 uses labels 61284 & 61285, /// 61284 is the primary label, so decoded metadata /// will be under that label. -pub(crate) struct DecodedMetadata(DashMap>); +pub(crate) struct DecodedMetadata(DashMap>); impl DecodedMetadata { /// Create new decoded metadata for a transaction. From fa0bcd588b33f4e5786dbd13b0368b89bf891fb4 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Thu, 26 Dec 2024 08:13:22 +0700 Subject: [PATCH 12/40] fix(cardano-chain-follower): update cip509 Signed-off-by: bkioshn --- .../src/metadata/cip509.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/rust/cardano-chain-follower/src/metadata/cip509.rs b/rust/cardano-chain-follower/src/metadata/cip509.rs index de98ea275..6cfa5eba5 100644 --- a/rust/cardano-chain-follower/src/metadata/cip509.rs +++ b/rust/cardano-chain-follower/src/metadata/cip509.rs @@ -7,11 +7,9 @@ use std::sync::Arc; use cardano_blockchain_types::{MetadatumLabel, TransactionAuxData}; use minicbor::{Decode, Decoder}; use pallas::ledger::traverse::MultiEraTx; -use rbac_registration::cardano::cip509::{Cip509 as RbacRegCip509, Cip509Validation, LABEL}; +use rbac_registration::cardano::cip509::{Cip509 as RbacRegCip509, Cip509Validation}; -use super::{ - DecodedMetadata, DecodedMetadataItem, DecodedMetadataValues, ValidationReport, -}; +use super::{DecodedMetadata, DecodedMetadataItem, DecodedMetadataValues, ValidationReport}; /// CIP509 metadatum. #[derive(Debug, PartialEq, Clone, Default)] @@ -42,7 +40,7 @@ impl Cip509 { let cip509 = match RbacRegCip509::decode(&mut decoder, &mut ()) { Ok(metadata) => metadata, Err(e) => { - Cip509::default().validation_failure( + Cip509::default().decoding_failed( &format!("Failed to decode CIP509 metadata: {e}"), &mut validation_report, decoded_metadata, @@ -56,7 +54,7 @@ impl Cip509 { // Create a Cip509 struct and insert it into decoded_metadata decoded_metadata.0.insert( - LABEL, + MetadatumLabel::CIP509_RBAC, Arc::new(DecodedMetadataItem { value: DecodedMetadataValues::Cip509(Arc::new(Cip509 { cip509, validation })), report: validation_report.clone(), @@ -64,14 +62,14 @@ impl Cip509 { ); } - /// Handle validation failure. - fn validation_failure( + /// Decoding of the CIP509 metadata failed, and can not continue. + fn decoding_failed( &self, reason: &str, validation_report: &mut ValidationReport, decoded_metadata: &DecodedMetadata, ) { validation_report.push(reason.into()); decoded_metadata.0.insert( - LABEL, + MetadatumLabel::CIP509_RBAC, Arc::new(DecodedMetadataItem { value: DecodedMetadataValues::Cip509(Arc::new(self.clone()).clone()), report: validation_report.clone(), From 194b327df1a3f6cd8e821f00b84714c6ce3fe718 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Thu, 26 Dec 2024 09:14:35 +0700 Subject: [PATCH 13/40] fix(cardano-chain-follower): nonce Signed-off-by: bkioshn --- .../src/metadata/cip36.rs | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/rust/cardano-chain-follower/src/metadata/cip36.rs b/rust/cardano-chain-follower/src/metadata/cip36.rs index 2f65b85c7..cef9a2b56 100644 --- a/rust/cardano-chain-follower/src/metadata/cip36.rs +++ b/rust/cardano-chain-follower/src/metadata/cip36.rs @@ -12,7 +12,7 @@ use pallas::ledger::traverse::MultiEraTx; use super::{DecodedMetadata, DecodedMetadataItem, DecodedMetadataValues, ValidationReport}; /// CIP 36 Registration Data. -#[derive(Clone, Debug, Default)] +#[derive(Clone, Default, Debug)] pub struct Cip36 { pub cip36: Cip36Registration, pub validation: Cip36Validation, @@ -43,8 +43,8 @@ impl Cip36 { /// Nothing. IF CIP36 Metadata is found it will be updated in `decoded_metadata`. #[allow(clippy::too_many_lines)] pub(crate) fn decode_and_validate( - decoded_metadata: &DecodedMetadata, slot: u64, txn: &MultiEraTx, - raw_aux_data: &TransactionAuxData, catalyst_strict: bool, network: Network, + decoded_metadata: &DecodedMetadata, slot: u64, _txn: &MultiEraTx, + raw_aux_data: &TransactionAuxData, is_catalyst_strict: bool, network: Network, ) { let Some(k61284) = raw_aux_data.metadata(MetadatumLabel::CIP036_REGISTRATION) else { return; @@ -58,7 +58,17 @@ impl Cip36 { let mut registration_witness = Decoder::new(k61285.as_ref()); let key_registration = match Cip36KeyRegistration::decode(&mut key_registration, &mut ()) { - Ok(metadata) => metadata, + Ok(mut metadata) => { + // FIXME: Don't like it here + let nonce = if is_catalyst_strict && metadata.raw_nonce > slot { + slot + } else { + metadata.raw_nonce + }; + + metadata.nonce = nonce; + metadata + }, Err(e) => { Cip36::default().decoding_failed( &format!("Failed to decode CIP36 Key Registration metadata: {e}"), @@ -84,13 +94,14 @@ impl Cip36 { }, }; + let cip36 = Cip36Registration { key_registration, registration_witness, - is_catalyst_strict: catalyst_strict, + is_catalyst_strict: is_catalyst_strict, }; - let validation = cip36.validate(network, &k61284, &mut validation_report); + let validation = cip36.validate(network, k61284, &mut validation_report); // Create a Cip509 struct and insert it into decoded_metadata decoded_metadata.0.insert( From 81bc83921819f443177df1279c3313f585e81da6 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Thu, 26 Dec 2024 09:24:36 +0700 Subject: [PATCH 14/40] fix(cardano-chain-follower): update get metadata by label Signed-off-by: bkioshn --- rust/cardano-chain-follower/src/metadata/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/cardano-chain-follower/src/metadata/mod.rs b/rust/cardano-chain-follower/src/metadata/mod.rs index 35fb88866..c95e8cc1f 100644 --- a/rust/cardano-chain-follower/src/metadata/mod.rs +++ b/rust/cardano-chain-follower/src/metadata/mod.rs @@ -59,7 +59,7 @@ impl DecodedMetadata { } /// Get the decoded metadata item at the given slot, or None if it doesn't exist. - pub fn get(&self, primary_label: u64) -> Option> { + pub fn get(&self, primary_label: MetadatumLabel) -> Option> { let entry = self.0.get(&primary_label)?; let value = entry.value(); Some(value.clone()) From 5e110f039744063bf16c65adead1075945091641 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Thu, 26 Dec 2024 10:20:24 +0700 Subject: [PATCH 15/40] fix(cardano-chain-follower): slot Signed-off-by: bkioshn --- rust/cardano-chain-follower/src/chain_sync.rs | 4 ++-- rust/cardano-chain-follower/src/mithril_snapshot_iterator.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rust/cardano-chain-follower/src/chain_sync.rs b/rust/cardano-chain-follower/src/chain_sync.rs index e32e9839a..40efd352b 100644 --- a/rust/cardano-chain-follower/src/chain_sync.rs +++ b/rust/cardano-chain-follower/src/chain_sync.rs @@ -194,7 +194,7 @@ async fn process_rollback( let slot_rollback_size = if head_slot > rollback_slot { head_slot - rollback_slot } else { - 0 + 0.into() }; // We actually do the work here... @@ -203,7 +203,7 @@ async fn process_rollback( // We never really know how many blocks are rolled back when advised by the peer, but we // can work out how many slots. This function wraps the real work, so we can properly // record the stats when the rollback is complete. Even if it errors. - stats::rollback(chain, stats::RollbackType::Peer, slot_rollback_size); + stats::rollback(chain, stats::RollbackType::Peer, slot_rollback_size.into()); Ok(response) } diff --git a/rust/cardano-chain-follower/src/mithril_snapshot_iterator.rs b/rust/cardano-chain-follower/src/mithril_snapshot_iterator.rs index c1662fb38..cdf2d9b6b 100644 --- a/rust/cardano-chain-follower/src/mithril_snapshot_iterator.rs +++ b/rust/cardano-chain-follower/src/mithril_snapshot_iterator.rs @@ -6,7 +6,7 @@ use std::{ sync::{Arc, Mutex}, }; -use cardano_blockchain_types::{MultiEraBlock, Network, Point, Slot}; +use cardano_blockchain_types::{MultiEraBlock, Network, Point}; use logcall::logcall; use tokio::task; use tracing::{debug, error}; @@ -54,7 +54,7 @@ pub(crate) struct MithrilSnapshotIterator { pub(crate) fn probe_point(point: &Point, distance: u64) -> Point { // Now that we have the tip, step back about 4 block intervals from tip, and do a fuzzy // iteration to find the exact two blocks at the end of the immutable chain. - let step_back_search = Slot::from_saturating(point.slot_or_default().into() - distance); + let step_back_search = point.slot_or_default() - distance.into(); // We stepped back to the origin, so just return Origin if step_back_search == 0.into() { From d568da1bad576798f5323d06375d2835ad91ad56 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Tue, 31 Dec 2024 14:18:35 +0700 Subject: [PATCH 16/40] fix(cardano-blockchain-types): follow_chains.rs Signed-off-by: bkioshn --- .../examples/follow_chains.rs | 155 ++++++++++-------- 1 file changed, 87 insertions(+), 68 deletions(-) diff --git a/rust/cardano-chain-follower/examples/follow_chains.rs b/rust/cardano-chain-follower/examples/follow_chains.rs index ec389b7f4..52c1305ca 100644 --- a/rust/cardano-chain-follower/examples/follow_chains.rs +++ b/rust/cardano-chain-follower/examples/follow_chains.rs @@ -5,9 +5,9 @@ // Allowing since this is example code. //#![allow(clippy::unwrap_used)] +use cardano_blockchain_types::{BlockAuxData, Fork, MetadatumLabel, Network, Point, TxnIndex}; #[cfg(feature = "mimalloc")] use mimalloc::MiMalloc; -use rbac_registration::cardano::cip509; /// Use Mimalloc for the global allocator. #[cfg(feature = "mimalloc")] @@ -17,9 +17,8 @@ static GLOBAL: MiMalloc = MiMalloc; use std::{error::Error, time::Duration}; use cardano_chain_follower::{ - ChainFollower, ChainSyncConfig, ChainUpdate, Kind, - Metadata::{self}, - Network, Statistics, ORIGIN_POINT, TIP_POINT, + metadata::DecodedMetadata, ChainFollower, ChainSyncConfig, ChainUpdate, Kind, Metadata, + Statistics, }; use clap::{arg, ArgAction, ArgMatches, Command}; use tokio::time::Instant; @@ -84,7 +83,6 @@ fn process_argument() -> (Vec, ArgMatches) { /// Start syncing a particular network async fn start_sync_for(network: &Network, matches: ArgMatches) -> Result<(), Box> { let mut cfg = ChainSyncConfig::default_for(*network); - let mut mithril_dl_connect_timeout = "Not Set".to_string(); let mut mithril_dl_data_timeout = "Not Set".to_string(); @@ -146,26 +144,26 @@ const RUNNING_UPDATE_INTERVAL: u64 = 100_000; #[allow(clippy::too_many_lines)] async fn follow_for(network: Network, matches: ArgMatches) { info!(chain = network.to_string(), "Following"); - let mut follower = ChainFollower::new(network, ORIGIN_POINT, TIP_POINT).await; + let mut follower = ChainFollower::new(network, Point::ORIGIN, Point::TIP).await; - let all_tip_blocks = matches.get_flag("all-tip-blocks"); - let all_live_blocks = matches.get_flag("all-live-blocks"); - let stop_at_tip = matches.get_flag("stop-at-tip"); - let halt_on_error = matches.get_flag("halt-on-error"); - let log_bad_cip36 = matches.get_flag("log-bad-cip36"); - let log_cip509 = matches.get_flag("log-cip509"); - let log_raw_aux = matches.get_flag("log-raw-aux"); - let largest_metadata = matches.get_flag("largest-metadata"); + let is_all_tip_blocks = matches.get_flag("all-tip-blocks"); + let is_all_live_blocks = matches.get_flag("all-live-blocks"); + let is_stop_at_tip = matches.get_flag("stop-at-tip"); + let is_halt_on_error = matches.get_flag("halt-on-error"); + let is_log_bad_cip36 = matches.get_flag("log-bad-cip36"); + let is_log_cip509 = matches.get_flag("log-cip509"); + let is_log_raw_aux = matches.get_flag("log-raw-aux"); + let is_largest_metadata = matches.get_flag("largest-metadata"); let mut current_era = String::new(); let mut last_update: Option = None; - let mut last_update_shown = false; + let mut is_last_update_shown = false; let mut prev_hash: Option> = None; - let mut last_immutable: bool = false; - let mut reached_tip = false; // After we reach TIP we show all block we process. + let mut is_last_immutable: bool = false; + let mut is_reached_tip = false; // After we reach TIP we show all block we process. let mut updates: u64 = 0; - let mut last_fork = 0; - let mut follow_all = false; + let mut last_fork: Fork = 0.into(); + let mut is_follow_all = false; let mut last_metrics_time = Instant::now(); @@ -175,7 +173,7 @@ async fn follow_for(network: Network, matches: ArgMatches) { updates += 1; if chain_update.tip { - reached_tip = true; + is_reached_tip = true; } let block = chain_update.block_data().decode(); @@ -183,9 +181,9 @@ async fn follow_for(network: Network, matches: ArgMatches) { // When we transition between important points, show the last block as well. if ((current_era != this_era) - || (chain_update.immutable() != last_immutable) + || (chain_update.immutable() != is_last_immutable) || (last_fork != chain_update.data.fork())) - && !last_update_shown + && !is_last_update_shown { if let Some(last_update) = last_update.clone() { info!( @@ -198,29 +196,29 @@ async fn follow_for(network: Network, matches: ArgMatches) { } // If these become true, we will show all blocks from the follower. - follow_all = follow_all - || (!chain_update.immutable() && all_live_blocks) - || ((chain_update.data.fork() > 1) && all_tip_blocks); + is_follow_all = is_follow_all + || (!chain_update.immutable() && is_all_live_blocks) + || ((chain_update.data.fork() > 1.into()) && is_all_tip_blocks); // Don't know if this update will show or not, so say it didn't. - last_update_shown = false; + is_last_update_shown = false; if (current_era != this_era) - || (chain_update.immutable() != last_immutable) - || reached_tip - || follow_all + || (chain_update.immutable() != is_last_immutable) + || is_reached_tip + || is_follow_all || (updates % RUNNING_UPDATE_INTERVAL == 0) || (last_fork != chain_update.data.fork()) { current_era = this_era; - last_immutable = chain_update.immutable(); + is_last_immutable = chain_update.immutable(); last_fork = chain_update.data.fork(); info!( chain = network.to_string(), "Chain Update {updates}:{}", chain_update ); // We already showed the last update, no need to show it again. - last_update_shown = true; + is_last_update_shown = true; } let this_prev_hash = block.header().previous_hash(); @@ -242,25 +240,44 @@ async fn follow_for(network: Network, matches: ArgMatches) { break; } + // Generate `BlockAuxData` from the block. + let block_aux_data = match BlockAuxData::try_from(block) { + Ok(aux_data) => aux_data, + Err(_) => continue, + }; + // Inspect the transactions in the block. - for (tx_idx, _tx) in block.txs().iter().enumerate() { - if let Some(aux_data) = - update_biggest_aux_data(&chain_update, tx_idx, largest_metadata, biggest_aux_data) - { + for (tx_idx, tx) in block.txs().iter().enumerate() { + // Get the auxiliary data for the transaction. + let tx_aux_data = match block_aux_data.get(TxnIndex::from_saturating(tx_idx)) { + Some(aux_data) => aux_data, + None => continue, + }; + + // Create new decoded metadata for the transaction. + let decoded_metadata = DecodedMetadata::new(network, block.slot(), tx, tx_aux_data); + + if let Some(aux_data) = update_biggest_aux_data( + &chain_update, + TxnIndex::from_saturating(tx_idx), + is_largest_metadata, + biggest_aux_data, + ) { biggest_aux_data = aux_data; } - // If flag `log_bad_cip36` is set, log the bad CIP36. - if log_bad_cip36 { - log_bad_cip36_info(&chain_update, network, tx_idx); + // If flag `is_log_bad_cip36` is set, log the bad CIP36. + if is_log_bad_cip36 { + log_bad_cip36_info(&decoded_metadata, network, tx_idx, block.number()); } - // If flag `log_cip509` is set, log the CIP509 validation. - if log_cip509 { - log_cip509_info(&chain_update, block.number(), network, tx_idx); + + // If flag `is_log_cip509` is set, log the CIP509 validation. + if !is_log_cip509 { + log_cip509_info(&decoded_metadata, network, tx_idx, block.number()); } } - if log_raw_aux { + if is_log_raw_aux { if let Some(x) = block.as_alonzo() { info!( chain = network.to_string(), @@ -282,7 +299,7 @@ async fn follow_for(network: Network, matches: ArgMatches) { prev_hash = Some(block.hash()); last_update = Some(chain_update); - if reached_tip && stop_at_tip { + if is_reached_tip && is_stop_at_tip { break; } @@ -294,7 +311,7 @@ async fn follow_for(network: Network, matches: ArgMatches) { info!("Json Metrics: {}", stats.as_json(true)); - if halt_on_error + if is_halt_on_error && (stats.mithril.download_or_validation_failed > 0 || stats.mithril.failed_to_get_tip > 0 || stats.mithril.tip_did_not_advance > 0 @@ -306,7 +323,7 @@ async fn follow_for(network: Network, matches: ArgMatches) { } } - if !last_update_shown { + if !is_last_update_shown { if let Some(last_update) = last_update.clone() { info!(chain = network.to_string(), "Last Update: {}", last_update); } @@ -318,20 +335,25 @@ async fn follow_for(network: Network, matches: ArgMatches) { info!(chain = network.to_string(), "Following Completed."); } +// FIXME: Why do we need this? Should it be finding the largest aux data? /// Helper function for updating the biggest aux data. +/// Comparing between CIP36 and CIP509. fn update_biggest_aux_data( - chain_update: &ChainUpdate, tx_idx: usize, largest_metadata: bool, biggest_aux_data: usize, + chain_update: &ChainUpdate, tx_idx: TxnIndex, largest_metadata: bool, biggest_aux_data: usize, ) -> Option { let raw_size_cip36 = match chain_update .data - .txn_raw_metadata(tx_idx, Metadata::cip36::LABEL) + .txn_metadata(tx_idx, MetadatumLabel::CIP036_REGISTRATION) { - Some(raw) => raw.len(), + Some(raw) => raw.as_ref().len(), None => 0, }; - let raw_size_cip509 = match chain_update.data.txn_raw_metadata(tx_idx, cip509::LABEL) { - Some(raw) => raw.len(), + let raw_size_cip509 = match chain_update + .data + .txn_metadata(tx_idx, MetadatumLabel::CIP509_RBAC) + { + Some(raw) => raw.as_ref().len(), None => 0, }; @@ -346,18 +368,15 @@ fn update_biggest_aux_data( } /// Helper function for logging bad CIP36. -fn log_bad_cip36_info(chain_update: &ChainUpdate, network: Network, tx_idx: usize) { - if let Some(decoded_metadata) = chain_update - .data - .txn_metadata(tx_idx, Metadata::cip36::LABEL) - { - if let Metadata::DecodedMetadataValues::Cip36(cip36) = &decoded_metadata.value { - if (!cip36.signed || !decoded_metadata.report.is_empty()) - && !decoded_metadata.report.is_empty() - { +fn log_bad_cip36_info( + decoded_metadata: &DecodedMetadata, network: Network, tx_idx: usize, block: u64, +) { + if let Some(m) = decoded_metadata.get(MetadatumLabel::CIP036_REGISTRATION) { + if let Metadata::DecodedMetadataValues::Cip36(cip36) = &m.value { + if !cip36.validation.is_valid_signature && !m.report.is_empty() { info!( chain = network.to_string(), - "CIP36 {tx_idx}: {:?}", decoded_metadata + block, "CIP36 {tx_idx}: {:?}", &cip36 ); } } @@ -365,22 +384,22 @@ fn log_bad_cip36_info(chain_update: &ChainUpdate, network: Network, tx_idx: usiz } /// Helper function for logging CIP509 validation. -fn log_cip509_info(chain_update: &ChainUpdate, block_num: u64, network: Network, tx_idx: usize) { - if let Some(decoded_metadata) = chain_update.data.txn_metadata(tx_idx, cip509::LABEL) { - info!("Block Number {}", block_num); - - if let Metadata::DecodedMetadataValues::Cip509(cip509) = &decoded_metadata.value { +fn log_cip509_info( + decoded_metadata: &DecodedMetadata, network: Network, tx_idx: usize, block: u64, +) { + if let Some(m) = decoded_metadata.get(MetadatumLabel::CIP509_RBAC) { + if let Metadata::DecodedMetadataValues::Cip509(cip509) = &m.value { info!( chain = network.to_string(), - "CIP509 {tx_idx}: {:?}", cip509.validation + block, "CIP509 {tx_idx}: {:?}", &cip509 ); } // If report is not empty, log it, log it as a warning. - if !decoded_metadata.report.is_empty() { + if !m.report.is_empty() { warn!( chain = network.to_string(), - "CIP509 {tx_idx}: {:?}", decoded_metadata.report + block, "CIP509 {tx_idx}: {:?}", decoded_metadata ); } } From 69f000f4f9916f29880aa91f5100303cb057c7a7 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Tue, 31 Dec 2024 14:19:40 +0700 Subject: [PATCH 17/40] fix(cardano-blockchain-types): decodedmetadata Signed-off-by: bkioshn --- rust/cardano-chain-follower/src/metadata/mod.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/rust/cardano-chain-follower/src/metadata/mod.rs b/rust/cardano-chain-follower/src/metadata/mod.rs index c95e8cc1f..cf0a6e3cb 100644 --- a/rust/cardano-chain-follower/src/metadata/mod.rs +++ b/rust/cardano-chain-follower/src/metadata/mod.rs @@ -41,11 +41,15 @@ pub struct DecodedMetadataItem { /// For example, CIP15/36 uses labels 61284 & 61285, /// 61284 is the primary label, so decoded metadata /// will be under that label. -pub(crate) struct DecodedMetadata(DashMap>); +#[allow(clippy::module_name_repetitions)] +pub struct DecodedMetadata(DashMap>); impl DecodedMetadata { /// Create new decoded metadata for a transaction. - fn new(chain: Network, slot: u64, txn: &MultiEraTx, raw_aux_data: &TransactionAuxData) -> Self { + #[must_use] + pub fn new( + chain: Network, slot: u64, txn: &MultiEraTx, raw_aux_data: &TransactionAuxData, + ) -> Self { let decoded_metadata = Self(DashMap::new()); // Process each known type of metadata here, and record the decoded result. @@ -59,6 +63,7 @@ impl DecodedMetadata { } /// Get the decoded metadata item at the given slot, or None if it doesn't exist. + #[must_use] pub fn get(&self, primary_label: MetadatumLabel) -> Option> { let entry = self.0.get(&primary_label)?; let value = entry.value(); From 70debef88fe164ad875de6f877f238fe664b17f5 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Tue, 31 Dec 2024 14:20:28 +0700 Subject: [PATCH 18/40] fix(cardano-blockchain-types): cleanup cip36 Signed-off-by: bkioshn --- .../src/metadata/cip36.rs | 305 +----------------- 1 file changed, 3 insertions(+), 302 deletions(-) diff --git a/rust/cardano-chain-follower/src/metadata/cip36.rs b/rust/cardano-chain-follower/src/metadata/cip36.rs index cef9a2b56..3bdd686c7 100644 --- a/rust/cardano-chain-follower/src/metadata/cip36.rs +++ b/rust/cardano-chain-follower/src/metadata/cip36.rs @@ -14,7 +14,9 @@ use super::{DecodedMetadata, DecodedMetadataItem, DecodedMetadataValues, Validat /// CIP 36 Registration Data. #[derive(Clone, Default, Debug)] pub struct Cip36 { + /// CIP36 data. pub cip36: Cip36Registration, + /// Validation value, not a part of CIP36, just storing validity of the data. pub validation: Cip36Validation, } @@ -94,11 +96,10 @@ impl Cip36 { }, }; - let cip36 = Cip36Registration { key_registration, registration_witness, - is_catalyst_strict: is_catalyst_strict, + is_catalyst_strict, }; let validation = cip36.validate(network, k61284, &mut validation_report); @@ -128,303 +129,3 @@ impl Cip36 { ); } } -// #[cfg(test)] -// mod tests { -// use dashmap::DashMap; - -// use super::*; - -// fn create_empty_cip36(strict: bool) -> Cip36 { -// Cip36 { -// cip36: None, -// voting_keys: vec![], -// stake_pk: None, -// payment_addr: vec![], -// payable: false, -// raw_nonce: 0, -// nonce: 0, -// purpose: 0, -// signed: false, -// strict_catalyst: strict, -// } -// } - -// #[test] -// fn test_decode_purpose_1() { -// let decoded_metadata = DecodedMetadata(DashMap::new()); -// let mut cip36 = create_empty_cip36(true); -// let mut decoder = Decoder::new(&[0x00]); -// let mut report = ValidationReport::new(); - -// let rc = cip36.decode_purpose(&mut decoder, &mut report, &decoded_metadata); - -// assert_eq!(report.len(), 0); -// assert_eq!(cip36.purpose, 0); -// assert_eq!(rc, Some(0)); -// } - -// #[test] -// fn test_decode_purpose_2() { -// let decoded_metadata = DecodedMetadata(DashMap::new()); -// let mut cip36 = create_empty_cip36(true); -// let mut decoder = Decoder::new(&[0x19, 0x30, 0x39]); -// let mut report = ValidationReport::new(); - -// let rc = cip36.decode_purpose(&mut decoder, &mut report, &decoded_metadata); - -// assert_eq!(report.len(), 1); -// assert_eq!(cip36.purpose, 12345); -// assert_eq!(rc, Some(12345)); -// } - -// #[test] -// fn test_decode_purpose_3() { -// let decoded_metadata = DecodedMetadata(DashMap::new()); -// let mut cip36 = create_empty_cip36(false); -// let mut decoder = Decoder::new(&[0x19, 0x30, 0x39]); -// let mut report = ValidationReport::new(); - -// let rc = cip36.decode_purpose(&mut decoder, &mut report, &decoded_metadata); - -// assert_eq!(report.len(), 0); -// assert_eq!(cip36.purpose, 12345); -// assert_eq!(rc, Some(12345)); -// } - -// #[test] -// fn test_decode_purpose_4() { -// let bytes_cases: &[&[u8]] = &[ -// &[0x80], // array(0) -// &[0xA0], // map(0) -// &[0x21], // negative(1) -// &[0xF9, 0x3C, 0x00], // primitive(15360) - 1.0 -// ]; - -// for bytes in bytes_cases { -// let decoded_metadata = DecodedMetadata(DashMap::new()); -// let mut cip36 = create_empty_cip36(false); -// let mut decoder = Decoder::new(bytes); -// let mut report = ValidationReport::new(); - -// let rc = cip36.decode_purpose(&mut decoder, &mut report, &decoded_metadata); - -// assert_eq!(report.len(), 1); -// assert_eq!(cip36.purpose, 0); -// assert_eq!(rc, None); -// } -// } - -// #[test] -// // valid `nonce`, strict = false, raw_nonce > slot -// fn test_decode_nonce_1() { -// let decoded_metadata = DecodedMetadata(DashMap::new()); -// let mut cip36 = create_empty_cip36(false); -// let mut decoder = Decoder::new(&[0x1B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]); -// let mut report = ValidationReport::new(); - -// let rc = cip36.decode_nonce(&mut decoder, &mut report, &decoded_metadata, 0); - -// assert_eq!(report.len(), 0); -// assert_eq!(cip36.raw_nonce, u64::MAX); -// assert_eq!(cip36.nonce, u64::MAX); -// assert_eq!(rc, Some(u64::MAX)); -// } - -// #[test] -// // valid `nonce`, strict = false, raw_nonce < slot -// fn test_decode_nonce_2() { -// let decoded_metadata = DecodedMetadata(DashMap::new()); -// let mut cip36 = create_empty_cip36(false); -// let mut decoder = Decoder::new(&[0x01]); -// let mut report = ValidationReport::new(); - -// let rc = cip36.decode_nonce(&mut decoder, &mut report, &decoded_metadata, 99); - -// assert_eq!(report.len(), 0); -// assert_eq!(cip36.raw_nonce, 1); -// assert_eq!(cip36.nonce, 1); -// assert_eq!(rc, Some(1)); -// } - -// #[test] -// // valid `nonce`, strict = true, raw_nonce > slot -// fn test_decode_nonce_3() { -// let decoded_metadata = DecodedMetadata(DashMap::new()); -// let mut cip36 = create_empty_cip36(true); -// let mut decoder = Decoder::new(&[0x10]); -// let mut report = ValidationReport::new(); - -// let rc = cip36.decode_nonce(&mut decoder, &mut report, &decoded_metadata, 1); - -// assert_eq!(report.len(), 0); -// assert_eq!(cip36.raw_nonce, 16); -// assert_eq!(cip36.nonce, 1); -// assert_eq!(rc, Some(1)); -// } - -// #[test] -// fn test_decode_nonce_4() { -// let bytes_cases: &[&[u8]] = &[ -// &[0x80], // array(0) -// &[0xA0], // map(0) -// &[0x21], // negative(1) -// &[0xF9, 0x3C, 0x00], // primitive(15360) - 1.0 -// ]; - -// for bytes in bytes_cases { -// let decoded_metadata = DecodedMetadata(DashMap::new()); -// let mut cip36 = create_empty_cip36(false); -// let mut decoder = Decoder::new(bytes); -// let mut report = ValidationReport::new(); - -// let rc = cip36.decode_nonce(&mut decoder, &mut report, &decoded_metadata, 0); - -// assert_eq!(report.len(), 1); -// assert_eq!(cip36.raw_nonce, 0); -// assert_eq!(cip36.nonce, 0); -// assert_eq!(rc, None); -// } -// } - -// #[test] -// fn test_decode_payment_address_1() { -// let hex_data = hex::decode( -// // 0x004777561e7d9ec112ec307572faec1aff61ff0cfed68df4cd5c847f1872b617657881e30ad17c46e4010c9cb3ebb2440653a34d32219c83e9 -// "5839004777561E7D9EC112EC307572FAEC1AFF61FF0CFED68DF4CD5C847F1872B617657881E30AD17C46E4010C9CB3EBB2440653A34D32219C83E9" -// ).expect("cannot decode hex"); -// let decoded_metadata = DecodedMetadata(DashMap::new()); -// let mut cip36 = create_empty_cip36(false); -// let mut decoder = Decoder::new(&hex_data); -// let mut report = ValidationReport::new(); -// let multi_era_tx: *const MultiEraTx = std::ptr::null(); -// let multi_era_tx = unsafe { &*multi_era_tx }; - -// let rc = cip36.decode_payment_address( -// &mut decoder, -// &mut report, -// &decoded_metadata, -// multi_era_tx, -// Network::Preprod, -// ); - -// assert_eq!(report.len(), 0); -// assert!(cip36.payable); -// assert_eq!(cip36.payment_addr.len(), 57); -// assert_eq!(rc, Some(57)); -// } - -// #[test] -// fn test_decode_stake_pub_1() { -// let hex_data = hex::decode( -// // 0xe3cd2404c84de65f96918f18d5b445bcb933a7cda18eeded7945dd191e432369 -// "5820E3CD2404C84DE65F96918F18D5B445BCB933A7CDA18EEDED7945DD191E432369", -// ) -// .expect("cannot decode hex"); -// let decoded_metadata = DecodedMetadata(DashMap::new()); -// let mut cip36 = create_empty_cip36(false); -// let mut decoder = Decoder::new(&hex_data); -// let mut report = ValidationReport::new(); - -// let rc = cip36.decode_stake_pub(&mut decoder, &mut report, &decoded_metadata); - -// assert_eq!(report.len(), 0); -// assert!(cip36.stake_pk.is_some()); -// assert_eq!(rc, Some(1)); -// } - -// #[test] -// fn test_decode_stake_pub_2() { -// let bytes_cases: &[Vec] = &[ -// vec![], -// hex::decode( -// // 0xe3cd2404c84de65f96918f18d5b445bcb933a7cda18eeded7945dd19 (28 bytes) -// "581CE3CD2404C84DE65F96918F18D5B445BCB933A7CDA18EEDED7945DD19", -// ) -// .expect("cannot decode hex"), -// ]; - -// for bytes in bytes_cases { -// let decoded_metadata = DecodedMetadata(DashMap::new()); -// let mut cip36 = create_empty_cip36(false); -// let mut decoder = Decoder::new(bytes); -// let mut report = ValidationReport::new(); - -// let rc = cip36.decode_stake_pub(&mut decoder, &mut report, &decoded_metadata); - -// assert_eq!(report.len(), 1); -// assert_eq!(rc, None); -// } -// } - -// #[test] -// // cip-36 version -// fn test_decode_voting_key_1() { -// let hex_data = hex::decode( -// // [["0x0036ef3e1f0d3f5989e2d155ea54bdb2a72c4c456ccb959af4c94868f473f5a0", 1]] -// "818258200036EF3E1F0D3F5989E2D155EA54BDB2A72C4C456CCB959AF4C94868F473F5A001", -// ) -// .expect("cannot decode hex"); -// let decoded_metadata = DecodedMetadata(DashMap::new()); -// let mut cip36 = create_empty_cip36(false); -// let mut decoder = Decoder::new(&hex_data); -// let mut report = ValidationReport::new(); - -// let rc = cip36.decode_voting_key(&mut decoder, &mut report, &decoded_metadata); - -// assert_eq!(report.len(), 0); -// assert_eq!(cip36.cip36, Some(true)); -// assert_eq!(cip36.voting_keys.len(), 1); -// assert_eq!(rc, Some(1)); -// } - -// #[test] -// // cip-15 version -// fn test_decode_voting_key_2() { -// let hex_data = hex::decode( -// // 0x0036ef3e1f0d3f5989e2d155ea54bdb2a72c4c456ccb959af4c94868f473f5a0 -// "58200036EF3E1F0D3F5989E2D155EA54BDB2A72C4C456CCB959AF4C94868F473F5A0", -// ) -// .expect("cannot decode hex"); -// let decoded_metadata = DecodedMetadata(DashMap::new()); -// let mut cip36 = create_empty_cip36(false); -// let mut decoder = Decoder::new(&hex_data); -// let mut report = ValidationReport::new(); - -// let rc = cip36.decode_voting_key(&mut decoder, &mut report, &decoded_metadata); - -// assert_eq!(report.len(), 0); -// assert_eq!(cip36.cip36, Some(false)); -// assert_eq!(cip36.voting_keys.len(), 1); -// assert_eq!(rc, Some(1)); -// } - -// #[test] -// fn test_decode_voting_key_3() { -// let bytes_cases: &[Vec] = &[ -// vec![], -// hex::decode( -// // [[]] (empty) -// "8180", -// ) -// .expect("cannot decode hex"), -// hex::decode( -// // [["0x0036ef3e1f0d3f5989e2d155ea54bdb2a72c4c456ccb959af4c94868f473f5a0"]] -// // (without weight) -// "818158200036EF3E1F0D3F5989E2D155EA54BDB2A72C4C456CCB959AF4C94868F473F5A0", -// ) -// .expect("cannot decode hex"), -// ]; - -// for bytes in bytes_cases { -// let decoded_metadata = DecodedMetadata(DashMap::new()); -// let mut cip36 = create_empty_cip36(false); -// let mut decoder = Decoder::new(bytes); -// let mut report = ValidationReport::new(); - -// let rc = cip36.decode_voting_key(&mut decoder, &mut report, &decoded_metadata); - -// assert_eq!(report.len(), 1); -// assert_eq!(rc, None); -// } -// } -// } From 06fbfa10471afc7fed71707f02161e0a524d9e45 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Tue, 31 Dec 2024 14:23:51 +0700 Subject: [PATCH 19/40] fix(cardano-blockchain-types): follow_chains.rs Signed-off-by: bkioshn --- rust/cardano-chain-follower/examples/follow_chains.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/cardano-chain-follower/examples/follow_chains.rs b/rust/cardano-chain-follower/examples/follow_chains.rs index 52c1305ca..a722bfb42 100644 --- a/rust/cardano-chain-follower/examples/follow_chains.rs +++ b/rust/cardano-chain-follower/examples/follow_chains.rs @@ -272,7 +272,7 @@ async fn follow_for(network: Network, matches: ArgMatches) { } // If flag `is_log_cip509` is set, log the CIP509 validation. - if !is_log_cip509 { + if is_log_cip509 { log_cip509_info(&decoded_metadata, network, tx_idx, block.number()); } } From 8b9f82c32259b80e4c16bfcee340f394587d9acf Mon Sep 17 00:00:00 2001 From: bkioshn Date: Tue, 31 Dec 2024 14:34:08 +0700 Subject: [PATCH 20/40] fix(cardano-blockchain-types): cleanup Signed-off-by: bkioshn --- rust/cardano-chain-follower/src/chain_sync_live_chains.rs | 4 ++-- rust/cardano-chain-follower/src/follow.rs | 4 ++-- rust/cardano-chain-follower/src/mithril_snapshot_iterator.rs | 2 +- rust/cardano-chain-follower/src/stats.rs | 1 + 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/rust/cardano-chain-follower/src/chain_sync_live_chains.rs b/rust/cardano-chain-follower/src/chain_sync_live_chains.rs index 0621230d2..530693993 100644 --- a/rust/cardano-chain-follower/src/chain_sync_live_chains.rs +++ b/rust/cardano-chain-follower/src/chain_sync_live_chains.rs @@ -346,7 +346,7 @@ impl ProtectedLiveChainBlockList { // Loop until we exhaust probe slots, OR we would step past genesis. while slot_age < reference_slot { - let ref_point = Point::fuzzy((reference_slot - slot_age).into()); + let ref_point = Point::fuzzy(reference_slot - slot_age); let Some(entry) = chain.lower_bound(Bound::Included(&ref_point)) else { break; }; @@ -372,7 +372,7 @@ impl ProtectedLiveChainBlockList { }; // Get the block <= the current slot. - let ref_point = Point::fuzzy(point.slot_or_default().into()); + let ref_point = Point::fuzzy(point.slot_or_default()); let mut entry = chain.upper_bound(Bound::Included(&ref_point))?; let mut this_block = entry.value().clone(); diff --git a/rust/cardano-chain-follower/src/follow.rs b/rust/cardano-chain-follower/src/follow.rs index 91c3ea544..caf71cd27 100644 --- a/rust/cardano-chain-follower/src/follow.rs +++ b/rust/cardano-chain-follower/src/follow.rs @@ -313,8 +313,8 @@ impl ChainFollower { let tips = Statistics::tips(chain); - let mithril_tip = Point::fuzzy(tips.0.into()); - let live_tip = Point::fuzzy(tips.1.into()); + let mithril_tip = Point::fuzzy(tips.0); + let live_tip = Point::fuzzy(tips.1); (mithril_tip, live_tip) } diff --git a/rust/cardano-chain-follower/src/mithril_snapshot_iterator.rs b/rust/cardano-chain-follower/src/mithril_snapshot_iterator.rs index cdf2d9b6b..5ee853887 100644 --- a/rust/cardano-chain-follower/src/mithril_snapshot_iterator.rs +++ b/rust/cardano-chain-follower/src/mithril_snapshot_iterator.rs @@ -62,7 +62,7 @@ pub(crate) fn probe_point(point: &Point, distance: u64) -> Point { } // Create a fuzzy search probe by making the hash zero length. - Point::fuzzy(step_back_search.into()) + Point::fuzzy(step_back_search) } impl MithrilSnapshotIterator { diff --git a/rust/cardano-chain-follower/src/stats.rs b/rust/cardano-chain-follower/src/stats.rs index 94dfe2ba9..4f9e267a0 100644 --- a/rust/cardano-chain-follower/src/stats.rs +++ b/rust/cardano-chain-follower/src/stats.rs @@ -292,6 +292,7 @@ impl Statistics { } /// Count the invalidly deserialized blocks +#[allow(dead_code)] pub(crate) fn stats_invalid_block(chain: Network, immutable: bool) { // This will actually always succeed. let Some(stats) = lookup_stats(chain) else { From f8096243dc3e60df214a87cdca87e9b82e5d79bc Mon Sep 17 00:00:00 2001 From: bkioshn Date: Tue, 31 Dec 2024 15:15:34 +0700 Subject: [PATCH 21/40] fix(cardano-chain-follower): remove blake2b hash Signed-off-by: bkioshn --- rust/cardano-chain-follower/src/utils.rs | 29 ------------------------ 1 file changed, 29 deletions(-) diff --git a/rust/cardano-chain-follower/src/utils.rs b/rust/cardano-chain-follower/src/utils.rs index cc8d43647..11a2a482a 100644 --- a/rust/cardano-chain-follower/src/utils.rs +++ b/rust/cardano-chain-follower/src/utils.rs @@ -1,7 +1,5 @@ //! Simple general purpose utility functions. -use blake2b_simd::{self, Params}; - /// Convert T to an i16. (saturate if out of range.) #[allow(dead_code)] // Its OK if we don't use this general utility function. pub(crate) fn i16_from_saturating>(value: T) -> i16 { @@ -73,30 +71,3 @@ pub(crate) fn u64_from_saturating< } } } - -/// Convert the given value to `blake2b_244` array. -#[allow(dead_code)] // Its OK if we don't use this general utility function. -pub(crate) fn blake2b_244(value: &[u8]) -> anyhow::Result<[u8; 28]> { - let h = Params::new().hash_length(28).hash(value); - let b = h.as_bytes(); - b.try_into() - .map_err(|_| anyhow::anyhow!("Invalid length of blake2b_244, expected 28 got {}", b.len())) -} - -/// Convert the given value to `blake2b_256` array. -#[allow(dead_code)] // Its OK if we don't use this general utility function. -pub(crate) fn blake2b_256(value: &[u8]) -> anyhow::Result<[u8; 32]> { - let h = Params::new().hash_length(32).hash(value); - let b = h.as_bytes(); - b.try_into() - .map_err(|_| anyhow::anyhow!("Invalid length of blake2b_256, expected 32 got {}", b.len())) -} - -/// Convert the given value to `blake2b_128` array. -#[allow(dead_code)] // Its OK if we don't use this general utility function. -pub(crate) fn blake2b_128(value: &[u8]) -> anyhow::Result<[u8; 16]> { - let h = Params::new().hash_length(16).hash(value); - let b = h.as_bytes(); - b.try_into() - .map_err(|_| anyhow::anyhow!("Invalid length of blake2b_128, expected 16 got {}", b.len())) -} From 31abce8549029aba18e967ff90faae63d8558b23 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Tue, 31 Dec 2024 16:09:05 +0700 Subject: [PATCH 22/40] fix(cardano-chain-follower): usecip36 contructor Signed-off-by: bkioshn --- rust/cardano-chain-follower/src/metadata/cip36.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/rust/cardano-chain-follower/src/metadata/cip36.rs b/rust/cardano-chain-follower/src/metadata/cip36.rs index 3bdd686c7..d02df8fa3 100644 --- a/rust/cardano-chain-follower/src/metadata/cip36.rs +++ b/rust/cardano-chain-follower/src/metadata/cip36.rs @@ -96,11 +96,8 @@ impl Cip36 { }, }; - let cip36 = Cip36Registration { - key_registration, - registration_witness, - is_catalyst_strict, - }; + let cip36 = + Cip36Registration::new(key_registration, registration_witness, is_catalyst_strict); let validation = cip36.validate(network, k61284, &mut validation_report); From 017b69e5dbe81a2099c500f83e5646a1dddd5992 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Tue, 31 Dec 2024 16:09:48 +0700 Subject: [PATCH 23/40] fix(cardano-chain-follower): naming chain -> network Signed-off-by: bkioshn --- .../examples/follow_chains.rs | 65 ++++---- rust/cardano-chain-follower/src/chain_sync.rs | 46 +++--- .../src/chain_sync_config.rs | 27 ++-- .../src/chain_sync_live_chains.rs | 82 +++++------ .../src/chain_sync_ready.rs | 24 +-- .../src/chain_update.rs | 2 +- rust/cardano-chain-follower/src/follow.rs | 68 ++++----- .../src/mithril_snapshot.rs | 12 +- .../src/mithril_snapshot_config.rs | 49 +++--- .../src/mithril_snapshot_data.rs | 14 +- .../src/mithril_snapshot_iterator.rs | 26 ++-- .../src/mithril_snapshot_sync.rs | 139 +++++++++--------- .../src/mithril_turbo_downloader.rs | 22 +-- .../cardano-chain-follower/src/snapshot_id.rs | 4 +- rust/cardano-chain-follower/src/stats.rs | 100 ++++++------- 15 files changed, 349 insertions(+), 331 deletions(-) diff --git a/rust/cardano-chain-follower/examples/follow_chains.rs b/rust/cardano-chain-follower/examples/follow_chains.rs index a722bfb42..673c67391 100644 --- a/rust/cardano-chain-follower/examples/follow_chains.rs +++ b/rust/cardano-chain-follower/examples/follow_chains.rs @@ -120,7 +120,7 @@ async fn start_sync_for(network: &Network, matches: ArgMatches) -> Result<(), Bo cfg.mithril_cfg = cfg.mithril_cfg.with_dl_config(dl_config); info!( - chain = cfg.chain.to_string(), + network = cfg.network.to_string(), mithril_sync_dl_workers = mithril_dl_workers, mithril_sync_dl_chunk_size = mithril_dl_chunk_size, mithril_sync_dl_queue_ahead = mithril_dl_queue_ahead, @@ -143,7 +143,7 @@ const RUNNING_UPDATE_INTERVAL: u64 = 100_000; /// Try and follow a chain continuously, from Genesis until Tip. #[allow(clippy::too_many_lines)] async fn follow_for(network: Network, matches: ArgMatches) { - info!(chain = network.to_string(), "Following"); + info!(network = network.to_string(), "Following"); let mut follower = ChainFollower::new(network, Point::ORIGIN, Point::TIP).await; let is_all_tip_blocks = matches.get_flag("all-tip-blocks"); @@ -181,13 +181,13 @@ async fn follow_for(network: Network, matches: ArgMatches) { // When we transition between important points, show the last block as well. if ((current_era != this_era) - || (chain_update.immutable() != is_last_immutable) + || (chain_update.is_immutable() != is_last_immutable) || (last_fork != chain_update.data.fork())) && !is_last_update_shown { if let Some(last_update) = last_update.clone() { info!( - chain = network.to_string(), + network = network.to_string(), "Chain Update {}:{}", updates - 1, last_update @@ -197,24 +197,24 @@ async fn follow_for(network: Network, matches: ArgMatches) { // If these become true, we will show all blocks from the follower. is_follow_all = is_follow_all - || (!chain_update.immutable() && is_all_live_blocks) + || (!chain_update.is_immutable() && is_all_live_blocks) || ((chain_update.data.fork() > 1.into()) && is_all_tip_blocks); // Don't know if this update will show or not, so say it didn't. is_last_update_shown = false; if (current_era != this_era) - || (chain_update.immutable() != is_last_immutable) + || (chain_update.is_immutable() != is_last_immutable) || is_reached_tip || is_follow_all || (updates % RUNNING_UPDATE_INTERVAL == 0) || (last_fork != chain_update.data.fork()) { current_era = this_era; - is_last_immutable = chain_update.immutable(); + is_last_immutable = chain_update.is_immutable(); last_fork = chain_update.data.fork(); info!( - chain = network.to_string(), + network = network.to_string(), "Chain Update {updates}:{}", chain_update ); // We already showed the last update, no need to show it again. @@ -234,7 +234,7 @@ async fn follow_for(network: Network, matches: ArgMatches) { "This Can't Happen".to_string() }; error!( - chain = network.to_string(), + network = network.to_string(), "Chain is broken: {chain_update} Does not follow: {display_last_update}", ); break; @@ -247,9 +247,11 @@ async fn follow_for(network: Network, matches: ArgMatches) { }; // Inspect the transactions in the block. - for (tx_idx, tx) in block.txs().iter().enumerate() { + for (txn_idx, tx) in block.txs().iter().enumerate() { + let txn_idx = TxnIndex::from_saturating(txn_idx); + // Get the auxiliary data for the transaction. - let tx_aux_data = match block_aux_data.get(TxnIndex::from_saturating(tx_idx)) { + let tx_aux_data = match block_aux_data.get(txn_idx) { Some(aux_data) => aux_data, None => continue, }; @@ -259,7 +261,7 @@ async fn follow_for(network: Network, matches: ArgMatches) { if let Some(aux_data) = update_biggest_aux_data( &chain_update, - TxnIndex::from_saturating(tx_idx), + txn_idx, is_largest_metadata, biggest_aux_data, ) { @@ -268,29 +270,29 @@ async fn follow_for(network: Network, matches: ArgMatches) { // If flag `is_log_bad_cip36` is set, log the bad CIP36. if is_log_bad_cip36 { - log_bad_cip36_info(&decoded_metadata, network, tx_idx, block.number()); + log_bad_cip36_info(&decoded_metadata, network, txn_idx, block.number()); } // If flag `is_log_cip509` is set, log the CIP509 validation. if is_log_cip509 { - log_cip509_info(&decoded_metadata, network, tx_idx, block.number()); + log_cip509_info(&decoded_metadata, network, txn_idx, block.number()); } } if is_log_raw_aux { if let Some(x) = block.as_alonzo() { info!( - chain = network.to_string(), + network = network.to_string(), "Raw Aux Data: {:02x?}", x.auxiliary_data_set ); } else if let Some(x) = block.as_babbage() { info!( - chain = network.to_string(), + network = network.to_string(), "Raw Aux Data: {:02x?}", x.auxiliary_data_set ); } else if let Some(x) = block.as_conway() { info!( - chain = network.to_string(), + network = network.to_string(), "Raw Aux Data: {:02x?}", x.auxiliary_data_set ); } @@ -325,25 +327,28 @@ async fn follow_for(network: Network, matches: ArgMatches) { if !is_last_update_shown { if let Some(last_update) = last_update.clone() { - info!(chain = network.to_string(), "Last Update: {}", last_update); + info!( + network = network.to_string(), + "Last Update: {}", last_update + ); } } let stats = Statistics::new(network); info!("Json Metrics: {}", stats.as_json(true)); - info!(chain = network.to_string(), "Following Completed."); + info!(network = network.to_string(), "Following Completed."); } // FIXME: Why do we need this? Should it be finding the largest aux data? /// Helper function for updating the biggest aux data. /// Comparing between CIP36 and CIP509. fn update_biggest_aux_data( - chain_update: &ChainUpdate, tx_idx: TxnIndex, largest_metadata: bool, biggest_aux_data: usize, + chain_update: &ChainUpdate, txn_idx: TxnIndex, largest_metadata: bool, biggest_aux_data: usize, ) -> Option { let raw_size_cip36 = match chain_update .data - .txn_metadata(tx_idx, MetadatumLabel::CIP036_REGISTRATION) + .txn_metadata(txn_idx, MetadatumLabel::CIP036_REGISTRATION) { Some(raw) => raw.as_ref().len(), None => 0, @@ -351,7 +356,7 @@ fn update_biggest_aux_data( let raw_size_cip509 = match chain_update .data - .txn_metadata(tx_idx, MetadatumLabel::CIP509_RBAC) + .txn_metadata(txn_idx, MetadatumLabel::CIP509_RBAC) { Some(raw) => raw.as_ref().len(), None => 0, @@ -369,14 +374,14 @@ fn update_biggest_aux_data( /// Helper function for logging bad CIP36. fn log_bad_cip36_info( - decoded_metadata: &DecodedMetadata, network: Network, tx_idx: usize, block: u64, + decoded_metadata: &DecodedMetadata, network: Network, txn_idx: TxnIndex, block: u64, ) { if let Some(m) = decoded_metadata.get(MetadatumLabel::CIP036_REGISTRATION) { if let Metadata::DecodedMetadataValues::Cip36(cip36) = &m.value { if !cip36.validation.is_valid_signature && !m.report.is_empty() { info!( - chain = network.to_string(), - block, "CIP36 {tx_idx}: {:?}", &cip36 + network = network.to_string(), + block, "CIP36 {txn_idx:?}: {:?}", &cip36 ); } } @@ -385,21 +390,21 @@ fn log_bad_cip36_info( /// Helper function for logging CIP509 validation. fn log_cip509_info( - decoded_metadata: &DecodedMetadata, network: Network, tx_idx: usize, block: u64, + decoded_metadata: &DecodedMetadata, network: Network, txn_idx: TxnIndex, block: u64, ) { if let Some(m) = decoded_metadata.get(MetadatumLabel::CIP509_RBAC) { if let Metadata::DecodedMetadataValues::Cip509(cip509) = &m.value { info!( - chain = network.to_string(), - block, "CIP509 {tx_idx}: {:?}", &cip509 + network = network.to_string(), + block, "CIP509 {txn_idx:?}: {:?}", &cip509 ); } // If report is not empty, log it, log it as a warning. if !m.report.is_empty() { warn!( - chain = network.to_string(), - block, "CIP509 {tx_idx}: {:?}", decoded_metadata + network = network.to_string(), + block, "CIP509 {txn_idx:?}: {:?}", decoded_metadata ); } } diff --git a/rust/cardano-chain-follower/src/chain_sync.rs b/rust/cardano-chain-follower/src/chain_sync.rs index 40efd352b..dd8cec25b 100644 --- a/rust/cardano-chain-follower/src/chain_sync.rs +++ b/rust/cardano-chain-follower/src/chain_sync.rs @@ -345,15 +345,15 @@ async fn persistent_reconnect(addr: &str, chain: Network) -> PeerClient { async fn live_sync_backfill( cfg: &ChainSyncConfig, update: &MithrilUpdateMessage, ) -> anyhow::Result<()> { - stats::backfill_started(cfg.chain); + stats::backfill_started(cfg.network); - let (fill_to, _oldest_fork) = get_fill_to_point(cfg.chain).await; + let (fill_to, _oldest_fork) = get_fill_to_point(cfg.network).await; let range = (update.tip.clone().into(), fill_to.clone().into()); let mut previous_point = update.previous.clone(); let range_msg = format!("{range:?}"); - let mut peer = persistent_reconnect(&cfg.relay_address, cfg.chain).await; + let mut peer = persistent_reconnect(&cfg.relay_address, cfg.network).await; // Request the range of blocks from the Peer. peer.blockfetch() @@ -365,7 +365,7 @@ async fn live_sync_backfill( while let Some(block_data) = peer.blockfetch().recv_while_streaming().await? { // Backfilled blocks get placed in the oldest fork currently on the live-chain. - let block = MultiEraBlock::new(cfg.chain, block_data, &previous_point, 1.into()) + let block = MultiEraBlock::new(cfg.network, block_data, &previous_point, 1.into()) .with_context(|| { format!( "Failed to decode block data. previous: {previous_point:?}, range: {range_msg}" @@ -399,9 +399,9 @@ async fn live_sync_backfill( let backfill_size = backfill_blocks.len() as u64; // Try and backfill, if anything doesn't work, or the chain integrity would break, fail. - live_chain_backfill(cfg.chain, &backfill_blocks)?; + live_chain_backfill(cfg.network, &backfill_blocks)?; - stats::backfill_ended(cfg.chain, backfill_size); + stats::backfill_ended(cfg.network, backfill_size); debug!("Backfilled Range OK: {}", range_msg); @@ -421,7 +421,7 @@ async fn live_sync_backfill_and_purge( debug!( "Before Backfill: Size of the Live Chain is: {} Blocks", - live_chain_length(cfg.chain) + live_chain_length(cfg.network) ); let live_chain_head: Point; @@ -435,56 +435,56 @@ async fn live_sync_backfill_and_purge( sleep(Duration::from_secs(10)).await; } - if let Some(head_point) = get_live_head_point(cfg.chain) { + if let Some(head_point) = get_live_head_point(cfg.network) { live_chain_head = head_point; break; } } stats::new_mithril_update( - cfg.chain, + cfg.network, update.tip.slot_or_default(), - live_chain_length(cfg.chain) as u64, + live_chain_length(cfg.network) as u64, live_chain_head.slot_or_default(), ); debug!( "After Backfill: Size of the Live Chain is: {} Blocks", - live_chain_length(cfg.chain) + live_chain_length(cfg.network) ); // Once Backfill is completed OK we can use the Blockchain data for Syncing and Querying sync_ready.signal(); - let mut update_sender = get_chain_update_tx_queue(cfg.chain).await; + let mut update_sender = get_chain_update_tx_queue(cfg.network).await; loop { let Some(update) = rx.recv().await else { - error!("Mithril Sync Failed, can not continue chain sync either."); + error!("Mithril Sync Failed, can not continue network sync either."); return; }; // We can't get an update sender until the sync is released. if update_sender.is_none() { - update_sender = get_chain_update_tx_queue(cfg.chain).await; + update_sender = get_chain_update_tx_queue(cfg.network).await; } debug!("Mithril Tip has advanced to: {update:?} : PURGE NEEDED"); let update_point: Point = update.tip.clone(); - if let Err(error) = purge_live_chain(cfg.chain, &update_point) { + if let Err(error) = purge_live_chain(cfg.network, &update_point) { // This should actually never happen. error!("Mithril Purge Failed: {}", error); } debug!( "After Purge: Size of the Live Chain is: {} Blocks", - live_chain_length(cfg.chain) + live_chain_length(cfg.network) ); notify_follower( - cfg.chain, + cfg.network, &update_sender, &chain_update::Kind::ImmutableBlockRollForward, ); @@ -515,11 +515,11 @@ async fn live_sync_backfill_and_purge( pub(crate) async fn chain_sync(cfg: ChainSyncConfig, rx: mpsc::Receiver) { debug!( "Chain Sync for: {} from {} : Starting", - cfg.chain, cfg.relay_address, + cfg.network, cfg.relay_address, ); // Start the SYNC_READY unlock task. - let sync_waiter = wait_for_sync_ready(cfg.chain); + let sync_waiter = wait_for_sync_ready(cfg.network); let backfill_cfg = cfg.clone(); @@ -531,13 +531,13 @@ pub(crate) async fn chain_sync(cfg: ChainSyncConfig, rx: mpsc::Receiver debug!("Tip Resynchronized to {tip}"), Err(error) => { error!( @@ -549,7 +549,7 @@ pub(crate) async fn chain_sync(cfg: ChainSyncConfig, rx: mpsc::Receiver = LazyLock::new(|| { #[derive(Clone, Debug)] pub struct ChainSyncConfig { /// Chain Network - pub chain: Network, + pub network: Network, /// Relay Node Address pub(crate) relay_address: String, /// Block buffer size option. @@ -59,13 +59,13 @@ impl ChainSyncConfig { /// Each network has a different set of defaults, so no single "default" can apply. /// This function is preferred to the `default()` standard function. #[must_use] - pub fn default_for(chain: Network) -> Self { + pub fn default_for(network: Network) -> Self { Self { - chain, - relay_address: chain.default_relay(), + network, + relay_address: network.default_relay(), chain_update_buffer_size: DEFAULT_CHAIN_UPDATE_BUFFER_SIZE, immutable_slot_window: DEFAULT_IMMUTABLE_SLOT_WINDOW, - mithril_cfg: MithrilSnapshotConfig::default_for(chain), + mithril_cfg: MithrilSnapshotConfig::default_for(network), } } @@ -126,16 +126,19 @@ impl ChainSyncConfig { /// `Error`: On error. pub async fn run(self) -> Result<()> { debug!( - chain = self.chain.to_string(), + network = self.network.to_string(), "Chain Synchronization Starting" ); - stats::sync_started(self.chain); + stats::sync_started(self.network); // Start the Chain Sync - IFF its not already running. - let lock_entry = match SYNC_JOIN_HANDLE_MAP.get(&self.chain) { + let lock_entry = match SYNC_JOIN_HANDLE_MAP.get(&self.network) { None => { - error!("Join Map improperly initialized: Missing {}!!", self.chain); + error!( + "Join Map improperly initialized: Missing {}!!", + self.network + ); return Err(Error::Internal); // Should not get here. }, Some(entry) => entry, @@ -143,8 +146,8 @@ impl ChainSyncConfig { let mut locked_handle = lock_entry.value().lock().await; if (*locked_handle).is_some() { - debug!("Chain Sync Already Running for {}", self.chain); - return Err(Error::ChainSyncAlreadyRunning(self.chain)); + debug!("Chain Sync Already Running for {}", self.network); + return Err(Error::ChainSyncAlreadyRunning(self.network)); } // Start the Mithril Snapshot Follower @@ -154,7 +157,7 @@ impl ChainSyncConfig { *locked_handle = Some(tokio::spawn(chain_sync(self.clone(), rx))); // sync_map.insert(chain, handle); - debug!("Chain Sync for {} : Started", self.chain); + debug!("Chain Sync for {} : Started", self.network); Ok(()) } diff --git a/rust/cardano-chain-follower/src/chain_sync_live_chains.rs b/rust/cardano-chain-follower/src/chain_sync_live_chains.rs index 530693993..e03af59c0 100644 --- a/rust/cardano-chain-follower/src/chain_sync_live_chains.rs +++ b/rust/cardano-chain-follower/src/chain_sync_live_chains.rs @@ -46,14 +46,14 @@ static PEER_TIP: LazyLock> = LazyLock::new(|| { }); /// Set the last TIP received from the peer. -fn update_peer_tip(chain: Network, tip: Point) { - PEER_TIP.insert(chain, tip); +fn update_peer_tip(network: Network, tip: Point) { + PEER_TIP.insert(network, tip); } /// Get the last TIP received from the peer. /// If the peer tip doesn't exist, get the UNKNOWN point. -pub(crate) fn get_peer_tip(chain: Network) -> Point { - (*PEER_TIP.get_or_insert(chain, Point::UNKNOWN).value()).clone() +pub(crate) fn get_peer_tip(network: Network) -> Point { + (*PEER_TIP.get_or_insert(network, Point::UNKNOWN).value()).clone() } /// Number of seconds to wait if we detect a `SyncReady` race condition. @@ -136,7 +136,7 @@ impl ProtectedLiveChainBlockList { /// The blocks MUST be contiguous and properly self referential. /// Note: This last condition is NOT enforced, but must be met or block chain /// iteration will fail. - fn backfill(&self, chain: Network, blocks: &[MultiEraBlock]) -> Result<()> { + fn backfill(&self, network: Network, blocks: &[MultiEraBlock]) -> Result<()> { let live_chain = self.0.write().map_err(|_| Error::Internal)?; // Make sure our first live block == the last mithril tip. @@ -145,7 +145,7 @@ impl ProtectedLiveChainBlockList { .first() .ok_or(Error::LiveSync("No first block for backfill.".to_string()))? .point(); - let latest_mithril_tip = latest_mithril_snapshot_id(chain).tip(); + let latest_mithril_tip = latest_mithril_snapshot_id(network).tip(); if !first_block_point.strict_eq(&latest_mithril_tip) { return Err(Error::LiveSync(format!( "First Block of Live BackFill {first_block_point} MUST be last block of Mithril Snapshot {latest_mithril_tip}." @@ -175,7 +175,7 @@ impl ProtectedLiveChainBlockList { }); // End of Successful backfill == Reaching TIP, because live sync is always at tip. - stats::tip_reached(chain); + stats::tip_reached(network); Ok(()) } @@ -193,7 +193,7 @@ impl ProtectedLiveChainBlockList { /// would be lost due to rollback. Will REFUSE to add a block which does NOT have /// a proper "previous" point defined. fn add_block_to_tip( - &self, chain: Network, block: MultiEraBlock, fork: &mut Fork, tip: Point, + &self, network: Network, block: MultiEraBlock, fork: &mut Fork, tip: Point, ) -> Result<()> { let live_chain = self.0.write().map_err(|_| Error::Internal)?; @@ -241,7 +241,7 @@ impl ProtectedLiveChainBlockList { // Record a rollback statistic (We record the ACTUAL size our rollback effected our // internal live chain, not what the node thinks.) - stats::rollback(chain, stats::RollbackType::LiveChain, rollback_size); + stats::rollback(network, stats::RollbackType::LiveChain, rollback_size); } let head_slot = block.point().slot_or_default(); @@ -250,10 +250,10 @@ impl ProtectedLiveChainBlockList { let _unused = live_chain.insert(block.point(), block); let tip_slot = tip.slot_or_default(); - update_peer_tip(chain, tip); + update_peer_tip(network, tip); // Record the new live chain stats after we add a new block. - stats::new_live_block(chain, live_chain.len() as u64, head_slot, tip_slot); + stats::new_live_block(network, live_chain.len() as u64, head_slot, tip_slot); Ok(()) } @@ -261,13 +261,13 @@ impl ProtectedLiveChainBlockList { /// Checks if the point exists in the live chain. /// If it does, removes all block preceding it (but not the point itself). /// Will refuse to purge if the point is not the TIP of the mithril chain. - fn purge(&self, chain: Network, point: &Point) -> Result<()> { + fn purge(&self, network: Network, point: &Point) -> Result<()> { // Make sure our first live block == the last mithril tip. // Ensures we are properly connected to the Mithril Chain. // But don't check this if we are about to purge the entire chain. // We do this before we bother locking the chain for update. if *point != Point::TIP { - let latest_mithril_tip = latest_mithril_snapshot_id(chain).tip(); + let latest_mithril_tip = latest_mithril_snapshot_id(network).tip(); if !point.strict_eq(&latest_mithril_tip) { return Err(Error::LiveSync(format!( "First Block of Live Purge {point} MUST be last block of Mithril Snapshot {latest_mithril_tip}." @@ -410,27 +410,27 @@ impl ProtectedLiveChainBlockList { } /// Get the `LiveChainBlockList` for a particular `Network`. -fn get_live_chain(chain: Network) -> ProtectedLiveChainBlockList { +fn get_live_chain(network: Network) -> ProtectedLiveChainBlockList { // Get a reference to our live chain storage. // This SHOULD always exist, because its initialized exhaustively. // If this FAILS, Recreate a blank chain, but log an error as its a serious UNRECOVERABLE // BUG. - let entry = if let Some(entry) = LIVE_CHAINS.get(&chain) { + let entry = if let Some(entry) = LIVE_CHAINS.get(&network) { entry } else { error!( - chain = chain.to_string(), - "Internal Error: Chain Sync Failed to find chain in LIVE_CHAINS" + network = network.to_string(), + "Internal Error: Chain Sync Failed to find network in LIVE_CHAINS" ); // Try and correct the error. - LIVE_CHAINS.insert(chain, ProtectedLiveChainBlockList::new()); + LIVE_CHAINS.insert(network, ProtectedLiveChainBlockList::new()); // This should NOT fail, because we just inserted it, its catastrophic failure if it does. #[allow(clippy::expect_used)] LIVE_CHAINS - .get(&chain) - .expect("Internal Error: Chain Sync Failed to find chain in LIVE_CHAINS") + .get(&network) + .expect("Internal Error: Chain Sync Failed to find network in LIVE_CHAINS") }; let value = entry.value(); @@ -438,17 +438,17 @@ fn get_live_chain(chain: Network) -> ProtectedLiveChainBlockList { } /// Get the head `Point` currently in the live chain. -pub(crate) fn get_live_head_point(chain: Network) -> Option { - let live_chain = get_live_chain(chain); +pub(crate) fn get_live_head_point(network: Network) -> Option { + let live_chain = get_live_chain(network); live_chain.get_live_head_point() } /// Get the Live block relative to the specified point. /// The starting block must exist if the search is strict. pub(crate) fn get_live_block( - chain: Network, point: &Point, advance: i64, strict: bool, + network: Network, point: &Point, advance: i64, strict: bool, ) -> Option { - let live_chain = get_live_chain(chain); + let live_chain = get_live_chain(network); live_chain.get_block(point, advance, strict) } @@ -458,8 +458,8 @@ pub(crate) fn get_live_block( /// /// Note: It MAY change between calling this function and actually backfilling. /// This is expected and normal behavior. -pub(crate) async fn get_fill_to_point(chain: Network) -> (Point, Fork) { - let live_chain = get_live_chain(chain); +pub(crate) async fn get_fill_to_point(network: Network) -> (Point, Fork) { + let live_chain = get_live_chain(network); loop { if let Some(earliest_block) = live_chain.get_earliest_block() { @@ -475,43 +475,43 @@ pub(crate) async fn get_fill_to_point(chain: Network) -> (Point, Fork) { /// `rollback_count` should be set to 1 on the very first connection, after that, /// it is maintained by this function, and MUST not be modified elsewhere. pub(crate) fn live_chain_add_block_to_tip( - chain: Network, block: MultiEraBlock, fork: &mut Fork, tip: Point, + network: Network, block: MultiEraBlock, fork: &mut Fork, tip: Point, ) -> Result<()> { - let live_chain = get_live_chain(chain); - live_chain.add_block_to_tip(chain, block, fork, tip) + let live_chain = get_live_chain(network); + live_chain.add_block_to_tip(network, block, fork, tip) } /// Backfill the live chain with the block set provided. -pub(crate) fn live_chain_backfill(chain: Network, blocks: &[MultiEraBlock]) -> Result<()> { - let live_chain = get_live_chain(chain); - live_chain.backfill(chain, blocks) +pub(crate) fn live_chain_backfill(network: Network, blocks: &[MultiEraBlock]) -> Result<()> { + let live_chain = get_live_chain(network); + live_chain.backfill(network, blocks) } /// Get the length of the live chain. /// Probably used by debug code only, so its ok if this is not use. -pub(crate) fn live_chain_length(chain: Network) -> usize { - let live_chain = get_live_chain(chain); +pub(crate) fn live_chain_length(network: Network) -> usize { + let live_chain = get_live_chain(network); live_chain.len() } /// On an immutable update, purge the live chain up to the new immutable tip. /// Will error if the point is not in the Live chain. -pub(crate) fn purge_live_chain(chain: Network, point: &Point) -> Result<()> { - let live_chain = get_live_chain(chain); - live_chain.purge(chain, point) +pub(crate) fn purge_live_chain(network: Network, point: &Point) -> Result<()> { + let live_chain = get_live_chain(network); + live_chain.purge(network, point) } /// Get intersection points to try and find best point to connect to the node on /// reconnect. -pub(crate) fn get_intersect_points(chain: Network) -> Vec { - let live_chain = get_live_chain(chain); +pub(crate) fn get_intersect_points(network: Network) -> Vec { + let live_chain = get_live_chain(network); live_chain.get_intersect_points() } /// Find best block from a fork relative to a point. pub(crate) fn find_best_fork_block( - chain: Network, point: &Point, previous_point: &Point, fork: Fork, + network: Network, point: &Point, previous_point: &Point, fork: Fork, ) -> Option<(MultiEraBlock, u64)> { - let live_chain = get_live_chain(chain); + let live_chain = get_live_chain(network); live_chain.find_best_fork_block(point, previous_point, fork) } diff --git a/rust/cardano-chain-follower/src/chain_sync_ready.rs b/rust/cardano-chain-follower/src/chain_sync_ready.rs index eb77a3edc..34e18f4d1 100644 --- a/rust/cardano-chain-follower/src/chain_sync_ready.rs +++ b/rust/cardano-chain-follower/src/chain_sync_ready.rs @@ -39,13 +39,13 @@ impl SyncReady { /// Sand a chain update to any subscribers that are listening. pub(crate) fn notify_follower( - chain: Network, update_sender: &Option>, + network: Network, update_sender: &Option>, kind: &chain_update::Kind, ) { if let Some(update_sender) = update_sender { if let Err(error) = update_sender.send(kind.clone()) { error!( - chain = chain.to_string(), + network = network.to_string(), "Failed to broadcast the Update {kind} : {error}" ); } @@ -84,14 +84,14 @@ static SYNC_READY: LazyLock>> = LazyLock::new /// Write Lock the `SYNC_READY` lock for a network. /// When we are signaled to be ready, set it to true and release the lock. -pub(crate) fn wait_for_sync_ready(chain: Network) -> SyncReadyWaiter { +pub(crate) fn wait_for_sync_ready(network: Network) -> SyncReadyWaiter { let (tx, rx) = oneshot::channel::<()>(); tokio::spawn(async move { // We are safe to use `expect` here because the SYNC_READY list is exhaustively // initialized. Its a Serious BUG if that not True, so panic is OK. #[allow(clippy::expect_used)] - let lock_entry = SYNC_READY.get(&chain).expect("network should exist"); + let lock_entry = SYNC_READY.get(&network).expect("network should exist"); let lock = lock_entry.value(); @@ -109,11 +109,11 @@ pub(crate) fn wait_for_sync_ready(chain: Network) -> SyncReadyWaiter { } /// Get a Read lock on the Sync State, and return if we are ready or not. -async fn check_sync_ready(chain: Network) -> bool { +async fn check_sync_ready(network: Network) -> bool { // We are safe to use `expect` here because the SYNC_READY list is exhaustively // initialized. Its a Serious BUG if that not True, so panic is OK. #[allow(clippy::expect_used)] - let lock_entry = SYNC_READY.get(&chain).expect("network should exist"); + let lock_entry = SYNC_READY.get(&network).expect("network should exist"); let lock = lock_entry.value(); let status = lock.read().await; @@ -128,22 +128,22 @@ const SYNC_READY_RACE_BACKOFF_SECS: u64 = 1; /// Block until the chain is synced to TIP. /// This is necessary to ensure the Blockchain data is fully intact before attempting to /// consume it. -pub(crate) async fn block_until_sync_ready(chain: Network) { +pub(crate) async fn block_until_sync_ready(network: Network) { // There is a potential race where we haven't yet write locked the SYNC_READY lock when we // check it. So, IF the ready state returns as false, sleep a while and try again. - while !check_sync_ready(chain).await { + while !check_sync_ready(network).await { sleep(Duration::from_secs(SYNC_READY_RACE_BACKOFF_SECS)).await; } } /// Get the Broadcast Receive queue for the given chain updates. pub(crate) async fn get_chain_update_rx_queue( - chain: Network, + network: Network, ) -> broadcast::Receiver { // We are safe to use `expect` here because the SYNC_READY list is exhaustively // initialized. Its a Serious BUG if that not True, so panic is OK. #[allow(clippy::expect_used)] - let lock_entry = SYNC_READY.get(&chain).expect("network should exist"); + let lock_entry = SYNC_READY.get(&network).expect("network should exist"); let lock = lock_entry.value(); @@ -154,12 +154,12 @@ pub(crate) async fn get_chain_update_rx_queue( /// Get the Broadcast Transmit queue for the given chain updates. pub(crate) async fn get_chain_update_tx_queue( - chain: Network, + network: Network, ) -> Option> { // We are safe to use `expect` here because the SYNC_READY list is exhaustively // initialized. Its a Serious BUG if that not True, so panic is OK. #[allow(clippy::expect_used)] - let lock_entry = SYNC_READY.get(&chain).expect("network should exist"); + let lock_entry = SYNC_READY.get(&network).expect("network should exist"); let lock = lock_entry.value(); diff --git a/rust/cardano-chain-follower/src/chain_update.rs b/rust/cardano-chain-follower/src/chain_update.rs index 4835efab9..2efc6d699 100644 --- a/rust/cardano-chain-follower/src/chain_update.rs +++ b/rust/cardano-chain-follower/src/chain_update.rs @@ -42,7 +42,7 @@ impl ChainUpdate { /// Is the chain update immutable? #[must_use] - pub fn immutable(&self) -> bool { + pub fn is_immutable(&self) -> bool { self.data.is_immutable() } } diff --git a/rust/cardano-chain-follower/src/follow.rs b/rust/cardano-chain-follower/src/follow.rs index caf71cd27..862061679 100644 --- a/rust/cardano-chain-follower/src/follow.rs +++ b/rust/cardano-chain-follower/src/follow.rs @@ -20,7 +20,7 @@ use crate::{ /// The Chain Follower pub struct ChainFollower { /// The Blockchain network we are following. - chain: Network, + network: Network, /// Where we end following. end: Point, /// Point we processed most recently. @@ -44,7 +44,7 @@ impl ChainFollower { /// /// # Arguments /// - /// * `chain` - The blockchain network to follow. + /// * `network` - The blockchain network to follow. /// * `start` - The point or tip to start following from (inclusive). /// * `end` - The point or tip to stop following from (inclusive). /// @@ -67,16 +67,16 @@ impl ChainFollower { /// /// To ONLY follow from TIP, set BOTH start and end to TIP. #[must_use] - pub async fn new(chain: Network, start: Point, end: Point) -> Self { - let rx = get_chain_update_rx_queue(chain).await; + pub async fn new(network: Network, start: Point, end: Point) -> Self { + let rx = get_chain_update_rx_queue(network).await; ChainFollower { - chain, + network, end, previous: Point::UNKNOWN, current: start, fork: 1.into(), // This is correct, because Mithril is Fork 0. - snapshot: MithrilSnapshot::new(chain), + snapshot: MithrilSnapshot::new(network), mithril_follower: None, mithril_tip: None, sync_updates: rx, @@ -85,7 +85,7 @@ impl ChainFollower { /// If we can, get the next update from the mithril snapshot. async fn next_from_mithril(&mut self) -> Option { - let current_mithril_tip = latest_mithril_snapshot_id(self.chain).tip(); + let current_mithril_tip = latest_mithril_snapshot_id(self.network).tip(); if current_mithril_tip > self.current { if self.mithril_follower.is_none() { @@ -115,7 +115,7 @@ impl ChainFollower { }; if roll_forward_condition { - let snapshot = MithrilSnapshot::new(self.chain); + let snapshot = MithrilSnapshot::new(self.network); if let Some(block) = snapshot.read_block_at(¤t_mithril_tip).await { // The Mithril Tip has moved forwards. self.mithril_tip = Some(current_mithril_tip); @@ -143,7 +143,7 @@ impl ChainFollower { // Special Case: point = TIP_POINT. Just return the latest block in the live chain. if self.current == Point::TIP { next_block = { - let block = get_live_block(self.chain, &self.current, -1, false)?; + let block = get_live_block(self.network, &self.current, -1, false)?; Some(block) }; } @@ -152,7 +152,7 @@ impl ChainFollower { if next_block.is_none() { // If we don't know the previous block, get the block requested. let advance = i64::from(!self.previous.is_unknown()); - next_block = get_live_block(self.chain, &self.current, advance, true); + next_block = get_live_block(self.network, &self.current, advance, true); } // If we can't get the next consecutive block, then @@ -163,7 +163,7 @@ impl ChainFollower { // IF this is an update still, and not us having caught up, then it WILL be a rollback. update_type = chain_update::Kind::Rollback; next_block = if let Some((block, depth)) = - find_best_fork_block(self.chain, &self.current, &self.previous, self.fork) + find_best_fork_block(self.network, &self.current, &self.previous, self.fork) { debug!("Found fork block: {block}"); // IF the block is the same as our current previous, there has been no chain @@ -176,12 +176,12 @@ impl ChainFollower { } } else { debug!("No block to find, rewinding to latest mithril tip."); - let latest_mithril_point = latest_mithril_snapshot_id(self.chain).tip(); - if let Some(block) = MithrilSnapshot::new(self.chain) + let latest_mithril_point = latest_mithril_snapshot_id(self.network).tip(); + if let Some(block) = MithrilSnapshot::new(self.network) .read_block_at(&latest_mithril_point) .await { - rollback_depth = live_chain_length(self.chain) as u64; + rollback_depth = live_chain_length(self.network) as u64; Some(block) } else { return None; @@ -192,7 +192,7 @@ impl ChainFollower { if let Some(next_block) = next_block { // Update rollback stats for the follower if one is reported. if update_type == chain_update::Kind::Rollback { - rollback(self.chain, stats::RollbackType::Follower, rollback_depth); + rollback(self.network, stats::RollbackType::Follower, rollback_depth); } // debug!("Pre Previous update 4 : {:?}", self.previous); self.previous = self.current.clone(); @@ -200,7 +200,7 @@ impl ChainFollower { self.current = next_block.point().clone(); self.fork = next_block.fork(); - let tip = point_at_tip(self.chain, &self.current).await; + let tip = point_at_tip(self.network, &self.current).await; let update = ChainUpdate::new(update_type, tip, next_block); return Some(update); } @@ -283,7 +283,7 @@ impl ChainFollower { } // Can't follow if SYNC is not ready. - block_until_sync_ready(self.chain).await; + block_until_sync_ready(self.network).await; // Get next block from the iteration. self.unprotected_next().await @@ -296,22 +296,22 @@ impl ChainFollower { /// /// This is a convenience function which just used `ChainFollower` to fetch a single /// block. - pub async fn get_block(chain: Network, point: Point) -> Option { + pub async fn get_block(network: Network, point: Point) -> Option { // Get the block from the chain. // This function suppose to run only once, so the end point // can be set to `TIP_POINT` - let mut follower = Self::new(chain, point, Point::TIP).await; + let mut follower = Self::new(network, point, Point::TIP).await; follower.next().await } /// Get the current Immutable and live tips. /// /// Note, this will block until the chain is synced, ready to be followed. - pub async fn get_tips(chain: Network) -> (Point, Point) { + pub async fn get_tips(network: Network) -> (Point, Point) { // Can't follow if SYNC is not ready. - block_until_sync_ready(chain).await; + block_until_sync_ready(network).await; - let tips = Statistics::tips(chain); + let tips = Statistics::tips(network); let mithril_tip = Point::fuzzy(tips.0); let live_tip = Point::fuzzy(tips.1); @@ -323,16 +323,16 @@ impl ChainFollower { /// /// # Arguments /// - /// * `chain` - The blockchain network to post the transaction on. + /// * `network` - The blockchain network to post the transaction on. /// * `txn` - The transaction to be posted. /// /// # Returns /// /// `TxId` - The ID of the transaction that was queued. #[allow(clippy::unused_async)] - pub async fn post_txn(chain: Network, txn: TxBody) -> TxId { + pub async fn post_txn(network: Network, txn: TxBody) -> TxId { #[allow(clippy::no_effect_underscore_binding)] - let _unused = chain; + let _unused = network; #[allow(clippy::no_effect_underscore_binding)] let _unused = txn; @@ -345,9 +345,9 @@ impl ChainFollower { /// After which, it should be on the blockchain, and its the applications job to track /// if a transaction made it on-chain or not. #[allow(clippy::unused_async)] - pub async fn txn_sent(chain: Network, id: TxId) -> bool { + pub async fn txn_sent(network: Network, id: TxId) -> bool { #[allow(clippy::no_effect_underscore_binding)] - let _unused = chain; + let _unused = network; #[allow(clippy::no_effect_underscore_binding)] let _unused = id; @@ -390,13 +390,13 @@ mod tests { #[tokio::test] // FIXME - This test should fail async fn test_chain_follower_new() { - let chain = Network::Mainnet; + let network = Network::Mainnet; let start = Point::new(100u64.into(), [0; 32].into()); let end = Point::fuzzy(999u64.into()); - let follower = ChainFollower::new(chain, start.clone(), end.clone()).await; + let follower = ChainFollower::new(network, start.clone(), end.clone()).await; - assert_eq!(follower.chain, chain); + assert_eq!(follower.network, network); assert_eq!(follower.end, end); assert_eq!(follower.previous, Point::UNKNOWN); assert_eq!(follower.current, start); @@ -408,11 +408,11 @@ mod tests { #[tokio::test] // FIXME - This test should fail async fn test_chain_follower_update_current_none() { - let chain = Network::Mainnet; + let network = Network::Mainnet; let start = Point::new(100u64.into(), [0; 32].into()); let end = Point::fuzzy(999u64.into()); - let mut follower = ChainFollower::new(chain, start.clone(), end.clone()).await; + let mut follower = ChainFollower::new(network, start.clone(), end.clone()).await; let result = follower.update_current(&None); @@ -422,11 +422,11 @@ mod tests { #[tokio::test] // FIXME - This test should fail async fn test_chain_follower_update_current() { - let chain = Network::Mainnet; + let network = Network::Mainnet; let start = Point::new(100u64.into(), [0; 32].into()); let end = Point::fuzzy(999u64.into()); - let mut follower = ChainFollower::new(chain, start.clone(), end.clone()).await; + let mut follower = ChainFollower::new(network, start.clone(), end.clone()).await; let block_data = mock_block(); let update = ChainUpdate::new(chain_update::Kind::Block, false, block_data); diff --git a/rust/cardano-chain-follower/src/mithril_snapshot.rs b/rust/cardano-chain-follower/src/mithril_snapshot.rs index 2d8c9d31a..4a0608b50 100644 --- a/rust/cardano-chain-follower/src/mithril_snapshot.rs +++ b/rust/cardano-chain-follower/src/mithril_snapshot.rs @@ -21,13 +21,13 @@ use crate::{ #[derive(Clone)] pub(crate) struct MithrilSnapshot { /// Network that this snapshot is configured for - chain: Network, + network: Network, } impl MithrilSnapshot { /// Create a new Mithril Snapshot handler - pub(crate) fn new(chain: Network) -> Self { - Self { chain } + pub(crate) fn new(network: Network) -> Self { + Self { network } } /// Checks if the snapshot contains a given point. @@ -40,7 +40,7 @@ impl MithrilSnapshot { /// Returns true if the point exists within the Mithril snapshot for the specified /// network, false otherwise. pub(crate) fn contains_point(&self, point: &Point) -> bool { - let latest_id = latest_mithril_snapshot_id(self.chain); + let latest_id = latest_mithril_snapshot_id(self.network); point.slot_or_default() <= latest_id.tip().slot_or_default() } @@ -61,7 +61,7 @@ impl MithrilSnapshot { pub(crate) async fn try_read_blocks_from_point( &self, point: &Point, ) -> Option { - let snapshot_id = latest_mithril_snapshot_id(self.chain); + let snapshot_id = latest_mithril_snapshot_id(self.network); let snapshot_path = snapshot_id.immutable_path(); // Quick check if the block can be within the immutable data. @@ -70,7 +70,7 @@ impl MithrilSnapshot { } // We don't know the previous block, so we need to find it. - MithrilSnapshotIterator::new(self.chain, &snapshot_path, point, None) + MithrilSnapshotIterator::new(self.network, &snapshot_path, point, None) .await .ok() } diff --git a/rust/cardano-chain-follower/src/mithril_snapshot_config.rs b/rust/cardano-chain-follower/src/mithril_snapshot_config.rs index e4c95a091..adefeb4e7 100644 --- a/rust/cardano-chain-follower/src/mithril_snapshot_config.rs +++ b/rust/cardano-chain-follower/src/mithril_snapshot_config.rs @@ -55,7 +55,7 @@ pub(crate) struct MithrilUpdateMessage { #[derive(Clone, Debug)] pub struct MithrilSnapshotConfig { /// What Blockchain network are we configured for. - pub chain: Network, + pub network: Network, /// Path to the Mithril snapshot the follower should use. /// Note: this is a base directory. The Actual data will be stored under here. /// archive downloads -> `/dl` @@ -76,12 +76,12 @@ impl MithrilSnapshotConfig { /// Each network has a different set of defaults, so no single "default" can apply. /// This function is preferred to the `default()` standard function. #[must_use] - pub fn default_for(chain: Network) -> Self { + pub fn default_for(network: Network) -> Self { Self { - chain, - path: chain.default_mithril_path(), - aggregator_url: chain.default_mithril_aggregator(), - genesis_key: chain.default_mithril_genesis_key(), + network, + path: network.default_mithril_path(), + aggregator_url: network.default_mithril_aggregator(), + genesis_key: network.default_mithril_genesis_key(), dl_config: None, } } @@ -126,7 +126,7 @@ impl MithrilSnapshotConfig { } if latest_immutable_file > 0 { - return SnapshotId::try_new(self.chain, &latest_path).await; + return SnapshotId::try_new(self.network, &latest_path).await; } None @@ -136,7 +136,7 @@ impl MithrilSnapshotConfig { /// And then remove any left over files in download or the tmp path, or old snapshots. pub(crate) async fn activate(&self, snapshot_number: u64) -> io::Result { let new_path = self.mithril_path(snapshot_number); - let latest_id = latest_mithril_snapshot_id(self.chain); + let latest_id = latest_mithril_snapshot_id(self.network); debug!( "Activating snapshot: {} {} {:?}", @@ -190,7 +190,7 @@ impl MithrilSnapshotConfig { }, Ok(mut entries) => { // Get latest mithril snapshot path and number. - let latest_snapshot = latest_mithril_snapshot_id(self.chain); + let latest_snapshot = latest_mithril_snapshot_id(self.network); loop { // Get the next entry, stop on any error, or no entries left. @@ -332,7 +332,7 @@ impl MithrilSnapshotConfig { // hex. let vkey = remove_whitespace(&self.genesis_key); if !is_hex(&vkey) { - return Err(Error::MithrilGenesisVKeyNotHex(self.chain)); + return Err(Error::MithrilGenesisVKeyNotHex(self.network)); } Ok(()) @@ -349,22 +349,22 @@ impl MithrilSnapshotConfig { // We do this by trying to use it to get a list of snapshots. let client = mithril_client::ClientBuilder::aggregator(&url, &key) .build() - .map_err(|e| Error::MithrilClient(self.chain, url.clone(), e))?; + .map_err(|e| Error::MithrilClient(self.network, url.clone(), e))?; let snapshots = client .snapshot() .list() .await - .map_err(|e| Error::MithrilClient(self.chain, url.clone(), e))?; + .map_err(|e| Error::MithrilClient(self.network, url.clone(), e))?; // Check we have a snapshot, and its for our network. match snapshots.first().and_then(|s| s.beacon.network.as_ref()) { Some(network) => { let _aggregator_network = Network::from_str(network.as_str()).map_err(|_err| { - Error::MithrilClientNetworkMismatch(self.chain, network.clone()) + Error::MithrilClientNetworkMismatch(self.network, network.clone()) })?; }, - None => return Err(Error::MithrilClientNoSnapshots(self.chain, url)), + None => return Err(Error::MithrilClientNoSnapshots(self.network, url)), } Ok(()) @@ -385,14 +385,17 @@ impl MithrilSnapshotConfig { /// Run a Mithril Follower for the given network and configuration. pub(crate) async fn run(&self) -> Result> { debug!( - chain = self.chain.to_string(), + network = self.network.to_string(), "Mithril Auto-update : Starting" ); // Start the Mithril Sync - IFF its not already running. - let lock_entry = match SYNC_JOIN_HANDLE_MAP.get(&self.chain) { + let lock_entry = match SYNC_JOIN_HANDLE_MAP.get(&self.network) { None => { - error!("Join Map improperly initialized: Missing {}!!", self.chain); + error!( + "Join Map improperly initialized: Missing {}!!", + self.network + ); return Err(Error::Internal); // Should not get here. }, Some(entry) => entry, @@ -400,8 +403,8 @@ impl MithrilSnapshotConfig { let mut locked_handle = lock_entry.value().lock().await; if (*locked_handle).is_some() { - debug!("Mithril Already Running for {}", self.chain); - return Err(Error::MithrilSnapshotSyncAlreadyRunning(self.chain)); + debug!("Mithril Already Running for {}", self.network); + return Err(Error::MithrilSnapshotSyncAlreadyRunning(self.network)); } self.validate().await?; @@ -417,7 +420,7 @@ impl MithrilSnapshotConfig { // sync_map.insert(chain, handle); debug!( - chain = self.chain.to_string(), + network = self.network.to_string(), "Mithril Auto-update : Started" ); @@ -492,7 +495,7 @@ mod tests { let network = Network::Preprod; let config = MithrilSnapshotConfig::default_for(network); - assert_eq!(config.chain, network); + assert_eq!(config.network, network); assert_eq!(config.path, network.default_mithril_path()); assert_eq!(config.aggregator_url, network.default_mithril_aggregator()); assert_eq!(config.genesis_key, network.default_mithril_genesis_key()); @@ -501,7 +504,7 @@ mod tests { #[tokio::test] async fn test_validate_genesis_vkey() { let config = MithrilSnapshotConfig { - chain: Network::Preprod, + network: Network::Preprod, path: PathBuf::new(), aggregator_url: String::new(), genesis_key: "1234abcd".to_string(), @@ -511,7 +514,7 @@ mod tests { assert!(config.validate_genesis_vkey().is_ok()); let invalid_config = MithrilSnapshotConfig { - chain: Network::Preprod, + network: Network::Preprod, path: PathBuf::new(), aggregator_url: String::new(), genesis_key: "1234abcz".to_string(), diff --git a/rust/cardano-chain-follower/src/mithril_snapshot_data.rs b/rust/cardano-chain-follower/src/mithril_snapshot_data.rs index 2dcdf912c..4711a70d1 100644 --- a/rust/cardano-chain-follower/src/mithril_snapshot_data.rs +++ b/rust/cardano-chain-follower/src/mithril_snapshot_data.rs @@ -39,24 +39,24 @@ static CURRENT_MITHRIL_SNAPSHOT: LazyLock> = LazyLock::new(DashMap::new); /// Get the current latest snapshot data we have recorded. -pub(crate) fn latest_mithril_snapshot_data(chain: Network) -> SnapshotData { +pub(crate) fn latest_mithril_snapshot_data(network: Network) -> SnapshotData { // There should ALWAYS be a snapshot for the chain if this is called. - match CURRENT_MITHRIL_SNAPSHOT.get(&chain) { + match CURRENT_MITHRIL_SNAPSHOT.get(&network) { Some(snapshot_data) => snapshot_data.value().clone(), None => SnapshotData::default(), } } /// Get the latest Mithril Snapshot for a network. -pub(crate) fn latest_mithril_snapshot_id(chain: Network) -> SnapshotId { - // There should ALWAYS be a snapshot for the chain if this is called. - latest_mithril_snapshot_data(chain).id +pub(crate) fn latest_mithril_snapshot_id(network: Network) -> SnapshotId { + // There should ALWAYS be a snapshot for the network if this is called. + latest_mithril_snapshot_data(network).id } /// Update the latest snapshot data. -pub(crate) fn update_latest_mithril_snapshot(chain: Network, snapshot_id: SnapshotId) { +pub(crate) fn update_latest_mithril_snapshot(network: Network, snapshot_id: SnapshotId) { let snapshot_data = SnapshotData::new(snapshot_id); // Save the current snapshot - CURRENT_MITHRIL_SNAPSHOT.insert(chain, snapshot_data); + CURRENT_MITHRIL_SNAPSHOT.insert(network, snapshot_data); } diff --git a/rust/cardano-chain-follower/src/mithril_snapshot_iterator.rs b/rust/cardano-chain-follower/src/mithril_snapshot_iterator.rs index 5ee853887..580dc52ec 100644 --- a/rust/cardano-chain-follower/src/mithril_snapshot_iterator.rs +++ b/rust/cardano-chain-follower/src/mithril_snapshot_iterator.rs @@ -24,7 +24,7 @@ const BACKWARD_SEARCH_SLOT_INTERVAL: u64 = 60; /// Synchronous Inner Iterator state struct MithrilSnapshotIteratorInner { /// The blockchain network being iterated - chain: Network, + network: Network, /// Point we want to start iterating from start: Point, /// Previous iteration point. @@ -37,8 +37,8 @@ impl Debug for MithrilSnapshotIteratorInner { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, - "MithrilSnapshotIteratorInner {{ chain: {:?}, start: {:?}, previous: {:?} }}", - self.chain, self.start, self.previous + "MithrilSnapshotIteratorInner {{ network: {:?}, start: {:?}, previous: {:?} }}", + self.network, self.start, self.previous ) } } @@ -68,7 +68,7 @@ pub(crate) fn probe_point(point: &Point, distance: u64) -> Point { impl MithrilSnapshotIterator { /// Try and probe to establish the iterator from the desired point. async fn try_fuzzy_iterator( - chain: Network, path: &Path, from: &Point, search_interval: u64, + network: Network, path: &Path, from: &Point, search_interval: u64, ) -> Option { let point = probe_point(from, search_interval); let Ok(mut iterator) = make_mithril_iterator(path, &point).await else { @@ -120,7 +120,7 @@ impl MithrilSnapshotIterator { Some(MithrilSnapshotIterator { inner: Arc::new(Mutex::new(MithrilSnapshotIteratorInner { - chain, + network, start: this, previous: previous?, inner: iterator, @@ -132,11 +132,13 @@ impl MithrilSnapshotIterator { /// We use this when we don't know the previous point, and need to find it. #[allow(clippy::indexing_slicing)] #[logcall("debug")] - async fn fuzzy_iterator(chain: Network, path: &Path, from: &Point) -> MithrilSnapshotIterator { + async fn fuzzy_iterator( + network: Network, path: &Path, from: &Point, + ) -> MithrilSnapshotIterator { let mut backwards_search = BACKWARD_SEARCH_SLOT_INTERVAL; loop { if let Some(iterator) = - Self::try_fuzzy_iterator(chain, path, from, backwards_search).await + Self::try_fuzzy_iterator(network, path, from, backwards_search).await { return iterator; } @@ -149,7 +151,7 @@ impl MithrilSnapshotIterator { /// /// # Arguments /// - /// `chain`: The blockchain network to iterate. + /// `network`: The blockchain network to iterate. /// `from`: The point to start iterating from. If the `Point` does not contain a /// hash, the iteration start is fuzzy. `previous`: The previous point we are /// iterating, if known. If the previous is NOT known, then the first block @@ -157,10 +159,10 @@ impl MithrilSnapshotIterator { #[allow(clippy::indexing_slicing)] #[logcall(ok = "debug", err = "error")] pub(crate) async fn new( - chain: Network, path: &Path, from: &Point, previous_point: Option, + network: Network, path: &Path, from: &Point, previous_point: Option, ) -> Result { if from.is_fuzzy() || (!from.is_origin() && previous_point.is_none()) { - return Ok(Self::fuzzy_iterator(chain, path, from).await); + return Ok(Self::fuzzy_iterator(network, path, from).await); } let previous = if from.is_origin() { @@ -178,7 +180,7 @@ impl MithrilSnapshotIterator { Ok(MithrilSnapshotIterator { inner: Arc::new(Mutex::new(MithrilSnapshotIteratorInner { - chain, + network, start: from.clone(), previous, inner: iterator, @@ -210,7 +212,7 @@ impl Iterator for MithrilSnapshotIteratorInner { if let Ok(block) = maybe_block { if !self.previous.is_unknown() { // We can safely fully decode this block. - match MultiEraBlock::new(self.chain, block, &self.previous, 0.into()) { + match MultiEraBlock::new(self.network, block, &self.previous, 0.into()) { Ok(block_data) => { // Update the previous point // debug!("Pre Previous update 1 : {:?}", self.previous); diff --git a/rust/cardano-chain-follower/src/mithril_snapshot_sync.rs b/rust/cardano-chain-follower/src/mithril_snapshot_sync.rs index 3bd2dcef5..781001f9a 100644 --- a/rust/cardano-chain-follower/src/mithril_snapshot_sync.rs +++ b/rust/cardano-chain-follower/src/mithril_snapshot_sync.rs @@ -112,7 +112,7 @@ fn create_client(cfg: &MithrilSnapshotConfig) -> Option<(Client, Arc c, Err(err) => { - error!(chain=cfg.chain.to_string(),"Unexpected Error [{}]: Unable to create Mithril Client. Mithril Snapshots can not update.", err); + error!(chain=cfg.network.to_string(),"Unexpected Error [{}]: Unable to create Mithril Client. Mithril Snapshots can not update.", err); return None; }, }; @@ -234,7 +234,7 @@ pub(crate) const MITHRIL_IMMUTABLE_SUB_DIRECTORY: &str = "immutable"; /// /// # Arguments /// -/// * `chain` - The network chain to get the tip block from. +/// * `network` - The network chain to get the tip block from. /// * `path` - The path where the immutable chain is stored. /// /// # Returns @@ -243,7 +243,7 @@ pub(crate) const MITHRIL_IMMUTABLE_SUB_DIRECTORY: &str = "immutable"; /// it in a tuple. #[allow(clippy::indexing_slicing)] #[logcall(ok = "debug", err = "error")] -pub(crate) async fn get_mithril_tip(chain: Network, path: &Path) -> Result { +pub(crate) async fn get_mithril_tip(network: Network, path: &Path) -> Result { let mut path = path.to_path_buf(); path.push(MITHRIL_IMMUTABLE_SUB_DIRECTORY); @@ -259,7 +259,7 @@ pub(crate) async fn get_mithril_tip(chain: Network, path: &Path) -> Result Result Option<(Snapshot, MithrilCertificate)> { - debug!("Mithril Snapshot background updater for: {chain} : Download snapshot from aggregator."); + debug!( + "Mithril Snapshot background updater for: {network} : Download snapshot from aggregator." + ); // Download the snapshot from the aggregator. - let Some(snapshot) = get_snapshot(client, item, chain).await else { + let Some(snapshot) = get_snapshot(client, item, network).await else { // If we couldn't get the snapshot then we don't need to do anything else, transient // error. return None; }; - debug!("Mithril Snapshot background updater for: {chain} : Download/Verify certificate."); + debug!("Mithril Snapshot background updater for: {network} : Download/Verify certificate."); // Download and Verify the certificate. - let certificate = download_and_verify_snapshot_certificate(client, &snapshot, chain).await?; + let certificate = download_and_verify_snapshot_certificate(client, &snapshot, network).await?; Some((snapshot, certificate)) } /// Validate that a Mithril Snapshot downloaded matches its certificate. async fn validate_mithril_snapshot( - chain: Network, certificate: &MithrilCertificate, path: &Path, + network: Network, certificate: &MithrilCertificate, path: &Path, ) -> bool { let cert = certificate.clone(); let mithril_path = path.to_path_buf(); @@ -311,7 +313,7 @@ async fn validate_mithril_snapshot( true } else { // If we couldn't match then assume its a transient error. - error!("Failed to Match Certificate and Computed Snapshot Message for {chain}!"); + error!("Failed to Match Certificate and Computed Snapshot Message for {network}!"); false } }, @@ -333,14 +335,14 @@ async fn validate_mithril_snapshot( /// 1. The actual latest mithril snapshot; AND /// 2. It must async fn get_latest_validated_mithril_snapshot( - chain: Network, client: &Client, cfg: &MithrilSnapshotConfig, + network: Network, client: &Client, cfg: &MithrilSnapshotConfig, ) -> Option { /// Purge a bad mithril snapshot from disk. - async fn purge_bad_mithril_snapshot(chain: Network, latest_mithril: &SnapshotId) { + async fn purge_bad_mithril_snapshot(network: Network, latest_mithril: &SnapshotId) { debug!("Purging Bad Mithril Snapshot: {latest_mithril}"); if let Err(error) = remove_dir_all(&latest_mithril).await { // This should NOT happen because we already checked the Mithril path is fully writable. - error!("Mithril Snapshot background updater for: {chain}: Failed to remove old snapshot {latest_mithril}: {error}"); + error!("Mithril Snapshot background updater for: {network}: Failed to remove old snapshot {latest_mithril}: {error}"); } } @@ -352,7 +354,7 @@ async fn get_latest_validated_mithril_snapshot( // Get the actual latest snapshot, shouldn't fail, but say the current is invalid if it // does. - let (actual_latest, _) = get_latest_snapshots(client, chain).await?; + let (actual_latest, _) = get_latest_snapshots(client, network).await?; // IF the mithril data we have is NOT the current latest (or the immediately previous), it // may as well be invalid. @@ -360,31 +362,31 @@ async fn get_latest_validated_mithril_snapshot( return None; } - let Some(snapshot) = get_snapshot_by_id(client, chain, &latest_mithril).await else { + let Some(snapshot) = get_snapshot_by_id(client, network, &latest_mithril).await else { // We have a latest snapshot, but the Aggregator does not know it. - error!("Mithril Snapshot background updater for: {chain}: Latest snapshot {latest_mithril} does not exist on the Aggregator."); - purge_bad_mithril_snapshot(chain, &latest_mithril).await; + error!("Mithril Snapshot background updater for: {network}: Latest snapshot {latest_mithril} does not exist on the Aggregator."); + purge_bad_mithril_snapshot(network, &latest_mithril).await; return None; }; // Download the snapshot/certificate from the aggregator. let Some((_, certificate)) = - get_mithril_snapshot_and_certificate(chain, client, &snapshot).await + get_mithril_snapshot_and_certificate(network, client, &snapshot).await else { error!("Mithril Snapshot : Failed to get Snapshot and certificate (Transient Error)."); // If we couldn't get the snapshot then we don't need to do anything else, transient // error. - // purge_bad_mithril_snapshot(chain, &latest_mithril).await; + // purge_bad_mithril_snapshot(network, &latest_mithril).await; return None; }; let path = latest_mithril.as_ref(); - let valid = validate_mithril_snapshot(chain, &certificate, path).await; + let valid = validate_mithril_snapshot(network, &certificate, path).await; if !valid { error!("Mithril Snapshot : Snapshot fails to validate, can not be recovered."); - purge_bad_mithril_snapshot(chain, &latest_mithril).await; + purge_bad_mithril_snapshot(network, &latest_mithril).await; return None; } @@ -396,7 +398,7 @@ async fn recover_existing_snapshot( cfg: &MithrilSnapshotConfig, tx: &Sender, ) -> Option { // This is a Mithril Validation, so record it. - mithril_validation_state(cfg.chain, stats::MithrilValidationState::Start); + mithril_validation_state(cfg.network, stats::MithrilValidationState::Start); // Note: we pre-validated connection before we ran, so failure here should be transient. // Just wait if we fail, and try again later. @@ -404,7 +406,7 @@ async fn recover_existing_snapshot( debug!( "Mithril Snapshot background updater for: {} : Client connected.", - cfg.chain + cfg.network ); let mut current_snapshot = None; @@ -412,15 +414,15 @@ async fn recover_existing_snapshot( // Check if we already have a Mithril snapshot downloaded, and IF we do validate it is // intact. if let Some(active_snapshot) = - get_latest_validated_mithril_snapshot(cfg.chain, &client, cfg).await + get_latest_validated_mithril_snapshot(cfg.network, &client, cfg).await { // Read the actual TIP block from the Mithril chain. - match get_mithril_tip(cfg.chain, &active_snapshot.path()).await { + match get_mithril_tip(cfg.network, &active_snapshot.path()).await { Ok(tip_block) => { // Validate the Snapshot ID matches the true TIP. if active_snapshot.tip() == tip_block.point() { current_snapshot = Some(active_snapshot.clone()); - update_latest_mithril_snapshot(cfg.chain, active_snapshot); + update_latest_mithril_snapshot(cfg.network, active_snapshot); // Tell the live sync service the current Mithril TIP. let update = MithrilUpdateMessage { @@ -430,7 +432,7 @@ async fn recover_existing_snapshot( if let Err(error) = tx.send(update).await { error!( "Failed to send new tip to the live updater for: {}: {error}", - cfg.chain + cfg.network ); }; } else { @@ -442,17 +444,17 @@ async fn recover_existing_snapshot( } }, Err(error) => { - error!("Mithril snapshot validation failed for: {}. Could not read the TIP Block : {}.", cfg.chain, error); + error!("Mithril snapshot validation failed for: {}. Could not read the TIP Block : {}.", cfg.network, error); }, } } else { - debug!("No latest validated snapshot for: {}", cfg.chain); + debug!("No latest validated snapshot for: {}", cfg.network); } if current_snapshot.is_none() { - mithril_validation_state(cfg.chain, stats::MithrilValidationState::Failed); + mithril_validation_state(cfg.network, stats::MithrilValidationState::Failed); } else { - mithril_validation_state(cfg.chain, stats::MithrilValidationState::Finish); + mithril_validation_state(cfg.network, stats::MithrilValidationState::Finish); } // Explicitly free the resources claimed by the Mithril Client and Downloader. @@ -472,19 +474,19 @@ enum SnapshotStatus { /// Check if we have a new snapshot to download, and if so, return its details. async fn check_snapshot_to_download( - chain: Network, client: &Client, current_snapshot: &Option, + network: Network, client: &Client, current_snapshot: &Option, ) -> SnapshotStatus { - debug!("Mithril Snapshot background updater for: {chain} : Getting Latest Snapshot."); + debug!("Mithril Snapshot background updater for: {network} : Getting Latest Snapshot."); // This should only fail if the Aggregator is offline. // Because we check we can talk to the aggregator before we create the downloader task. let Some((latest_snapshot, chronologically_previous_snapshot)) = - get_latest_snapshots(client, chain).await + get_latest_snapshots(client, network).await else { return SnapshotStatus::Sleep(DOWNLOAD_ERROR_RETRY_DURATION); }; - debug!("Mithril Snapshot background updater for: {chain} : Checking if we are up-to-date {current_snapshot:?}."); + debug!("Mithril Snapshot background updater for: {network} : Checking if we are up-to-date {current_snapshot:?}."); // Check if the latest snapshot is different from our actual previous one. if let Some(current_mithril_snapshot) = ¤t_snapshot { @@ -500,7 +502,7 @@ async fn check_snapshot_to_download( // Download the snapshot/certificate from the aggregator. let Some((snapshot, certificate)) = - get_mithril_snapshot_and_certificate(chain, client, &latest_snapshot).await + get_mithril_snapshot_and_certificate(network, client, &latest_snapshot).await else { // If we couldn't get the snapshot then we don't need to do anything else, transient // error. @@ -514,30 +516,30 @@ async fn check_snapshot_to_download( /// Start Mithril Validation in the background, and return a handle so we can check when /// it finishes. fn background_validate_mithril_snapshot( - chain: Network, certificate: MithrilCertificate, tmp_path: PathBuf, + network: Network, certificate: MithrilCertificate, tmp_path: PathBuf, ) -> tokio::task::JoinHandle { tokio::spawn(async move { debug!( "Mithril Snapshot background updater for: {} : Check Certificate.", - chain + network ); - stats::mithril_validation_state(chain, stats::MithrilValidationState::Start); + stats::mithril_validation_state(network, stats::MithrilValidationState::Start); - if !validate_mithril_snapshot(chain, &certificate, &tmp_path).await { - stats::mithril_validation_state(chain, stats::MithrilValidationState::Failed); + if !validate_mithril_snapshot(network, &certificate, &tmp_path).await { + stats::mithril_validation_state(network, stats::MithrilValidationState::Failed); // If we couldn't build the message then assume its a transient error. error!( - chain = %chain, + network = %network, "Failed to Compute Snapshot Message" ); return false; } - stats::mithril_validation_state(chain, stats::MithrilValidationState::Finish); + stats::mithril_validation_state(network, stats::MithrilValidationState::Finish); debug!( "Mithril Snapshot background updater for: {} : Certificate Validated OK.", - chain + network ); true @@ -581,7 +583,7 @@ async fn download_and_validate_snapshot( ) -> bool { debug!( "Mithril Snapshot background updater for: {} : Download and unpack the Mithril snapshot.", - cfg.chain + cfg.network ); // Download and unpack the actual snapshot archive. @@ -597,21 +599,21 @@ async fn download_and_validate_snapshot( debug!( "Mithril Snapshot background updater for: {} : Add statistics for download.", - cfg.chain + cfg.network ); if let Err(error) = client.snapshot().add_statistics(snapshot).await { // Just log not fatal to anything. error!( "Could not increment snapshot download statistics for {}: {error}", - cfg.chain + cfg.network ); // We can process the download even after this fails. } debug!( "Mithril Snapshot background updater for: {} : Index and Check Certificate.", - cfg.chain + cfg.network ); let chunk_list = downloader.get_new_chunks(); @@ -620,10 +622,10 @@ async fn download_and_validate_snapshot( trim_chunk_list(&chunk_list, max_chunk); let validate_handle = - background_validate_mithril_snapshot(cfg.chain, certificate, cfg.tmp_path()); + background_validate_mithril_snapshot(cfg.network, certificate, cfg.tmp_path()); if !validate_handle.await.unwrap_or(false) { - error!("Failed to validate for {}", cfg.chain); + error!("Failed to validate for {}", cfg.network); return false; } @@ -636,7 +638,7 @@ async fn cleanup(cfg: &MithrilSnapshotConfig) { if let Err(error) = cfg.cleanup().await { error!( "Mithril Snapshot background updater for: {} : Error cleaning up: {:?}", - cfg.chain, error + cfg.network, error ); } } @@ -647,7 +649,7 @@ async fn sleep_until_next_probable_update( ) -> Duration { debug!( "Mithril Snapshot background updater for: {} : Sleeping for {}.", - cfg.chain, + cfg.network, format_duration(*next_sleep) ); // Wait until its likely we have a new snapshot ready to download. @@ -685,7 +687,7 @@ pub(crate) async fn background_mithril_update( ) { debug!( "Mithril Snapshot background updater for: {} from {} to {} : Starting", - cfg.chain, + cfg.network, cfg.aggregator_url, cfg.path.to_string_lossy() ); @@ -703,7 +705,7 @@ pub(crate) async fn background_mithril_update( let (client, downloader) = connect_client(&cfg).await; let (snapshot, certificate) = - match check_snapshot_to_download(cfg.chain, &client, ¤t_snapshot).await { + match check_snapshot_to_download(cfg.network, &client, ¤t_snapshot).await { SnapshotStatus::Sleep(sleep) => { next_sleep = sleep; next_iteration!(client, downloader); @@ -721,21 +723,24 @@ pub(crate) async fn background_mithril_update( .await { error!("Failed to Download or Validate a snapshot."); - mithril_sync_failure(cfg.chain, stats::MithrilSyncFailures::DownloadOrValidation); + mithril_sync_failure( + cfg.network, + stats::MithrilSyncFailures::DownloadOrValidation, + ); next_iteration!(client, downloader); } // Download was A-OK - Update the new immutable tip. - let tip = match get_mithril_tip(cfg.chain, &cfg.tmp_path()).await { + let tip = match get_mithril_tip(cfg.network, &cfg.tmp_path()).await { Ok(tip) => tip, Err(error) => { // If we couldn't get the tip then assume its a transient error. error!( "Failed to Get Tip from Snapshot for {}: {error}", - cfg.chain + cfg.network ); - mithril_sync_failure(cfg.chain, stats::MithrilSyncFailures::FailedToGetTip); + mithril_sync_failure(cfg.network, stats::MithrilSyncFailures::FailedToGetTip); next_iteration!(client, downloader); }, @@ -748,9 +753,9 @@ pub(crate) async fn background_mithril_update( if tip <= active_snapshot.tip() { error!( "New Tip is not more advanced than the old tip for: {}", - cfg.chain + cfg.network ); - mithril_sync_failure(cfg.chain, stats::MithrilSyncFailures::TipDidNotAdvance); + mithril_sync_failure(cfg.network, stats::MithrilSyncFailures::TipDidNotAdvance); next_iteration!(client, downloader); } } @@ -760,13 +765,13 @@ pub(crate) async fn background_mithril_update( Ok(new_path) => { debug!( "Mithril Snapshot background updater for: {} : Updated TIP.", - cfg.chain + cfg.network ); current_snapshot = SnapshotId::new(&new_path, tip.point()); if let Some(latest_snapshot) = current_snapshot.clone() { // Update the latest snapshot data record - update_latest_mithril_snapshot(cfg.chain, latest_snapshot); + update_latest_mithril_snapshot(cfg.network, latest_snapshot); // Tell the live updater that the Immutable TIP has updated. if let Err(error) = tx @@ -778,10 +783,10 @@ pub(crate) async fn background_mithril_update( { error!( "Failed to send new tip to the live updater for: {}: {error}", - cfg.chain + cfg.network ); mithril_sync_failure( - cfg.chain, + cfg.network, stats::MithrilSyncFailures::TipFailedToSendToUpdater, ); next_iteration!(client, downloader); @@ -790,11 +795,11 @@ pub(crate) async fn background_mithril_update( }, Err(err) => { error!( - chain = cfg.chain.to_string(), + network = cfg.network.to_string(), "Failed to activate new snapshot : {err}" ); mithril_sync_failure( - cfg.chain, + cfg.network, stats::MithrilSyncFailures::FailedToActivateNewSnapshot, ); next_iteration!(client, downloader); diff --git a/rust/cardano-chain-follower/src/mithril_turbo_downloader.rs b/rust/cardano-chain-follower/src/mithril_turbo_downloader.rs index de0d030e5..06f588688 100644 --- a/rust/cardano-chain-follower/src/mithril_turbo_downloader.rs +++ b/rust/cardano-chain-follower/src/mithril_turbo_downloader.rs @@ -99,7 +99,7 @@ impl Inner { }; let tmp_dir = self.cfg.tmp_path(); - let latest_snapshot = latest_mithril_snapshot_data(self.cfg.chain); + let latest_snapshot = latest_mithril_snapshot_data(self.cfg.network); for entry in entries { let mut entry = match entry { @@ -162,13 +162,13 @@ impl Inner { } if let Err(error) = std::fs::write(&abs_file, buf) { - error!(chain = %self.cfg.chain, "Failed to write file {} got {}", abs_file.display(), error); + error!(network = %self.cfg.network, "Failed to write file {} got {}", abs_file.display(), error); bail!("Failed to write file {} got {}", abs_file.display(), error); } } else { // No dedup, just extract it into the tmp directory as-is. entry.unpack_in(&tmp_dir)?; - debug!(chain = %self.cfg.chain, "DeDup: Extracted file {rel_file:?}:{entry_size}"); + debug!(network = %self.cfg.network, "DeDup: Extracted file {rel_file:?}:{entry_size}"); } new_file!(self, rel_file, abs_file, entry_size); } @@ -177,9 +177,9 @@ impl Inner { bail!("Failed to get the Parallel Download processor!"); }; - debug!(chain = %self.cfg.chain, "Download {} bytes", dl_handler.dl_size()); + debug!(network = %self.cfg.network, "Download {} bytes", dl_handler.dl_size()); - stats::mithril_dl_finished(self.cfg.chain, Some(dl_handler.dl_size())); + stats::mithril_dl_finished(self.cfg.network, Some(dl_handler.dl_size())); Ok(()) } @@ -203,7 +203,7 @@ impl Inner { /// Check if we are supposed to extract this file from the archive or not. fn check_for_extract(&self, path: &Path, extract_type: EntryType) -> bool { if path.is_absolute() { - error!(chain = %self.cfg.chain, "DeDup : Cannot extract an absolute path: {:?}", path); + error!(network = %self.cfg.network, "DeDup : Cannot extract an absolute path: {:?}", path); return false; } @@ -213,7 +213,7 @@ impl Inner { } if !extract_type.is_file() { - error!(chain = %self.cfg.chain, "DeDup : Cannot extract a non-file: {:?}:{:?}", path, extract_type); + error!(network = %self.cfg.network, "DeDup : Cannot extract a non-file: {:?}:{:?}", path, extract_type); return false; } @@ -306,7 +306,7 @@ impl MithrilTurboDownloader { return result; } - stats::mithril_dl_finished(self.inner.cfg.chain, None); + stats::mithril_dl_finished(self.inner.cfg.network, None); bail!("Download and Dedup task failed"); } } @@ -349,7 +349,7 @@ impl SnapshotDownloader for MithrilTurboDownloader { let new_files = self.inner.new_files.load(Ordering::SeqCst); stats::mithril_extract_finished( - self.inner.cfg.chain, + self.inner.cfg.network, Some(self.inner.ext_size.load(Ordering::SeqCst)), self.inner.dedup_size.load(Ordering::SeqCst), tot_files - (chg_files + new_files), @@ -369,10 +369,10 @@ impl SnapshotDownloader for MithrilTurboDownloader { let dl_processor = ParallelDownloadProcessor::new(location, dl_config).await?; // Decompress and extract and de-dupe each file in the archive. - stats::mithril_extract_started(self.inner.cfg.chain); + stats::mithril_extract_started(self.inner.cfg.network); // We also immediately start downloading now. - stats::mithril_dl_started(self.inner.cfg.chain); + stats::mithril_dl_started(self.inner.cfg.network); // Save the DownloadProcessor in the inner struct for use to process the downloaded data. if let Err(_error) = self.inner.dl_handler.set(dl_processor) { diff --git a/rust/cardano-chain-follower/src/snapshot_id.rs b/rust/cardano-chain-follower/src/snapshot_id.rs index 08584daaf..0e7655280 100644 --- a/rust/cardano-chain-follower/src/snapshot_id.rs +++ b/rust/cardano-chain-follower/src/snapshot_id.rs @@ -57,8 +57,8 @@ impl SnapshotId { /// Try and create a new `SnapshotID` from a given path. /// Includes properly getting the immutable TIP. - pub(crate) async fn try_new(chain: Network, path: &Path) -> Option { - let Ok(tip) = get_mithril_tip(chain, path).await else { + pub(crate) async fn try_new(network: Network, path: &Path) -> Option { + let Ok(tip) = get_mithril_tip(network, path).await else { return None; }; diff --git a/rust/cardano-chain-follower/src/stats.rs b/rust/cardano-chain-follower/src/stats.rs index 4f9e267a0..c75915263 100644 --- a/rust/cardano-chain-follower/src/stats.rs +++ b/rust/cardano-chain-follower/src/stats.rs @@ -199,8 +199,8 @@ static STATS_MAP: LazyLock = LazyLock::new(|| { }); /// Get the stats for a particular chain. -fn lookup_stats(chain: Network) -> Option>> { - let Some(chain_entry) = STATS_MAP.get(&chain) else { +fn lookup_stats(network: Network) -> Option>> { + let Some(chain_entry) = STATS_MAP.get(&network) else { error!("Stats MUST BE exhaustively pre-allocated."); return None; }; @@ -213,8 +213,8 @@ fn lookup_stats(chain: Network) -> Option>> { impl Statistics { /// Get a new statistics struct for a given blockchain network. #[must_use] - pub fn new(chain: Network) -> Self { - let Some(stats) = lookup_stats(chain) else { + pub fn new(network: Network) -> Self { + let Some(stats) = lookup_stats(network) else { return Statistics::default(); }; @@ -224,9 +224,9 @@ impl Statistics { let mut this_stats = chain_stats.clone(); // Set the current rollback stats. - this_stats.live.rollbacks.live = rollbacks(chain, RollbackType::LiveChain); - this_stats.live.rollbacks.peer = rollbacks(chain, RollbackType::Peer); - this_stats.live.rollbacks.follower = rollbacks(chain, RollbackType::Follower); + this_stats.live.rollbacks.live = rollbacks(network, RollbackType::LiveChain); + this_stats.live.rollbacks.peer = rollbacks(network, RollbackType::Peer); + this_stats.live.rollbacks.follower = rollbacks(network, RollbackType::Follower); this_stats } @@ -238,9 +238,9 @@ impl Statistics { } /// Get the current tips of the immutable chain and live chain. - pub(crate) fn tips(chain: Network) -> (Slot, Slot) { + pub(crate) fn tips(network: Network) -> (Slot, Slot) { let zero_slot = Slot::from_saturating(0); - let Some(stats) = lookup_stats(chain) else { + let Some(stats) = lookup_stats(network) else { return (zero_slot, zero_slot); }; @@ -253,8 +253,8 @@ impl Statistics { /// Reset amd return cumulative counters contained in the statistics. #[must_use] - pub fn reset(chain: Network) -> Self { - let Some(stats) = lookup_stats(chain) else { + pub fn reset(network: Network) -> Self { + let Some(stats) = lookup_stats(network) else { return Statistics::default(); }; @@ -266,9 +266,9 @@ impl Statistics { let mut this_stats = chain_stats.clone(); // Reset the current rollback stats. - this_stats.live.rollbacks.live = rollbacks_reset(chain, RollbackType::LiveChain); - this_stats.live.rollbacks.peer = rollbacks_reset(chain, RollbackType::Peer); - this_stats.live.rollbacks.follower = rollbacks_reset(chain, RollbackType::Follower); + this_stats.live.rollbacks.live = rollbacks_reset(network, RollbackType::LiveChain); + this_stats.live.rollbacks.peer = rollbacks_reset(network, RollbackType::Peer); + this_stats.live.rollbacks.follower = rollbacks_reset(network, RollbackType::Follower); this_stats } @@ -293,9 +293,9 @@ impl Statistics { /// Count the invalidly deserialized blocks #[allow(dead_code)] -pub(crate) fn stats_invalid_block(chain: Network, immutable: bool) { +pub(crate) fn stats_invalid_block(network: Network, immutable: bool) { // This will actually always succeed. - let Some(stats) = lookup_stats(chain) else { + let Some(stats) = lookup_stats(network) else { return; }; @@ -314,10 +314,10 @@ pub(crate) fn stats_invalid_block(chain: Network, immutable: bool) { /// Count the validly deserialized blocks pub(crate) fn new_live_block( - chain: Network, total_live_blocks: u64, head_slot: Slot, tip_slot: Slot, + network: Network, total_live_blocks: u64, head_slot: Slot, tip_slot: Slot, ) { // This will actually always succeed. - let Some(stats) = lookup_stats(chain) else { + let Some(stats) = lookup_stats(network) else { return; }; @@ -335,10 +335,10 @@ pub(crate) fn new_live_block( /// Track the end of the current mithril update pub(crate) fn new_mithril_update( - chain: Network, mithril_tip: Slot, total_live_blocks: u64, tip_slot: Slot, + network: Network, mithril_tip: Slot, total_live_blocks: u64, tip_slot: Slot, ) { // This will actually always succeed. - let Some(stats) = lookup_stats(chain) else { + let Some(stats) = lookup_stats(network) else { return; }; @@ -355,9 +355,9 @@ pub(crate) fn new_mithril_update( } /// When did we start the backfill. -pub(crate) fn backfill_started(chain: Network) { +pub(crate) fn backfill_started(network: Network) { // This will actually always succeed. - let Some(stats) = lookup_stats(chain) else { + let Some(stats) = lookup_stats(network) else { return; }; @@ -378,9 +378,9 @@ pub(crate) fn backfill_started(chain: Network) { } /// When did we start the backfill. -pub(crate) fn backfill_ended(chain: Network, backfill_size: u64) { +pub(crate) fn backfill_ended(network: Network, backfill_size: u64) { // This will actually always succeed. - let Some(stats) = lookup_stats(chain) else { + let Some(stats) = lookup_stats(network) else { return; }; @@ -395,9 +395,9 @@ pub(crate) fn backfill_ended(chain: Network, backfill_size: u64) { } /// Track statistics about connections to the cardano peer node. -pub(crate) fn peer_connected(chain: Network, active: bool, peer_address: &str) { +pub(crate) fn peer_connected(network: Network, active: bool, peer_address: &str) { // This will actually always succeed. - let Some(stats) = lookup_stats(chain) else { + let Some(stats) = lookup_stats(network) else { return; }; @@ -420,9 +420,9 @@ pub(crate) fn peer_connected(chain: Network, active: bool, peer_address: &str) { } /// Record when we started syncing -pub(crate) fn sync_started(chain: Network) { +pub(crate) fn sync_started(network: Network) { // This will actually always succeed. - let Some(stats) = lookup_stats(chain) else { + let Some(stats) = lookup_stats(network) else { return; }; @@ -437,9 +437,9 @@ pub(crate) fn sync_started(chain: Network) { /// Record when we first reached tip. This can safely be called multiple times. /// Except for overhead, only the first call will actually record the time. -pub(crate) fn tip_reached(chain: Network) { +pub(crate) fn tip_reached(network: Network) { // This will actually always succeed. - let Some(stats) = lookup_stats(chain) else { + let Some(stats) = lookup_stats(network) else { return; }; @@ -455,9 +455,9 @@ pub(crate) fn tip_reached(chain: Network) { } /// Record that a Mithril snapshot Download has started. -pub(crate) fn mithril_dl_started(chain: Network) { +pub(crate) fn mithril_dl_started(network: Network) { // This will actually always succeed. - let Some(stats) = lookup_stats(chain) else { + let Some(stats) = lookup_stats(network) else { return; }; @@ -472,9 +472,9 @@ pub(crate) fn mithril_dl_started(chain: Network) { /// Record when DL finished, if it fails, set size to None, otherwise the size of the /// downloaded file. -pub(crate) fn mithril_dl_finished(chain: Network, dl_size: Option) { +pub(crate) fn mithril_dl_finished(network: Network, dl_size: Option) { // This will actually always succeed. - let Some(stats) = lookup_stats(chain) else { + let Some(stats) = lookup_stats(network) else { return; }; @@ -497,9 +497,9 @@ pub(crate) fn mithril_dl_finished(chain: Network, dl_size: Option) { } /// Record that extracting the mithril snapshot archive has started. -pub(crate) fn mithril_extract_started(chain: Network) { +pub(crate) fn mithril_extract_started(network: Network) { // This will actually always succeed. - let Some(stats) = lookup_stats(chain) else { + let Some(stats) = lookup_stats(network) else { return; }; @@ -515,11 +515,11 @@ pub(crate) fn mithril_extract_started(chain: Network) { /// Record when DL finished, if it fails, set size to None, otherwise the size of the /// downloaded file. pub(crate) fn mithril_extract_finished( - chain: Network, extract_size: Option, deduplicated_size: u64, deduplicated_files: u64, + network: Network, extract_size: Option, deduplicated_size: u64, deduplicated_files: u64, changed_files: u64, new_files: u64, ) { // This will actually always succeed. - let Some(stats) = lookup_stats(chain) else { + let Some(stats) = lookup_stats(network) else { return; }; @@ -553,9 +553,9 @@ pub(crate) enum MithrilValidationState { } /// Record when Mithril Cert validation starts, ends or fails). -pub(crate) fn mithril_validation_state(chain: Network, mithril_state: MithrilValidationState) { +pub(crate) fn mithril_validation_state(network: Network, mithril_state: MithrilValidationState) { // This will actually always succeed. - let Some(stats) = lookup_stats(chain) else { + let Some(stats) = lookup_stats(network) else { return; }; @@ -588,9 +588,9 @@ pub(crate) enum MithrilSyncFailures { } /// Record when Mithril Cert validation starts, ends or fails). -pub(crate) fn mithril_sync_failure(chain: Network, failure: MithrilSyncFailures) { +pub(crate) fn mithril_sync_failure(network: Network, failure: MithrilSyncFailures) { // This will actually always succeed. - let Some(stats) = lookup_stats(chain) else { + let Some(stats) = lookup_stats(network) else { return; }; @@ -650,9 +650,9 @@ static ROLLBACKS_MAP: LazyLock = LazyLock::new(|| { /// Get the actual rollback map for a chain. fn lookup_rollback_map( - chain: Network, rollback: RollbackType, + network: Network, rollback: RollbackType, ) -> Option>> { - let Some(chain_rollback_map) = ROLLBACKS_MAP.get(&chain) else { + let Some(chain_rollback_map) = ROLLBACKS_MAP.get(&network) else { error!("Rollback stats SHOULD BE exhaustively pre-allocated."); return None; }; @@ -668,8 +668,8 @@ fn lookup_rollback_map( } /// Extract the current rollback stats as a vec. -fn rollbacks(chain: Network, rollback: RollbackType) -> Vec { - let Some(rollback_map) = lookup_rollback_map(chain, rollback) else { +fn rollbacks(network: Network, rollback: RollbackType) -> Vec { + let Some(rollback_map) = lookup_rollback_map(network, rollback) else { return Vec::new(); }; @@ -689,8 +689,8 @@ fn rollbacks(chain: Network, rollback: RollbackType) -> Vec { } /// Reset ALL the rollback stats for a given blockchain. -fn rollbacks_reset(chain: Network, rollback: RollbackType) -> Vec { - let Some(rollback_map) = lookup_rollback_map(chain, rollback) else { +fn rollbacks_reset(network: Network, rollback: RollbackType) -> Vec { + let Some(rollback_map) = lookup_rollback_map(network, rollback) else { return Vec::new(); }; @@ -705,8 +705,8 @@ fn rollbacks_reset(chain: Network, rollback: RollbackType) -> Vec { } /// Count a rollback -pub(crate) fn rollback(chain: Network, rollback: RollbackType, depth: u64) { - let Some(rollback_map) = lookup_rollback_map(chain, rollback) else { +pub(crate) fn rollback(network: Network, rollback: RollbackType, depth: u64) { + let Some(rollback_map) = lookup_rollback_map(network, rollback) else { return; }; From 1d095c5ed5011ccd9b9d6e02467a5d0cdb138a61 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Tue, 7 Jan 2025 13:42:48 +0700 Subject: [PATCH 24/40] fix(cardano-chain-follower): remove unnecessary file Signed-off-by: bkioshn --- rust/cardano-chain-follower/src/lib.rs | 3 - .../src/metadata/cip36.rs | 128 ------------------ .../src/metadata/cip509.rs | 79 ----------- .../src/metadata/mod.rs | 84 ------------ rust/cardano-chain-follower/src/utils.rs | 73 ---------- 5 files changed, 367 deletions(-) delete mode 100644 rust/cardano-chain-follower/src/metadata/cip36.rs delete mode 100644 rust/cardano-chain-follower/src/metadata/cip509.rs delete mode 100644 rust/cardano-chain-follower/src/metadata/mod.rs delete mode 100644 rust/cardano-chain-follower/src/utils.rs diff --git a/rust/cardano-chain-follower/src/lib.rs b/rust/cardano-chain-follower/src/lib.rs index 29f4f20d6..68cc30645 100644 --- a/rust/cardano-chain-follower/src/lib.rs +++ b/rust/cardano-chain-follower/src/lib.rs @@ -7,7 +7,6 @@ mod chain_sync_ready; mod chain_update; mod error; mod follow; -pub mod metadata; mod mithril_query; mod mithril_snapshot; mod mithril_snapshot_config; @@ -18,11 +17,9 @@ mod mithril_turbo_downloader; mod snapshot_id; mod stats; pub mod turbo_downloader; -mod utils; pub use chain_sync_config::ChainSyncConfig; pub use chain_update::{ChainUpdate, Kind}; pub use error::Result; pub use follow::ChainFollower; -pub use metadata as Metadata; pub use stats::Statistics; diff --git a/rust/cardano-chain-follower/src/metadata/cip36.rs b/rust/cardano-chain-follower/src/metadata/cip36.rs deleted file mode 100644 index d02df8fa3..000000000 --- a/rust/cardano-chain-follower/src/metadata/cip36.rs +++ /dev/null @@ -1,128 +0,0 @@ -//! Decoder and Validator for CIP36 Metadata - -use std::sync::Arc; - -use cardano_blockchain_types::{ - Cip36 as Cip36Registration, Cip36KeyRegistration, Cip36RegistrationWitness, Cip36Validation, - MetadatumLabel, Network, TransactionAuxData, -}; -use minicbor::{Decode, Decoder}; -use pallas::ledger::traverse::MultiEraTx; - -use super::{DecodedMetadata, DecodedMetadataItem, DecodedMetadataValues, ValidationReport}; - -/// CIP 36 Registration Data. -#[derive(Clone, Default, Debug)] -pub struct Cip36 { - /// CIP36 data. - pub cip36: Cip36Registration, - /// Validation value, not a part of CIP36, just storing validity of the data. - pub validation: Cip36Validation, -} - -impl Cip36 { - /// Decode and validate CIP36/15 Metadata - /// - /// CIP15 is a subset of CIP36. - /// - /// See: - /// * - /// * - /// - /// # Parameters - /// * `decoded_metadata` - Decoded Metadata - Will be updated only if CIP36 Metadata - /// is found. - /// * `slot` - Current Slot - /// * `txn` - Transaction data was attached to and to be validated/decoded against. - /// Not used for CIP36 Metadata. - /// * `raw_aux_data` - Raw Auxiliary Data for the transaction. - /// * `catalyst_strict` - Strict Catalyst Validation - otherwise Catalyst Specific - /// rules/workarounds are not applied. - /// * `network` - Network Chain - /// - /// # Returns - /// - /// Nothing. IF CIP36 Metadata is found it will be updated in `decoded_metadata`. - #[allow(clippy::too_many_lines)] - pub(crate) fn decode_and_validate( - decoded_metadata: &DecodedMetadata, slot: u64, _txn: &MultiEraTx, - raw_aux_data: &TransactionAuxData, is_catalyst_strict: bool, network: Network, - ) { - let Some(k61284) = raw_aux_data.metadata(MetadatumLabel::CIP036_REGISTRATION) else { - return; - }; - let Some(k61285) = raw_aux_data.metadata(MetadatumLabel::CIP036_WITNESS) else { - return; - }; - - let mut validation_report = ValidationReport::new(); - let mut key_registration = Decoder::new(k61284.as_ref()); - let mut registration_witness = Decoder::new(k61285.as_ref()); - - let key_registration = match Cip36KeyRegistration::decode(&mut key_registration, &mut ()) { - Ok(mut metadata) => { - // FIXME: Don't like it here - let nonce = if is_catalyst_strict && metadata.raw_nonce > slot { - slot - } else { - metadata.raw_nonce - }; - - metadata.nonce = nonce; - metadata - }, - Err(e) => { - Cip36::default().decoding_failed( - &format!("Failed to decode CIP36 Key Registration metadata: {e}"), - &mut validation_report, - decoded_metadata, - MetadatumLabel::CIP036_REGISTRATION, - ); - return; - }, - }; - - let registration_witness = - match Cip36RegistrationWitness::decode(&mut registration_witness, &mut ()) { - Ok(metadata) => metadata, - Err(e) => { - Cip36::default().decoding_failed( - &format!("Failed to decode CIP36 Registration Witness metadata: {e}"), - &mut validation_report, - decoded_metadata, - MetadatumLabel::CIP036_WITNESS, - ); - return; - }, - }; - - let cip36 = - Cip36Registration::new(key_registration, registration_witness, is_catalyst_strict); - - let validation = cip36.validate(network, k61284, &mut validation_report); - - // Create a Cip509 struct and insert it into decoded_metadata - decoded_metadata.0.insert( - MetadatumLabel::CIP036_REGISTRATION, - Arc::new(DecodedMetadataItem { - value: DecodedMetadataValues::Cip36(Arc::new(Cip36 { cip36, validation })), - report: validation_report.clone(), - }), - ); - } - - /// Decoding of the CIP36 metadata failed, and can not continue. - fn decoding_failed( - &self, reason: &str, validation_report: &mut ValidationReport, - decoded_metadata: &DecodedMetadata, label: MetadatumLabel, - ) { - validation_report.push(reason.into()); - decoded_metadata.0.insert( - label, - Arc::new(DecodedMetadataItem { - value: DecodedMetadataValues::Cip36(Arc::new(self.clone()).clone()), - report: validation_report.clone(), - }), - ); - } -} diff --git a/rust/cardano-chain-follower/src/metadata/cip509.rs b/rust/cardano-chain-follower/src/metadata/cip509.rs deleted file mode 100644 index 6cfa5eba5..000000000 --- a/rust/cardano-chain-follower/src/metadata/cip509.rs +++ /dev/null @@ -1,79 +0,0 @@ -//! Cardano Improvement Proposal 509 (CIP-509) metadata module. -//! Doc Reference: -//! CDDL Reference: - -use std::sync::Arc; - -use cardano_blockchain_types::{MetadatumLabel, TransactionAuxData}; -use minicbor::{Decode, Decoder}; -use pallas::ledger::traverse::MultiEraTx; -use rbac_registration::cardano::cip509::{Cip509 as RbacRegCip509, Cip509Validation}; - -use super::{DecodedMetadata, DecodedMetadataItem, DecodedMetadataValues, ValidationReport}; - -/// CIP509 metadatum. -#[derive(Debug, PartialEq, Clone, Default)] -pub struct Cip509 { - /// CIP509 data. - pub cip509: RbacRegCip509, - /// Validation value, not a part of CIP509, justs storing validity of the data. - pub validation: Cip509Validation, -} - -impl Cip509 { - /// Decode and validate CIP509 Metadata - /// - /// # Returns - /// - /// Nothing. IF CIP509 Metadata is found it will be updated in `decoded_metadata`. - pub(crate) fn decode_and_validate( - decoded_metadata: &DecodedMetadata, txn: &MultiEraTx, raw_aux_data: &TransactionAuxData, - ) { - // Get the CIP509 metadata if possible - let Some(k509) = raw_aux_data.metadata(MetadatumLabel::CIP509_RBAC) else { - return; - }; - - let mut validation_report = ValidationReport::new(); - let mut decoder = Decoder::new(k509.as_ref()); - - let cip509 = match RbacRegCip509::decode(&mut decoder, &mut ()) { - Ok(metadata) => metadata, - Err(e) => { - Cip509::default().decoding_failed( - &format!("Failed to decode CIP509 metadata: {e}"), - &mut validation_report, - decoded_metadata, - ); - return; - }, - }; - - // Validate the decoded metadata - let validation = cip509.validate(txn, &mut validation_report); - - // Create a Cip509 struct and insert it into decoded_metadata - decoded_metadata.0.insert( - MetadatumLabel::CIP509_RBAC, - Arc::new(DecodedMetadataItem { - value: DecodedMetadataValues::Cip509(Arc::new(Cip509 { cip509, validation })), - report: validation_report.clone(), - }), - ); - } - - /// Decoding of the CIP509 metadata failed, and can not continue. - fn decoding_failed( - &self, reason: &str, validation_report: &mut ValidationReport, - decoded_metadata: &DecodedMetadata, - ) { - validation_report.push(reason.into()); - decoded_metadata.0.insert( - MetadatumLabel::CIP509_RBAC, - Arc::new(DecodedMetadataItem { - value: DecodedMetadataValues::Cip509(Arc::new(self.clone()).clone()), - report: validation_report.clone(), - }), - ); - } -} diff --git a/rust/cardano-chain-follower/src/metadata/mod.rs b/rust/cardano-chain-follower/src/metadata/mod.rs deleted file mode 100644 index cf0a6e3cb..000000000 --- a/rust/cardano-chain-follower/src/metadata/mod.rs +++ /dev/null @@ -1,84 +0,0 @@ -//! Metadata decoding and validating. - -use std::{fmt::Debug, sync::Arc}; - -use cardano_blockchain_types::{MetadatumLabel, Network, TransactionAuxData}; -use cip36::Cip36; -use cip509::Cip509; -use dashmap::DashMap; -use pallas::ledger::traverse::MultiEraTx; - -pub mod cip36; -pub mod cip509; - -/// List of all validation errors (as strings) Metadata is considered Valid if this list -/// is empty. -pub type ValidationReport = Vec; - -/// Possible Decoded Metadata Values. -/// Must match the key they relate too, but the consumer needs to check this. -#[derive(Debug)] -pub enum DecodedMetadataValues { - // Json Metadata // TODO - // Json(serde_json::Value), // TODO - /// CIP-36/CIP-15 Catalyst Registration metadata. - Cip36(Arc), - /// CIP-509 RBAC metadata. - Cip509(Arc), -} - -/// An individual decoded metadata item. -#[derive(Debug)] -pub struct DecodedMetadataItem { - /// The decoded metadata itself. - pub value: DecodedMetadataValues, - /// Validation report for this metadata item. - pub report: ValidationReport, -} - -/// Decoded Metadata for a single transaction. -/// The key is the Primary Label of the Metadata. -/// For example, CIP15/36 uses labels 61284 & 61285, -/// 61284 is the primary label, so decoded metadata -/// will be under that label. -#[allow(clippy::module_name_repetitions)] -pub struct DecodedMetadata(DashMap>); - -impl DecodedMetadata { - /// Create new decoded metadata for a transaction. - #[must_use] - pub fn new( - chain: Network, slot: u64, txn: &MultiEraTx, raw_aux_data: &TransactionAuxData, - ) -> Self { - let decoded_metadata = Self(DashMap::new()); - - // Process each known type of metadata here, and record the decoded result. - Cip36::decode_and_validate(&decoded_metadata, slot, txn, raw_aux_data, true, chain); - Cip509::decode_and_validate(&decoded_metadata, txn, raw_aux_data); - - // if !decoded_metadata.0.is_empty() { - // debug!("Decoded Metadata final: {decoded_metadata:?}"); - //} - decoded_metadata - } - - /// Get the decoded metadata item at the given slot, or None if it doesn't exist. - #[must_use] - pub fn get(&self, primary_label: MetadatumLabel) -> Option> { - let entry = self.0.get(&primary_label)?; - let value = entry.value(); - Some(value.clone()) - } -} - -impl Debug for DecodedMetadata { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str("DecodedMetadata {")?; - for kv in &self.0 { - let k = kv.key(); - let v = kv.value().clone(); - f.write_fmt(format_args!("{k:?}:{v:?} "))?; - } - f.write_str("}") - } -} diff --git a/rust/cardano-chain-follower/src/utils.rs b/rust/cardano-chain-follower/src/utils.rs deleted file mode 100644 index 11a2a482a..000000000 --- a/rust/cardano-chain-follower/src/utils.rs +++ /dev/null @@ -1,73 +0,0 @@ -//! Simple general purpose utility functions. - -/// Convert T to an i16. (saturate if out of range.) -#[allow(dead_code)] // Its OK if we don't use this general utility function. -pub(crate) fn i16_from_saturating>(value: T) -> i16 { - match value.try_into() { - Ok(value) => value, - Err(_) => i16::MAX, - } -} - -/// Convert an `` to `usize`. (saturate if out of range.) -#[allow(dead_code)] // Its OK if we don't use this general utility function. -pub(crate) fn usize_from_saturating< - T: Copy - + TryInto - + std::ops::Sub - + std::cmp::PartialOrd - + num_traits::identities::Zero, ->( - value: T, -) -> usize { - if value < T::zero() { - usize::MIN - } else { - match value.try_into() { - Ok(value) => value, - Err(_) => usize::MAX, - } - } -} - -/// Convert an `` to `u32`. (saturate if out of range.) -#[allow(dead_code)] // Its OK if we don't use this general utility function. -pub(crate) fn u32_from_saturating< - T: Copy - + TryInto - + std::ops::Sub - + std::cmp::PartialOrd - + num_traits::identities::Zero, ->( - value: T, -) -> u32 { - if value < T::zero() { - u32::MIN - } else { - match value.try_into() { - Ok(converted) => converted, - Err(_) => u32::MAX, - } - } -} - -/// Convert an `` to `u64`. (saturate if out of range.) -#[allow(dead_code)] // Its OK if we don't use this general utility function. -pub(crate) fn u64_from_saturating< - T: Copy - + TryInto - + std::ops::Sub - + std::cmp::PartialOrd - + num_traits::identities::Zero, ->( - value: T, -) -> u64 { - if value < T::zero() { - u64::MIN - } else { - match value.try_into() { - Ok(converted) => converted, - Err(_) => u64::MAX, - } - } -} From 244c3b1a8963e5755bdc116f05459a7c2825dd8f Mon Sep 17 00:00:00 2001 From: bkioshn Date: Wed, 8 Jan 2025 14:30:40 +0700 Subject: [PATCH 25/40] fix(cardano-chain-follower): use function from catalyst-types Signed-off-by: bkioshn --- .../cardano-chain-follower/src/mithril_turbo_downloader.rs | 4 ++-- rust/cardano-chain-follower/src/turbo_downloader/mod.rs | 7 +++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/rust/cardano-chain-follower/src/mithril_turbo_downloader.rs b/rust/cardano-chain-follower/src/mithril_turbo_downloader.rs index d5ea88a6e..0f389c3b1 100644 --- a/rust/cardano-chain-follower/src/mithril_turbo_downloader.rs +++ b/rust/cardano-chain-follower/src/mithril_turbo_downloader.rs @@ -14,6 +14,7 @@ use std::{ use anyhow::{anyhow, bail}; use async_trait::async_trait; +use catalyst_types::conversion::from_saturating; use dashmap::DashSet; use fmmap::MmapFileExt; use memx::memcmp; @@ -30,7 +31,6 @@ use crate::{ mithril_snapshot_data::latest_mithril_snapshot_data, stats::{self}, turbo_downloader::ParallelDownloadProcessor, - utils::usize_from_saturating, }; /// A snapshot downloader that accelerates Download using `aria2`. @@ -137,7 +137,7 @@ impl Inner { if let Ok((prev_mmap, _)) = Self::can_deduplicate(&rel_file, entry_size, prev_file.as_ref()) { - let expected_file_size = usize_from_saturating(entry_size); + let expected_file_size = from_saturating(entry_size); let mut buf: Vec = Vec::with_capacity(expected_file_size); if entry.read_to_end(&mut buf)? != expected_file_size { bail!( diff --git a/rust/cardano-chain-follower/src/turbo_downloader/mod.rs b/rust/cardano-chain-follower/src/turbo_downloader/mod.rs index 5ae5495d4..2424159bf 100644 --- a/rust/cardano-chain-follower/src/turbo_downloader/mod.rs +++ b/rust/cardano-chain-follower/src/turbo_downloader/mod.rs @@ -19,6 +19,7 @@ use std::{ }; use anyhow::{bail, Context, Result}; +use catalyst_types::conversion::from_saturating; use dashmap::DashMap; use http::{ header::{ACCEPT_RANGES, CONTENT_LENGTH, RANGE}, @@ -26,8 +27,6 @@ use http::{ }; use tracing::{debug, error}; -use crate::utils::u64_from_saturating; - /// A Simple DNS Balancing Resolver struct BalancingResolver { /// The actual resolver @@ -333,7 +332,7 @@ impl ParallelDownloadProcessorInner { let bytes_read = get_range_response .into_reader() - .take(u64_from_saturating(range_size)) + .take(from_saturating(range_size)) .read_to_end(&mut bytes)?; if bytes_read != range_size { @@ -474,7 +473,7 @@ impl ParallelDownloadProcessor { if let Some(ref block) = block { if let Some(dl_stat) = params.bytes_downloaded.get(worker_id) { - let this_bytes_downloaded = u64_from_saturating(block.len()); + let this_bytes_downloaded = from_saturating(block.len()); let _last_bytes_downloaded = dl_stat .fetch_add(this_bytes_downloaded, std::sync::atomic::Ordering::SeqCst); // debug!("Worker {worker_id} DL chunk {next_chunk}: From 56286635a28013ada9d976d0939f9733ed147bc0 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Wed, 8 Jan 2025 14:31:18 +0700 Subject: [PATCH 26/40] fix(cardano-chain-follower): minor fixes Signed-off-by: bkioshn --- rust/cardano-chain-follower/src/chain_sync.rs | 6 +++--- rust/cardano-chain-follower/src/chain_sync_ready.rs | 2 +- rust/cardano-chain-follower/src/mithril_snapshot_sync.rs | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/rust/cardano-chain-follower/src/chain_sync.rs b/rust/cardano-chain-follower/src/chain_sync.rs index cfcf34146..b37848f3c 100644 --- a/rust/cardano-chain-follower/src/chain_sync.rs +++ b/rust/cardano-chain-follower/src/chain_sync.rs @@ -189,9 +189,9 @@ async fn process_rollback( ) -> anyhow::Result { let rollback_slot = point.slot_or_default(); let head_slot = previous_point.slot_or_default(); - debug!("Head slot: {}", head_slot); - debug!("Rollback slot: {}", rollback_slot); - let slot_rollback_size = head_slot.saturating_sub(rollback_slot); + debug!("Head slot: {head_slot:?}"); + debug!("Rollback slot: {rollback_slot:?}"); + let slot_rollback_size = head_slot - rollback_slot; // We actually do the work here... let response = process_rollback_actual(peer, chain, point, tip, fork).await?; diff --git a/rust/cardano-chain-follower/src/chain_sync_ready.rs b/rust/cardano-chain-follower/src/chain_sync_ready.rs index 34e18f4d1..102b24132 100644 --- a/rust/cardano-chain-follower/src/chain_sync_ready.rs +++ b/rust/cardano-chain-follower/src/chain_sync_ready.rs @@ -39,7 +39,7 @@ impl SyncReady { /// Sand a chain update to any subscribers that are listening. pub(crate) fn notify_follower( - network: Network, update_sender: &Option>, + network: Network, update_sender: Option<&broadcast::Sender>, kind: &chain_update::Kind, ) { if let Some(update_sender) = update_sender { diff --git a/rust/cardano-chain-follower/src/mithril_snapshot_sync.rs b/rust/cardano-chain-follower/src/mithril_snapshot_sync.rs index 26560f271..7979a7e57 100644 --- a/rust/cardano-chain-follower/src/mithril_snapshot_sync.rs +++ b/rust/cardano-chain-follower/src/mithril_snapshot_sync.rs @@ -705,7 +705,8 @@ pub(crate) async fn background_mithril_update( let (client, downloader) = connect_client(&cfg).await; let (snapshot, certificate) = - match check_snapshot_to_download(cfg.network, &client, current_snapshot.as_ref()).await { + match check_snapshot_to_download(cfg.network, &client, current_snapshot.as_ref()).await + { SnapshotStatus::Sleep(sleep) => { next_sleep = sleep; next_iteration!(client, downloader); From 595dd5d896666f73a842f44c29202a5ca347601f Mon Sep 17 00:00:00 2001 From: bkioshn Date: Wed, 8 Jan 2025 14:33:58 +0700 Subject: [PATCH 27/40] test(cardano-chain-follower): recheck test in follow.rs Signed-off-by: bkioshn --- rust/cardano-chain-follower/src/follow.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/rust/cardano-chain-follower/src/follow.rs b/rust/cardano-chain-follower/src/follow.rs index f9f736a10..2c2616543 100644 --- a/rust/cardano-chain-follower/src/follow.rs +++ b/rust/cardano-chain-follower/src/follow.rs @@ -388,7 +388,6 @@ mod tests { } #[tokio::test] - // FIXME - This test should fail async fn test_chain_follower_new() { let network = Network::Mainnet; let start = Point::new(100u64.into(), [0; 32].into()); @@ -406,7 +405,6 @@ mod tests { } #[tokio::test] - // FIXME - This test should fail async fn test_chain_follower_update_current_none() { let network = Network::Mainnet; let start = Point::new(100u64.into(), [0; 32].into()); @@ -420,7 +418,6 @@ mod tests { } #[tokio::test] - // FIXME - This test should fail async fn test_chain_follower_update_current() { let network = Network::Mainnet; let start = Point::new(100u64.into(), [0; 32].into()); From 41363e23b5680db49f62c0b8668baaa5af1fc8ca Mon Sep 17 00:00:00 2001 From: bkioshn Date: Wed, 8 Jan 2025 15:45:27 +0700 Subject: [PATCH 28/40] fix(cardano-chain-follower): add blockchain-types and cat-types lib Signed-off-by: bkioshn --- rust/cardano-chain-follower/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rust/cardano-chain-follower/Cargo.toml b/rust/cardano-chain-follower/Cargo.toml index c3259c85f..bd3cd1527 100644 --- a/rust/cardano-chain-follower/Cargo.toml +++ b/rust/cardano-chain-follower/Cargo.toml @@ -15,14 +15,14 @@ pallas = { version = "0.30.1", git = "https://github.com/input-output-hk/catalys pallas-hardano = { version = "0.30.1", git = "https://github.com/input-output-hk/catalyst-pallas.git", rev = "9b5183c8b90b90fe2cc319d986e933e9518957b3" } pallas-crypto = { version = "0.30.1", git = "https://github.com/input-output-hk/catalyst-pallas.git", rev = "9b5183c8b90b90fe2cc319d986e933e9518957b3" } -# mithril-client = { version = "0.10.4", git = "https://github.com/input-output-hk/mithril", rev = "c6c7ebafae0158b2c1672eb96f6ef832fd542f93", default-features = false, features = [ mithril-client = { version = "0.10.4", default-features = false, features = [ "full", "num-integer-backend", ] } rbac-registration = { version = "0.0.2", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "v0.0.8" } -cardano-blockchain-types = { git = "https://github.com/input-output-hk/catalyst-libs.git", branch = "feat/cardano-blockchain-types" } +cardano-blockchain-types = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", branch = "fix/cardano-bc-types-base-change" } +catalyst-types = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250107-00" } thiserror = "1.0.69" tokio = { version = "1.42.0", features = [ From 589ac4800f6bcf7e86fece88df3ed417722fbf39 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Thu, 9 Jan 2025 11:42:52 +0700 Subject: [PATCH 29/40] fix(cardano-chain-follower): try out new cip36 Signed-off-by: bkioshn --- rust/cardano-chain-follower/Cargo.toml | 4 +- .../examples/follow_chains.rs | 204 +++++++++--------- 2 files changed, 99 insertions(+), 109 deletions(-) diff --git a/rust/cardano-chain-follower/Cargo.toml b/rust/cardano-chain-follower/Cargo.toml index bd3cd1527..349eeda5a 100644 --- a/rust/cardano-chain-follower/Cargo.toml +++ b/rust/cardano-chain-follower/Cargo.toml @@ -21,8 +21,8 @@ mithril-client = { version = "0.10.4", default-features = false, features = [ ] } rbac-registration = { version = "0.0.2", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "v0.0.8" } -cardano-blockchain-types = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", branch = "fix/cardano-bc-types-base-change" } -catalyst-types = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250107-00" } +cardano-blockchain-types = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", branch = "fix/cip36" } +catalyst-types = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250108-00" } thiserror = "1.0.69" tokio = { version = "1.42.0", features = [ diff --git a/rust/cardano-chain-follower/examples/follow_chains.rs b/rust/cardano-chain-follower/examples/follow_chains.rs index 673c67391..ca86ebbaa 100644 --- a/rust/cardano-chain-follower/examples/follow_chains.rs +++ b/rust/cardano-chain-follower/examples/follow_chains.rs @@ -5,7 +5,7 @@ // Allowing since this is example code. //#![allow(clippy::unwrap_used)] -use cardano_blockchain_types::{BlockAuxData, Fork, MetadatumLabel, Network, Point, TxnIndex}; +use cardano_blockchain_types::{Cip36, Fork, MultiEraBlock, Network, Point}; #[cfg(feature = "mimalloc")] use mimalloc::MiMalloc; @@ -16,10 +16,7 @@ static GLOBAL: MiMalloc = MiMalloc; use std::{error::Error, time::Duration}; -use cardano_chain_follower::{ - metadata::DecodedMetadata, ChainFollower, ChainSyncConfig, ChainUpdate, Kind, Metadata, - Statistics, -}; +use cardano_chain_follower::{ChainFollower, ChainSyncConfig, ChainUpdate, Kind, Statistics}; use clap::{arg, ArgAction, ArgMatches, Command}; use tokio::time::Instant; use tracing::{error, info, level_filters::LevelFilter, warn}; @@ -151,9 +148,9 @@ async fn follow_for(network: Network, matches: ArgMatches) { let is_stop_at_tip = matches.get_flag("stop-at-tip"); let is_halt_on_error = matches.get_flag("halt-on-error"); let is_log_bad_cip36 = matches.get_flag("log-bad-cip36"); - let is_log_cip509 = matches.get_flag("log-cip509"); + let _is_log_cip509 = matches.get_flag("log-cip509"); let is_log_raw_aux = matches.get_flag("log-raw-aux"); - let is_largest_metadata = matches.get_flag("largest-metadata"); + let _is_largest_metadata = matches.get_flag("largest-metadata"); let mut current_era = String::new(); let mut last_update: Option = None; @@ -167,7 +164,7 @@ async fn follow_for(network: Network, matches: ArgMatches) { let mut last_metrics_time = Instant::now(); - let mut biggest_aux_data: usize = 0; + // let mut biggest_aux_data: usize = 0; while let Some(chain_update) = follower.next().await { updates += 1; @@ -240,44 +237,28 @@ async fn follow_for(network: Network, matches: ArgMatches) { break; } - // Generate `BlockAuxData` from the block. - let block_aux_data = match BlockAuxData::try_from(block) { - Ok(aux_data) => aux_data, - Err(_) => continue, - }; - - // Inspect the transactions in the block. - for (txn_idx, tx) in block.txs().iter().enumerate() { - let txn_idx = TxnIndex::from_saturating(txn_idx); - - // Get the auxiliary data for the transaction. - let tx_aux_data = match block_aux_data.get(txn_idx) { - Some(aux_data) => aux_data, - None => continue, - }; - - // Create new decoded metadata for the transaction. - let decoded_metadata = DecodedMetadata::new(network, block.slot(), tx, tx_aux_data); - - if let Some(aux_data) = update_biggest_aux_data( - &chain_update, - txn_idx, - is_largest_metadata, - biggest_aux_data, - ) { - biggest_aux_data = aux_data; - } - - // If flag `is_log_bad_cip36` is set, log the bad CIP36. - if is_log_bad_cip36 { - log_bad_cip36_info(&decoded_metadata, network, txn_idx, block.number()); - } - - // If flag `is_log_cip509` is set, log the CIP509 validation. - if is_log_cip509 { - log_cip509_info(&decoded_metadata, network, txn_idx, block.number()); - } + // Logging bad CIP36. + if !is_log_bad_cip36 { + log_bad_cip36_info(chain_update.block_data(), network); } + // // Inspect the transactions in the block. + // for (txn_idx, _tx) in block.txs().iter().enumerate() { + // // if let Some(aux_data) = update_biggest_aux_data( + // // &chain_update, + // // txn_idx, + // // is_largest_metadata, + // // biggest_aux_data, + // // ) { + // // biggest_aux_data = aux_data; + // // } + + // // If flag `is_log_bad_cip36` is set, log the bad CIP36. + + // // If flag `is_log_cip509` is set, log the CIP509 validation. + // // if is_log_cip509 { + // // log_cip509_info(&decoded_metadata, network, txn_idx, block.number()); + // // } + // } if is_log_raw_aux { if let Some(x) = block.as_alonzo() { @@ -340,75 +321,84 @@ async fn follow_for(network: Network, matches: ArgMatches) { info!(network = network.to_string(), "Following Completed."); } -// FIXME: Why do we need this? Should it be finding the largest aux data? -/// Helper function for updating the biggest aux data. -/// Comparing between CIP36 and CIP509. -fn update_biggest_aux_data( - chain_update: &ChainUpdate, txn_idx: TxnIndex, largest_metadata: bool, biggest_aux_data: usize, -) -> Option { - let raw_size_cip36 = match chain_update - .data - .txn_metadata(txn_idx, MetadatumLabel::CIP036_REGISTRATION) - { - Some(raw) => raw.as_ref().len(), - None => 0, - }; - - let raw_size_cip509 = match chain_update - .data - .txn_metadata(txn_idx, MetadatumLabel::CIP509_RBAC) - { - Some(raw) => raw.as_ref().len(), - None => 0, - }; - - // Get the maximum raw size from both cip36 and cip509 - let raw_size = raw_size_cip36.max(raw_size_cip509); - - if largest_metadata && raw_size > biggest_aux_data { - return Some(raw_size); - } - - None -} +// // FIXME: Why do we need this? Should it be finding the largest aux data? +// /// Helper function for updating the biggest aux data. +// /// Comparing between CIP36 and CIP509. +// fn update_biggest_aux_data( +// chain_update: &ChainUpdate, txn_idx: TxnIndex, largest_metadata: bool, +// biggest_aux_data: usize, ) -> Option { +// let raw_size_cip36 = match chain_update +// .data +// .txn_metadata(txn_idx, MetadatumLabel::CIP036_REGISTRATION) +// { +// Some(raw) => raw.as_ref().len(), +// None => 0, +// }; + +// let raw_size_cip509 = match chain_update +// .data +// .txn_metadata(txn_idx, MetadatumLabel::CIP509_RBAC) +// { +// Some(raw) => raw.as_ref().len(), +// None => 0, +// }; + +// // Get the maximum raw size from both cip36 and cip509 +// let raw_size = raw_size_cip36.max(raw_size_cip509); + +// if largest_metadata && raw_size > biggest_aux_data { +// return Some(raw_size); +// } + +// None +// } /// Helper function for logging bad CIP36. -fn log_bad_cip36_info( - decoded_metadata: &DecodedMetadata, network: Network, txn_idx: TxnIndex, block: u64, -) { - if let Some(m) = decoded_metadata.get(MetadatumLabel::CIP036_REGISTRATION) { - if let Metadata::DecodedMetadataValues::Cip36(cip36) = &m.value { - if !cip36.validation.is_valid_signature && !m.report.is_empty() { - info!( - network = network.to_string(), - block, "CIP36 {txn_idx:?}: {:?}", &cip36 - ); +/// Bad CIP36 include: +/// - CIP36 that is valid decoded, but have problem. +/// - CIP36 that is invalid decoded. +fn log_bad_cip36_info(block: &MultiEraBlock, network: Network) { + if let Some(map) = Cip36::cip36_from_block(block, true) { + for (key, value) in &map { + match value { + Ok(value) => { + // Logging the problematic CIP36. + if value.err_report().is_problematic() { + info!( + network = network.to_string(), + "CIP36 valid decoded, but have problem: index {:?}, {}", key, value + ); + } + }, + Err(e) => { + warn!("CIP36 decode err {}: ", e); + }, } } } } -/// Helper function for logging CIP509 validation. -fn log_cip509_info( - decoded_metadata: &DecodedMetadata, network: Network, txn_idx: TxnIndex, block: u64, -) { - if let Some(m) = decoded_metadata.get(MetadatumLabel::CIP509_RBAC) { - if let Metadata::DecodedMetadataValues::Cip509(cip509) = &m.value { - info!( - network = network.to_string(), - block, "CIP509 {txn_idx:?}: {:?}", &cip509 - ); - } - - // If report is not empty, log it, log it as a warning. - if !m.report.is_empty() { - warn!( - network = network.to_string(), - block, "CIP509 {txn_idx:?}: {:?}", decoded_metadata - ); - } - } -} +// /// Helper function for logging CIP509 validation. +// fn log_cip509_info( +// decoded_metadata: &DecodedMetadata, network: Network, txn_idx: TxnIndex, block: +// u64, ) { +// if let Some(m) = decoded_metadata.get(MetadatumLabel::CIP509_RBAC) { +// if let Metadata::DecodedMetadataValues::Cip509(cip509) = &m.value { +// info!( +// network = network.to_string(), +// block, "CIP509 {txn_idx:?}: {:?}", &cip509 +// ); +// } + +// // If report is not empty, log it, log it as a warning. +// if !m.report.is_empty() { +// warn!( +// network = network.to_string(), +// block, "CIP509 {txn_idx:?}: {:?}", decoded_metadata +// ); +// } +// } +// } #[tokio::main] async fn main() -> Result<(), Box> { From 99f9b1a88406ef41b66960bfb3dcacf2f82d4cba Mon Sep 17 00:00:00 2001 From: bkioshn Date: Thu, 9 Jan 2025 11:54:06 +0700 Subject: [PATCH 30/40] fix(cardano-chain-follower): remove redundant file data Signed-off-by: bkioshn --- .../cardano-chain-follower/src/data/Readme.md | 15 --------- .../src/data/mainnet-genesis.vkey | 1 - .../src/data/preprod-genesis.vkey | 1 - .../src/data/preview-genesis.vkey | 1 - .../test_data/allegra.block | 1 - .../test_data/alonzo.block | 1 - .../test_data/babbage.block | 1 - .../test_data/byron.block | 1 - .../test_data/conway_tx_rbac/Readme.md | 33 ------------------- .../test_data/conway_tx_rbac/conway_1.block | 1 - .../test_data/conway_tx_rbac/conway_2.block | 1 - .../test_data/conway_tx_rbac/conway_3.block | 1 - .../test_data/mary.block | 1 - 13 files changed, 59 deletions(-) delete mode 100644 rust/cardano-chain-follower/src/data/Readme.md delete mode 100644 rust/cardano-chain-follower/src/data/mainnet-genesis.vkey delete mode 100644 rust/cardano-chain-follower/src/data/preprod-genesis.vkey delete mode 100644 rust/cardano-chain-follower/src/data/preview-genesis.vkey delete mode 100644 rust/cardano-chain-follower/test_data/allegra.block delete mode 100644 rust/cardano-chain-follower/test_data/alonzo.block delete mode 100644 rust/cardano-chain-follower/test_data/babbage.block delete mode 100644 rust/cardano-chain-follower/test_data/byron.block delete mode 100644 rust/cardano-chain-follower/test_data/conway_tx_rbac/Readme.md delete mode 100644 rust/cardano-chain-follower/test_data/conway_tx_rbac/conway_1.block delete mode 100644 rust/cardano-chain-follower/test_data/conway_tx_rbac/conway_2.block delete mode 100644 rust/cardano-chain-follower/test_data/conway_tx_rbac/conway_3.block delete mode 100644 rust/cardano-chain-follower/test_data/mary.block diff --git a/rust/cardano-chain-follower/src/data/Readme.md b/rust/cardano-chain-follower/src/data/Readme.md deleted file mode 100644 index f2012dfaa..000000000 --- a/rust/cardano-chain-follower/src/data/Readme.md +++ /dev/null @@ -1,15 +0,0 @@ -# Data files used by the Follower Crate - -## Mithril signature genesis keys - -These keys are required to validate mithril signatures for each respective Cardano network. - -| File | Network | Source | -| --- | --- | --- | -| `mainnet-genesis.vkey` | Main network. | [mainnet-genesis.vkey] | -| `preprod-genesis.vkey` | Pre-production network. | [preprod-genesis.vkey] | -| `preview-genesis.vkey` | Preview network. | [preview-genesis.vkey] | - -[mainnet-genesis.vkey]: https://raw.githubusercontent.com/input-output-hk/mithril/main/mithril-infra/configuration/release-mainnet/genesis.vkey -[preprod-genesis.vkey]: https://raw.githubusercontent.com/input-output-hk/mithril/main/mithril-infra/configuration/release-preprod/genesis.vkey -[preview-genesis.vkey]: https://raw.githubusercontent.com/input-output-hk/mithril/main/mithril-infra/configuration/pre-release-preview/genesis.vkey diff --git a/rust/cardano-chain-follower/src/data/mainnet-genesis.vkey b/rust/cardano-chain-follower/src/data/mainnet-genesis.vkey deleted file mode 100644 index 4bbe653ff..000000000 --- a/rust/cardano-chain-follower/src/data/mainnet-genesis.vkey +++ /dev/null @@ -1 +0,0 @@ -5b3139312c36362c3134302c3138352c3133382c31312c3233372c3230372c3235302c3134342c32372c322c3138382c33302c31322c38312c3135352c3230342c31302c3137392c37352c32332c3133382c3139362c3231372c352c31342c32302c35372c37392c33392c3137365d \ No newline at end of file diff --git a/rust/cardano-chain-follower/src/data/preprod-genesis.vkey b/rust/cardano-chain-follower/src/data/preprod-genesis.vkey deleted file mode 100644 index 575154ce7..000000000 --- a/rust/cardano-chain-follower/src/data/preprod-genesis.vkey +++ /dev/null @@ -1 +0,0 @@ -5b3132372c37332c3132342c3136312c362c3133372c3133312c3231332c3230372c3131372c3139382c38352c3137362c3139392c3136322c3234312c36382c3132332c3131392c3134352c31332c3233322c3234332c34392c3232392c322c3234392c3230352c3230352c33392c3233352c34345d \ No newline at end of file diff --git a/rust/cardano-chain-follower/src/data/preview-genesis.vkey b/rust/cardano-chain-follower/src/data/preview-genesis.vkey deleted file mode 100644 index 575154ce7..000000000 --- a/rust/cardano-chain-follower/src/data/preview-genesis.vkey +++ /dev/null @@ -1 +0,0 @@ -5b3132372c37332c3132342c3136312c362c3133372c3133312c3231332c3230372c3131372c3139382c38352c3137362c3139392c3136322c3234312c36382c3132332c3131392c3134352c31332c3233322c3234332c34392c3232392c322c3234392c3230352c3230352c33392c3233352c34345d \ No newline at end of file diff --git a/rust/cardano-chain-follower/test_data/allegra.block b/rust/cardano-chain-follower/test_data/allegra.block deleted file mode 100644 index a276b1f3a..000000000 --- a/rust/cardano-chain-follower/test_data/allegra.block +++ /dev/null @@ -1 +0,0 @@ -820384828f1a004f3c641a011e1523582008d4d3e0caf55d66233e1e3421f97ea7423c2a82666e22ae216e464ff431a85058203593d74edc6c343c9e9b9d329f8356aedda414992f2f97c2bef93cf606b7b87a58205cd4a875fd1317f8176a910c6705cfdc80308d031c9a3fa6b1bc2b4b4d5621468258407b7d4c4bb23bf66c8aca7ce4830b9f1cadaee5061f89fa57995a8d07ec59f126730368e2b03c754b143a38a31c7a39ca830fb6de287129a27496a48602d39df058500c8cdf0ccba508d39bb915018c420dd057cd5d94fd2cf17b1c3a5f4522581dbdecc54e9de4d1e61d12b4d09db5a5be92b145d1b63e563ee8039af378b69b2e81669daca047d5e34750c34542e3503f0c825840000607436ed04d36164ca57f0f70bfe10ddc3f276540750dff3c0ca399047292c3355e4a488d0f13e548134661056f434f4c966c52f20c6580252c8a25601ded5850cb50509a5659569e8a1881d77dc335a781b245a14a499a7c04cdb9f6ee04be3ab3bf096c42a6c817198477bd2f10a426f7a7cf70d579d2238fecc3ca4597f8793ca02b02574ceb45fe9892997509ed0f1908ae5820dc6af41ca2a4eeb3d2969e559ddb65d2672f1b9aaf901fe4af425407952e290958209d0d3abaefdf5a2ccad0832a80759b8f8eb3c0629e9dc8bda3d44ebf658ab97601188d584051977ef95fbb458fa81ddc7e1ca6345e3f5fc70ae5b80b47d95fd39ed2940d1751ca7ce6dd24901265c299bf1994b3830ca10e995d7fde4beab807cbce03470604005901c0750da95fc1de2debd8cbde31d7f658bb41170695319a9468cde8cf21a93124f7db032571299748da724cbfda88d5f79fd89ac2b3fbd0748e25129ec2e74da20f96364f691ca551f8a7e71305d225a810783947759bf28d580a51244029c290e7c27e1d249f52ed39ac65f66529240ab76e36a4001df5a24b971557475379b24a695a9529646eeb7f1681a3d215fd6fe550654a1e7b06089b68f525b0aba6d91adf229eef5af4a3d602c1d29ba5f18c8a93bd6c950134f37ccf0ebf1b78fa2909f98ed560220de39302f56453b979da7843f6b0cacbe1a33739aa272f193bf9de69d083c2c885c1e226c0e0a35a2400059cead716cfa8064fb98f20162b2b3586c5dd29ac557ad542c610dd6576669823c757353fd03208313d8715268b32ef8ab62e02edaad3ea9c96de888d5933ccfc13e757f92bba98b23a5deb1cb860550f272f685a5bb9b88e2f6bbf227c049f90aea4540347bdac041b09bb75c83352fcea02f91c648156aeada5877eb3adba690c073a6fc1372a48ce8115ba3537243938ce366078d07c2f9dfdd92db07e0047b8d78d32fb4b55fec8810fd9d128c88df3c5d435dc82e163f9275dac718d06f680a3be8db4dc8dd512b059b1631191f283a500818258201e8f5d41ab9915c4cb0fcf1c4127e18585d957ac95b2b4879c3e02b02205cdcf00018182583901495a5a4dd65a483a5eaf6630f59a2c33e02e2c15d1d1bc39d1708ac457fd410378da5864e6b313db03488a085ca56376af0ab5e9854376401a3b76264b021a00029eb9031a011e324b05a1581de157fd410378da5864e6b313db03488a085ca56376af0ab5e9854376401a0068d5dba400848258201f15d61fa4462dffdb330d625b1fcbec930ea633b7bff5fce23e969660702ef500825820cc59f188f8e4027e98fa33404a7ce69b76e0c6b211f11ad71b4daacf67906ec900825820da82abf561c83cffd8657c05d27244081739eacb880b3b5b4db03b1a411911fa0d825820e125166ebe2e0b7bc781b9e7aa886a032ec87cb40e0bdc1acb5058a0555a8f82000188825839015fa4a029126ea6679f6cf29d15369dde7206472bf0f9d63e12a88f575fa4a029126ea6679f6cf29d15369dde7206472bf0f9d63e12a88f571b000000019fbcb30c82583901785eb7eb6c8286b8011a0adbf3ca1b4d37589b80cc6e42fdb4679adc39bc6cf63c0f9dd4f03df80accce7246bea60d649de4a8c4d5c0dca41a16d9fbfb82584c82d818584283581cacf4df690f13b4eaf82b816f399b2e1d8ab86976da93009b813d7758a101581e581cca3e553c9c63c5c2eef54d43a2e23449490865698bb72b3b1c039082001afa0dcc441b00000067e78e120582582b82d818582183581c62d2399c601895246274b8068266fa3138fd09f79fe636aa432db929a0001a5d1abc701a1263562082584c82d818584283581c3cc42d469376e7a5cfba6823160d341b5867c66d009124bd000bb109a101581e581cca3e553c9c63c5e89765f8436cd338c66da66d119ab3c27738826333001a65307a281b00000004dc9ffb9982584c82d818584283581c05bd51fb87d91b5290ecf18958de205badec391e4d643740edb2f0dfa101581e581c735437123ef5c61d0591c67ef0c94a5dc5c18653d6c629949595edef001adf8508d81a2c932a0382584c82d818584283581c5acbd13c916ce291ac4f41b1df2c4c75b8e917622040b54e3376e42da101581e581cca3e553c9c63c5dd0255704321b81423e0ffb4018d237e8e9a96ce3e001af6cde4f81b000000095b4f070082584c82d818584283581c8c8a6f436c8b04fe1c682aa81d417f2e82b41ebb06bf9aeb8a65a198a101581e581cca3e553c9c63c5b7f725d5432632ff88fecdf5936a00291efb732202001a1ec13f971b0000003452024d88021a00036a91031a011e30d9a5008182582026571cc2e731014dfee8536a0be0b816cc38b10ce38501db0e1a5eec4f04ae860001818258390192da16a658a4ecdb2c18b01e464f4ce2924f8830a304648674c1c2756162cdee35822637a84e896c6a8b05214cf21947f91b69122eb985891a00495250021a00061a1c031a011e3123048183028200581c6162cdee35822637a84e896c6a8b05214cf21947f91b69122eb98589581cae66e56ab11ccb39e882669f220a37956c683e4ce84fefd910012d7a83a100828258205f6f43cb12b59a3e5bf242528c8ab85e4feeb2acb89aa08e4948968f7bf2d9e0584010d19b492320347d5b6adf2137ec89f9c13d3fc07cc9b32f86a71fe001fcb75f36e3958949ef2b7e37377d89246b4a39463846402fa870f81d1845ef7c5c1d04825820f49ae225837477663687484ce73ac607ab7fe78600ca08d61db09e2e35d8e1b6584096c80781bd34262ab6f7b12f6592f0b943021e97e9c70ffc23635272c742932a51e4a252341c47a79f4e698235ab22beb3a75256b6476fd46749a68c6e86f60fa102848458200915adaebbd25d0f9a3242bb83c14bf5b012967ab8462acdee1912062a76117f58407a9ebc40eefdbcb1586e9805043ccc3285ee3864686fb1fb0d6d8075a41abd026864d0e92224982acfef061da2765effb26c75faa62c5ef3b656386782987c065820aa35c675609419a21a79ed83318278cbe669d4a4dadbfdcd6234e1315ba7c9685822a101581e581cca3e553c9c63c5a59118f7438117a8d6603837bc193303b5001b095b8458202f84330afbe6ab81c368ab0a850e8b6fa02daacc91709faf6bbdc811b4b5f82e5840bb878822cb198b1d245e2c46c20c930996067fbcb3469a8d36b68d6531add3e3e5081200890d906c70b1bd9e4333115a7c17df8da18eb19148a88a431993900f5820e91eab0e2dae5b26ff019c4b1d56183bfd8f5abd1fd258e4f58b13d55cba36f55822a101581e581cca3e553c9c63c5c0e20ac0433519070b0d32e51dbf04b191a57d44b3845820894b8d96727c3d68a30a7165c67c9bff346260628ee624268dc35d660e55794b584062b68793ff855c0b11a0c0e147de91a9f0631c565d28d270fdc146571d0c23839c970996188bf4e86b7a2d529e694b4301de1692366349913b4966f06be9df01582033aacbefeda60713a90163575735e391b5a1a00fe8629e52875657ed5c93ecba5822a101581e581cca3e553c9c63c58681fbd14353af0a213e5ab85001e4e2cbad09ec518458208e2c6fc08234b2a3437e5bae310f6957c69a62143318c562bc1b72c85141df6d58402f02c6375f5074b287aa72e940a3280f39d6fd2c24240b087f208fb92cb2abaf911657eb06b6e24756dea333628972c611da12aad9cc8dfa6b15a41f1e4bb70258201d6ed1791e5bb28ead7bcc582d7e5e70d264cf5293222352597bf0c2a773e9925822a101581e581cca3e553c9c63c5f777eddd432f2063462cf96a64e586148173444979a10082825820036dc0c351864d35c3d8fb72a0acbd0efb343e005f457b0a845e3a82a48bdaee5840ef6eaf7713acfa2623a589e6a5764f93fff7bed4d60d549a0e47d985bcccdba34e79b6954768b423db879e99be2ea205a151974072734fa996d240dd876bf600825820f2acaa3d79a96db3f8cfbf87792b62e39fa74a4d9ba1bcb82ba1562ca524c0a158406da704b6ca04547fd8fda632d1acdc1f15c5efaaee4e1d92f35c714b59148511828870dce8602de968da15263e938c6f71b37e6db9b47fa217661efc1c117b01a0 \ No newline at end of file diff --git a/rust/cardano-chain-follower/test_data/alonzo.block b/rust/cardano-chain-follower/test_data/alonzo.block deleted file mode 100644 index bc6359292..000000000 --- a/rust/cardano-chain-follower/test_data/alonzo.block +++ /dev/null @@ -1 +0,0 @@ -820585828f1a002f48941a0295f18a58206fe2f80eb8cf6ad02d3a3857391b05aef41e575486168d7c36ab693be24c76f25820e7c3155586042372b19c1fe0491b771bfb2eb04f24af76f3870cda983551f4e75820d8ae2a59f1ff6ec33d0df8161fd89d820533b9580a4e43f4e9f6a628582b10ae8258402b498e5bd3f73130e1b7e5ac199fac1a688d948d73d71ec7a951913a6543131c44dcdba5215341b1dc2581c096e99fcf5885f42a9cdcf476322b38cc837111b858508f08dc2bc1e3c6c8a3e6f7f5f1d7af8d2ad33c4d31022f4777641a946938ba0c3af0f78076cae00ab741f4d39dec2be431710acfe55d2b3f5868b24847506b77fb42d639e95bdd025f5f406abec9240f8258400022f7e10e560aad60a6f16b743ff04b4abcd4ba9b572e02c67bde6defd29290a9345b3c1b28ee1dfdadf631a3887bc21807ec5bcadeb6a495f3cde7cfc0b1085850e6db5933067747401ea665a7d8fdb5a0ae131bfa757aa07e2b3fa619e0d94245233806ebf7340826f076f6ff62fe4600e427643ed77e3f02be7c39370c7d46f266e4f5a23c2cee05735e2152b1a73c0e1906965820c48e87eaae5983daca6d2611e5b45a09c4a8300ed2e36f747058761b976c2303582060ffa1e3c1ab6d03a5447d2f40ab023dbce45b13f0e372d63a964d31c7ee60790619014858405915c6868aa7c19b007464392dd4878f710c033e83d1421e188a993dc13a66c3bd60454228eb8105a3d37509ef0302633e42d4b20f86003a83b25a87b8b1ae0c06005901c0eac3f1484e8d6278c81251ce80767faa39153ae2c509795065f6859d87e5ca60356f2e0528e26441091d5fe855b430659f8c113b8e090ac7b5dc2a3f55811b09ff956db28c653766bcd95ca7ed09a8e0c744b75c4cac7b48561ad922978a866bb9014ce731cf098a346d58fd9602b5c712c587cb4ad2d31fc3c869b1d68fa3eb53c94453e0fa42c15686ace90df691b14f1372eb7e86897c0f22d26ae043b105978b6652d4144c7a3c5ef9b61e7d46403acbbf158075e31e4d45969ec968b62a27c05f4c2c8448da438d9b2b0f98a6df9245326476310ac26b164ff0b40e3b7e1f05c38d227f5b9ab87d82c7b64af3351a636ccdb951b6445f7909e56507f301b267d9780335863b3ed7d3ba16ebca3e9b77bc3ddee15436279b3a33eca8dc66a87b2864a550b003dc43622aab8183e891780ab8cd56fcd4ae28775ad6b69a786e19fca6362905d65d92f3b59f8259c1e1f52a8fe125d29c3dda7fcd45c7c71eff039986ce812e9a1f66f6795f53857ac57d32901f6a1992e42e7c8d7a942d25f77f46beb8e4cf801c80372c958face6b1a9dfacc38182310d66ad4816a08b329451c088889a2cb62fedac1944addffaaa0a8dc5cb54b2974b70411226918b8285a40081825820bf1f12a83095ac6738ecce5e3e540ad2cff160c46af9137eb6dc0b971f0ac5de000181825839009493315cd92eb5d8c4304e67b7e16ae36d61d34502694657811a2c8e32c728d3861e164cab28cb8f006448139c8f1740ffb8e7aa9e5232dc1b0000000450b745b6021a0002aeb5075820f607381cf971f3ab1119ad680f73bcc66c8d8d30136afbf82fe05f44f7924487a40081825820df4ebe9ac3ad31a55a06f3e51ca0dbaa947aaf25857ab3a12fe9315cabec11d30001818258390076b0d16f5d09ac02dd1786981066f6fedf7ac165a08b3b6f0fb33f039bf76872ce2fc9debc7c431ce4700ea060a5aefdec0a173d8ed6b4261a02fe430f021a00029d590758200013eb4278b47fcc6298f02bd42b31c919cef864dd20a9929d5eee315e13a557a60081825820087138a5596168650835c8c00f488e167e869bd991ef0683d2dbf3696b0e6650010d80018282581d6095ca37fc71b3b73f2d0e57258ac66857661f33a509436c10917aaf6b1a0022e4be825839005790dbdd97b76eb273e290122d6edb7504ed392c7ea7b011bd25d936719b6905b4122f96283e50a0dad9a9e577553ad49a17bbec3cb715181a2deefb98021a00028f6d031a02960d5d0e80a80081825820cc9f28625de0b5b9bbe8f61c9332bfda2c987162f85d2e42e437666c27826573000d80018182583900be8bb38da7b499acdb1eac0c05dd2649c8de5d791ac87969903df470244805c91110d844e9f4a776a5f201c71313358c13caaa3ee7b488e6821a00bade29a1581c6d566ad1e649b6e86a2f4fa16a4cdf99616230b78742332cbabc5fa4a140183b021a0002c959031a0296183b08000e8009a1581c6d566ad1e649b6e86a2f4fa16a4cdf99616230b78742332cbabc5fa4a14020a30081825820d0965859ce9b3025ccbe64f24e3cb30f7400252eb3e235c3604986c2fdd755db010182825839000e87d178321157275dd6a10f9c40ead38a78ae4703a23a23be57f1cad723da7bf8787357a74b3fa486b13462578ecf6ab6774dd4f15043681aa0eebb0082581d607c4a71a51d0c7400a15a748fa2338f20c8386f1ed4ebc56c2ffec4b01a02f59afe021a0002ad2985a1008182582073fea80d424276ad0978d4fe5310e8bc2d485f5f6bb3bf87612989f112ad5a7d5840abe07f7afebbcfd1816e2f70b66cbe2a0be6a46db86fa783949e4319e203e8faed12930489841f287dde09d00c5d1ed15bc4d47ba1e1deba2bf59350fcadec0fa100818258209dd11e64a93710854fedf85f1b4b23192079b812b67ac3ee0b97bdb11113806158404cf3a0c85491d39ef8ef91dc5b34107da610376301b53ebb2a7ce7c2b8397f6871890f1bf875e8f964146dd7107ddb89b08c343e0d4561481ff5b9e9b7f3ec09a100818258200530deb7fd4edb6b32e312806c7231d3c507f53fc27d5894c14a454936b16a435840369d46b7c720cbd253327c45861c0be0c741babd4b82a29c42c531fbc87562e40496934689289162082eeefe583e3dcd89aeeda671457d30bc21e5f9ba2b8e07a200818258208b5a5251b8a3f1f1b76e38377b3cf857d38284cfa48a2eee46c93df89221e0275840cfc689b9ab1ebc2dcec3f27fba6448b610b4bbbe46ec430c7e9e86ab0b454ca9b3b08efb6e843783f860512b8f2aaa142073766a7fb43ab6ca7ac5ac426f680f018182018282051a02b5a9468200581cbe8bb38da7b499acdb1eac0c05dd2649c8de5d791ac87969903df470a10081825820a87e24f3f590c98c9bc1f34e11607db0e04446afb3b02f3201b8a6972e50512d584018f04cd87d600d8fbd03d1292e4e16cd3ee4f8fc3cc6e504216373e1a8bf8826e17e365931e988e025b2345a390e9e6bbd78f0b0abcb24e0d238df7592570b07a200a11907c1a56641444142544381a266736f7572636569636f696e4765636b6f6576616c75656a302e30303030323937326641444145555281a266736f7572636569636f696e4765636b6f6576616c756563312e35664144414a505981a266736f7572636569636f696e4765636b6f6576616c7565663139332e39386641444155534481a266736f7572636569636f696e4765636b6f6576616c756564312e3639674254434449464681a266736f75726365667472657a6f726576616c75657132323637343134383233333435332e313101a11907c1a363636f3281a266736f75726365664d485a3031396576616c7565633438306868756d696469747981a266736f757263656553485433316576616c75656439362e396b74656d706572617475726581a266736f757263656553485433316576616c756563392e3480 \ No newline at end of file diff --git a/rust/cardano-chain-follower/test_data/babbage.block b/rust/cardano-chain-follower/test_data/babbage.block deleted file mode 100644 index aeb4df9c1..000000000 --- a/rust/cardano-chain-follower/test_data/babbage.block +++ /dev/null @@ -1 +0,0 @@ -820685828a1a002751831a0409c74758208f359d2ca9a3e513b574cc88c93346506e2520f9939eadfc2e02e6c251a94769582069b5785508a9898605833a7c346c9fa294eb9e6793e0887a0230a1e026ebd1fa5820e9fff58586a4a588f15f371b4d7bfc04344b6a281bce39a7ab81fe5b6751cbac825840df4ca9e1e98212e3bfa0356274e63890304710237e92973de89d8dfba015f3eb8e925557cadcb70031cd644fe84b043f260e81342bf865d811409ae2aefb528458509aab92e40a5c75252e190d6860fbe0274ee6f7de16d12256df1dbd1f08b0f835fc0f333395d8d94464e5181e72c3fd935573005f03656191e9e95855f8fbcfd3456a6c268df905c805c9e510dff0df0f190c505820e6aebff5e8b2049914014d88821ef94b873b219ea32b44a50161b7bd2442deb5845820356e1f77552adeab6d94c2383cb4f7a5fb1b644858a6639cf9f71da339ad1e17081901ff5840fc25623ba50cf9f2858463dca7a3b1c703b97bd49d54e965d2df9602424986bf26e29ab4dac9b82f185cb825cd4a0b6dbc90374defd9ca20206cd25f47dc01058209015901c07d47377a4d51a9ed20b203308e73c500db49947189f6c92e951ab0d24b131d20d0f157fdf10a90aad4c8c6173dcd8d16b834ff47f1914556ae14b8015d7edc0ea0c33c70c7867e06a2952efe9066ceae6e1b9b23c59c76148f01917099657153af53c0cb5bb0a601d6e7e504033c2522fe069dda3a488d189032fd4ff59273526b263cabf7966326054aa26bb3d3e24010aa1edec3a545c80a1e1e357b0bea164c6663240e865cff3e29d30862b99f1ce52ca042f5d7d065bc29cc7d4ccce45acce31cc0da588c4ddec1fd4e3444ace1bf583df247ba168e0375862090fa4f49fa95fd28df6ce88f72e303d1f9cd4353abdd2d1a4472164d15220142e922b03eb6657152f340cf460514bbe57e892b81fe633d395773c00b91025237ed84ef5c6541d6bccb5a56f736b294fc6500aaa9e958c7b41bd422200545efbf0e5eb0ff95fc2394ab22cb543854aab426f60ab5dc04fa9ca3d9cc71a2abcf00c1ef8287f9bd9f7508fc5cc6a4513faac33b05b06304883ec50acb9c1ee3033604ce4eebe75beba7e97a731f92c6e779ecf700c3220ec992752b49708cab9d9a079803a01832cb14da7c59d069c4538cadd38c90b6502ce3b311424eaba7676f3dbc720b84ab008382582022d427bf2262a44dc3a3a2c9555696a741d779eb89afecf624e91a1ebdf3335400825820533e9251fd0ed7ac8613fe3d05813ce3bde7d96a6e446019a93421a0c6b785a50282582090b06350ad57403e8dcdb49d4f9fad5de1b244668fd5a0c98cd08b78d5f343b3010183a300581d704e3b75eb68829ca9e63b541f3645f78afe8d119932a7a2528171e74901821a001e8480a1581c5cf48c225e057f8da0787eae1e2bc62a1cf1d2ee34c7e2a9498b19b5a1484e6f64654665656401028201d8185840d87a9fd8799f581cba4ab50bdecca85162f3b8114739bc5ba3aaa6490e2b1d15ad0f9c66d8799fd8799f1b0000000da0e77c201b00000191449a86f5ffffffff82581d60ba4ab50bdecca85162f3b8114739bc5ba3aaa6490e2b1d15ad0f9c661a0089544082581d60ba4ab50bdecca85162f3b8114739bc5ba3aaa6490e2b1d15ad0f9c661a00ac398c021a00044c8c031a0409c766081a0409c6ee0b5820dbf505c29f869273f15ea579723e9ca9bcf31fdb8c4cb4e4085268f3714b99b90d818258206f8ebcf2a2b04f5cb5f977aa1e41001301634e64a532a8de1e98147cc84e6502010e81581cba4ab50bdecca85162f3b8114739bc5ba3aaa6490e2b1d15ad0f9c661082581d60ba4ab50bdecca85162f3b8114739bc5ba3aaa6490e2b1d15ad0f9c661a00524801111a00370c3f1281825820efd8a48f69e5270cb73b438067e1b566d39758329a45e5d6d36755f2c732618400ab00838258201df5c710d3251bea8457e05813101bd7f8defaba978114939ffa38035d42672a02825820e04bce69a5659295c235502d5fdb62b29e43f773e698c97e533e394d92d9228001825820ec4b6e2455e84a8aaa365cdc4c41ee446314ea74c209e698f1785c94c9952910000183a300581d704e3b75eb68829ca9e63b541f3645f78afe8d119932a7a2528171e74901821a001e8480a1581c5cf48c225e057f8da0787eae1e2bc62a1cf1d2ee34c7e2a9498b19b5a1484e6f64654665656401028201d8185840d87a9fd8799f581c3f2728ec78ef8b0f356e91a5662ff3124add324a7b7f5aeed69362f4d8799fd8799f1b0000000da0cc2bf01b00000191449a8523ffffffff82581d603f2728ec78ef8b0f356e91a5662ff3124add324a7b7f5aeed69362f41a0089544082581d603f2728ec78ef8b0f356e91a5662ff3124add324a7b7f5aeed69362f41a00a1cf51021a0004529a031a0409c766081a0409c6ee0b5820ed60fdd0e4e9cc43b5fa9a601a3d013c6a8f26916ff80e9b5c5a41813493f04e0d8182582040d412944923070bbdeca4887e30983b497e455e62a150209d522c4f2eec82f5020e81581c3f2728ec78ef8b0f356e91a5662ff3124add324a7b7f5aeed69362f41082581d603f2728ec78ef8b0f356e91a5662ff3124add324a7b7f5aeed69362f41a00455948111a00370c3f1281825820efd8a48f69e5270cb73b438067e1b566d39758329a45e5d6d36755f2c732618400ab00838258203efd5491b62cec43b8421eeb9978d9544a451cf938b454278dabfe508a867175008258204d1deb722bdab493e69840eca2fbb2af5eed36a82d2cd196754ce4af2618ecb902825820f1883a3368b6baa87f5d051d3e7fedb0c571519333f38860b54ec7b4dec3253e010183a300581d704e3b75eb68829ca9e63b541f3645f78afe8d119932a7a2528171e74901821a001e8480a1581c5cf48c225e057f8da0787eae1e2bc62a1cf1d2ee34c7e2a9498b19b5a1484e6f64654665656401028201d8185840d87a9fd8799f581c17942ff3849b623d24e31ec709c1c94c53b9240311820a9601ad4af0d8799fd8799f1b0000000da0cc2bf01b00000191449a8522ffffffff82581d6017942ff3849b623d24e31ec709c1c94c53b9240311820a9601ad4af01a0089544082581d6017942ff3849b623d24e31ec709c1c94c53b9240311820a9601ad4af01a0073c968021a00044c8c031a0409c766081a0409c6ee0b5820dbf505c29f869273f15ea579723e9ca9bcf31fdb8c4cb4e4085268f3714b99b90d818258204c6d1cb7cba6122de41fb91be0f78b61316399096d6f54bd7e3f2f76dd63b92e020e81581c17942ff3849b623d24e31ec709c1c94c53b9240311820a9601ad4af01082581d6017942ff3849b623d24e31ec709c1c94c53b9240311820a9601ad4af01a004df567111a00370c3f1281825820efd8a48f69e5270cb73b438067e1b566d39758329a45e5d6d36755f2c732618400a50081825820aa7bbea2a5101b867d969ad7e6ff7d95d440199ef4ba6621751d25521566101400018182583900eb21979c03eed7207020b2a0b47565b5aafb1a2c3849b59a1fa8e6c5e075be10ec5c575caffb68b08c31470666d4fe1aeea07c16d64739031b00000002525569af021a00032471075820420e72fc38474ce192fc9ba39380a11ddf9e5ac96a814d3fdb68c24cbf81e4600f0084a200818258209a12ec259e59bd8fc60244062f294f11555539f5fd45e77d8a57f16b5987dc4458401944ed87d70eb6646aa840b9914c462b1e4e3513831d1f5ec817a6966d00c0b6f12bf24b0576ea9593ed4f9c9dac2f0d9e15473088e64f688f3dea4416dbe90d0581840000d87980821a0012a1311a15d0fa8ba20081825820499300f082db931c561f42b9ca7d5ea4b288ae74cf1969d1fbd7bf41e7b02e8e5840504c78c1fe246730ca7c2469ba6731cf7e0aff42bd027091283568fe25d2a9f35da1593fb89e5bfd2f7d2db58316ee86ed1c8380e8fb77d61362c78f64374a010581840002d87980821a0012eff61a1622a0d4a20081825820ae01a85ba5eb8e67830cf6b422cb819cac1eaf0c7f62dbc496f12d9735b170d7584004dd05c7ea8b1ab964f67bfe4515e18451b23ee7950c8224f9b355aa1005ba1c7051951e82883c9cb25be7ada388fe2b708eaa6d9f1590516f2782f8b5ff20050581840000d87980821a0012a1311a15d0fa8ba100818258208469288efa6f9cb49040b43dcff93f40969d72433f751afde50235012c01602058401d84bfa159ac070a11834e2a41b38f205ce1628ccdc693fe2000e21c680e6ead1a23a23043bb99ac1de8460fee2f5b40d3a736566b9434d1b551b115956b5004a103a11901fda50050ca7a1457ef9f4c7f9c747f8c4a4cfa6c0150152a368b96d95f61ae69513dd5f6e92a0258204d3f576f26db29139981a69443c2325daa812cc353a31b5a4db794a5bcbb06c20b8c58401b3d030866084fcb259de07496d3197e913a39fd628a3db0a4ed6839261a00c51cb0a5b9c16194064132ace375ea23c75c60659400cba304d0d689c00086195d5840ff28714da02c35e7295815ba58b77f227e576fa254c464e2f9c6f9dfa900a0208250033c054a468c38e08819601d073c034a4727a524ff39995477443c1fca235840839c927599b253887f50487c1caf757c0aaf79bc3fcacd42252b8f2ae1f1a8b282929ca22bb5c2885cc23a66005c0cc1ca20142b82310c3a137d44c1943e40995840a7a7ce5c3475b5887a3765ede2ff3b7bfea90f255e2edf37fd44e27f26b8e6cf408aef4b20bebf7257b3dabc7eda65fff4ed278b50219f0a52367ff5b80e46b758403875f55a394d17a5d9a6b1a1deff5b2206e9e9734e9fbefa6a1cdfeb7a104546dfb6e46c46feaeb65a7f4648c276e29e87b27bc053bffef79359300220d0c3875840f2a05cc4880317358e19c758fd9ab9917551ce3987af2e35d73b6958a0f5732784621b0c92f68a93537f16f48445424890f955d7a597c13c2eb54a82b39f0307584097507df5fef916fabb6dafdfb516fb9184783e2cb4e89d048a6c1e5c04818bdb76ffb5cbef1fbe452658d904cd152ee72a3bfc6efe1199fb3b51f1979629cd4e5840fdb7df511723d4cead3d2b2eb9c1f18cbbfcf9f5cc8eac46dc03cd55fcac3303c391437f50400923e65c02e981af5461b6867a47fb25ebe9b0fb4d9e41ec210e58404b9011000206414523c0990f9ee20b5d8a745393d3febaf6413a448b994f1567eb7945df7a0ab44afd55561e0190b376d411026c5d7a4a49a19e0bd3f5addd6c5840492fde46eee8d75b587286291dfeb6a78fdf59c1a6bfa2717b1f41dfa878756140ce7c77504b64b094b870ade78569566eec66369133af5aa8c8eab9f95e29df58409ec10be251547101b24c495c8ff4fa55378dbb4a5c6e89b18a12ac033343d61c3b7f5fba725b51536d92a5cbfaef9be6d24a3e5b3d75a1c0e29e42f523567fac4d0f8200811c822d2210b97f5708186358407b322d37df11460b98e13f6c3c4d5d4985ad984768d09f77516e8e0f61ed24e646c466a995c2bf2b547302b96d4582be9b65f8d52f9fbc4857e7bef79948860180 \ No newline at end of file diff --git a/rust/cardano-chain-follower/test_data/byron.block b/rust/cardano-chain-follower/test_data/byron.block deleted file mode 100644 index 2c26a9a3a..000000000 --- a/rust/cardano-chain-follower/test_data/byron.block +++ /dev/null @@ -1 +0,0 @@ -820183851a2d964a0958208b5add21497fa1749292318f1ac96a252ee58ac9bf60d321d1273f5135e72f2f8483025820eba8b3720ab760171e4900b88cc0379bf6c78c4dac55d1dc3d646b00c13515405820187817e2ba9ff807dd905e3a4e0d061630979da49071495b2b38201f7ffbc97b8300582025777aca9e4a73d48fc73b4f961d345b06d4a6f349cb7916570d35537d53479f5820d36a2619a672494604e11bb447cbcf5231e9f2ba25c2169177edc941bd50ad6c5820afc0da64183bf2664f3d4eec7238d524ba607faeeab24fc100eb861dba69971b58204e66280cd94d591072349bec0a3090a53aa945562efb6d08d56e53654b0e40988482189619056558400bdb1f5ef3d994037593f2266255f134a564658bb2df814b3b9cefb96da34fa9c888591c85b770fd36726d5f3d991c668828affc7bbe0872fd699136e664d9d8811a00316fa2820282840058400bdb1f5ef3d994037593f2266255f134a564658bb2df814b3b9cefb96da34fa9c888591c85b770fd36726d5f3d991c668828affc7bbe0872fd699136e664d9d858405fddeedade2714d6db2f9e1104743d2d8d818ecddc306e176108db14caadd441b457d5840c60f8840b99c8f78c290ae229d4f8431e678ba7a545c35607b94ddb5840552741f728196e62f218047b944b24ce4d374300d04b9b281426f55aa000d53ded66989ad5ea0908e6ff6492001ff18ece6c7040a934060759e9ae09863bf20358400e663202ff860e5a1cc84f32ad8ceffb0adb6cf476b07829e922312e038ba23573728e02f3775f6714b3b731f8b8084d92b3f38f51a41ba859e7e700feeeab038483000200826a63617264616e6f2d736c01a058204ba92aa320c60acc9ad7b9a64f2eda55c4d2ec28e604faf186708b4f0c4e8edf849f82839f8200d8185824825820da832fb5ef57df5b91817e9a7448d26e92552afb34f8ee5adb491b24bbe990d50eff9f8282d818584283581cdac5d9464c2140aeb0e3b6d69f0657e61f51e0c259fe19681ed268e8a101581e581c2b5a44277e3543c08eae5d9d9d1146f43ba009fea6e285334f2549be001ae69c4d201b0000000172a84e408282d818584283581c2b8e5e0cb6495ec275872d1340b0581613b04a49a3c6f2f760ecaf95a101581e581cca3e553c9c63c5b66689e943ce7dad7d560ae84d7c2eaf21611c024c001ad27c159a1b00000003355d95efffa0818200d8185885825840888cdf85991d85f2023423ba4c80d41570ebf1fc878c9f5731df1d20c64aecf3e8aa2bbafc9beba8ef33acb4d7e199b445229085718fba83b7f86ab6a3bcf782584063e34cf5fa6d8c0288630437fa5e151d93907e826e66ba273145e3ee712930b6f446ff81cb91d7f0cb4ceccd0466ba9ab14448d7eab9fc480a122324bd80170e82839f8200d8185824825820e059de2179400cd7e81ddb6683c0136c9d68119ff3a27a472ad2d98e2f1fbc9c038200d8185824825820adeb5745e6dba2c05a98f0ad9162b947f1484e998b8b3335f98213e0c67f426e008200d8185824825820f0fb258a6e741a02ae91b8dc7fe340b9e5b601a6048bf2a0c205f9cc6f51768d018200d8185824825820c2e4e1f1d8217724b76d979166b16cb0cf5cd6506f70f48c618a085b10460c44028200d8185824825820aaca2f41f4a17fe464481c69f1220a7bfd93b1a6854f52006094271204e7df7c008200d818582482582089185f2daf9ea3bdfdb5d1fef7eced7e890cb89b8821275c0bf0973be08c4ee901ff9f8282d818582183581cb8340f839cc48449e2ee6085bf1ab6f152fb20d2e071f429085bbe13a0001a5bf6bee11b00000011972734888282d818584283581c7ed455da1e6e026b35204699d4fa39b3bc9dc47ed27d36d2b47ec3eca101581e581c082dcccc3e51655ddc77c01953f7b64c7cf6aca758c686d9c51a32fe001ab116b6251b00000005bd6bbf308282d818582183581cc2a3e4bb135f14d44b5659fd3cac5f950e7515f8ce243f264dfe1befa0001ad2e633181a84dbd7408282d818584283581ca492c5ad6316f8e7e84177673acf32f53ec25b2baee5a52ff50964f9a101581e581c1e9a0361bdc37dd4b96893a363943b3fa8e2e89b8761c3f0ff7568bc001a600064881b0000008cc4df8c118282d818584283581cf73d2b9c66ae7c8d479151c7e43e2fae59fba02e7108ac4d643a4909a101581e581c1e9a0361bdc37de543987ea3cadcec1c18fa6cf784794fec37146f34001a7103195d1b00000004f92e889b8282d818584283581cbd765f3097754bda870653533855012a82a22cedf508afc97a05f912a101581e581c1e9a0361bdc37d9d5470dca3256d2b36da565a1be6fd6c319321d8c9001a743764aa1b00000011b52f1056ffa0868200d8185885825840b43ac73cca84eb7baa30f0ad3c4d427ea43e8d8831eb8de34ae9994bc6f00313d81f35d51d695e30f88b267572f96f056ddff1b39acf011b8227c14df833371258408a0c1d59791fd04e6329adcf532fe2749a8da282ca4bdba9942a6acea07b3e4d9d30cc0dcd9a602e151694a417d069fdaa8a3bbbb2e1724b9c9671850498430a8200d81858858258408a3c3f38a7a598bd4b62fa4b56f92b96be3d1b7f1df1a713a3cb4978f835396f935c09b245ab312efda634d3ac4af1f843fb0577725a27579c9fd665d14c24fa5840a27f622daaf26f1047845723f20a13247ce866005f5263397082657a80d60095d81856e127e27e2fe36391c1631170ac630d3e340aed71c9cb8c323eec148a058200d81858858258409322bcf07526e852e5a0830d7c24d4a2a0dcf8a894f176e0a8fe3f742fa485906206283cdab4fdba8280fdc51e818ccdd1e9e6cd530381b18152f38dc598b6cc5840d0edd562447c433cc7870913fb8d90a2169d4a1f9aae8695eedf07e0eff67213fd7c339f03860ecd83ceed1a324aa10067671e4ee1d3f762f355678dd4d0ff008200d8185885825840ac4a10ea86a183dfc8ab8f9ccf7a61eb9b11e471b53321725bafe403bd101abdfac85680f85d72f5462b4abf234759f3d833f7fe5372884f8a84475f4989edbd5840181183c6c147ba34c9f39269ab36949d0b1ec0a7dd950afa1ea2dd27b2d691412948de68f93471935905edf07934a7965926f52f8162841299a55246a5a97d0b8200d818588582584004bff1f0caaf06b7942f52218c1b8a1583f425014ec78ff2c4030f90dfe191ec861f537833d47898185d34746877e9d9d31cb827c145729d1200c1463625b22058401ffcb034120b9b20d84af9baec86bb0b2593d804e8b544d7dcde662b0e2a3da4b4afda77007a4133a9e0ea5306a92edff4fd82a14db371407e6a67bbc644250b8200d81858858258408a3c3f38a7a598bd4b62fa4b56f92b96be3d1b7f1df1a713a3cb4978f835396f935c09b245ab312efda634d3ac4af1f843fb0577725a27579c9fd665d14c24fa5840a27f622daaf26f1047845723f20a13247ce866005f5263397082657a80d60095d81856e127e27e2fe36391c1631170ac630d3e340aed71c9cb8c323eec148a05ff8300d9010280d90102809fff82809fff81a0 \ No newline at end of file diff --git a/rust/cardano-chain-follower/test_data/conway_tx_rbac/Readme.md b/rust/cardano-chain-follower/test_data/conway_tx_rbac/Readme.md deleted file mode 100644 index 1851d2b8f..000000000 --- a/rust/cardano-chain-follower/test_data/conway_tx_rbac/Readme.md +++ /dev/null @@ -1,33 +0,0 @@ -# Test data for CIP-0509 RBAC validation - -## Role Based Access Control (RBAC) validation - -The current validation includes - -1. Hashing the transaction input `0: transaction inputs` within the transaction should match the `1: txn-inputs-hash`. -2. `?7: auxiliary_data_hash` should match the hash of the auxiliary data. - This also log the pre-hashed of the auxiliary data (auxiliary data with `99: validation signature` set to 0x00). -3. Role 0 validation - 1. Stake public key extracted from URI in X509 or C509 subject alternative name should match some of the - witness set within the transaction. - 2. Reference `?3: payment-key` - 1. Negative index reference - reference to transaction output in transaction: should match some of the - key within witness set. - 2. Positive index reference - reference to transaction input in transaction: check only the index - exist within the transaction input. - -## Test Data - -* `conway_1.block`: Block number: `2761995`, Absolute slot number: `72605027` -* `conway_2.block`: Block number: `2762138`, Absolute slot number: `72609251` -* `conway_3.block`: Block number: `2762050`, Absolute slot number: `72606545` - -## References - -* [Conway CDDL](https://github.com/IntersectMBO/cardano-ledger/blob/ab8d57cf43be912a336e872b68d1a2526c93dc6a/eras/conway/impl/cddl-files/conway.cddl) - -* [CIP-0509 RBAC Registration](https://github.com/input-output-hk/catalyst-CIPs/tree/x509-rbac-signing-with-cip30/CIP-XXXX) -* [CIP-0509 Metadata Envelope](https://github.com/input-output-hk/catalyst-CIPs/tree/x509-envelope-metadata/CIP-XXXX) -* [CIP-0509 Role Registration](https://github.com/input-output-hk/catalyst-CIPs/tree/x509-role-registration-metadata/CIP-XXXX/) - -**Note: CIP-0509 is still in process and may be subject to change.** diff --git a/rust/cardano-chain-follower/test_data/conway_tx_rbac/conway_1.block b/rust/cardano-chain-follower/test_data/conway_tx_rbac/conway_1.block deleted file mode 100644 index ee2341dbf..000000000 --- a/rust/cardano-chain-follower/test_data/conway_tx_rbac/conway_1.block +++ /dev/null @@ -1 +0,0 @@ -820785828a1a002a250b1a0453dd635820de837235735da44fef4d3dd7c810e36df43a56741f36488d43c7724844bdb93a5820087932a594533b96a2abd339715dd222835d36856ac2c0b8fcd171e3ec944b8e5820b5b14e8eb25a9366e0c1a43afcd8d0859249202f3a8dc03b13f416c70d4de7d78258408f9c0c36c36241dc497cf218bbaa28569b20da43d0dde22c42a06c7dbf9086f67a2724d3743749893edb73027bffb9382b3534e48e0210c50755b7e1c53faf885850a981acb25e4fe8018eb69799e8625a7b415d3acf8c7935a32b010018f29415ad7a0f48738dda9bb34fbaff868f777670e7b7b512b3fbe5ba3878ff16adda7f5a12c7f45f4f9a8c20cf29867534c6830619156858202de40ebb5bb7974675746077e043354f77856687144dcbeba15b5b039bc757438458208cc744c58c7a05709e02beb11b63c311687a1c1308b11e483d1c728f4f6fbf7d041901fd5840ba3364505403cd1f409595472bbf1e9e020fa331b39cf9c8a9652841ad6fe609de243d2368861351e83c685eff105f8b7bb7389d11c898cb94876202803115008209015901c080e7950464897eace2060d54656948ba519f9ce3e78eb93b29798f77940c49d17b310966cc580cd96162aa138d71c119cd8e76118daa8c3d32bf714fa6d8a409b5a92156fd374d4d912307b8652f38df7faf5608febf3599bca862c578ef7b68e1dfffb9be2a836067727899337e2be78b79913b35f7097ffb20a0972c0c5aee723debf8f922e55b0f93a194c9e8cdb21a1bcffa1ab6341e1d8cbff21c1f4d60d59a5bfc24176fc987241cfddd27e0882c3f8dc958a2a181829fcce9415554a96b5f62d71578479dd496ab0feddd385e3bfaa86229bacd1977799b7d4039f918659c7a8d73c6168d9708a4a6c10060dd58907423f0da8e79bc1024c7942fa9a20144540af7e596892aeb3057cab0ad6d2fc676d90bb4eca2bc42c84dadb719ddad18f036f0563f29eb67d7fee36b700117a243dae2732ecaafc1629cdcfb0a80c94d4f89321969289f0852d693c0b899f8f698465d7cff645879cb54c50eaa24d44fc48a79066c73c54d9438145136d161f1efdaefa9a544d3e3c35244ed941f968e917cc68a627df194e19d08bfc18482638deb4f2da42f7096d2cbc7e8b4f472f1027f53cca668252e30946f6e9ca4c3e224cd40f764ea59fe85d420b0bbe785a90082825820a8ee092381312ff15f5af09c8de5d9f75e661982873a92bf14b80c7a64d10c6400825820a8ee092381312ff15f5af09c8de5d9f75e661982873a92bf14b80c7a64d10c64010d81825820a8ee092381312ff15f5af09c8de5d9f75e661982873a92bf14b80c7a64d10c64011281825820db62a0577b70a84aadf81883f9314e5ed3f01a79429010c81875d719dcb3eb05010182a300581d7055f73a4556031cccd599cac389b4a98457c44cef77ef8647639ad5fe01821a001b9f18a1581c0c64e02d195a9a4a86a3e080ccc643cd79223b7fc45676d07cf3a802a14d446a65644f7261636c654e465401028201d81858a6d8799f5840d4d88111d26121908711b6c375d659e0f9bb1bc320912715324644f802fb01f0b9ef630c309aa38e26c779eadb66abe906d7755645ebbc73d23ed23d03b59407d8799fd8799f1a0007a1201a0002c5a3ffd8799fd8799fd87a9f1b0000019266006960ffd87a80ffd8799fd87a9f1b00000192660e2500ffd87a80ffff43555344ff581c0c64e02d195a9a4a86a3e080ccc643cd79223b7fc45676d07cf3a802ff82583900f8e2356e21af3563556c167c31bcc00f9fc061a8a852a16a42ffcc7927ce10b87147e3e19a5dc622b6a535ab9ce01cb2d586a3a690a74c0e1a8acb1ea0021a0003fa8a031a0453e0a0081a0453dd1c0e81581cf8e2356e21af3563556c167c31bcc00f9fc061a8a852a16a42ffcc790b5820d342f73527d192f78a35b8b6517964bdab319c68ad9b15ae024d323656675848a90082825820551cc8d750767bb04fec1cefed55b2ba230d769d3d42907de8dd4e2fdca901ec00825820551cc8d750767bb04fec1cefed55b2ba230d769d3d42907de8dd4e2fdca901ec010d81825820551cc8d750767bb04fec1cefed55b2ba230d769d3d42907de8dd4e2fdca901ec0112818258205de304d9c8884dd62ad8535d529e3d8fd5f212cc3c0c39410e4f3bccfca6e46b010182a300581d7039a4c3afe97b4c2d3385fefd5206d1865c74786b7ce955ebb6532e7a01821a001b9f18a1581cdab1406f1c769fbdb00514c494eed47a54c7ffc5d7aafc524cca069aa14d446a65644f7261636c654e465401028201d81858a6d8799f5840908c7e221021da9411c2951209f58ec0e5b00e2c6dbb5e64476ab9e185afd51b9c929893d36b0a8f727103fb31f981505483fbc4d3a9e95bc080362862fc5001d8799fd8799f1a000f42401a00058b45ffd8799fd8799fd87a9f1b0000019266006960ffd87a80ffd8799fd87a9f1b00000192660e2500ffd87a80ffff43555344ff581cdab1406f1c769fbdb00514c494eed47a54c7ffc5d7aafc524cca069aff82583900f0a26fc170ad82b64a3d43dede08e78ea6e2028b5101058d0263a80a4c0ec23eba3aa27a4b8d61107f59f3e0d24b7bb6d7ae1a4bbd689c8d1ab75f0348021a0003fa8a031a0453e0a0081a0453dd1c0e81581cf0a26fc170ad82b64a3d43dede08e78ea6e2028b5101058d0263a80a0b5820d342f73527d192f78a35b8b6517964bdab319c68ad9b15ae024d323656675848ab0084825820157dcc88aa4a0278d4eebd6764fdd3a7f7d53716d298d5366cb7fff5b124553901825820d8c2aa33753209ba095bb811a8cfe92a32539bdfae5bec771eca3ecd996d269100825820d8c2aa33753209ba095bb811a8cfe92a32539bdfae5bec771eca3ecd996d269101825820d8c2aa33753209ba095bb811a8cfe92a32539bdfae5bec771eca3ecd996d2691020184a300581d703f89c436844cd0acd2714201817836b2cd16b082e03e3a21bb69e5ad01821a002dc6c0a2581c2b556df9f37c04ef31b8f7f581c4e48174adcf5041e8e52497d81556a148416767537461746501581cc6f192a236596e2bbaac5900d67e9700dec7c77d9da626c98e0ab2aca14c5061796d656e74546f6b656e1a3890bbd1028201d81858eed87b9fd8799fd8799f9f581c59184749e2d67a7ea2ca31ef48fc0befb3c3fad5a88af7264531ae07581c1be17c0feca072beb5a395a286ca4bf269f74f33db80509337ff3dbd581c564b2400e0901e336538bea2eb48f0bac8aa77b0c3a948f07cd15ff0581cbd05c7354d160113edb39a32a2ce6045f48f51d5728ffafdae2decef581cbdebe65210d74725fffa6635f28ddeae6cbcd1a8aa6898ab75cfd5e3ff1917701a001b77401a001b774018c81927101a000493e0d8799f186418c81864ff021905dcd8799f9f581c1a550d5f572584e1add125b5712f709ac3b9828ad86581a4759022baff01ffffffffa300581d703f89c436844cd0acd2714201817836b2cd16b082e03e3a21bb69e5ad01821a001e8480a1581c2b556df9f37c04ef31b8f7f581c4e48174adcf5041e8e52497d81556a14a4f7261636c654665656401028201d8185823d8799fd87b9fa3001a0005c7a4011b000001926600b8ef021b00000192661c302fffffa300581d703f89c436844cd0acd2714201817836b2cd16b082e03e3a21bb69e5ad01821a002dc6c0a2581c2b556df9f37c04ef31b8f7f581c4e48174adcf5041e8e52497d81556a14652657761726401581cc6f192a236596e2bbaac5900d67e9700dec7c77d9da626c98e0ab2aca14c5061796d656e74546f6b656e1a02a74bc3028201d81858d2d87c9fd8799f9fd8799f581c59184749e2d67a7ea2ca31ef48fc0befb3c3fad5a88af7264531ae071a00838e05ffd8799f581c1be17c0feca072beb5a395a286ca4bf269f74f33db80509337ff3dbd1a00822d24ffd8799f581c564b2400e0901e336538bea2eb48f0bac8aa77b0c3a948f07cd15ff01a0081fd52ffd8799f581cbd05c7354d160113edb39a32a2ce6045f48f51d5728ffafdae2decef1a00a66f7cffd8799f581cbdebe65210d74725fffa6635f28ddeae6cbcd1a8aa6898ab75cfd5e31a0014151cffff1a00650eb0ffff82581d6059184749e2d67a7ea2ca31ef48fc0befb3c3fad5a88af7264531ae071a006e2d88021a001b26b8031a0453dd94081a0453dd1c0b5820d04e736b347a342ad321aab49d0a731d1fe97b8cadc5cfad8d0954ffd826a22f0d81825820157dcc88aa4a0278d4eebd6764fdd3a7f7d53716d298d5366cb7fff5b1245539010e81581c59184749e2d67a7ea2ca31ef48fc0befb3c3fad5a88af7264531ae071082581d6059184749e2d67a7ea2ca31ef48fc0befb3c3fad5a88af7264531ae071a00524801111a00370c3f128782582056859125fa6486f85015233788e398546004743bd6af30692e51ce7d464cc9b100825820c9a9d5b5b100c69c3eafa6cf5b9d48c8b49251bd5cf7f78496f4b90b852fbd2d008258204d3550e32ba844e8e11df2bdca827cf11eaad9f35aaee2b925365de452ceda4900825820157dcc88aa4a0278d4eebd6764fdd3a7f7d53716d298d5366cb7fff5b1245539008258201a28375b01a8928f21a87598e24165ab5806e7c3e77a5eb4d78c56e3cf07894c00825820a9baf90b688b11a30dfb0c29b8cdfda8447476a5a87dff05b451aa0d6c40be6600825820991b8a8b8f3d2423d5c7bba99b7698a7a4d68fc62681b4d8a52ff7ca2822edf801a600818258206fcd3774965658d24f131cea65bca5230b8014f0022652a978fbc4b1fffcd831000181a200583900eb21979c03eed7207020b2a0b47565b5aafb1a2c3849b59a1fa8e6c5e075be10ec5c575caffb68b08c31470666d4fe1aeea07c16d6473903011b000000024fd8978e021a0003997d0758209d9ab1f617ed24eda3f6acc4b6cb4dfc0792ef85da7cda5123d9809e3d16101b0e81581ce075be10ec5c575caffb68b08c31470666d4fe1aeea07c16d64739030f00ab00838258205a3450aa523f773eb21e3a047c61aea074d74396ca65f216bd358840d7babb11018258205c03aab3f3c954d6ffcdda26f2a84cca50170484773b15ba0c6b26f1f34dcfeb00825820862cf9c5c614b27d95f2893c77f8cba673b273d3be714401cbf1eb3fc0079bd7020183a300581d70a74ce540e819f246e6f65f3b4597daaaf9d37c0443fbcb13618a10c901821a001e8480a1581c1116903479e7320b8e4592207aaebf627898267fcd80e2d9646cbf07a1484e6f64654665656401028201d818583cd87a9fd8799f581cc91e84382cbd1f0b5e407232743d80894e7aae5bec7c835334841e72d8799fd8799f1a00058ac01b0000019266010bc2ffffffff82581d60c91e84382cbd1f0b5e407232743d80894e7aae5bec7c835334841e721a0089544082581d60c91e84382cbd1f0b5e407232743d80894e7aae5bec7c835334841e721a00a6ab3d021a0009ce9c031a0453dd94081a0453dd1c0b582091b0d6dba1d88661433fb0ed0097faa20ddc563980b6b66039fdb211cc8a30ee0d818258205c03aab3f3c954d6ffcdda26f2a84cca50170484773b15ba0c6b26f1f34dcfeb020e81581cc91e84382cbd1f0b5e407232743d80894e7aae5bec7c835334841e721082581d60c91e84382cbd1f0b5e407232743d80894e7aae5bec7c835334841e721a0079705c111a00370c3f1281825820b31179a89f31d9b08bc0f075a4661c72a31c2270eb27ce42f9d4170180118def0085a20081825820c58b6e67ad72d3e4de04c0c143b15e0e60573ea9b740cf0a8fbfafb0475d50fd584076b53453d37a56ba653f93a741805181973fb19a62e6668481e82a82296cbaf539cdc2f15d2678499abe776cccb27bdec9a0937c63f6cf3846c611aa2287de040581840000d87980821a000669651a0a708998a200818258205401b7f67442e6cc870fbcffe921d24ab03e97e03bb655a24b4f424fd832c615584023858e80006b6c668029a3de035a1e993f887f1a525ece7c3fc27491cff587655271f3ed74f9fb240aa0643091cc2ac6caccc7cdf9ef66bbbd732213409e480f0581840000d87980821a000669651a0a708998a2008182582047075e86572a64490e20b0d020f6e7a4cfa74c591ac057ec59839d30c64471745840d0bede6b68fd1dbe68b61eeb6d6c13b6f0dd36cc56ef7becd3c6e9349fa10c4ff5d6c96595b99373cb067a744f297f5cb2b1bea456e32d3c37396e43360d0a0505a382000182d87c80821a009f8e921a7f561c3082000282d87c80821a00091aa91a08e642dc82000382d87c80821a000bfb2c1a0b89b757a100828258208469288efa6f9cb49040b43dcff93f40969d72433f751afde50235012c016020584038522b52e1abe30dd9d587abbee42ffe62aaa3a7f99cdbb07a9c3e9b73a365252ac2cf78aa26cb117802ac6d7fa34f716060d526f3eabb9979e58e3b4de1dd0782582076af5530fa318a370820270031d1838545a4ceed8696510627563d1114d4182b584007230be41958bfe1a41c9de16f804f1f82cb6ed1de7947b07eb4683bd94204c07f2b02ff9c8b74a5420a664c56764d4983154ec93b946778707882b839aca805a200818258206b7e1b2d051ed3f4651688ffb184e6d0b415b0b3025ef63c57d231404a73564458403e7e6eb19d2377c2603e1df5f5ca96bf9443203547d60ab19494ece629785fac0dc7c4786fc1f7b8248246a356e8a867cb23fbce48d1984c0187335ba1fb7e0a0581840001d87980821a0012c8941a106a99c6a103a11901fda50050ca7a1457ef9f4c7f9c747f8c4a4cfa6c0150226d126819472b7afad7d0b8c7b89aa20258204d3f576f26db29139981a69443c2325daa812cc353a31b5a4db794a5bcbb06c20b9458401b03060066006fd5b67002167882eac0b5f2b11da40788a39bfa0324c494f7003a6b4c1c4bac378e322cb280230a4002f5b2754e863806f7e524afc99996aa28584032f02b600cbf04c6a09e05100880a09ee59b6627dc78d68175469b8c5b1fac141a6da5c6c2ea446597b6f0b6efea00a04ac0c1756455589908a5e089ba604a1258405917d6ee2b2535959d806c00eb2958929ababb40d681b5245751538e915d3d90f561ddcaa9aaa9cd78a30882a22a99c742c4f7610b43750a0d6651e8640a8d4c58402167427cfa933d6430c026640888210cd0c4e93e7015100300dcaef47b9c155ea4ccb27773c27f5d6a44fbf98065a14e5f0eca530e57082a971cbf22fa9065585840ae72e2a061eb558d3fd7727e87a8f07b5faf0d3cedf8d99ab6e0c845f5dd3ce78d31d7365c523b5a4dfe5d35bfafaefb2f60dd7473cbe8d6aa6bf557b1fbdf775840bf96bcd3ffdbfc7d20b65be7f5c7dba1cf635e3b449bb644bdfc73e0e49a5db73edddc7ed331220ba732f62f3aee8503f5c6f9bd5f7fedb37dc6580196052e50584027fdd7e8bfe9146561ad1ebc79ecef0ee1df7081cf9cd1fd929569ef3d55972d5b7ff882ce2213f789fc08787164f14aa86d55e98e332b220a07fa464aaa7c335840ce4bcfb268ed577f72e87fdea4442107bf2da93fe05121d5befa7ae5aecc5f3f9c732e82108003166380198c0146b0e214114a31d7c62b0ec18afd5834034c2b58402b2c515b350d8980a16932071b6d8d125ea1eb53dc28a8aee1787a1670b9e8c4c8cb00c726f3515a39ca1689f870295752820a64721e05e1a234710583416316584031d80291ac9a2b66a04cba844b85f9928a4a04a9928b2805124a25b3aaa4422e45e5d422a9b88a028ba4a5123ac244b8b472164b86085ac21357c3aae7696be25840f1104878009b03813d9e6c53255722402090206058a009d2b808aff772fb712d75f1dea09507fd83838e045dd9ce3eb59e4554f5ed02b8aeb60700f4b39dd9fe584064e1d5a137de0fa4c6cccfd71f831bee372756d72990b357a44e2f9eaf3854db65379db466cfcb55517ba71550acade564f4b7efd1fd95fa57228cee6fa9ae3458405ce1ae79b77f7cd5bdecfcb800fbdb7eaf720eae5995176d94a07c326c71aaf5e6f8439e577edb2d1ed64959324b5a7476e9159bf37bdf226edb747787b79b9e5840bc6ab5b84714eefa4a8c2df4aba37a36757d8b39dd79ec41b4a2f3ee96eabdc0e1f65b37264bdbfdf79eebbc820a7deab4e39f7e1cbf6610402fd8fb55fbef3d584038226e4d37c42970c830184b2e1c5026eadb9677ae8f6d300975ca6ceec5c8920382e827c1f636f7dd9f8d492737f4520a944bfeebba5ca2d5efa80ad453a43f584004c357ecccfc4dab75ce560b0300db9092ced52625d0c8df6fc89da9a45b6dc9c2461f21e6ee7b7afd877fbd8c1a1fa7ff38fa506e14749ebb68e24571c6220c584004208c284d628c2148b252f91b8b50014b080b040554095b52ca862bb974218222d412112ae5d2584c54584ae157f22b183cb4ba9c5fc42ba6894ad074ffe0875840c69ee921211d0ce4cd0f89b7e708163b3ab9286fe26a8c68ed85930cabc5dbfed7f9681c535dbdbfeb56f7a2b32d1f43de1dbcc934676edefacb3df7c1210067584064a1b8d94448b7f22a77dc736edb12f7c2c52b2eb8d4a80b78147d89f9a3a0659c03e10bbb336e391b3961f1afbfa08af3de2a817fceddea0cb57f438b0f8947581e9782ee92e890df65636d835d2d465cc5521c0ec05470e002800015eecf5818635840e0427f23196c17cf13f030595335343030c11d914bc7a84b56af7040930af4110fd4ca29b0bc0e83789adb8668ea2ef28c1dd10dc1fd35ea6ae8c06ee769540d80 \ No newline at end of file diff --git a/rust/cardano-chain-follower/test_data/conway_tx_rbac/conway_2.block b/rust/cardano-chain-follower/test_data/conway_tx_rbac/conway_2.block deleted file mode 100644 index d38c51b88..000000000 --- a/rust/cardano-chain-follower/test_data/conway_tx_rbac/conway_2.block +++ /dev/null @@ -1 +0,0 @@ -820785828a1a002a259a1a0453ede35820b2acff53e862876989980fe9cac80548c2c3ed417951324c54d69b4d86daf5da58202f5ad4772c00767b6d75c8c1fae31e3479d91921abf41b1989346d2896b61de258201003b81af09c4acb552e0fbb33ffe12415360f2842c0e020b11b09cb82f7c5e48258406db3ca895414ace8710f345f8e93536ef2f24d7d6d2fb29e50a8844c83fe2eb5f64aa72968d70d681f9b01f4fe7332ce675a6a809448bd6b95c1f5cb2c86011c58503bb668495b649f05239672b7b8eecf33bec1cb060d1bdf5a1676fdd4b03d4218e6e6e41c87ff6f22759ccf4da65caffff14c1099ea7d4e2b56f76de67f33d80e72212e7a709db122a7ca33ea53690c021914ae58206fc671bd90b0d6955b8f48e9f8195291ffaedadd191d77884adc695edadb4853845820873bdd3584228477e9d9ee6b60a9cd6000627acf154126162178860ba752e9cd0619020d5840e461305c25b0690c1001e96f882d51c3a12ca32bae4cd25f9f46a98a0e9a7fe9b43ed108f230393c474444ce5ea88cc1bd299b94e7a60795d883e0a16004c0068209015901c06bb09e2dc5ca2e8e8b4124323489a64dcfacb9f80db18c6ef99f74a700d033b44fa89ebd120443c94312a92b9cf6e59c49541649c9e2e1d51d3ea16679d9f4078efa53d0f18fde0a05b87670b6f58d8d1e749f02f193d4d6ce790c21ae001f1550d19b5a842060a4d5d0120e311886a172b74585f7dac0ed59d1ec45f66ed0c760458b7616e67b0df1b5539d0eaea60f0230b5c9e50097c918559a85d57111b13b230b6f222b03cf501ad53911235154a7f0dd6970e7a3a16036d351b4aaba08cf2dff5f669ab4795ae5484935ba59e01116e16dc84b1eed1a4613ebc17d3f8ddda8113b492fcfbc85edeee2191051abff6a6f91d4295964764e8696623ac78ee14e248a3bdda80e04c28e0024f3922993bd4642d92de6c907ed6f0f9371d8d7a7c4c45091f33b1389b0aeedf05f33c9355196326f06b6264c3504d60c2fc790044f7d3ecfbd9dbe013ea5dbd3c2b7d572dab25512dad0dae1cb96a49a0d3b1b6f5c6f71d4118b6b032db7096e4044d6fb78861cfd0187475ae7720782a881555e93cb843f7db6a80ae06161a8d373325fd19a0efcf6bc4c76635513353213c1d9d07e1fa563adabd17558a2ff1fece92c75a0957b3592ac2816f4fd9ad8773d87a500d9010282825820020363f4cfc9f3a1b7594e064e74f5d9de740e25b246de6b01d4f18c931c99b318198258204567c47047668e8f0bd8f536bbca83b1de2fefa9148fb25c45d08859e29122a00001828258390069241e2a942d7b68cb729426261c1b0826982443a6b0702a7665e98979e7d3f2262b8b84c28cd004f11c89d98bd515ee0af810b9c369034e1a00596d488258390019c0438fe64e704bb98508e75b156fddc62d6e579c77d86ab67ca5af79e7d3f2262b8b84c28cd004f11c89d98bd515ee0af810b9c369034e1a007974e7021a0002bd51031a0454098f075820e84a468c26df3ac2f928642aeb3b85bf2609ff7f48888cb37b5a7d7edfd0ad8ca500d901028182582098069e04919bc65917e47a4e9027e0f65cd56ecc9779eccb0a9cc29fe17e171f182201828258390069241e2a942d7b68cb729426261c1b0826982443a6b0702a7665e98979e7d3f2262b8b84c28cd004f11c89d98bd515ee0af810b9c369034e1a00596d4882583900b1d55f9f64c24cfcc88aa5b49db76ea43386b35b7f2e80966bf37ace79e7d3f2262b8b84c28cd004f11c89d98bd515ee0af810b9c369034e1a002d4133021a0002a5c5031a04540993075820fc22a7f998d4a138fbca3bc375f6f2ec040152b965369c8997b90d3439b6c9b6a900d9010283825820b3458ce9b7e9f45d5a6c34ed20105fa899fcd5b8fe19d82a7468c88cdc64fc1504825820ca98a9e90895b7e8af44e48ea7b0c3ed837c5ed0c0802bc3f5bb4c35543351a001825820ca98a9e90895b7e8af44e48ea7b0c3ed837c5ed0c0802bc3f5bb4c35543351a00501828358391044376a5f63342097a4f20401088c62da272639e60644a9ec1d70f444358a4e4105c08f59e4779070699c7a72566893332f9857db4e742beb821a005d1420a3581c53827a77e4ed3d5c211706708c0aa9b9a3be19db901b1cbf7fa515b8a15820c76aa2e728cac2a3b9f61f88f0fdc6c603c367696596fc1bb6746983bb9f135701581cc6e65ba7878b2f8ea0ad39287d3e2fd256dc5c4160fc19bdf4c4d87ea1457447454e531a02a8ec66581cf03eca9ebdd30db76c5d5c0b450c97bbb4faccbc67cbf683e483197ca145745553444d1a03db7e7258204e86ed215442ac3225e8b68e43d4942be391c1c165e224ea1cdcaaaac3d070c78258390078886065c99d810efddc589ffb760821e57314fd3760263038a12096f3213e19402ff9bd59d0c506a727c34ae4b12ad5eb9c9706def94db8821a35a33db7a2581cc6e65ba7878b2f8ea0ad39287d3e2fd256dc5c4160fc19bdf4c4d87ea1457447454e531a00d74746581cf03eca9ebdd30db76c5d5c0b450c97bbb4faccbc67cbf683e483197ca145745553444d1a1cbd7691021a000615140758209f7a0691b5cd8c61203de22560c3290776c33d6f4de92717d6ef9a813d9228620b582057dd2ba2828bbe242b69bdd76b11474b997107d19691d9f518b1be9954fe7d210dd9010281825820f9e68746ebb05beba703c12fe31c97a9605196a5bcbf470b4d66210bb4122aac04108258390078886065c99d810efddc589ffb760821e57314fd3760263038a12096f3213e19402ff9bd59d0c506a727c34ae4b12ad5eb9c9706def94db81a00432ba2111a00091f9e12d901028282582016647d6365020555d905d6e0edcf08b90a567886f875b40b3d7cec1c704826240082582016647d6365020555d905d6e0edcf08b90a567886f875b40b3d7cec1c7048262402a60081825820e33e183249d63e516c7f5ec8b41c89d4fc9d24b2626c441407a6e78d0784e95d000181a200583900eb21979c03eed7207020b2a0b47565b5aafb1a2c3849b59a1fa8e6c5e075be10ec5c575caffb68b08c31470666d4fe1aeea07c16d6473903011b000000024fcdca3b021a000399d5075820377701c2f4f80a44c251a3bc8e5e12244cbeffa5c26d9a959a93642916d2bf890e81581ce075be10ec5c575caffb68b08c31470666d4fe1aeea07c16d64739030f00a300d9010281825820beb5f158de66dda9a234e887c27eb6aa0961afb9d142445bb30a05f0a0604bec183d01818258393040fc34adeda87d8eb4c7f3bf1b811b95fa835d356aa129a0089822a4d448965f62c0afafd791b02435b2dca9f6215df84d3c30a5ae35da261b00000002540be400021a00030d40a500d9010281825820fe63bacd187869d23260b844e7c6ffab508b411786156c0f0265ecc99593ff81184201828258390069241e2a942d7b68cb729426261c1b0826982443a6b0702a7665e98979e7d3f2262b8b84c28cd004f11c89d98bd515ee0af810b9c369034e1a00596d4882583900dbf48c2c653ad449fcb447670692bad9d9e28689f59d2f5aff908f4d79e7d3f2262b8b84c28cd004f11c89d98bd515ee0af810b9c369034e1a0091e8d7021a0002a5c5031a045409ff07582065e215890ab4d0ed1e1c1386d3d4b56fa1db85cabed224fcf4da3fe90b8d5f9da300d9010281825820beb5f158de66dda9a234e887c27eb6aa0961afb9d142445bb30a05f0a0604bec183e0181825839007eb505be585918dea709480a7b3ff664c72b77f28e8337e7c92d71e16de8be2814a24b0f2bd8918faf3d07685078b94e14303d5333ff4cb11b00000002540be400021a00030d4087a100d9010282825820081397fd90c2cd717f732e85b9df6a60f258b468e633583b6e847f27c6238fcc584067d605eed13606c8298ea57176e0396af8a601e4321866a59c6b970c16ab777faf192a20471278d7e118704a0d13d7d1449b5b9082bdad0b8c6a343a6cbdfc0082582079d1ab518df51b5584ab6710e9b06f72d7d292008252aaf20b1f00821ba392655840f3e981bec4eee7d8d9afa2c9d662b4071f46db5a8c9384a63a766a8acb355cc60faae6b50b2ab64772ef65cc756c40b16174368fde166ec1fe08ac240bc21d0ba100d901028182582079d1ab518df51b5584ab6710e9b06f72d7d292008252aaf20b1f00821ba392655840fbe829ffb25dd94bbed898eb5c6f7baec81731641073c864c516348ea9bc98e1b60e1d33859df31291c11bd1c0bfff5d79988681657117c6f9651fa97c72600da300d901028282582025333b67631e94b6c5cf329fd664eb8952d9521901863b07930892b5b1b793c65840d216f8ff58a379a5671bd741b0791682a5729426d41dd1feec26ea3dd1e739fa9e9c53ef7542fdd74c2da7e1e4fda98180b82e4b6a4909bb09ba70b7c243a307825820e8ad851eecf7d7af03934a076dde98241f081b7dd2a482309018fcbb24404ec5584093cd8d4fffe095596f008e5a5aa301a59768ad3a799cba3b2e2724e8bbc3ec9617b4c90e393555792a7ea85616840f5a3f38d3148cb025ec9a343e7afd1c6f0c04d9010282d8799f581c25195af85c41b9d97da7f4f215d3e74c9cef7f04739d6ba473ba72a2d8799fd8799f581c25195af85c41b9d97da7f4f215d3e74c9cef7f04739d6ba473ba72a2ffd8799fd8799fd8799f581c358a4e4105c08f59e4779070699c7a72566893332f9857db4e742bebffffffffd8799f581cc6e65ba7878b2f8ea0ad39287d3e2fd256dc5c4160fc19bdf4c4d87e457447454e53ff1a077359401a02a3338ed8799f581cf03eca9ebdd30db76c5d5c0b450c97bbb4faccbc67cbf683e483197c45745553444dffd8799f0405ff5820c76aa2e728cac2a3b9f61f88f0fdc6c603c367696596fc1bb6746983bb9f1357d87a80d87a80041a000f42401a000f4240d8799f1a003d09001a0005b8d81a0001c6b0ff1a03d9b7c2ffd8799f581c25195af85c41b9d97da7f4f215d3e74c9cef7f04739d6ba473ba72a2d8799fd8799f581c25195af85c41b9d97da7f4f215d3e74c9cef7f04739d6ba473ba72a2ffd8799fd8799fd8799f581c358a4e4105c08f59e4779070699c7a72566893332f9857db4e742bebffffffffd8799f581cc6e65ba7878b2f8ea0ad39287d3e2fd256dc5c4160fc19bdf4c4d87e457447454e53ff1a077359401a0361efaed8799f581cf03eca9ebdd30db76c5d5c0b450c97bbb4faccbc67cbf683e483197c45745553444dffd8799f0405ff5820c76aa2e728cac2a3b9f61f88f0fdc6c603c367696596fc1bb6746983bb9f1357d87a80d87a80031a000f42401a000f4240d8799f1a002dc6c01a0005b8d81a00015180ff1a03412142ff05a182000182d87a9f1a00bebc20ff821a000f49ff1a13bd0568a100828258208469288efa6f9cb49040b43dcff93f40969d72433f751afde50235012c01602058404a54c5c6b967a7c10fb561b63b898759faad058302fdc8b964d68b550cc5ece049b379ade714d07170e19c030c93c809bfd8568b24a9183f1e6939ef368e1f0182582076af5530fa318a370820270031d1838545a4ceed8696510627563d1114d4182b584057bf74e35d877b23ddfa939d6efcf157c09e3df9a4d5960f30fc64b6931e15e7d9caaa02451c9895644bafd3f36b5caf4a64a80668d21b97099943ad11eaec0aa100d901028182582045a35a111726f809cf2c33980ca06e45d29db1b06153c54e6eaafb6e4abfb2e958405909ae97282b146c27d506eca06e4a986703e4a5171c2a11c4896649768df5fb08a2f5b91db0766f2fca122ad981b271281e074f6fc4a8c36c804702e4fa4009a100d9010281825820d8229d65d9939ea5113366904b94715a816b9f21b128c4a95b6d15fc29032d265840455baffb3b01684ce9b461456addb02a3b7c35a182b92b7557178d161585236d19c682696c2839df4f513ee2906c5fea516f8c0d460a6c5e5e6cd170b0195d03a100d901028182582045a35a111726f809cf2c33980ca06e45d29db1b06153c54e6eaafb6e4abfb2e9584077feddb21c3d1ccbb7a23489febea4456c541f63fb7f32ba2ae0d79765c9f540edc229677fb2c067a08f2396fef7fc04c670e58267848efea4344fa977258d04a500d90103a100a11a000bb3f4a16376696478403938333831333164336462346535316531626237616232656334613661383037386334393266663637383062393932366435383030646466306464346633613601d90103a100a11a000bb3f4a16376696478406136336433636264333238643834326465373031633132363339393964613066633831393534336564326363636437363363643530633032383764373466623802d90103a100a11902a2a1636d736781781947656e6975735969656c643a204f726465722066696c6c656403a11901fda50050ca7a1457ef9f4c7f9c747f8c4a4cfa6c0150616f4c5a8adc62d5634102eeb7faea6f0258204d3f576f26db29139981a69443c2325daa812cc353a31b5a4db794a5bcbb06c20b9458401b0306006678baf9873001af26aafd1674e5b11bf549d4bea0a39bfa0324c494f7003a6b4c1c4bac378e322cb280230a4002f5b2754e863806f7e524afc9995658406829cb08ab014e580e707468318ac0086262ffa6d3039a557178a3c556cbee076b44163b02b2812e49d3ab27b5e7bb2e0c6b1321d042d1069a24b4884032468a58400a28c6c0b0af3474b476028a193051b0641d5d778162040c24d7d2d1cc925f3d504c8171e5b4757466bc5104a11147eeb110f17d6067ae4b0d04a1d4200a3590584042a59443fca0277bc8e0b053c8101ca338ac0fe93e702d048761686fe9bdf0d511e472c6bb85a27f033a24d745712b933dbe1c51141d6309d9cb4fa9c41f2acc5840995aa78f9877abf5fe4c55fd4ed2120cbfde107fcefdb363e0e2e35774f7357a6ec99ada7c55e70497f29bb3e860cbe05fd8b1e3e6f6193b3853ad6afcfef77d5840afa5ef4cff767e1fcb1e347afdf176f2f3acd76e99d65d192fff1c3eb37eefad4f3777dd744fab80b466fecbcc79e11670e3d281afbf0e3a3f0b5e8d30e217eb584092ffeb8ddef4c8b073d44ddc36f3ef6ed1df5461d4428bfbf43525effdb557aedc74ecb2d1522bdfd9b5696059fab43568cfdaa6dde757a7d58f8d4ca773a2cb58402ec92e8406f6aa7f8607fd795394c13ff26d79eb613f96cc50fd7acddef25f3f3cabae20280cc1cb70d806e0b005509e25a145b68604e551a03c844733c00db25840c212b5b5d3900818fa2673b0d1d32e6dacf77e8a1b755c5eb8bf7f1d8d864d8c9a0c706c8a000b64626162b10034d1a4744c28573452f9342c50c20a0e0e0c695840080e138ae55c9a24180b0992d2028040ca62f3f91c85985a27a5b243387496428629021a64120e1588654dd2207e089f16c80c0d95f3852d69947081f679dafa584004028a101f005b207025906daae14d828944320a0f0b31417a17114c5eee3a65a02b3990b0e6486c62c2f104d5aeb0b39b5844b5df2e0c0df43c80d19fbd21bd58404f96a827de443e9059867cbefe18d97cbf339fdba2e45f50c93c5e3c5f7db479c0655ec1fafd2fd7661c98a744b39dede7647efb9e39ca3655a559dcdfce659b5840aff6d5bf3b3a6bedbdcada9c38d7db31afaa8eac5f5b936991a779266559b1e3b6dca3feaadf2ecb268d8a962f202fbdb042e574e9c05bbecf4ee37da9bdd6675840d40ecb86c4a9deaf24f892989600ff8e816f59e7fa4f3ec854f6dfddce3d001febbd75634e536fec818bfd2a4c14d56298fbf4e3ac29b3b8a0ba035f0dffde0358406939eb07d1f03ab732b39985f5639a24536766ffa6ec36ab648ff2ce619c223d2ccc7c92e8ea74dff7d94cd99ccdc3d43a4dfa7f63afab81adbb39f126cad2875840482ae68dc83e43f47e9d1418764ea2f7afb3a2a34b177f43ee4cabd4617b053ee311dfd677ff70ece4af9719b36605fd38f15061917089b674f68b69654b71045840467192ac80318630c94ae56f2c163436b11a58805dc71484d2316aa8284c2ce38a25f40601d6100c42802c8015868582c05045a83c882e14622209b734969068584057bc65eca05168123b2db2fcc886fd6bafcddeebf1c2573515e1aaff3981776ce9a7339f12e6382207df6f3c7e3df750de8f58d753bf33ba2877a4ab8e5e5e435840b6b053deec20963a4430ddf75fdcb9dcb77ed9eacb5e3c5d6123d5546afb286165f8e1d4258365b73c2d3cf0dcd75f30e5a548adf83f176ff527bbbe09cc1dda5820334badf960b27d7aa97150b5db2ac882a65c014130ae05210b0075d0a2fd8c05186358404d9ecc0d2e40dba79d29e8c1f8b264b93ccbbb60a49ef419e12827196991aedfddfe44ca0388415b708579c060fd8047d96e6d68a0d7b8f2e6a3b9448fd53e0905d90103a100a11a000bb3f4a16376696478403638393139396437303165383961333138336536336230383336653230373062343131313538333139396562326237393934633038663762663332636365383380 \ No newline at end of file diff --git a/rust/cardano-chain-follower/test_data/conway_tx_rbac/conway_3.block b/rust/cardano-chain-follower/test_data/conway_tx_rbac/conway_3.block deleted file mode 100644 index 09dd13e19..000000000 --- a/rust/cardano-chain-follower/test_data/conway_tx_rbac/conway_3.block +++ /dev/null @@ -1 +0,0 @@ -820785828a1a002a25421a0453e3515820ab3904be7f5116a7ae4ffb8749b06ed1a6a09f2abdc0828b2b9f6b9621e45bc75820ac16ce463e6697d7b49bd22add462f092d9f6ceb808f74a4ecdbd8ed4ae1bbd758202596aa11710a0e31e9b3a8602005df3560a1d78e2f57e0dac408d205ead1835c825840765bb637312728cc374a634017e65c5fa8f6a477106d5c5ffb4620c847d417d0be21f88b8effdf14aec3cc632bd8016f504b6cd1a28595fd079bb64237d294cf5850e2be622ef7ed6d351b064f6f7eac04b2487a3320d3b1a7fc10481463abcf642e3b0b3e3e6aa88dc2adef6ab24ece460921bc5fc087d398a17c3bd89c93a825a68ec451ec589b199cb0019d20fd765801190726582036eca374937cb8fe6e5fa8c30a1af65ab42e2c18be80fdc793e9b224ae3efa788458206f897ea416c6817010ce15d184b1692da860fa1efce2dc87edf9ff517447c1b80919021c5840803cf49927cd22d4a68a6f4c91177d0478de2c33974870e20168ca5ebd6e7e49de2a615a3aeb3f38d9906ee20e6d86ef70f82a98247fa2d6998bcf252884260d8209015901c055a847c305997bad4458d8e08f53fa97fa99520ac46fc80834888485ed928476bc1c5b2a21d8db8fc85f258b8e09d1b45db0688edbba85ce836d7dd40345d40c5ecc67ae0dd6446c97071b3ba1ec6b71fa8f44de0d157c07180a83c043d1c813437ae50016f77e01a105d0e189020138f0b3427785c40a716e4310fae99bba5cd0d981a0ca5e9ca103216d71f4c03da7dde73b3d532a0c72d1986db62b4aeb037a8fba11119ec1154db04df51bc8c62a8ef1d035057970109c78378b47debdfe9ae2ecf9a35d15804db55ac2749c48e80b2e05312b734333484401eede425978e7ae6994c271c92f392a89ca2a6e419d4f9044aadc74baf32568067520db3f74543165ee22b69b57acd21ba4f3c762196a045d34c37274f33ce483666e42d149afc97e8495eb1ea5804c38d3fd728c5550513d1f20f26090dc67325315b71a0740a81c259dfd387e7dabb52d89baf37c5ed526a52b8171974221794d0db0213d224a7e68209452f3eed343dc3ac76107681efc39126d4133ae07f43232cd3fab7369a4238b74638c7ea0aa0c92468f2b9fb09275f8099fef584b15c62f700d91f857670868cbea6fd6bc409b37448efa78cc6b6b25a9ab4a8bdc6ed7d1d6bed481a60081825820a87b4642a59eba961124544a483d98568711284d8652e65105b051a6777e134e000181a200583900eb21979c03eed7207020b2a0b47565b5aafb1a2c3849b59a1fa8e6c5e075be10ec5c575caffb68b08c31470666d4fe1aeea07c16d6473903011b000000024fd4fde5021a000399a907582079af25e1de0c8377fe74ffda579a5a121b58511f78c6cb80dd37dea97cd123d40e81581ce075be10ec5c575caffb68b08c31470666d4fe1aeea07c16d64739030f0081a100828258208469288efa6f9cb49040b43dcff93f40969d72433f751afde50235012c0160205840fbfdebfa5d695157394d1306fb369abd4b8d541f7686d8f5ec0cdf00262cedce6379b9fdd18fdef149be17f5ad215b08ec0e96cd9f7ebda8a6ce77fdeb84e90a82582076af5530fa318a370820270031d1838545a4ceed8696510627563d1114d4182b5840ee532d8f465da42639109a93a21a4f693d65ba71e5326f8a34ec2f5d82c1b29fa23ae9213da417f3ba1507c592b7087819183722630fce4503c90f6953cb1d0ea100a11901fda50050ca7a1457ef9f4c7f9c747f8c4a4cfa6c015060ab06a8774b60aa1b1389f7a307a15f0258204d3f576f26db29139981a69443c2325daa812cc353a31b5a4db794a5bcbb06c20b9458401b03060066006fd5b67002167882eac0b5f2b11da40788a39bfa0324c494f7003a6b4c1c4bac378e322cb280230a4002f5b2754e863806f7e524afc99996aa28584032f02b600cbf04c6a09e05100880a09ee59b6627dc78d68175469b8c5b1fac141a6da5c6c2ea446597b6f0b6efea00a04ac0c1756455589908a5e089ba604a1258405917d6ee2b2535959d806c00eb2958929ababb40d681b5245751538e915d3d90f561ddcaa9aaa9cd78a30882a22a99c742c4f7610b43750a0d6651e8640a8d4c58402167427cfa933d6430c026640888210cd0c4e93e7015100300dcaef47b9c155ea4ccb27773c27f5d6a44fbf98065a14e5f0eca530e57082a971cbf22fa9065585840ae72e2a061eb558d3fd7727e87a8f07b5faf0d3cedf8d99ab6e0c845f5dd3ce78d31d7365c523b5a4dfe5d35bfafaefb2f60dd7473cbe8d6aa6bf557b1fbdf775840bf96bcd3ffdbfc7d20b65be7f5c7dba1cf635e3b449bb644bdfc73e0e49a5db73edddc7ed331220ba732f62f3aee8503f5c6f9bd5f7fedb37dc6580196052e50584027fdd7e8bfe9146561ad1ebc79ecef0ee1df7081cf9cd1fd929569ef3d55972d5b7ff882ce2213f789fc08787164f14aa86d55e98e332b220a07fa464aaa7c335840ce4bcfb268ed577f72e87fdea4442107bf2da93fe05121d5befa7ae5aecc5f3f9c732e82108003166380198c0146b0e214114a31d7c62b0ec18afd5834034c2b58402b2c515b350d8980a16932071b6d8d125ea1eb53dc28a8aee1787a1670b9e8c4c8cb00c726f3515a39ca1689f870295752820a64721e05e1a234710583416316584031d80291ac9a2b66a04cba844b85f9928a4a04a9928b2805124a25b3aaa4422e45e5d422a9b88a028ba4a5123ac244b8b472164b86085ac21357c3aae7696be25840f1104878009b03813d9e6c53255722402090206058a009d2b808aff772fb712d75f1dea09507fd83838e045dd9ce3eb59e4554f5ed02b8aeb60700f4b39dd9fe584064e1d5a137de0fa4c6cccfd71f831bee372756d72990b357a44e2f9eaf3854db65379db466cfcb55517ba71550acade564f4b7efd1fd95fa57228cee6fa9ae3458405ce1ae79b77f7cd5bdecfcb800fbdb7eaf720eae5995176d94a07c326c71aaf5e6f8439e577edb2d1ed64959324b5a7476e9159bf37bdf226edb747787b79b9e5840bc6ab5b84714eefa4a8c2df4aba37a36757d8b39dd79ec41b4a2f3ee96eabdc0e1f65b37264bdbfdf79eebbc820a7deab4e39f7e1cbf6610402fd8fb55fbef3d584038226e4d37c42970c830184b2e1c5026eadb9677ae8f6d300975ca6ceec5c8920382e827c1f636f7dd9f8d492737f4520a944bfeebba5ca2d5efa80ad453a43f584004c357ecccfc4dab75ce560b0300db9092ced52625d0c8df6fc89da9a45b6dc9c2461f21e6ee7b7afd877fbd8c1a1fa7ff38fa506e14749ebb68e24571c6220c584004208c284d628c2148b252f91b8b50014b080b040554095b52ca862bb974218222d412112ae5d2584c54584ae157f22b183cb4ba9c5fc42ba6894ad074ffe0875840c69ee921211d0ce4cd0f89b7e708163b3ab9286fe26a8c68ed85930cabc5dbfed7f9681c535dbdbfeb56f7a2b32d1f43de1dbcc934676edefacb3df7c1210067584064a1b8d94448b7f22a77dc736edb12f7c2c52b2eb8d4a80b78147d89f9a3a0659c03e10bbb336e391b3961f1afbfa08af3de2a817fceddea0cb57f438b0f8947581f9782ee92e890df65636d835d2d465cc5521c0ec05470e00280ac54b83f630118635840353ab6bd8dee46d19c9f0f19304e5088a9d866cdfbb13fb8c517d3129978b8a78d447201df75b604ad0b144a7e7f11cfe6ba70980c7bab8d4af158c90d39d40980820785828a1a00291dbb1a043840285820160ea19fb19f00088e2ef986fa354c958f0f40db89d29c32f188e5247a410736582054ca56226c90d5544bf6f558026b814027b634e60de0bc215237944110569c6c582037d6147adbf2907948d66f9e4751774bbe9d6c4ad562ce04ef66f0fc1e7ac301825840f4db3a5ec9aabd655c9f651071036626a368e855152897a01115661660f32b19bb406669ef359e30745c48dbe4872e1f5d110191de27d750230243f6150494f758505af67e52747541a74c5b13d1d24a4706fe7c84ce254b1eab283e1f38fe1398d055ce36a4ba4268d67ce1ef84580f093bc671dbbbf5887f96c2bf192ad1bb3d8b97765cdb927219f3e0988c93bbb0510c190f2b58202f98cae65753f272fa96ba2a7ab566f4aa81356e97c1800b57f6246fc193aeb5845820579c45732473db77b8acd430585aeb79ccf7e76b7b118f1e7302291a2cb3d958071901ff5840cad68c6ebff25b637335d3ea1647707cc0e91ecdbc00f1e4a8e3639f1879a5560d50bc948792d43dd2d7cbf54c3e188df16c7ad79f1f78ad1ec760b0725fbe0a820a005901c0f98f0569ea6ff5df6d3483aaa68e195ac1866edb28b03499a0adc8b2655a06855d69b15c39e94d13db695281a6249a65d175d37bcc029c422ba3cadf2afdde070f5658ef64058ab83e1435b5066a132195fba0981f76c4badaa93dd5cbe25a7028efed14eefadf9988557610d4e875a2d9375d25e5fe2939ebf23a5c44c0e4be7b107dfdc93a3b21c6a87ff9b46f69b65c53a204e5ead4fe9b1ae756e7a2755fd5a6dd9b4b67bc511479247eab6089e0eb17fea1eca7ac5fcd03dad404798a3067a2669d5eba8c3d762de40b42157486cd99746c0a021c213054b868a1f35f747933368ec3bd901b18ddddc09918d9d3562dfb425c9a3f442929c71ea09984f9a2d1f9a5f67016b07c406f319e9bda78158204f8641c215e9d6a726f1bba21ccf82a241e31ecf24624e95d5c82b42bea18435946706671969b91157f2071609c3cbb4b5e944e4829392e85b6c20920072ef246d1c9aec109331fc83c9f1d4b07d0d012547f82da0b83d514e2981186cb2d6b6e392c57465010414ae32bcbaf60f5e77e321a6a78b24e4ad9c44d5e6f1dfebb74d11d470cfd77d05848bab980308cdfd157edbc572c75a2f2c6462c9351607e1e7a944e9d0b41e1bfd1ef2dbdb387ab0083825820c3ad11a79c6b2b131fd37fec1f85be7dda6d5e8891f7523377008205ad6122b002825820ddebcb766e4902dc1b2537178875ff80da782402858254e994c9b782aa1dee3b01825820fe7258dd047bd4bb15641c1589ba9c9e5ebeccc689d2b01ae4210613f4d52d5b000183a300581d703f89c436844cd0acd2714201817836b2cd16b082e03e3a21bb69e5ad01821a001e8480a1581c2b556df9f37c04ef31b8f7f581c4e48174adcf5041e8e52497d81556a1484e6f64654665656401028201d818583cd87a9fd8799f581c564b2400e0901e336538bea2eb48f0bac8aa77b0c3a948f07cd15ff0d8799fd8799f1a0004fc6f1b00000191fa22918effffffff82581d60564b2400e0901e336538bea2eb48f0bac8aa77b0c3a948f07cd15ff01a0089544082581d60564b2400e0901e336538bea2eb48f0bac8aa77b0c3a948f07cd15ff01a006f2857021a0009d160031a0438406d081a04383ff50b5820d5adb9576273dc98ae443e7248d3ba5a35ba7befa01b37ead68c0810aa40882e0d81825820fe7258dd047bd4bb15641c1589ba9c9e5ebeccc689d2b01ae4210613f4d52d5b010e81581c564b2400e0901e336538bea2eb48f0bac8aa77b0c3a948f07cd15ff01082581d60564b2400e0901e336538bea2eb48f0bac8aa77b0c3a948f07cd15ff01a00524801111a00370c3f12818258201a28375b01a8928f21a87598e24165ab5806e7c3e77a5eb4d78c56e3cf07894c00a6008182582030133b1ce7dd59fedcf79adbd0012f7fab64bc54d08ea9621e0df25cf18ac656000181a200583900eb21979c03eed7207020b2a0b47565b5aafb1a2c3849b59a1fa8e6c5e075be10ec5c575caffb68b08c31470666d4fe1aeea07c16d6473903011b000000024fdc310b021a0003372d075820aa05878c56074cd1241e91b49a63ef718988ff544c596e44521f1a8dc6b387650e81581ce075be10ec5c575caffb68b08c31470666d4fe1aeea07c16d64739030f00a500818258202d9559bceafc74514c59ce55bbd9e2bec6dc31790f277d4aba4e042e85f4112a000181825839009fbdc6a75e10012d8c42017e375337cbc3760e96f911c87aacb6dfbe74b1d8380c8d4a9dfe1781ce3616c5f099b74854da5aa69532235ba91a04b04d51021a00029a6d031a04385c0e075820880443667460ae3b3016366d5bf66aca62c8149d67a53e94dde37120adffa624a500818258209e911e840789b2727a194f4d00959b4ee1f94db95542a16f2b0fde5cc14e03ff010182825839006f2c165bfb9e28a313da02d395eafe57ee1081bb14b8faac1856b0473907b2a702a6dcd0d937d4cbdd2ea8db46c335f9c6980ee93b0ee9b31a00a542f782583900fe33b43ae102d26c495a616187fd535a8ab31cf0cb0d7bc4f2ac35343f05a30548ea2f467860ff3ea675fcebf50bccf21eb99c9fc92d854a1b00000001d6236a82021a000295c9031a04385b0f081a005c5a2da40082825820139e2c770f1c836164cd9a04b756dc34622a672289f579efd42b48e929c3bf0a01825820bf1f24ac9ffcd9938f71a5dc2ce457f496d877440c57de1134334dc66378cc6d000182825839006d874798dee894262bb80ff32409e1ccb5c662f438d0832f7e83635b93cfb33930fd28cae34fd9a508f9a1c98bdd52561297e062983583dc821a001226b8a1581cf0ff48bbb7bbe9d59a40f1ce90e9e9d0ff5002ec48f232b49ca0fb9aa150000de14068616e646c65746f73656e640182583900f3cb671c88d464460e064deca0dcdbdb68a5753a1f08a09deeed716a7fc7000fdaeb72ac4f46ead88304fb4b036d953184cd114522c60f2b821a034df563a1581c63f01fe6cd68ec6438c95a46cea4a6cd27efb791b5e8cc1fa92af329a1524c616365204e46542050726570726f64313501021a0002a98d031a04385c15a400d9010281825820c5fc4abb70cb78e2dd81ede78769187a5e62a2cbe61e89e3241cc87bf49d3c9901018282584f82d818584583581cb0c95c61063a9438de2cadd7835078da4fd3d967b325b0ef49a98be2a201581e581c0e3885905f8f51eb31f58ee644d9adbf925e914c7953bcd14859471e024101001ac50f88b51a0010602782584f82d818584583581cacdf62c4488e78c07e28c4c80539f4aa0bcf0f7d14b37c9eeef45173a201581e581c0e3885905f8f5185d980efe6b5befe429093a12e9751ccae2633a713024101001afd4bab7e1a17d16bed021a0002a6a1031a04385c2fa30082825820c0ded58d1f20a8b7e1c01087ebb1d1ebb94af490e8a93e3b9e5bb20a98ebf41e01825820ffb031c142583f453bb67564b3994f38edcaf175ef66edb778d447b3faffa558010183a300581d70c05492bb753dd4750beaf12356ce4e8252f3930cbf92d06854f6852d011a00b71b00028201d8185842d8799f43323435581cdf95da5f1f11e588bad36eef8c9ea171a706e4cdf529fd97156e74ebd8799f1a01312d00d879801a0007a12000d87980d8798001d87a80ffff82583900df95da5f1f11e588bad36eef8c9ea171a706e4cdf529fd97156e74eb758ab9d2ac7b679542638ee8024dfea41e77d462389977872454f2cc821a00129c92a1581c8a746b4319053b7855c68ac5ed9c943525702afa94c0b303684bc814a2463234305f6e6f1a012b1280473234305f7965731a012b128082583900df95da5f1f11e588bad36eef8c9ea171a706e4cdf529fd97156e74eb758ab9d2ac7b679542638ee8024dfea41e77d462389977872454f2cc1a9925a57b021a0002b3dd87a2008182582002205785797b8efa694d21d7dbc3a290d2ae09538957920c9409999c261ecb2f584084d1baa591107d76dc8d2c0ee9780ebe3840b0f249ab8a00539aa25002adabd96e36f081241eeafa071a02c4982c756ce2dd6e077c9cdd380c9dbd96feb076030581840002d87980821a0012eff61a1085253da100828258208469288efa6f9cb49040b43dcff93f40969d72433f751afde50235012c016020584047f575a45ba7a644eb8131f0c2a85475873fd3ea71d0a5104905dcd637013407b113b1cbf4b7af8cfc2922de2a416168a1276839946b293c0aa6dda61b87960d82582076af5530fa318a370820270031d1838545a4ceed8696510627563d1114d4182b584019db9a32be1507c0c13b2177086c17ddc39d0d0c7956258da66dfab937cc57d8c39f6384ef2a07ccffddbea56b1afbbfd0d2cf82446d099f4658bcd2989a0506a10081825820f398d21bc567394b5e2670bf2b8088a36c0355a60786f83033aaee90c51a0652584088064631469320af98bae7571a1f6ea50f733c46dd65c5cd1e79153096063a4b4b3f508dbfb715f80742bcf751d1d913a8e082b4a5be73b4dce608160c355000a1008182582046c7b1430923a9aa57971324819633d7f0dc984ae03ba37b2c58631ea9f18f1d584096465f0d4f1b715d26f027edf5be6624558aefe6d3d2dec6f3cd1b3f7b62269e2f578b1c8f1e539652f5d9f0758536a2fa860b199771e53e1705b139ad2b5f07a10081825820fa198ff264f1191a846af5f6067afa341b36b9c882988810b209613ef4686d585840ebb8757498a9209c4ff1b7e92ec69e44f89df18ea1093d978dbf0cc1a2ca6edcf4d1950887acc0c710f8828d2988854eb15e34b64325b6b1cfcec53d5155e400a102d9010281845820847953db74a03327eecedf38f424d510bd6dbfb0da2be989d5be80251b76319b58400789ea001bac725e24ee88673706771013c356f864f3a268544ff985f72d1dcc26a4a9992a367ad9e9ae9ba83325f73dcb37f76d6f262031837e94256431d90b582053ecfa2c8bc4ab302ec166256aa48a95d549c4a7c01f1e0a98153c654e94c16e5825a201581e581c0e3885905f8f51949c09b5e6d340fe92426bdf4a912d78ef9422b32a024101a10081825820975277c2fe1db3f260850e3f4946f15affa868a6df0388dbb9b4fcb40725e1c858402f68e3b0716c37dc105d6cee678ed5f734f1d906dcd37a72f7da4768629e42bd9b345f8d356733ee85a9231d45d7eed711acc9d11fa3c6f8a14928897441c002a201a11901fda50050ca7a1457ef9f4c7f9c747f8c4a4cfa6c0150cb6c2b83991a305eb48f60c933913acf0258204d3f576f26db29139981a69443c2325daa812cc353a31b5a4db794a5bcbb06c20b8b58401b09048064084f8b2b0dc2dd44a61d5c0c4ef620f87f37f5000ff1946fb706d0f7268e255684615920797acf734fc8224eb7197419d8ab868cb5be7696f3994258406c0360b135c350c9221c43314ccf2774cfee070b8dd79c709dd157d779a7e943d4cc0580a47057652be88502c0a3f05c825260b9d9500164bee00af9dd011a005840bde49a23144104280752cbf8425e6ad77503d4078a850542e1442bd2109e3675a1a42c9f030b4391970f08845e1082406f581492be6f46e7b990742b6e8df4735840dd542ee353bdda6ecea406fcce7c29a5d5bb02d12abec73a636fb8f257db52e62360de0166816f9bcb08660660a6b2dd6256fa1ae6194ff0fc58604bcad3446d5840447687b2ca55828795cd2d419e9e9534adf6d4c8c52e97be31a8536b02b440a3a9f4ee08eca80d048db4afb655ddea5da35377d23e01fe6a6dad575b635b839f584052dd5cdf56ad54f9e86ad44080af2921081c231f01f319db13048eb9ae144a921c1cdd2e5646e28b849ebdf9fd3cb95fee9fd53e137f87584cb9107cb8c8999b5840874722f9f71256ae0dec4a9c23183b07b9bdad2439b33e63ad6a7dbc38f3787ee16164d9cdf5a6e3f6dc06a9572ce04ddf7b5bf1cd2b53a79ec765b2b94b73125840ea47ede0e931058f9184839d037d07ab7326c7a3a86d6ccde8b526aa2727743fa20f1dbfc06a5b313bfd49abb9fbbef11153ffbc4e9e39d3f7d7f1c7dd46d1175840e925b35ea90a97b0188ab354276d7fb6b020a264c330a4c768e5a7a4691fc7e20ffef38e8df03dfeaae0cfdca04393824cdcc71e497c71ff95b0d6ebb945f8c6584095b2439d0d3d275295cddcd143765ce1d8159df9989105737b902cb00aae77dc7761c732f7aaa5ab2eb9b488344a2ffd0ef327d12b820e252c1e5b78c7d9c8895834cd009d9daf3f3b4d35d7d7db36e139f4389ae1b2cb2779eacbe08f974e9eb2d9b1ffef48239a598e2028cb47b0c3805bf1e9bf9118635840466ebf1f9df0f881cdaafa8a876b55ae6c38c958f9242261df29f48be13dfd9226f44fd82e60bc868353d5e790a920b006a42d36b63e3405d891ad297123500502a1191acea165706f6f6c7381a26269647838353136366636393434336666376433356136356637356330333565653765626637663964626531376334396234643861383262613439623566776569676874186480 \ No newline at end of file diff --git a/rust/cardano-chain-follower/test_data/mary.block b/rust/cardano-chain-follower/test_data/mary.block deleted file mode 100644 index 7d71682e3..000000000 --- a/rust/cardano-chain-follower/test_data/mary.block +++ /dev/null @@ -1 +0,0 @@ -820484828f1a0055b4ac1a01a1eabe5820e9aac7ed907b246dda5548cf8d78269ddc5006368eac3d6d953800e4531ba7855820cca475e401893077582e74e5f694e741e5ec78df16f5ca4f979a2f297d02c54e58202a20b39a975102c19ea1d145df120579a2595ce6d696753424b13eeceb157fdf825840ec7d0f21df996a302d64f5700d24c11595d95cf30e755295575d9a33bdc9e0a49f777c501e0018161595b8d417e2ef3643f0315dc5f1ff63a2806a7c5c635eb85850aeba5ff94a58858ba358c540ec6fc7cccf4e55af1b45ea0b6f67a20d5def696d3d42cfb1571fe6b282bba6480d407b933d90228f4d9a5a1aa1a7da41e4464e5a9163c8a4ea5b1c95f41dffd9b905680982584000063af76ceade8a17009a28ae666fc90d59b42e0c0a37d4f4537755a66bf2b76d8b7dac1b8bba2b09a5784ca6878d95cee62b6e9987cf3c8d7d22f71526313f5850e584c25e328ce17b61038b33295e1317bf1b0b6b193a9e6f9d9ab455047dd6b5163db4d0a54de492e61a5fc36757880556369522326b2439e14ccc7bdf78eee3f0edae0d2900c38910a0d64d8f8d6509194c4958207cdc18ac07604d453229464652123b6b51c137abe9279e2eef9c0621d504423d58206dc1e500ee69ee4f02d67254ca3fb8ede4c592f4dc145ba4a9a001225913ad5d0418af58407d82457cde034555f832f7a2e01623b0b5f519d54b643e87add08cd6192a161a05dd0da2979d9b547ffcff442372d30e1df19e3c2e5179e4a04de4931fc1430204005901c0b37b5e3b093ef3082bdd548bd5f931f6621a2eca32a6358b38a42a296f2bd4c5600839e7e504fa340812e45337065007fcd5e1e41e1c4ecbec52c33895d187034b970683ab069478692cf6b98fcac79530c2c9bfe2295203e228a8809ba3f9208084a984e5588274ed0a26c6942ef729df8faaf644f7173c68ab986bfdc20f6108d7b3586c7bca66c5e9caedb0b021a23f2131b8f37a030be68e56d52761d8be70493151d0c6c1905e33701b8e7d1ada6a08e4fb410c8c5fda62fccba93d5da1d01477969f12ed67e981961b1a3cbd6cf981bdd593ff28fdb753a5f11ceb62621dc2e87472def58d90742c8a26b5b64573cbbfd32d317b3d77e08c3883f75b148af2784e0c1b5cc84b5b3266cab7bda13c3a893e05ef85d8b063ad239aca2c6018c10ce411aa8bd96abb0be37dd3b629d4aa4ddcded309a6a4cf8e1771aa97b943ffe352719145859c78e07409ff8893802bc1e492486566892c5c48b508423aee0890b940bab42014f9f6d29165a1fb8b53098f995a45e112a0bc66d3d9ce11ddb31739878295fe07db1e66b425cc52a5d73e9088ac1cedf6f3cb832b5fba8ef878cfb5e61813d2d56c6219ef54e2ce0f29c6ffae6f4a776a2ddc70a08be9d58ea50081825820790feaca64576990e3b2ed9cafdb8d2b874c561019f767827e685164577974b30001818258390111aca4f4fe84f5d89a30e8bd1697b52d0620c6b8e2a243c07e226f58f2971be702006ff49954fb5c064347451746ffb7e619bd2774caf59c1a3b7ca69f021a0002ac21031a01a2068e048282008200581cf2971be702006ff49954fb5c064347451746ffb7e619bd2774caf59c83028200581cf2971be702006ff49954fb5c064347451746ffb7e619bd2774caf59c581c024dcb42f0aa6d81a7e26ccdd525a2ed3e9665d126b38ba0f8b77b50a400828258205ed7d5280841f21b89d7d4885e0f4a3fec1d0d05856b68735ed5982677414a9603825820792c27f11f603e2a580847d42f4efc35c23492ae44ae3fd4a5f0deb7bcd8143803018482583901105d5846c4d6054a032092ab231ced9d9ec1cd381c685ecdb15a18eb105d5846c4d6054a032092ab231ced9d9ec1cd381c685ecdb15a18eb1a05ffd451825839015a06e23444ea5af6480d86f01d593cd2c061a1002db515a36df3fbf05a06e23444ea5af6480d86f01d593cd2c061a1002db515a36df3fbf01a126cab0282584c82d818584283581c4bb5beb1813d875ef62a2d8fc47674812a361f1834994e9cd5cbf0eda101581e581c9b1771bd305e4a22633e79a9257cf2458a580a65a4647d834268213d001ae8f33c161a0c66eca582584c82d818584283581c2a224ea8eb307e51dc1c9d3287dd5b73fff36ed2f318d34e4fe73204a101581e581c9b1771bd305e4a615d497aa98e87cc5b8bc918de283f0d9fc265d865001a4954b2701a25f6df28021a0002e715031a01a206c4a40082825820b34f463a8a91f91c207cf3148cfb253b2795eea8643b89281fb1bd043bf35cc700825820911ee5b314df7fa744ea47231bc42ddf3bcee2c910e19fdc3ecfa087912e78a101018282581d613dc0992a980257fbf7e6ae1e9b43af62932885f1e119279f1ce43f511a1a18ff2782581d61d91ef01b73f3010bb173945cf5417257c00c002715a13052015ab54f1a08655352021a0002bf35031a01a1ee84a40082825820861d31b11b125f78a88aea42a81a5463cec8bba58f6671227436822cf79506970082582017949570550c96e1d58abb5a4f07861ebde9472de865e56f0bdf04ba5165e86d00018282584c82d818584283581cbdcd97d67a94fc9e1af08ba34fd47405631a62362482b5c63aefaedda101581e581c7111304fa69dc398fa2055a1b012921e540374ca44f739beb09131c8001ab1e823421a03ea796c82581d610237be10f5ec0ccb6cbd226b112f0940fed44ae0466d9b53962ba8b11a2381e19a021a0002bf35031a01a1ee84a50082825820f74dccfef00ea5dd7a5360f4870de9f664bcbe8c0bf4611ba4d8f5dec687cc9f00825820f74dccfef00ea5dd7a5360f4870de9f664bcbe8c0bf4611ba4d8f5dec687cc9f010182825839012250f08ab10f7bf12f49291e78527f35a4f66ebd03e66524ed9ac8dd2250f08ab10f7bf12f49291e78527f35a4f66ebd03e66524ed9ac8dd1a000f4240825839012250f08ab10f7bf12f49291e78527f35a4f66ebd03e66524ed9ac8dd2250f08ab10f7bf12f49291e78527f35a4f66ebd03e66524ed9ac8dd1a85e84858021a0003096c031a05f5e100048182018200581c2250f08ab10f7bf12f49291e78527f35a4f66ebd03e66524ed9ac8dda40081825820900c833fd9754d4f65d7a1493ce62aaa943c887dc39921d0975976896bbd4e8a00018282581d61dfb778ad19859d22c8909f541b570dd4c386efb78d72173e4af2d2481a04c4b40082583901e683340376e5d57ab9af32493fc8f40c21682621432ebc85ffb4af4eee0df6c2ebfe5d3648def953480b811698b54c9a38164dcf0bf6c0eb1a2ee6c16d021a00028c81031a01a20663a40083825820750a3eab714b04bc4718f43407fee903b996700aa3b0e171f840602b608ce52e00825820d57e3d99a481cdc928a82d2a39b689f49a54044c6cd12239a8e5b2376536659b008258204316395f1f1421863c5faa3590d5cfa91eab9f8c5737afd0e6df8914b8ca5b5700018282583901b46bdb5502435a418fcc35273339c218300e0d633e4c532d98133907cb970842e16c849f65ffb4c0d88243289cf7519aa90bc57b3c3597a0821a00160a5ba1581c73ed4b685261a41c66ba62193572c3ce78652793df0a2d4a75c127cda144574545440182583901306fc9574d0f8c774fa8fde9b5d540e2d4f22c67e1ccdb862f8bc6d1f68419a027bf56bf179f07acdf872cd78e0d6ce129772028dd2d1a81821a002a804fa2581c36e8f59542d444e3afca00cecca881cbdf8257c1b07a2fd84ed25730a1574570737465696e4469646e744b696c6c48696d73656c661a000dbba0581c73ed4b685261a41c66ba62193572c3ce78652793df0a2d4a75c127cda14457454544195d5b021a0002b5c1031a01a206b7a400828258206c027d63a875e6ab52abc975594f6060dc8d8d9342a42899ff64e4b5a8041cc4018258207c1cc2472c9808612e77b75d2c253c9aa05d0a83cf1d72b929fb41cc2b8054ff00018282583901a9274ec0157902ffe776bca9a7b24aac3373044a3c71e0c27ec8f741a9274ec0157902ffe776bca9a7b24aac3373044a3c71e0c27ec8f7411a0e99550c82584c82d818584283581cfa4589909bc695cb0c7fbf23c37b5206fb180f4c5216a6d86c5caa40a101581e581c2b0b011ba3683d5a9b32802aa60b6f471a2bdab01598f0fa5d3ee332001ae706cac71b00000004d4f8ee05021a0002cb3d031a01a206c8a500818258207b9c5b2a8da20bdedb61f836c802ddf361fcc363faa7f64ecebcd3a5fcf8936105018182583901d3b46b29180c65567b03fcbdf0b897f4d3e58ee5ac9c7eb7b7a128e368b887d2e2b58bbb0c238406b77270089d0f370d9e28ab87c57d29f01a0049a28f021a0002a8b1031a01a20672048282008200581c68b887d2e2b58bbb0c238406b77270089d0f370d9e28ab87c57d29f083028200581c68b887d2e2b58bbb0c238406b77270089d0f370d9e28ab87c57d29f0581ce811a4b2f8ef3ec84143e3026d706564bc1cc98dc199a305e0fbb8e3a400818258200cda8d6a05ed90f3618b9a1d69cbaa112d7f508df405b3f7da7e4e348011219a01018282584c82d818584283581c9db8ac183b28b32e9fc70bb83345ff3f02cb6822086bccf9b272a56ea101581e581c6c62a9e3a4d9cc731469d72e5e097859162fe94cfb1149f980d46e36001a2c0ef42d1a12d1332082581d61d91ef01b73f3010bb173945cf5417257c00c002715a13052015ab54f1a166f4db4021a00029cd5031a01a1ee84a500818258204254c7128386731cdb4c709cb10c15080f0bb25a2e00ebaa7c4ba808811a5ece000181825839017c8c932fe58987c54752b4592ae73a9fccafa15553174ca7397eac61193e0d9a2f810bec4a2632006bba910de6dafb246ff3f6829fe3c8f81a755bc688021a00029e09031a01a206cb05a1581de1193e0d9a2f810bec4a2632006bba910de6dafb246ff3f6829fe3c8f81a0058a159a60081825820cd0bd822e080672736f6e10af4053eb7f5b36120fa154dfe647ada2a2a68e08e00018182581d71a5f1baef9bf194a48068c2545d5dd58e93da01a5c395a2f595c955ea821a08e513dba1581c5d2c310ba30ee79a9139defb690af87a110444492c9caf4b2038e0f1bf5443617264616e6f4b69647a303033384643323236015443617264616e6f4b69647a303033384643323237015443617264616e6f4b69647a303033384643323238015443617264616e6f4b69647a303033384643323239015443617264616e6f4b69647a303033384643323330015443617264616e6f4b69647a303033384643323331015443617264616e6f4b69647a303033384643323332015443617264616e6f4b69647a303033384643323333015443617264616e6f4b69647a303033384643323334015443617264616e6f4b69647a303033384643323335015443617264616e6f4b69647a303033384643323336015443617264616e6f4b69647a303033384643323337015443617264616e6f4b69647a303033384643323338015443617264616e6f4b69647a303033384643323339015443617264616e6f4b69647a303033384643323430015443617264616e6f4b69647a303033384643323431015443617264616e6f4b69647a303033384643323432015443617264616e6f4b69647a303033384643323433015443617264616e6f4b69647a303033384643323434015443617264616e6f4b69647a303033384643323435015443617264616e6f4b69647a303033384643323436015443617264616e6f4b69647a303033384643323437015443617264616e6f4b69647a303033384643323438015443617264616e6f4b69647a303033384643323439015443617264616e6f4b69647a303033384643323530015443617264616e6f4b69647a303033384643323531015443617264616e6f4b69647a303033384643323532015443617264616e6f4b69647a303033384643323533015443617264616e6f4b69647a303033384643323534015443617264616e6f4b69647a303033384643323535015443617264616e6f4b69647a303033384643323536015443617264616e6f4b69647a303033384643323537015443617264616e6f4b69647a303033384643323538015443617264616e6f4b69647a303033384643323539015443617264616e6f4b69647a303033384643323630015443617264616e6f4b69647a303033384643323631015443617264616e6f4b69647a303033384643323632015443617264616e6f4b69647a303033384643323633015443617264616e6f4b69647a303033384643323634015443617264616e6f4b69647a303033384643323635015443617264616e6f4b69647a303033384643323636015443617264616e6f4b69647a303033384643323637015443617264616e6f4b69647a303033384643323638015443617264616e6f4b69647a303033384643323639015443617264616e6f4b69647a303033384643323730015443617264616e6f4b69647a303033384643323731015443617264616e6f4b69647a303033384643323732015443617264616e6f4b69647a303033384643323733015443617264616e6f4b69647a303033384643323734015443617264616e6f4b69647a303033384643323735015443617264616e6f4b69647a303033384643323736015443617264616e6f4b69647a303033384643323737015443617264616e6f4b69647a303033384643323738015443617264616e6f4b69647a303033384643323739015443617264616e6f4b69647a303033384643323830015443617264616e6f4b69647a303033384643323831015443617264616e6f4b69647a303033384643323832015443617264616e6f4b69647a303033384643323833015443617264616e6f4b69647a303033384643323834015443617264616e6f4b69647a303033384643323835015443617264616e6f4b69647a303033384643323836015443617264616e6f4b69647a303033384643323837015443617264616e6f4b69647a303033384643323838015443617264616e6f4b69647a303033384643323839015443617264616e6f4b69647a303033384643323930015443617264616e6f4b69647a303033384643323931015443617264616e6f4b69647a303033384643323932015443617264616e6f4b69647a303033384643323933015443617264616e6f4b69647a303033384643323934015443617264616e6f4b69647a303033384643323935015443617264616e6f4b69647a303033384643323936015443617264616e6f4b69647a303033384643323937015443617264616e6f4b69647a303033384643323938015443617264616e6f4b69647a303033384643323939015443617264616e6f4b69647a303033384643333030015443617264616e6f4b69647a303033384643333031015443617264616e6f4b69647a30303338464333303201ff021a000bbda5031a01a4b0cb07582020203a2d332f99480ab1a242d20ab11fe4a3fe1deb7be47dd65d0605e260633709a1581c5d2c310ba30ee79a9139defb690af87a110444492c9caf4b2038e0f1bf5443617264616e6f4b69647a303033384643323236015443617264616e6f4b69647a303033384643323237015443617264616e6f4b69647a303033384643323238015443617264616e6f4b69647a303033384643323239015443617264616e6f4b69647a303033384643323330015443617264616e6f4b69647a303033384643323331015443617264616e6f4b69647a303033384643323332015443617264616e6f4b69647a303033384643323333015443617264616e6f4b69647a303033384643323334015443617264616e6f4b69647a303033384643323335015443617264616e6f4b69647a303033384643323336015443617264616e6f4b69647a303033384643323337015443617264616e6f4b69647a303033384643323338015443617264616e6f4b69647a303033384643323339015443617264616e6f4b69647a303033384643323430015443617264616e6f4b69647a303033384643323431015443617264616e6f4b69647a303033384643323432015443617264616e6f4b69647a303033384643323433015443617264616e6f4b69647a303033384643323434015443617264616e6f4b69647a303033384643323435015443617264616e6f4b69647a303033384643323436015443617264616e6f4b69647a303033384643323437015443617264616e6f4b69647a303033384643323438015443617264616e6f4b69647a303033384643323439015443617264616e6f4b69647a303033384643323530015443617264616e6f4b69647a303033384643323531015443617264616e6f4b69647a303033384643323532015443617264616e6f4b69647a303033384643323533015443617264616e6f4b69647a303033384643323534015443617264616e6f4b69647a303033384643323535015443617264616e6f4b69647a303033384643323536015443617264616e6f4b69647a303033384643323537015443617264616e6f4b69647a303033384643323538015443617264616e6f4b69647a303033384643323539015443617264616e6f4b69647a303033384643323630015443617264616e6f4b69647a303033384643323631015443617264616e6f4b69647a303033384643323632015443617264616e6f4b69647a303033384643323633015443617264616e6f4b69647a303033384643323634015443617264616e6f4b69647a303033384643323635015443617264616e6f4b69647a303033384643323636015443617264616e6f4b69647a303033384643323637015443617264616e6f4b69647a303033384643323638015443617264616e6f4b69647a303033384643323639015443617264616e6f4b69647a303033384643323730015443617264616e6f4b69647a303033384643323731015443617264616e6f4b69647a303033384643323732015443617264616e6f4b69647a303033384643323733015443617264616e6f4b69647a303033384643323734015443617264616e6f4b69647a303033384643323735015443617264616e6f4b69647a303033384643323736015443617264616e6f4b69647a303033384643323737015443617264616e6f4b69647a303033384643323738015443617264616e6f4b69647a303033384643323739015443617264616e6f4b69647a303033384643323830015443617264616e6f4b69647a303033384643323831015443617264616e6f4b69647a303033384643323832015443617264616e6f4b69647a303033384643323833015443617264616e6f4b69647a303033384643323834015443617264616e6f4b69647a303033384643323835015443617264616e6f4b69647a303033384643323836015443617264616e6f4b69647a303033384643323837015443617264616e6f4b69647a303033384643323838015443617264616e6f4b69647a303033384643323839015443617264616e6f4b69647a303033384643323930015443617264616e6f4b69647a303033384643323931015443617264616e6f4b69647a303033384643323932015443617264616e6f4b69647a303033384643323933015443617264616e6f4b69647a303033384643323934015443617264616e6f4b69647a303033384643323935015443617264616e6f4b69647a303033384643323936015443617264616e6f4b69647a303033384643323937015443617264616e6f4b69647a303033384643323938015443617264616e6f4b69647a303033384643323939015443617264616e6f4b69647a303033384643333030015443617264616e6f4b69647a303033384643333031015443617264616e6f4b69647a30303338464333303201ffa400818258206ee70506daa57d2de6544d9c0790beafe592a4daf124f8046ce22859fdd3c1a901018282584c82d818584283581cde35879ae16e897627eb20baf26be7e7bd325583bd17aa9c67713b0aa101581e581ce378ee30d5681449869d426d33e11d95dc7896854fefac8feea15d66001a7d335c381a08583b0082581d6179e67550b2ff311da1883ad0ccc6fb2bb7c75e5489acff735fcc68781a53a6fb32021a00029cd5031a01a1ee84a40083825820a396e38605b4b3fee941a69ca1736e17516be67d6b596ef7e854557cf918738900825820c9f12ee2577895339a74d286bf77134dbcca5f806dc955c3fa94567a0118cfdf0b8258207807540ef1577df8d3282fb18e157d1480535dd6f39648207bea759a28f3cdf217018282584c82d818584283581cdcfe05e2cb99a7e14c0142d453115ebc1ce1d00e68149eb762c47fc5a101581e581c7111304fa69dc3f1644da7a1db41603fa288f170bb5dc225f80da24b001aa9adf1101b00000002363e7f0082583901f765168cd378460d748f14d32cc462c62ef882f74bee0cc3fb38ecfd55ecd0372bb6dad0892a5154802adfe36be613d2c1690498059a8f631a813a2d36021a0002c45d031a01a206878ea10082825820e120d1e68b27660a9346947d2a3f79f5f702b66e58dfd542edc1443923ca89e058409c4e5759292092a773a2a14623f9a83799bd7297291f29e82cb552544765ba8c961dc12872067671e47fa141d2048a237407def2f6756cabfa682cca1c96960e825820b186a878bc2f6aae02a288abcbe1da7ebf6bd9125dc5a5e8e2addaf461c01a1e5840367d70340c36a58756fad5f2a25aef4317444b90cc96d5cbc7aab7c872c204ed7d3273f35fd75606a4b57124e2943e0ee87dedcd1f2c259e3d2a72684556e506a102828458201a66c53814b9b716280d25e928e28281984cecfa644a83cdabb5f2d9fdcdd5d258407ebe78a4009731b6ad5803147b086d7269c2727b4e21685de04f14b0b0a33b93159b167f180414d1696b779057ead145eb053f1bdd4a9a38948c5139aa4374055820deef140087f9cca73b50452ff9afe31fa179959cf7da3b341f7248a5d03d0fff5822a101581e581c9b1771bd305e4a4407f82ca9ce993f8be1c0f19a30307d6de3b5391c84582006334624d8da907649c765188d197b23e561c122c4b42835f26a91412c3e24865840f58e48db026fb30c3f2ac65cfb169ca31276eb73897c5ef495d1582cec422bf6e60efb69690199a9edaf424be7161bc24bd8a53a004662e990a11212f4d1e8025820dbd18cf22cb5c42e86e1dcc1a5d16fe24f2422e57be7a45f1b83e8c4ef18221f5822a101581e581c9b1771bd305e4a339d86c8a93fe0e379c4c7a24c04024e34b9a6659ca10082825820be12a95cfcd1011bfb59bd760ef683e040de4cb0355843683dfac00312b3535d58401ece9f0d7ea618e840bb8eeb2657baf19139d9b1c467e91345930ecf167a42e5ccd92ec95bf26038dc0a8b8cb404f5074990dffeda4d76bc61d9c7eac23965048258200d197b7eeef1b961962a2911d4b553f0d9c3114b8d3e61de3beb4f39dc348eb05840d3fc852714c1c741ab5effeaf50a47b449291d0613d4dd538aea58870a13819f05491726ccea72fc76407ee253f4aff23229a45604523fd5ced2c85dabfaf10ea10082825820d85a190eb4f193ae18c5395bf9d5493ceef6cffde1923fc3d41a3549f68f314b58400847fc53c36acf1f68f4de7b99afcea8706984958c4093d6db7d8e53c86e4daec7cb3ea313acc48b171ed6c3bf0c88951c4e62b1c80f43d72af54dbbeef0ff05825820c2aad03f77eb131a808e04efde662e7fb84034e811810c866cece5462b6dfc7b5840ec86663c28c1494d8ef004202c31747b038e36f7f0a446803bcf0c09f1b98f7ac3b539234b925292c6b88c96529501d3f614c92f83fb3d3eed0abef870cfe208a10083825820a080d8e4a44af1c986d93975807cf10f5d3670b7892f4c34cf91d7f12bbb4e6d5840156631a0c031bcc40e281b2f5405670cd8f87a2b04218a1d577337d1695d20319b6bd6490797b1be5abbc9d2c120469ce1f55fdffb6959bea43d1bb336bb1603825820a080d8e4a44af1c986d93975807cf10f5d3670b7892f4c34cf91d7f12bbb4e6d5840156631a0c031bcc40e281b2f5405670cd8f87a2b04218a1d577337d1695d20319b6bd6490797b1be5abbc9d2c120469ce1f55fdffb6959bea43d1bb336bb1603825820a080d8e4a44af1c986d93975807cf10f5d3670b7892f4c34cf91d7f12bbb4e6d5840156631a0c031bcc40e281b2f5405670cd8f87a2b04218a1d577337d1695d20319b6bd6490797b1be5abbc9d2c120469ce1f55fdffb6959bea43d1bb336bb1603a10081825820dbaa64dac9db1e42c8e7a65cb0a19b0d5bcd9d7492fbbdffa4aa1c6eeefef6055840134ddda8c219f15fcfc5a5760c51dd192d6e6c5765373b49c1f61b03e281ae65c702f53976f2e3ddf604e66dd5601edfa9b76cf7b7744bd56e99eb21ec3ac106a10081825820fa10a8aad3525bae5e6fc86f002a29fdeacf7e2c3adbbd42fb18ce37f46d6da758400b9c109eee0f20b17c2182c4b4356fe27ce61585a7b87c4454133ab9b4eeefa822290eb02210a6faa466113788e74f0b6f15dbd7564ad146b341b5d89aa34800a10282845820ca29c439ebe4e46749b5cd58ccd4a80c3e63590532b5e3e47929dcffadfe6f915840234f256bdaebabc73069dae65682f2bfd642854f37a901532d542537716f14445e4516cb7116d8fcf62b8dfe8d358ef76b3a8877b9e33f8e0ec49cc151b49d025820b5fa70b1f92b6f51f40a1214c83d072ee3463d37dd5a4ab93fd3880c1c2b78705822a101581e581c2b0b011ba3683d3b39e26d2a2a7538c41e52733b9a31fd976489dceb84582090f9faab0162b29b4ae704ec6b34b907ff4b460d95067416847c9de869fcffbd58402cc2a20369497238a6eafc0a73a9b20d0616a9b37769b1ca1f4b85fc0c787d0bb360255bd5008adc6a731b712886e13631f05ca293b1a0c7f0d6402e0e35800e582042273fb0f6b6eeae752bfa1efa18d3a52fe906cad33d9789f42875dccf122b3d5822a101581e581c2b0b011ba3683d6727811e2a7055eba994d24d6d5dbe938c685b65b1a100828258201bf61889f47fb0c57f000efc792c108058abd09ded1b92c8e321d5157dcc0b03584031ef0ade7e1c6aef0020f252650cc1e4278378d8292f68fef83c3cecb7d147fcb11dd12eddd16140ce3bc074f8ef96514558c7c031d7096da5eb9a8bb81c190282582068afabddeff38f0274543bdeca22982ba317c80534e2087b6e9ebb5bcbee2d255840dfc59eb00d76baed7333f8cf737fa9906b28bca9002a5484f0fb982d5458989536d6b5267d2d43cb7a032e166bb4df86a042c44f1c5a9c8fafd88dade88b8002a100818258200d197b7eeef1b961962a2911d4b553f0d9c3114b8d3e61de3beb4f39dc348eb05840d6863f876b33fb84a0f5ae757495136c1d38776a3ce3b7ce45ec4d19d51463fce731ce1d266e35c354ccee3e23b8f539c3122a6185594c2bca8530839f63620da10082825820c936c5031dfe7302a9577d20f39121a05186da762040ea7930ba40b4e75117095840dff4972a083973d9e4393520ab2263d47a8e9fd081e77215ba059eeaf188e3bbcd54f3efd20d6d711d9d29106b2d0ab484e37c24b72f82feb6adfe91eadc5901825820f9b39400c618265f9ba86e002b8df2eb114f2c5129a6c8cad4c749d024bcf73c584098147dd4e497e9aefcca6229e5ca1a28d43e2c6291d0ff627e9f4939341ebd80494fab7bad689f187c03b3d7fcbbf24fa7a04aabcd0c77455756f6ee4708560ca20081825820b58007aa837902c5f9deb45b0720ce9edb90231ab51d8d8a04223abbe91660c15840c592e5a6f8cc80c5897680120a23744aff93bdda1c39008090f5103d758dbe5284125ff5a2b8c060a4fceab1b2a86f5ececfc8ae016c7b352a0fe18d5778cc0e01828200581c026786de9ea6d7de570eb20d7bcb3c815bf88a46cdd9bcf7b5b357158201828200581c026786de9ea6d7de570eb20d7bcb3c815bf88a46cdd9bcf7b5b3571582051a01a4b0cba100818258206687a36f0a4b8abf2671f8affb7febeb8940e9ee83548d2a2924dbc74679c46658403523bc8f616d9e7e7035fbade81505c88d1ea80e1c6e47412b1024c79f20a1221ffbadc68fbc8bca68ba1818d5f5c0446691e409958e43e64993cba32b8d170aa100838258201e148f63439d8482ac734d737dd4bf1d0f2c7053ed9810beea3151f3f4545356584063945f682dd36acc2ba795588b6bd501a1809869d9f7f6106fd12e4bf2ed0b891e875915938c8cca59da16cfe8fe07f414a98923cc3a29e0495193c6a1aa6c008258201cb6da608e12fbed48e93574274838bd855d965661874e734eba54ab138517b15840da0fee21f01f79738d37dc995e9bb2b009e037e652a48742a16d8af9598ddaf800273d35d65a0ac110644dd6e06798592b43025f1a0c2802790c27374599b7028258207b42a33d3b1cc39f54db7273d589c66146f55d2fc3ec784ed596b5b737f8ee7d584094948408e251b18f1ffe93eff189b3bdfb033dacbd1fa8ca3dc8c76e19b6a44598db9968a77480feddd34dabdc8d41e18872e4f085840c5a8cba14dfa9765c03a10b82a11902d1a478383564326333313062613330656537396139313339646566623639306166383761313130343434343932633963616634623230333865306631b84d7443617264616e6f4b69647a303033384643323236a362696418e265696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3232365d7443617264616e6f4b69647a303033384643323237a362696418e365696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3232375d7443617264616e6f4b69647a303033384643323238a362696418e465696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3232385d7443617264616e6f4b69647a303033384643323239a362696418e565696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3232395d7443617264616e6f4b69647a303033384643323330a362696418e665696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3233305d7443617264616e6f4b69647a303033384643323331a362696418e765696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3233315d7443617264616e6f4b69647a303033384643323332a362696418e865696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3233325d7443617264616e6f4b69647a303033384643323333a362696418e965696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3233335d7443617264616e6f4b69647a303033384643323334a362696418ea65696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3233345d7443617264616e6f4b69647a303033384643323335a362696418eb65696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3233355d7443617264616e6f4b69647a303033384643323336a362696418ec65696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3233365d7443617264616e6f4b69647a303033384643323337a362696418ed65696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3233375d7443617264616e6f4b69647a303033384643323338a362696418ee65696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3233385d7443617264616e6f4b69647a303033384643323339a362696418ef65696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3233395d7443617264616e6f4b69647a303033384643323430a362696418f065696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3234305d7443617264616e6f4b69647a303033384643323431a362696418f165696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3234315d7443617264616e6f4b69647a303033384643323432a362696418f265696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3234325d7443617264616e6f4b69647a303033384643323433a362696418f365696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3234335d7443617264616e6f4b69647a303033384643323434a362696418f465696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3234345d7443617264616e6f4b69647a303033384643323435a362696418f565696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3234355d7443617264616e6f4b69647a303033384643323436a362696418f665696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3234365d7443617264616e6f4b69647a303033384643323437a362696418f765696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3234375d7443617264616e6f4b69647a303033384643323438a362696418f865696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3234385d7443617264616e6f4b69647a303033384643323439a362696418f965696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3234395d7443617264616e6f4b69647a303033384643323530a362696418fa65696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3235305d7443617264616e6f4b69647a303033384643323531a362696418fb65696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3235315d7443617264616e6f4b69647a303033384643323532a362696418fc65696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3235325d7443617264616e6f4b69647a303033384643323533a362696418fd65696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3235335d7443617264616e6f4b69647a303033384643323534a362696418fe65696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3235345d7443617264616e6f4b69647a303033384643323535a362696418ff65696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3235355d7443617264616e6f4b69647a303033384643323536a362696419010065696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3235365d7443617264616e6f4b69647a303033384643323537a362696419010165696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3235375d7443617264616e6f4b69647a303033384643323538a362696419010265696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3235385d7443617264616e6f4b69647a303033384643323539a362696419010365696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3235395d7443617264616e6f4b69647a303033384643323630a362696419010465696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3236305d7443617264616e6f4b69647a303033384643323631a362696419010565696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3236315d7443617264616e6f4b69647a303033384643323632a362696419010665696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3236325d7443617264616e6f4b69647a303033384643323633a362696419010765696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3236335d7443617264616e6f4b69647a303033384643323634a362696419010865696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3236345d7443617264616e6f4b69647a303033384643323635a362696419010965696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3236355d7443617264616e6f4b69647a303033384643323636a362696419010a65696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3236365d7443617264616e6f4b69647a303033384643323637a362696419010b65696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3236375d7443617264616e6f4b69647a303033384643323638a362696419010c65696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3236385d7443617264616e6f4b69647a303033384643323639a362696419010d65696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3236395d7443617264616e6f4b69647a303033384643323730a362696419010e65696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3237305d7443617264616e6f4b69647a303033384643323731a362696419010f65696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3237315d7443617264616e6f4b69647a303033384643323732a362696419011065696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3237325d7443617264616e6f4b69647a303033384643323733a362696419011165696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3237335d7443617264616e6f4b69647a303033384643323734a362696419011265696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3237345d7443617264616e6f4b69647a303033384643323735a362696419011365696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3237355d7443617264616e6f4b69647a303033384643323736a362696419011465696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3237365d7443617264616e6f4b69647a303033384643323737a362696419011565696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3237375d7443617264616e6f4b69647a303033384643323738a362696419011665696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3237385d7443617264616e6f4b69647a303033384643323739a362696419011765696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3237395d7443617264616e6f4b69647a303033384643323830a362696419011865696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3238305d7443617264616e6f4b69647a303033384643323831a362696419011965696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3238315d7443617264616e6f4b69647a303033384643323832a362696419011a65696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3238325d7443617264616e6f4b69647a303033384643323833a362696419011b65696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3238335d7443617264616e6f4b69647a303033384643323834a362696419011c65696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3238345d7443617264616e6f4b69647a303033384643323835a362696419011d65696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3238355d7443617264616e6f4b69647a303033384643323836a362696419011e65696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3238365d7443617264616e6f4b69647a303033384643323837a362696419011f65696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3238375d7443617264616e6f4b69647a303033384643323838a362696419012065696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3238385d7443617264616e6f4b69647a303033384643323839a362696419012165696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3238395d7443617264616e6f4b69647a303033384643323930a362696419012265696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3239305d7443617264616e6f4b69647a303033384643323931a362696419012365696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3239315d7443617264616e6f4b69647a303033384643323932a362696419012465696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3239325d7443617264616e6f4b69647a303033384643323933a362696419012565696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3239335d7443617264616e6f4b69647a303033384643323934a362696419012665696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3239345d7443617264616e6f4b69647a303033384643323935a362696419012765696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3239355d7443617264616e6f4b69647a303033384643323936a362696419012865696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3239365d7443617264616e6f4b69647a303033384643323937a362696419012965696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3239375d7443617264616e6f4b69647a303033384643323938a362696419012a65696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3239385d7443617264616e6f4b69647a303033384643323939a362696419012b65696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3239395d7443617264616e6f4b69647a303033384643333030a362696419012c65696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3330305d7443617264616e6f4b69647a303033384643333031a362696419012d65696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3330315d7443617264616e6f4b69647a303033384643333032a362696419012e65696d616765783a697066733a2f2f697066732f516d6232704e3454536f4363333476687a6f59534363444b357936593833344c44794e6843715837556f55627752646e616d65781b43617264616e6f204b69647a204e46542030303338205b3330325d69636f70797269676874782f436f707972696768742043617264616e6f4b69647a20323032313b20616c6c20726967687473207265736572766564697075626c69736865728267636e66742e696f6f63617264616e6f6b69647a2e636f6d6776657273696f6e0180 \ No newline at end of file From e96216aae8c60b5e6b75c46a4c5d6520dc63398b Mon Sep 17 00:00:00 2001 From: bkioshn Date: Thu, 9 Jan 2025 14:28:13 +0700 Subject: [PATCH 31/40] fix(cardano-chain-follower): break down stats Signed-off-by: bkioshn --- rust/cardano-chain-follower/src/chain_sync.rs | 9 +- .../src/chain_sync_live_chains.rs | 8 +- rust/cardano-chain-follower/src/follow.rs | 8 +- .../src/stats/follower.rs | 22 ++ .../src/stats/live_chain.rs | 62 ++++ .../src/stats/mithril.rs | 75 +++++ .../src/{stats.rs => stats/mod.rs} | 287 +----------------- .../src/stats/rollback.rs | 141 +++++++++ 8 files changed, 329 insertions(+), 283 deletions(-) create mode 100644 rust/cardano-chain-follower/src/stats/follower.rs create mode 100644 rust/cardano-chain-follower/src/stats/live_chain.rs create mode 100644 rust/cardano-chain-follower/src/stats/mithril.rs rename rust/cardano-chain-follower/src/{stats.rs => stats/mod.rs} (64%) create mode 100644 rust/cardano-chain-follower/src/stats/rollback.rs diff --git a/rust/cardano-chain-follower/src/chain_sync.rs b/rust/cardano-chain-follower/src/chain_sync.rs index b37848f3c..8f62b0198 100644 --- a/rust/cardano-chain-follower/src/chain_sync.rs +++ b/rust/cardano-chain-follower/src/chain_sync.rs @@ -33,7 +33,8 @@ use crate::{ error::{Error, Result}, mithril_snapshot_config::MithrilUpdateMessage, mithril_snapshot_data::latest_mithril_snapshot_id, - stats, ChainSyncConfig, + stats::{self}, + ChainSyncConfig, }; /// The maximum number of seconds we wait for a node to connect. @@ -199,7 +200,11 @@ async fn process_rollback( // We never really know how many blocks are rolled back when advised by the peer, but we // can work out how many slots. This function wraps the real work, so we can properly // record the stats when the rollback is complete. Even if it errors. - stats::rollback(chain, stats::RollbackType::Peer, slot_rollback_size.into()); + stats::rollback::rollback( + chain, + stats::rollback::RollbackType::Peer, + slot_rollback_size.into(), + ); Ok(response) } diff --git a/rust/cardano-chain-follower/src/chain_sync_live_chains.rs b/rust/cardano-chain-follower/src/chain_sync_live_chains.rs index e03af59c0..5815a6d77 100644 --- a/rust/cardano-chain-follower/src/chain_sync_live_chains.rs +++ b/rust/cardano-chain-follower/src/chain_sync_live_chains.rs @@ -15,7 +15,7 @@ use tracing::{debug, error}; use crate::{ error::{Error, Result}, mithril_snapshot_data::latest_mithril_snapshot_id, - stats, + stats::{self}, }; /// Type we use to manage the Sync Task handle map. @@ -241,7 +241,11 @@ impl ProtectedLiveChainBlockList { // Record a rollback statistic (We record the ACTUAL size our rollback effected our // internal live chain, not what the node thinks.) - stats::rollback(network, stats::RollbackType::LiveChain, rollback_size); + stats::rollback::rollback( + network, + stats::rollback::RollbackType::LiveChain, + rollback_size, + ); } let head_slot = block.point().slot_or_default(); diff --git a/rust/cardano-chain-follower/src/follow.rs b/rust/cardano-chain-follower/src/follow.rs index 2c2616543..3c1d323ca 100644 --- a/rust/cardano-chain-follower/src/follow.rs +++ b/rust/cardano-chain-follower/src/follow.rs @@ -13,7 +13,7 @@ use crate::{ mithril_snapshot::MithrilSnapshot, mithril_snapshot_data::latest_mithril_snapshot_id, mithril_snapshot_iterator::MithrilSnapshotIterator, - stats::{self, rollback}, + stats::{self}, Statistics, }; @@ -192,7 +192,11 @@ impl ChainFollower { if let Some(next_block) = next_block { // Update rollback stats for the follower if one is reported. if update_type == chain_update::Kind::Rollback { - rollback(self.network, stats::RollbackType::Follower, rollback_depth); + stats::rollback::rollback( + self.network, + stats::rollback::RollbackType::Follower, + rollback_depth, + ); } // debug!("Pre Previous update 4 : {:?}", self.previous); self.previous = self.current.clone(); diff --git a/rust/cardano-chain-follower/src/stats/follower.rs b/rust/cardano-chain-follower/src/stats/follower.rs new file mode 100644 index 000000000..1bd819147 --- /dev/null +++ b/rust/cardano-chain-follower/src/stats/follower.rs @@ -0,0 +1,22 @@ +//! Individual Follower Statistics. + +use cardano_blockchain_types::Slot; +use chrono::{DateTime, Utc}; +use serde::Serialize; + +/// Individual Follower stats +#[derive(Debug, Default, Clone, Serialize)] +pub struct Follower { + /// Synthetic follower connection ID + pub id: u64, + /// Starting slot for this follower (0 = Start at Genesis Block for the chain). + pub start: Slot, + /// Current slot for this follower. + pub current: Slot, + /// Target slot for this follower (MAX U64 == Follow Tip Forever). + pub end: Slot, + /// Current Sync Time. + pub sync_start: DateTime, + /// When this follower reached TIP or its destination slot. + pub sync_end: Option>, +} diff --git a/rust/cardano-chain-follower/src/stats/live_chain.rs b/rust/cardano-chain-follower/src/stats/live_chain.rs new file mode 100644 index 000000000..1c3b17f2a --- /dev/null +++ b/rust/cardano-chain-follower/src/stats/live_chain.rs @@ -0,0 +1,62 @@ +//! Live Blockchain Statistics. + +use cardano_blockchain_types::Slot; +use chrono::{DateTime, Utc}; +use serde::Serialize; + +use super::{follower::Follower, rollback::Rollbacks}; + +/// Statistics related to the live blockchain +#[derive(Debug, Default, Clone, Serialize)] +pub struct Live { + /// The Time that synchronization to this blockchain started + pub sync_start: DateTime, + /// The Time that synchronization to this blockchain was complete up-to-tip. None = + /// Not yet synchronized. + pub sync_end: Option>, + /// When backfill started + pub backfill_start: Option>, + /// Backfill size to achieve synchronization. (0 before sync completed) + pub backfill_size: u64, + /// When backfill ended + pub backfill_end: Option>, + /// Backfill Failures + pub backfill_failures: u64, + /// The time of the last backfill failure + pub backfill_failure_time: Option>, + /// Current Number of Live Blocks + pub blocks: u64, + /// The current head of the live chain slot# + pub head_slot: Slot, + /// The current live tip slot# as reported by the peer. + pub tip: Slot, + /// Number of times we connected/re-connected to the Node. + pub reconnects: u64, + /// Last reconnect time, + pub last_connect: DateTime, + /// Last reconnect time, + pub last_connected_peer: String, + /// Last disconnect time, + pub last_disconnect: DateTime, + /// Last disconnect time, + pub last_disconnected_peer: String, + /// Is there an active connection to the node + pub connected: bool, + /// Rollback statistics. + pub rollbacks: Rollbacks, + /// New blocks read from blockchain. + pub new_blocks: u64, + /// Blocks that failed to deserialize from the blockchain. + pub invalid_blocks: u64, + /// Active Followers (range and current depth) + pub follower: Vec, +} + +impl Live { + /// Reset incremental counters in the live statistics. + pub(crate) fn reset(&mut self) { + self.new_blocks = 0; + self.reconnects = 0; + self.invalid_blocks = 0; + } +} diff --git a/rust/cardano-chain-follower/src/stats/mithril.rs b/rust/cardano-chain-follower/src/stats/mithril.rs new file mode 100644 index 000000000..32803a227 --- /dev/null +++ b/rust/cardano-chain-follower/src/stats/mithril.rs @@ -0,0 +1,75 @@ +//! Mithril Snapshot Statistics + +use cardano_blockchain_types::Slot; +use chrono::{DateTime, Utc}; +use serde::Serialize; + +/// Statistics related to Mithril Snapshots +#[derive(Debug, Default, Clone, Serialize)] +pub struct Mithril { + /// Number of Mithril Snapshots that have downloaded successfully. + pub updates: u64, + /// The Immutable TIP Slot# - Origin = No downloaded snapshot + pub tip: Slot, + /// Time we started downloading the current snapshot. 1/1/1970-00:00:00 UTC = Never + /// downloaded. + pub dl_start: DateTime, + /// Time we finished downloading the current snapshot. if < `dl_start` its the + /// previous time we finished. + pub dl_end: DateTime, + /// Number of times download failed (bad server connection) + pub dl_failures: u64, + /// The time the last download took, in seconds. + pub last_dl_duration: u64, + /// The size of the download archive, in bytes. (If not started and not ended, current + /// partial download size). + pub dl_size: u64, + /// Extraction start time. 1/1/1970-00:00:00 UTC = Never extracted. + pub extract_start: DateTime, + /// Extraction end time. if `extract_end` < `extract_start` its the previous time we + /// finished extracting. + pub extract_end: DateTime, + /// Number of times extraction failed (bad archive) + pub extract_failures: u64, + /// Size of last extracted snapshot, in bytes. + pub extract_size: u64, + /// Deduplicated Size vs previous snapshot. + pub deduplicated_size: u64, + /// Number of identical files deduplicated from previous snapshot. + pub deduplicated: u64, + /// Number of changed files from previous snapshot. + pub changed: u64, + /// Number of new files from previous snapshot. + pub new: u64, + /// Mithril Certificate Validation Start Time. 1/1/1970-00:00:00 UTC = Never + /// validated. + pub validate_start: DateTime, + /// Mithril Certificate Validation End Time. if validate end < validate start its the + /// previous time we finished validating. + pub validate_end: DateTime, + /// Number of times validation failed (bad snapshot) + pub validate_failures: u64, + /// Blocks that failed to deserialize from the mithril immutable chain. + pub invalid_blocks: u64, + /// Download Or Validation Failed + pub download_or_validation_failed: u64, + /// Failed to get tip from mithril snapshot. + pub failed_to_get_tip: u64, + /// Tip failed to advance + pub tip_did_not_advance: u64, + /// Failed to send new tip to updater. + pub tip_failed_to_send_to_updater: u64, + /// Failed to activate new snapshot + pub failed_to_activate_new_snapshot: u64, +} + +impl Mithril { + /// Reset incremental counters in the mithril statistics. + pub(crate) fn reset(&mut self) { + self.updates = 0; + self.dl_failures = 0; + self.extract_failures = 0; + self.validate_failures = 0; + self.invalid_blocks = 0; + } +} diff --git a/rust/cardano-chain-follower/src/stats.rs b/rust/cardano-chain-follower/src/stats/mod.rs similarity index 64% rename from rust/cardano-chain-follower/src/stats.rs rename to rust/cardano-chain-follower/src/stats/mod.rs index c75915263..530f36a98 100644 --- a/rust/cardano-chain-follower/src/stats.rs +++ b/rust/cardano-chain-follower/src/stats/mod.rs @@ -1,180 +1,23 @@ //! Cardano Chain Follower Statistics +pub(crate) mod follower; +pub(crate) mod live_chain; +pub(crate) mod mithril; +pub(crate) mod rollback; + use std::sync::{Arc, LazyLock, RwLock}; use cardano_blockchain_types::{Network, Slot}; -use chrono::{DateTime, Utc}; +use chrono::Utc; use dashmap::DashMap; +use rollback::{rollbacks, rollbacks_reset, RollbackType}; use serde::Serialize; -use strum::{EnumIter, IntoEnumIterator}; +use strum::IntoEnumIterator; use tracing::error; -// -------- GENERAL STATISTIC TRACKING - -/// Statistics related to Mithril Snapshots -#[derive(Debug, Default, Clone, Serialize)] -pub struct Mithril { - /// Number of Mithril Snapshots that have downloaded successfully. - pub updates: u64, - /// The Immutable TIP Slot# - Origin = No downloaded snapshot - pub tip: Slot, - /// Time we started downloading the current snapshot. 1/1/1970-00:00:00 UTC = Never - /// downloaded. - pub dl_start: DateTime, - /// Time we finished downloading the current snapshot. if < `dl_start` its the - /// previous time we finished. - pub dl_end: DateTime, - /// Number of times download failed (bad server connection) - pub dl_failures: u64, - /// The time the last download took, in seconds. - pub last_dl_duration: u64, - /// The size of the download archive, in bytes. (If not started and not ended, current - /// partial download size). - pub dl_size: u64, - /// Extraction start time. 1/1/1970-00:00:00 UTC = Never extracted. - pub extract_start: DateTime, - /// Extraction end time. if `extract_end` < `extract_start` its the previous time we - /// finished extracting. - pub extract_end: DateTime, - /// Number of times extraction failed (bad archive) - pub extract_failures: u64, - /// Size of last extracted snapshot, in bytes. - pub extract_size: u64, - /// Deduplicated Size vs previous snapshot. - pub deduplicated_size: u64, - /// Number of identical files deduplicated from previous snapshot. - pub deduplicated: u64, - /// Number of changed files from previous snapshot. - pub changed: u64, - /// Number of new files from previous snapshot. - pub new: u64, - /// Mithril Certificate Validation Start Time. 1/1/1970-00:00:00 UTC = Never - /// validated. - pub validate_start: DateTime, - /// Mithril Certificate Validation End Time. if validate end < validate start its the - /// previous time we finished validating. - pub validate_end: DateTime, - /// Number of times validation failed (bad snapshot) - pub validate_failures: u64, - /// Blocks that failed to deserialize from the mithril immutable chain. - pub invalid_blocks: u64, - /// Download Or Validation Failed - pub download_or_validation_failed: u64, - /// Failed to get tip from mithril snapshot. - pub failed_to_get_tip: u64, - /// Tip failed to advance - pub tip_did_not_advance: u64, - /// Failed to send new tip to updater. - pub tip_failed_to_send_to_updater: u64, - /// Failed to activate new snapshot - pub failed_to_activate_new_snapshot: u64, -} - -impl Mithril { - /// Reset incremental counters in the mithril statistics. - fn reset(&mut self) { - self.updates = 0; - self.dl_failures = 0; - self.extract_failures = 0; - self.validate_failures = 0; - self.invalid_blocks = 0; - } -} - -/// Statistics related to a single depth of rollback -#[derive(Debug, Default, Clone, Serialize)] -pub struct Rollback { - /// How deep was the rollback from tip. - pub depth: u64, - /// How many times has a rollback been this deep. - pub count: u64, -} - -/// Statistics for all our known rollback types -/// Rollback Vec is sorted by depth, ascending. -#[derive(Debug, Default, Clone, Serialize)] -pub struct Rollbacks { - /// These are the ACTUAL rollbacks we did on our live-chain in memory. - pub live: Vec, - /// These are the rollbacks reported by the Peer Node, which may not == an actual - /// rollback on our internal live chain. - pub peer: Vec, - /// These are the rollbacks synthesized for followers, based on their reading of the - /// chain tip. - pub follower: Vec, -} - -/// Individual Follower stats -#[derive(Debug, Default, Clone, Serialize)] -pub struct Follower { - /// Synthetic follower connection ID - pub id: u64, - /// Starting slot for this follower (0 = Start at Genesis Block for the chain). - pub start: Slot, - /// Current slot for this follower. - pub current: Slot, - /// Target slot for this follower (MAX U64 == Follow Tip Forever). - pub end: Slot, - /// Current Sync Time. - pub sync_start: DateTime, - /// When this follower reached TIP or its destination slot. - pub sync_end: Option>, -} +use crate::stats::{live_chain::Live, mithril::Mithril}; -/// Statistics related to the live blockchain -#[derive(Debug, Default, Clone, Serialize)] -pub struct Live { - /// The Time that synchronization to this blockchain started - pub sync_start: DateTime, - /// The Time that synchronization to this blockchain was complete up-to-tip. None = - /// Not yet synchronized. - pub sync_end: Option>, - /// When backfill started - pub backfill_start: Option>, - /// Backfill size to achieve synchronization. (0 before sync completed) - pub backfill_size: u64, - /// When backfill ended - pub backfill_end: Option>, - /// Backfill Failures - pub backfill_failures: u64, - /// The time of the last backfill failure - pub backfill_failure_time: Option>, - /// Current Number of Live Blocks - pub blocks: u64, - /// The current head of the live chain slot# - pub head_slot: Slot, - /// The current live tip slot# as reported by the peer. - pub tip: Slot, - /// Number of times we connected/re-connected to the Node. - pub reconnects: u64, - /// Last reconnect time, - pub last_connect: DateTime, - /// Last reconnect time, - pub last_connected_peer: String, - /// Last disconnect time, - pub last_disconnect: DateTime, - /// Last disconnect time, - pub last_disconnected_peer: String, - /// Is there an active connection to the node - pub connected: bool, - /// Rollback statistics. - pub rollbacks: Rollbacks, - /// New blocks read from blockchain. - pub new_blocks: u64, - /// Blocks that failed to deserialize from the blockchain. - pub invalid_blocks: u64, - /// Active Followers (range and current depth) - pub follower: Vec, -} - -impl Live { - /// Reset incremental counters in the live statistics. - fn reset(&mut self) { - self.new_blocks = 0; - self.reconnects = 0; - self.invalid_blocks = 0; - } -} +// -------- GENERAL STATISTIC TRACKING /// Statistics for a single follower network. #[derive(Debug, Default, Clone, Serialize)] @@ -615,116 +458,6 @@ pub(crate) fn mithril_sync_failure(network: Network, failure: MithrilSyncFailure } } -// -------- ROLLBACK STATISTIC TRACKING -// ---------------------------------------------------------- - -/// The types of rollbacks we track for a chain. -#[derive(EnumIter, Eq, Ord, PartialEq, PartialOrd, Copy, Clone, Hash)] -pub enum RollbackType { - /// Rollback on the in-memory live chain. - LiveChain, - /// Rollback signaled by the peer. - Peer, - /// Rollback synthesized for the Follower. - Follower, -} - -/// Individual rollback records. -type RollbackRecords = DashMap; -/// Rollback Records per rollback type. -type RollbackTypeMap = DashMap>>; -/// Record of rollbacks. -type RollbackMap = DashMap; -/// Statistics of rollbacks detected per chain. -static ROLLBACKS_MAP: LazyLock = LazyLock::new(|| { - let map = RollbackMap::new(); - for network in Network::iter() { - let type_map = RollbackTypeMap::new(); - for rollback in RollbackType::iter() { - type_map.insert(rollback, Arc::new(RwLock::new(RollbackRecords::new()))); - } - map.insert(network, type_map); - } - map -}); - -/// Get the actual rollback map for a chain. -fn lookup_rollback_map( - network: Network, rollback: RollbackType, -) -> Option>> { - let Some(chain_rollback_map) = ROLLBACKS_MAP.get(&network) else { - error!("Rollback stats SHOULD BE exhaustively pre-allocated."); - return None; - }; - let chain_rollback_map = chain_rollback_map.value(); - - let Some(rollback_map) = chain_rollback_map.get(&rollback) else { - error!("Rollback stats SHOULD BE exhaustively pre-allocated."); - return None; - }; - let rollback_map = rollback_map.value(); - - Some(rollback_map.clone()) -} - -/// Extract the current rollback stats as a vec. -fn rollbacks(network: Network, rollback: RollbackType) -> Vec { - let Some(rollback_map) = lookup_rollback_map(network, rollback) else { - return Vec::new(); - }; - - let Ok(rollback_values) = rollback_map.read() else { - error!("Rollback stats LOCK Poisoned, should not happen."); - return vec![]; - }; - - let mut rollbacks = Vec::new(); - - // Get all the rollback stats. - for stat in rollback_values.iter() { - rollbacks.push(stat.value().clone()); - } - - rollbacks -} - -/// Reset ALL the rollback stats for a given blockchain. -fn rollbacks_reset(network: Network, rollback: RollbackType) -> Vec { - let Some(rollback_map) = lookup_rollback_map(network, rollback) else { - return Vec::new(); - }; - - let Ok(rollbacks) = rollback_map.write() else { - error!("Rollback stats LOCK Poisoned, should not happen."); - return vec![]; - }; - - rollbacks.clear(); - - Vec::new() -} - -/// Count a rollback -pub(crate) fn rollback(network: Network, rollback: RollbackType, depth: u64) { - let Some(rollback_map) = lookup_rollback_map(network, rollback) else { - return; - }; - - let Ok(rollbacks) = rollback_map.write() else { - error!("Rollback stats LOCK Poisoned, should not happen."); - return; - }; - - let mut value = match rollbacks.get(&depth) { - Some(value_entry) => (*value_entry.value()).clone(), - None => Rollback { depth, count: 0 }, - }; - - value.count += 1; - - let _unused = rollbacks.insert(depth, value); -} - #[cfg(test)] #[allow(clippy::unwrap_used)] mod tests { diff --git a/rust/cardano-chain-follower/src/stats/rollback.rs b/rust/cardano-chain-follower/src/stats/rollback.rs new file mode 100644 index 000000000..646348480 --- /dev/null +++ b/rust/cardano-chain-follower/src/stats/rollback.rs @@ -0,0 +1,141 @@ +//! Rollback statistics. + +use std::sync::{Arc, LazyLock, RwLock}; + +use cardano_blockchain_types::Network; +use dashmap::DashMap; +use serde::Serialize; +use strum::{EnumIter, IntoEnumIterator}; +use tracing::error; + +/// Statistics related to a single depth of rollback +#[derive(Debug, Default, Clone, Serialize)] +pub struct Rollback { + /// How deep was the rollback from tip. + pub depth: u64, + /// How many times has a rollback been this deep. + pub count: u64, +} + +/// Statistics for all our known rollback types +/// Rollback Vec is sorted by depth, ascending. +#[derive(Debug, Default, Clone, Serialize)] +pub struct Rollbacks { + /// These are the ACTUAL rollbacks we did on our live-chain in memory. + pub live: Vec, + /// These are the rollbacks reported by the Peer Node, which may not == an actual + /// rollback on our internal live chain. + pub peer: Vec, + /// These are the rollbacks synthesized for followers, based on their reading of the + /// chain tip. + pub follower: Vec, +} + +/// The types of rollbacks we track for a chain. +#[derive(EnumIter, Eq, Ord, PartialEq, PartialOrd, Copy, Clone, Hash)] +#[allow(clippy::module_name_repetitions)] +pub enum RollbackType { + /// Rollback on the in-memory live chain. + LiveChain, + /// Rollback signaled by the peer. + Peer, + /// Rollback synthesized for the Follower. + Follower, +} + +/// Individual rollback records. +type RollbackRecords = DashMap; +/// Rollback Records per rollback type. +type RollbackTypeMap = DashMap>>; +/// Record of rollbacks. +type RollbackMap = DashMap; + +/// Statistics of rollbacks detected per chain. +static ROLLBACKS_MAP: LazyLock = LazyLock::new(|| { + let map = RollbackMap::new(); + for network in Network::iter() { + let type_map = RollbackTypeMap::new(); + for rollback in RollbackType::iter() { + type_map.insert(rollback, Arc::new(RwLock::new(RollbackRecords::new()))); + } + map.insert(network, type_map); + } + map +}); + +/// Get the actual rollback map for a chain. +fn lookup_rollback_map( + network: Network, rollback: RollbackType, +) -> Option>> { + let Some(chain_rollback_map) = ROLLBACKS_MAP.get(&network) else { + error!("Rollback stats SHOULD BE exhaustively pre-allocated."); + return None; + }; + let chain_rollback_map = chain_rollback_map.value(); + + let Some(rollback_map) = chain_rollback_map.get(&rollback) else { + error!("Rollback stats SHOULD BE exhaustively pre-allocated."); + return None; + }; + let rollback_map = rollback_map.value(); + + Some(rollback_map.clone()) +} + +/// Extract the current rollback stats as a vec. +pub(crate) fn rollbacks(network: Network, rollback: RollbackType) -> Vec { + let Some(rollback_map) = lookup_rollback_map(network, rollback) else { + return Vec::new(); + }; + + let Ok(rollback_values) = rollback_map.read() else { + error!("Rollback stats LOCK Poisoned, should not happen."); + return vec![]; + }; + + let mut rollbacks = Vec::new(); + + // Get all the rollback stats. + for stat in rollback_values.iter() { + rollbacks.push(stat.value().clone()); + } + + rollbacks +} + +/// Reset ALL the rollback stats for a given blockchain. +pub(crate) fn rollbacks_reset(network: Network, rollback: RollbackType) -> Vec { + let Some(rollback_map) = lookup_rollback_map(network, rollback) else { + return Vec::new(); + }; + + let Ok(rollbacks) = rollback_map.write() else { + error!("Rollback stats LOCK Poisoned, should not happen."); + return vec![]; + }; + + rollbacks.clear(); + + Vec::new() +} + +/// Count a rollback +pub(crate) fn rollback(network: Network, rollback: RollbackType, depth: u64) { + let Some(rollback_map) = lookup_rollback_map(network, rollback) else { + return; + }; + + let Ok(rollbacks) = rollback_map.write() else { + error!("Rollback stats LOCK Poisoned, should not happen."); + return; + }; + + let mut value = match rollbacks.get(&depth) { + Some(value_entry) => (*value_entry.value()).clone(), + None => Rollback { depth, count: 0 }, + }; + + value.count += 1; + + let _unused = rollbacks.insert(depth, value); +} From e74e3b542080bb30def52d5ffe79a9f899c74694 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Thu, 9 Jan 2025 14:33:29 +0700 Subject: [PATCH 32/40] fix(cardano-chain-follower): example log cip36 Signed-off-by: bkioshn --- rust/cardano-chain-follower/examples/follow_chains.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/cardano-chain-follower/examples/follow_chains.rs b/rust/cardano-chain-follower/examples/follow_chains.rs index ca86ebbaa..ba733fb6a 100644 --- a/rust/cardano-chain-follower/examples/follow_chains.rs +++ b/rust/cardano-chain-follower/examples/follow_chains.rs @@ -238,7 +238,7 @@ async fn follow_for(network: Network, matches: ArgMatches) { } // Logging bad CIP36. - if !is_log_bad_cip36 { + if is_log_bad_cip36 { log_bad_cip36_info(chain_update.block_data(), network); } // // Inspect the transactions in the block. From 7ab857c3e38792eb2a90f82db10d3da55d7db7e8 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Thu, 9 Jan 2025 14:38:47 +0700 Subject: [PATCH 33/40] fix(cardano-chain-follower): remove unused dependencies Signed-off-by: bkioshn --- rust/cardano-chain-follower/Cargo.toml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/rust/cardano-chain-follower/Cargo.toml b/rust/cardano-chain-follower/Cargo.toml index 349eeda5a..d0389d456 100644 --- a/rust/cardano-chain-follower/Cargo.toml +++ b/rust/cardano-chain-follower/Cargo.toml @@ -20,7 +20,7 @@ mithril-client = { version = "0.10.4", default-features = false, features = [ "num-integer-backend", ] } -rbac-registration = { version = "0.0.2", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "v0.0.8" } +# rbac-registration = { version = "0.0.2", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "v0.0.8" } cardano-blockchain-types = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", branch = "fix/cip36" } catalyst-types = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250108-00" } @@ -38,14 +38,12 @@ url = "2.5.4" anyhow = "1.0.95" chrono = "0.4.39" async-trait = "0.1.83" -dirs = "5.0.1" futures = "0.3.31" humantime = "2.1.0" crossbeam-skiplist = "0.1.3" crossbeam-channel = "0.5.14" crossbeam-epoch = "0.9.18" strum = "0.26.3" -ouroboros = "0.18.4" hex = "0.4.3" rayon = "1.10.0" serde = "1.0.217" @@ -53,11 +51,7 @@ serde_json = "1.0.134" mimalloc = { version = "0.1.43", optional = true } memx = "0.1.32" fmmap = { version = "0.3.3", features = ["sync", "tokio-async"] } -minicbor = { version = "0.25.1", features = ["alloc", "derive", "half"] } zstd = "0.13.2" -ed25519-dalek = "2.1.1" -blake2b_simd = "1.0.2" -num-traits = "0.2.19" logcall = "0.1.11" tar = "0.4.43" ureq = { version = "2.12.1", features = ["native-certs"] } From 60c7237f9f6cf32321ac31d01617ab2683f98c73 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Thu, 9 Jan 2025 18:36:43 +0700 Subject: [PATCH 34/40] fix(cardano-chain-follower): modify logging metadata example Signed-off-by: bkioshn --- rust/cardano-chain-follower/Cargo.toml | 4 +- .../examples/follow_chains.rs | 105 +++--------------- 2 files changed, 16 insertions(+), 93 deletions(-) diff --git a/rust/cardano-chain-follower/Cargo.toml b/rust/cardano-chain-follower/Cargo.toml index d0389d456..5b1709199 100644 --- a/rust/cardano-chain-follower/Cargo.toml +++ b/rust/cardano-chain-follower/Cargo.toml @@ -19,8 +19,6 @@ mithril-client = { version = "0.10.4", default-features = false, features = [ "full", "num-integer-backend", ] } - -# rbac-registration = { version = "0.0.2", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "v0.0.8" } cardano-blockchain-types = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", branch = "fix/cip36" } catalyst-types = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250108-00" } @@ -60,12 +58,12 @@ hickory-resolver = { version = "0.24.2", features = ["dns-over-rustls"] } moka = { version = "0.12.9", features = ["sync"] } [dev-dependencies] -hex = "0.4.3" tracing-subscriber = { version = "0.3.19", features = ["env-filter"] } test-log = { version = "0.2.16", default-features = false, features = [ "trace", ] } clap = "4.5.23" +# rbac-registration = { version = "0.0.2", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "v0.0.8" } # Note, these features are for support of features exposed by dependencies. [features] diff --git a/rust/cardano-chain-follower/examples/follow_chains.rs b/rust/cardano-chain-follower/examples/follow_chains.rs index ba733fb6a..de9da9b33 100644 --- a/rust/cardano-chain-follower/examples/follow_chains.rs +++ b/rust/cardano-chain-follower/examples/follow_chains.rs @@ -37,14 +37,8 @@ fn process_argument() -> (Vec, ArgMatches) { .action(ArgAction::SetTrue), arg!(--"halt-on-error" "Stop the process when an error occurs without retrying.") .action(ArgAction::SetTrue), - arg!(--"log-bad-cip36" "Dump Bad CIP36 registrations detected.") - .action(ArgAction::SetTrue), - arg!(--"log-cip509" "Dump CIP509 validation.") - .action(ArgAction::SetTrue), arg!(--"log-raw-aux" "Dump raw auxiliary data.") .action(ArgAction::SetTrue), - arg!(--"largest-metadata" "Dump The largest transaction metadata we find (as we find it).") - .action(ArgAction::SetTrue), arg!(--"mithril-sync-workers" "The number of workers to use when downloading the blockchain snapshot.") .value_parser(clap::value_parser!(u16).range(1..)) .action(ArgAction::Set), @@ -60,6 +54,9 @@ fn process_argument() -> (Vec, ArgMatches) { arg!(--"mithril-sync-data-read-timeout" "The HTTP Data Read Timeout for mithril downloads, in seconds.") .value_parser(clap::value_parser!(u64).range(1..)) .action(ArgAction::Set), + // Metadata + arg!(--"log-bad-cip36" "Dump Bad CIP36 registrations detected.") + .action(ArgAction::SetTrue), ]) .get_matches(); @@ -147,10 +144,10 @@ async fn follow_for(network: Network, matches: ArgMatches) { let is_all_live_blocks = matches.get_flag("all-live-blocks"); let is_stop_at_tip = matches.get_flag("stop-at-tip"); let is_halt_on_error = matches.get_flag("halt-on-error"); - let is_log_bad_cip36 = matches.get_flag("log-bad-cip36"); - let _is_log_cip509 = matches.get_flag("log-cip509"); let is_log_raw_aux = matches.get_flag("log-raw-aux"); - let _is_largest_metadata = matches.get_flag("largest-metadata"); + + // Metadata + let is_log_bad_cip36 = matches.get_flag("log-bad-cip36"); let mut current_era = String::new(); let mut last_update: Option = None; @@ -164,8 +161,6 @@ async fn follow_for(network: Network, matches: ArgMatches) { let mut last_metrics_time = Instant::now(); - // let mut biggest_aux_data: usize = 0; - while let Some(chain_update) = follower.next().await { updates += 1; @@ -237,29 +232,6 @@ async fn follow_for(network: Network, matches: ArgMatches) { break; } - // Logging bad CIP36. - if is_log_bad_cip36 { - log_bad_cip36_info(chain_update.block_data(), network); - } - // // Inspect the transactions in the block. - // for (txn_idx, _tx) in block.txs().iter().enumerate() { - // // if let Some(aux_data) = update_biggest_aux_data( - // // &chain_update, - // // txn_idx, - // // is_largest_metadata, - // // biggest_aux_data, - // // ) { - // // biggest_aux_data = aux_data; - // // } - - // // If flag `is_log_bad_cip36` is set, log the bad CIP36. - - // // If flag `is_log_cip509` is set, log the CIP509 validation. - // // if is_log_cip509 { - // // log_cip509_info(&decoded_metadata, network, txn_idx, block.number()); - // // } - // } - if is_log_raw_aux { if let Some(x) = block.as_alonzo() { info!( @@ -279,6 +251,13 @@ async fn follow_for(network: Network, matches: ArgMatches) { } } + // Illustrate how the chain-follower works with metadata. + // Log bad CIP36. + if is_log_bad_cip36 { + log_bad_cip36_info(chain_update.block_data(), network); + } + // TODO - Add CIP509 example. + prev_hash = Some(block.hash()); last_update = Some(chain_update); @@ -321,40 +300,8 @@ async fn follow_for(network: Network, matches: ArgMatches) { info!(network = network.to_string(), "Following Completed."); } -// // FIXME: Why do we need this? Should it be finding the largest aux data? -// /// Helper function for updating the biggest aux data. -// /// Comparing between CIP36 and CIP509. -// fn update_biggest_aux_data( -// chain_update: &ChainUpdate, txn_idx: TxnIndex, largest_metadata: bool, -// biggest_aux_data: usize, ) -> Option { -// let raw_size_cip36 = match chain_update -// .data -// .txn_metadata(txn_idx, MetadatumLabel::CIP036_REGISTRATION) -// { -// Some(raw) => raw.as_ref().len(), -// None => 0, -// }; - -// let raw_size_cip509 = match chain_update -// .data -// .txn_metadata(txn_idx, MetadatumLabel::CIP509_RBAC) -// { -// Some(raw) => raw.as_ref().len(), -// None => 0, -// }; - -// // Get the maximum raw size from both cip36 and cip509 -// let raw_size = raw_size_cip36.max(raw_size_cip509); - -// if largest_metadata && raw_size > biggest_aux_data { -// return Some(raw_size); -// } - -// None -// } - -/// Helper function for logging bad CIP36. -/// Bad CIP36 include: +/// Function for logging bad CIP36. +/// Bad CIP36 includes: /// - CIP36 that is valid decoded, but have problem. /// - CIP36 that is invalid decoded. fn log_bad_cip36_info(block: &MultiEraBlock, network: Network) { @@ -378,28 +325,6 @@ fn log_bad_cip36_info(block: &MultiEraBlock, network: Network) { } } -// /// Helper function for logging CIP509 validation. -// fn log_cip509_info( -// decoded_metadata: &DecodedMetadata, network: Network, txn_idx: TxnIndex, block: -// u64, ) { -// if let Some(m) = decoded_metadata.get(MetadatumLabel::CIP509_RBAC) { -// if let Metadata::DecodedMetadataValues::Cip509(cip509) = &m.value { -// info!( -// network = network.to_string(), -// block, "CIP509 {txn_idx:?}: {:?}", &cip509 -// ); -// } - -// // If report is not empty, log it, log it as a warning. -// if !m.report.is_empty() { -// warn!( -// network = network.to_string(), -// block, "CIP509 {txn_idx:?}: {:?}", decoded_metadata -// ); -// } -// } -// } - #[tokio::main] async fn main() -> Result<(), Box> { tracing_subscriber::fmt() From cbe8f864699683b2d7fe179b8043ff58556f19e3 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Fri, 10 Jan 2025 13:50:43 +0700 Subject: [PATCH 35/40] fix(cardano-chain-follower): revert changes Signed-off-by: bkioshn --- .../examples/follow_chains.rs | 77 +++++----- rust/cardano-chain-follower/src/chain_sync.rs | 82 +++++----- .../src/chain_sync_config.rs | 27 ++-- .../src/chain_sync_live_chains.rs | 94 ++++++------ .../src/chain_sync_ready.rs | 24 +-- .../src/chain_update.rs | 2 +- rust/cardano-chain-follower/src/error.rs | 2 +- rust/cardano-chain-follower/src/follow.rs | 68 ++++----- .../src/mithril_snapshot.rs | 12 +- .../src/mithril_snapshot_config.rs | 49 +++--- .../src/mithril_snapshot_data.rs | 14 +- .../src/mithril_snapshot_iterator.rs | 30 ++-- .../src/mithril_snapshot_sync.rs | 142 +++++++++--------- .../src/mithril_turbo_downloader.rs | 22 +-- .../cardano-chain-follower/src/snapshot_id.rs | 44 +++--- 15 files changed, 340 insertions(+), 349 deletions(-) diff --git a/rust/cardano-chain-follower/examples/follow_chains.rs b/rust/cardano-chain-follower/examples/follow_chains.rs index de9da9b33..bab914bab 100644 --- a/rust/cardano-chain-follower/examples/follow_chains.rs +++ b/rust/cardano-chain-follower/examples/follow_chains.rs @@ -114,7 +114,7 @@ async fn start_sync_for(network: &Network, matches: ArgMatches) -> Result<(), Bo cfg.mithril_cfg = cfg.mithril_cfg.with_dl_config(dl_config); info!( - network = cfg.network.to_string(), + chain = cfg.chain.to_string(), mithril_sync_dl_workers = mithril_dl_workers, mithril_sync_dl_chunk_size = mithril_dl_chunk_size, mithril_sync_dl_queue_ahead = mithril_dl_queue_ahead, @@ -137,27 +137,27 @@ const RUNNING_UPDATE_INTERVAL: u64 = 100_000; /// Try and follow a chain continuously, from Genesis until Tip. #[allow(clippy::too_many_lines)] async fn follow_for(network: Network, matches: ArgMatches) { - info!(network = network.to_string(), "Following"); + info!(chain = network.to_string(), "Following"); let mut follower = ChainFollower::new(network, Point::ORIGIN, Point::TIP).await; - let is_all_tip_blocks = matches.get_flag("all-tip-blocks"); - let is_all_live_blocks = matches.get_flag("all-live-blocks"); - let is_stop_at_tip = matches.get_flag("stop-at-tip"); - let is_halt_on_error = matches.get_flag("halt-on-error"); - let is_log_raw_aux = matches.get_flag("log-raw-aux"); + let all_tip_blocks = matches.get_flag("all-tip-blocks"); + let all_live_blocks = matches.get_flag("all-live-blocks"); + let stop_at_tip = matches.get_flag("stop-at-tip"); + let halt_on_error = matches.get_flag("halt-on-error"); + let log_raw_aux = matches.get_flag("log-raw-aux"); // Metadata - let is_log_bad_cip36 = matches.get_flag("log-bad-cip36"); + let log_bad_cip36 = matches.get_flag("log-bad-cip36"); let mut current_era = String::new(); let mut last_update: Option = None; - let mut is_last_update_shown = false; + let mut last_update_shown = false; let mut prev_hash: Option> = None; - let mut is_last_immutable: bool = false; - let mut is_reached_tip = false; // After we reach TIP we show all block we process. + let mut last_immutable: bool = false; + let mut reached_tip = false; // After we reach TIP we show all block we process. let mut updates: u64 = 0; let mut last_fork: Fork = 0.into(); - let mut is_follow_all = false; + let mut follow_all = false; let mut last_metrics_time = Instant::now(); @@ -165,7 +165,7 @@ async fn follow_for(network: Network, matches: ArgMatches) { updates += 1; if chain_update.tip { - is_reached_tip = true; + reached_tip = true; } let block = chain_update.block_data().decode(); @@ -173,13 +173,13 @@ async fn follow_for(network: Network, matches: ArgMatches) { // When we transition between important points, show the last block as well. if ((current_era != this_era) - || (chain_update.is_immutable() != is_last_immutable) + || (chain_update.immutable() != last_immutable) || (last_fork != chain_update.data.fork())) - && !is_last_update_shown + && !last_update_shown { if let Some(last_update) = last_update.clone() { info!( - network = network.to_string(), + chain = network.to_string(), "Chain Update {}:{}", updates - 1, last_update @@ -188,29 +188,29 @@ async fn follow_for(network: Network, matches: ArgMatches) { } // If these become true, we will show all blocks from the follower. - is_follow_all = is_follow_all - || (!chain_update.is_immutable() && is_all_live_blocks) - || ((chain_update.data.fork() > 1.into()) && is_all_tip_blocks); + follow_all = follow_all + || (!chain_update.immutable() && all_live_blocks) + || ((chain_update.data.fork() > 1.into()) && all_tip_blocks); // Don't know if this update will show or not, so say it didn't. - is_last_update_shown = false; + last_update_shown = false; if (current_era != this_era) - || (chain_update.is_immutable() != is_last_immutable) - || is_reached_tip - || is_follow_all + || (chain_update.immutable() != last_immutable) + || reached_tip + || follow_all || (updates % RUNNING_UPDATE_INTERVAL == 0) || (last_fork != chain_update.data.fork()) { current_era = this_era; - is_last_immutable = chain_update.is_immutable(); + last_immutable = chain_update.immutable(); last_fork = chain_update.data.fork(); info!( - network = network.to_string(), + chain = network.to_string(), "Chain Update {updates}:{}", chain_update ); // We already showed the last update, no need to show it again. - is_last_update_shown = true; + last_update_shown = true; } let this_prev_hash = block.header().previous_hash(); @@ -226,26 +226,26 @@ async fn follow_for(network: Network, matches: ArgMatches) { "This Can't Happen".to_string() }; error!( - network = network.to_string(), + chain = network.to_string(), "Chain is broken: {chain_update} Does not follow: {display_last_update}", ); break; } - if is_log_raw_aux { + if log_raw_aux { if let Some(x) = block.as_alonzo() { info!( - network = network.to_string(), + chain = network.to_string(), "Raw Aux Data: {:02x?}", x.auxiliary_data_set ); } else if let Some(x) = block.as_babbage() { info!( - network = network.to_string(), + chain = network.to_string(), "Raw Aux Data: {:02x?}", x.auxiliary_data_set ); } else if let Some(x) = block.as_conway() { info!( - network = network.to_string(), + chain = network.to_string(), "Raw Aux Data: {:02x?}", x.auxiliary_data_set ); } @@ -253,7 +253,7 @@ async fn follow_for(network: Network, matches: ArgMatches) { // Illustrate how the chain-follower works with metadata. // Log bad CIP36. - if is_log_bad_cip36 { + if log_bad_cip36 { log_bad_cip36_info(chain_update.block_data(), network); } // TODO - Add CIP509 example. @@ -261,7 +261,7 @@ async fn follow_for(network: Network, matches: ArgMatches) { prev_hash = Some(block.hash()); last_update = Some(chain_update); - if is_reached_tip && is_stop_at_tip { + if reached_tip && stop_at_tip { break; } @@ -273,7 +273,7 @@ async fn follow_for(network: Network, matches: ArgMatches) { info!("Json Metrics: {}", stats.as_json(true)); - if is_halt_on_error + if halt_on_error && (stats.mithril.download_or_validation_failed > 0 || stats.mithril.failed_to_get_tip > 0 || stats.mithril.tip_did_not_advance > 0 @@ -285,19 +285,16 @@ async fn follow_for(network: Network, matches: ArgMatches) { } } - if !is_last_update_shown { + if !last_update_shown { if let Some(last_update) = last_update.clone() { - info!( - network = network.to_string(), - "Last Update: {}", last_update - ); + info!(chain = network.to_string(), "Last Update: {}", last_update); } } let stats = Statistics::new(network); info!("Json Metrics: {}", stats.as_json(true)); - info!(network = network.to_string(), "Following Completed."); + info!(chain = network.to_string(), "Following Completed."); } /// Function for logging bad CIP36. diff --git a/rust/cardano-chain-follower/src/chain_sync.rs b/rust/cardano-chain-follower/src/chain_sync.rs index 8f62b0198..abccfb428 100644 --- a/rust/cardano-chain-follower/src/chain_sync.rs +++ b/rust/cardano-chain-follower/src/chain_sync.rs @@ -123,7 +123,7 @@ async fn resync_live_tip(client: &mut PeerClient, chain: Network) -> Result anyhow::Result { let block_data = peer .blockfetch() @@ -131,8 +131,8 @@ async fn fetch_block_from_peer( .await .with_context(|| "Fetching block data")?; - debug!("{chain}, {previous_point}, {fork:?}"); - let live_block_data = MultiEraBlock::new(chain, block_data, &previous_point, fork)?; + debug!("{chain}, {previous_point}, {fork_count:?}"); + let live_block_data = MultiEraBlock::new(chain, block_data, &previous_point, fork_count)?; Ok(live_block_data) } @@ -142,7 +142,7 @@ async fn fetch_block_from_peer( /// Fetch the rollback block, and try and insert it into the live-chain. /// If its a real rollback, it will purge the chain ahead of the block automatically. async fn process_rollback_actual( - peer: &mut PeerClient, chain: Network, point: Point, tip: &Tip, fork: &mut Fork, + peer: &mut PeerClient, chain: Network, point: Point, tip: &Tip, fork_count: &mut Fork, ) -> anyhow::Result { debug!("RollBackward: {:?} {:?}", point, tip); @@ -150,8 +150,8 @@ async fn process_rollback_actual( // rest of live chain tip. And increments the fork count. if let Some(mut block) = get_live_block(chain, &point, 0, true) { // Even though we are re-adding the known block, increase the fork count. - block.set_fork(*fork); - live_chain_add_block_to_tip(chain, block, fork, tip.0.clone().into())?; + block.set_fork(*fork_count); + live_chain_add_block_to_tip(chain, block, fork_count, tip.0.clone().into())?; return Ok(point); } @@ -176,8 +176,9 @@ async fn process_rollback_actual( latest_mithril_snapshot_id(chain).tip() }; debug!("Previous point: {:?}", previous_point); - let block = fetch_block_from_peer(peer, chain, point.clone(), previous_point, *fork).await?; - live_chain_add_block_to_tip(chain, block, fork, tip.0.clone().into())?; + let block = + fetch_block_from_peer(peer, chain, point.clone(), previous_point, *fork_count).await?; + live_chain_add_block_to_tip(chain, block, fork_count, tip.0.clone().into())?; // Next block we receive is a rollback. Ok(point) @@ -186,7 +187,7 @@ async fn process_rollback_actual( /// Process a rollback detected from the peer. async fn process_rollback( peer: &mut PeerClient, chain: Network, point: Point, tip: &Tip, previous_point: &Point, - fork: &mut Fork, + fork_count: &mut Fork, ) -> anyhow::Result { let rollback_slot = point.slot_or_default(); let head_slot = previous_point.slot_or_default(); @@ -195,7 +196,7 @@ async fn process_rollback( let slot_rollback_size = head_slot - rollback_slot; // We actually do the work here... - let response = process_rollback_actual(peer, chain, point, tip, fork).await?; + let response = process_rollback_actual(peer, chain, point, tip, fork_count).await?; // We never really know how many blocks are rolled back when advised by the peer, but we // can work out how many slots. This function wraps the real work, so we can properly @@ -212,7 +213,7 @@ async fn process_rollback( /// Process a rollback detected from the peer. async fn process_next_block( peer: &mut PeerClient, chain: Network, header: HeaderContent, tip: &Tip, - previous_point: &Point, fork: &mut Fork, + previous_point: &Point, fork_count: &mut Fork, ) -> anyhow::Result { // Decode the Header of the block so we know what to fetch. let decoded_header = MultiEraHeader::decode( @@ -231,7 +232,7 @@ async fn process_next_block( chain, block_point.clone(), previous_point.clone(), - *fork, + *fork_count, ) .await?; @@ -244,7 +245,7 @@ async fn process_next_block( // one. Just return it's point. debug!("Not storing the block, because we did not know the previous point."); } else { - live_chain_add_block_to_tip(chain, block, fork, tip.0.clone().into())?; + live_chain_add_block_to_tip(chain, block, fork_count, tip.0.clone().into())?; } Ok(block_point) @@ -255,7 +256,7 @@ async fn process_next_block( /// /// We take ownership of the client because of that. async fn follow_chain( - peer: &mut PeerClient, chain: Network, fork: &mut Fork, + peer: &mut PeerClient, chain: Network, fork_count: &mut Fork, ) -> anyhow::Result<()> { let mut update_sender = get_chain_update_tx_queue(chain).await; let mut previous_point = Point::UNKNOWN; @@ -286,7 +287,8 @@ async fn follow_chain( // subtracting current block height and the tip block height. // IF the TIP is <= the current block height THEN we are at tip. previous_point = - process_next_block(peer, chain, header, &tip, &previous_point, fork).await?; + process_next_block(peer, chain, header, &tip, &previous_point, fork_count) + .await?; // This update is just for followers to know to look again at their live chains for // new data. @@ -294,7 +296,7 @@ async fn follow_chain( }, chainsync::NextResponse::RollBackward(point, tip) => { previous_point = - process_rollback(peer, chain, point.into(), &tip, &previous_point, fork) + process_rollback(peer, chain, point.into(), &tip, &previous_point, fork_count) .await?; // This update is just for followers to know to look again at their live chains for // new data. @@ -346,15 +348,15 @@ async fn persistent_reconnect(addr: &str, chain: Network) -> PeerClient { async fn live_sync_backfill( cfg: &ChainSyncConfig, update: &MithrilUpdateMessage, ) -> anyhow::Result<()> { - stats::backfill_started(cfg.network); + stats::backfill_started(cfg.chain); - let (fill_to, _oldest_fork) = get_fill_to_point(cfg.network).await; + let (fill_to, _oldest_fork) = get_fill_to_point(cfg.chain).await; let range = (update.tip.clone().into(), fill_to.clone().into()); let mut previous_point = update.previous.clone(); let range_msg = format!("{range:?}"); - let mut peer = persistent_reconnect(&cfg.relay_address, cfg.network).await; + let mut peer = persistent_reconnect(&cfg.relay_address, cfg.chain).await; // Request the range of blocks from the Peer. peer.blockfetch() @@ -366,7 +368,7 @@ async fn live_sync_backfill( while let Some(block_data) = peer.blockfetch().recv_while_streaming().await? { // Backfilled blocks get placed in the oldest fork currently on the live-chain. - let block = MultiEraBlock::new(cfg.network, block_data, &previous_point, 1.into()) + let block = MultiEraBlock::new(cfg.chain, block_data, &previous_point, 1.into()) .with_context(|| { format!( "Failed to decode block data. previous: {previous_point:?}, range: {range_msg}" @@ -400,9 +402,9 @@ async fn live_sync_backfill( let backfill_size = backfill_blocks.len() as u64; // Try and backfill, if anything doesn't work, or the chain integrity would break, fail. - live_chain_backfill(cfg.network, &backfill_blocks)?; + live_chain_backfill(cfg.chain, &backfill_blocks)?; - stats::backfill_ended(cfg.network, backfill_size); + stats::backfill_ended(cfg.chain, backfill_size); debug!("Backfilled Range OK: {}", range_msg); @@ -422,7 +424,7 @@ async fn live_sync_backfill_and_purge( debug!( "Before Backfill: Size of the Live Chain is: {} Blocks", - live_chain_length(cfg.network) + live_chain_length(cfg.chain) ); let live_chain_head: Point; @@ -436,56 +438,56 @@ async fn live_sync_backfill_and_purge( sleep(Duration::from_secs(10)).await; } - if let Some(head_point) = get_live_head_point(cfg.network) { + if let Some(head_point) = get_live_head_point(cfg.chain) { live_chain_head = head_point; break; } } stats::new_mithril_update( - cfg.network, + cfg.chain, update.tip.slot_or_default(), - live_chain_length(cfg.network) as u64, + live_chain_length(cfg.chain) as u64, live_chain_head.slot_or_default(), ); debug!( "After Backfill: Size of the Live Chain is: {} Blocks", - live_chain_length(cfg.network) + live_chain_length(cfg.chain) ); // Once Backfill is completed OK we can use the Blockchain data for Syncing and Querying sync_ready.signal(); - let mut update_sender = get_chain_update_tx_queue(cfg.network).await; + let mut update_sender = get_chain_update_tx_queue(cfg.chain).await; loop { let Some(update) = rx.recv().await else { - error!("Mithril Sync Failed, can not continue network sync either."); + error!("Mithril Sync Failed, can not continue chain sync either."); return; }; // We can't get an update sender until the sync is released. if update_sender.is_none() { - update_sender = get_chain_update_tx_queue(cfg.network).await; + update_sender = get_chain_update_tx_queue(cfg.chain).await; } debug!("Mithril Tip has advanced to: {update:?} : PURGE NEEDED"); let update_point: Point = update.tip.clone(); - if let Err(error) = purge_live_chain(cfg.network, &update_point) { + if let Err(error) = purge_live_chain(cfg.chain, &update_point) { // This should actually never happen. error!("Mithril Purge Failed: {}", error); } debug!( "After Purge: Size of the Live Chain is: {} Blocks", - live_chain_length(cfg.network) + live_chain_length(cfg.chain) ); notify_follower( - cfg.network, + cfg.chain, update_sender.as_ref(), &chain_update::Kind::ImmutableBlockRollForward, ); @@ -516,11 +518,11 @@ async fn live_sync_backfill_and_purge( pub(crate) async fn chain_sync(cfg: ChainSyncConfig, rx: mpsc::Receiver) { debug!( "Chain Sync for: {} from {} : Starting", - cfg.network, cfg.relay_address, + cfg.chain, cfg.relay_address, ); // Start the SYNC_READY unlock task. - let sync_waiter = wait_for_sync_ready(cfg.network); + let sync_waiter = wait_for_sync_ready(cfg.chain); let backfill_cfg = cfg.clone(); @@ -532,13 +534,13 @@ pub(crate) async fn chain_sync(cfg: ChainSyncConfig, rx: mpsc::Receiver debug!("Tip Resynchronized to {tip}"), Err(error) => { error!( @@ -550,7 +552,7 @@ pub(crate) async fn chain_sync(cfg: ChainSyncConfig, rx: mpsc::Receiver = LazyLock::new(|| { #[derive(Clone, Debug)] pub struct ChainSyncConfig { /// Chain Network - pub network: Network, + pub chain: Network, /// Relay Node Address pub(crate) relay_address: String, /// Block buffer size option. @@ -59,13 +59,13 @@ impl ChainSyncConfig { /// Each network has a different set of defaults, so no single "default" can apply. /// This function is preferred to the `default()` standard function. #[must_use] - pub fn default_for(network: Network) -> Self { + pub fn default_for(chain: Network) -> Self { Self { - network, - relay_address: network.default_relay(), + chain, + relay_address: chain.default_relay(), chain_update_buffer_size: DEFAULT_CHAIN_UPDATE_BUFFER_SIZE, immutable_slot_window: DEFAULT_IMMUTABLE_SLOT_WINDOW, - mithril_cfg: MithrilSnapshotConfig::default_for(network), + mithril_cfg: MithrilSnapshotConfig::default_for(chain), } } @@ -126,19 +126,16 @@ impl ChainSyncConfig { /// `Error`: On error. pub async fn run(self) -> Result<()> { debug!( - network = self.network.to_string(), + chain = self.chain.to_string(), "Chain Synchronization Starting" ); - stats::sync_started(self.network); + stats::sync_started(self.chain); // Start the Chain Sync - IFF its not already running. - let lock_entry = match SYNC_JOIN_HANDLE_MAP.get(&self.network) { + let lock_entry = match SYNC_JOIN_HANDLE_MAP.get(&self.chain) { None => { - error!( - "Join Map improperly initialized: Missing {}!!", - self.network - ); + error!("Join Map improperly initialized: Missing {}!!", self.chain); return Err(Error::Internal); // Should not get here. }, Some(entry) => entry, @@ -146,8 +143,8 @@ impl ChainSyncConfig { let mut locked_handle = lock_entry.value().lock().await; if (*locked_handle).is_some() { - debug!("Chain Sync Already Running for {}", self.network); - return Err(Error::ChainSyncAlreadyRunning(self.network)); + debug!("Chain Sync Already Running for {}", self.chain); + return Err(Error::ChainSyncAlreadyRunning(self.chain)); } // Start the Mithril Snapshot Follower @@ -157,7 +154,7 @@ impl ChainSyncConfig { *locked_handle = Some(tokio::spawn(chain_sync(self.clone(), rx))); // sync_map.insert(chain, handle); - debug!("Chain Sync for {} : Started", self.network); + debug!("Chain Sync for {} : Started", self.chain); Ok(()) } diff --git a/rust/cardano-chain-follower/src/chain_sync_live_chains.rs b/rust/cardano-chain-follower/src/chain_sync_live_chains.rs index 5815a6d77..be129d422 100644 --- a/rust/cardano-chain-follower/src/chain_sync_live_chains.rs +++ b/rust/cardano-chain-follower/src/chain_sync_live_chains.rs @@ -46,14 +46,14 @@ static PEER_TIP: LazyLock> = LazyLock::new(|| { }); /// Set the last TIP received from the peer. -fn update_peer_tip(network: Network, tip: Point) { - PEER_TIP.insert(network, tip); +fn update_peer_tip(chain: Network, tip: Point) { + PEER_TIP.insert(chain, tip); } /// Get the last TIP received from the peer. /// If the peer tip doesn't exist, get the UNKNOWN point. -pub(crate) fn get_peer_tip(network: Network) -> Point { - (*PEER_TIP.get_or_insert(network, Point::UNKNOWN).value()).clone() +pub(crate) fn get_peer_tip(chain: Network) -> Point { + (*PEER_TIP.get_or_insert(chain, Point::UNKNOWN).value()).clone() } /// Number of seconds to wait if we detect a `SyncReady` race condition. @@ -136,7 +136,7 @@ impl ProtectedLiveChainBlockList { /// The blocks MUST be contiguous and properly self referential. /// Note: This last condition is NOT enforced, but must be met or block chain /// iteration will fail. - fn backfill(&self, network: Network, blocks: &[MultiEraBlock]) -> Result<()> { + fn backfill(&self, chain: Network, blocks: &[MultiEraBlock]) -> Result<()> { let live_chain = self.0.write().map_err(|_| Error::Internal)?; // Make sure our first live block == the last mithril tip. @@ -145,14 +145,14 @@ impl ProtectedLiveChainBlockList { .first() .ok_or(Error::LiveSync("No first block for backfill.".to_string()))? .point(); - let latest_mithril_tip = latest_mithril_snapshot_id(network).tip(); + let latest_mithril_tip = latest_mithril_snapshot_id(chain).tip(); if !first_block_point.strict_eq(&latest_mithril_tip) { return Err(Error::LiveSync(format!( "First Block of Live BackFill {first_block_point} MUST be last block of Mithril Snapshot {latest_mithril_tip}." ))); } - // Get the current oldest block in the live chain. + // Get the current Oldest block in the live chain. let check_first_live_point = Self::get_first_live_point(&live_chain)?; let last_backfill_block = blocks @@ -161,7 +161,7 @@ impl ProtectedLiveChainBlockList { .clone(); let last_backfill_point = last_backfill_block.point(); - // Make sure the backfill will properly connect the partial live chain to the Mithril + // Make sure the backfill will properly connect the partial Live chain to the Mithril // chain. if !last_backfill_point.strict_eq(&check_first_live_point) { return Err(Error::LiveSync(format!( @@ -175,7 +175,7 @@ impl ProtectedLiveChainBlockList { }); // End of Successful backfill == Reaching TIP, because live sync is always at tip. - stats::tip_reached(network); + stats::tip_reached(chain); Ok(()) } @@ -193,7 +193,7 @@ impl ProtectedLiveChainBlockList { /// would be lost due to rollback. Will REFUSE to add a block which does NOT have /// a proper "previous" point defined. fn add_block_to_tip( - &self, network: Network, block: MultiEraBlock, fork: &mut Fork, tip: Point, + &self, chain: Network, block: MultiEraBlock, fork_count: &mut Fork, tip: Point, ) -> Result<()> { let live_chain = self.0.write().map_err(|_| Error::Internal)?; @@ -203,11 +203,11 @@ impl ProtectedLiveChainBlockList { let last_live_point = Self::get_last_live_point(&live_chain); if !previous_point.strict_eq(&last_live_point) { // Detected a rollback, so increase the fork count. - fork.incr(); + fork_count.incr(); let mut rollback_size: u64 = 0; // We are NOT contiguous, so check if we can become contiguous with a rollback. - debug!("Detected non-contiguous block, rolling back. Fork: {fork:?}"); + debug!("Detected non-contiguous block, rolling back. Fork: {fork_count:?}"); // First check if the previous is >= the earliest block in the live chain. // This is because when we start syncing we could rollback earlier than our @@ -242,7 +242,7 @@ impl ProtectedLiveChainBlockList { // Record a rollback statistic (We record the ACTUAL size our rollback effected our // internal live chain, not what the node thinks.) stats::rollback::rollback( - network, + chain, stats::rollback::RollbackType::LiveChain, rollback_size, ); @@ -254,10 +254,10 @@ impl ProtectedLiveChainBlockList { let _unused = live_chain.insert(block.point(), block); let tip_slot = tip.slot_or_default(); - update_peer_tip(network, tip); + update_peer_tip(chain, tip); // Record the new live chain stats after we add a new block. - stats::new_live_block(network, live_chain.len() as u64, head_slot, tip_slot); + stats::new_live_block(chain, live_chain.len() as u64, head_slot, tip_slot); Ok(()) } @@ -265,13 +265,13 @@ impl ProtectedLiveChainBlockList { /// Checks if the point exists in the live chain. /// If it does, removes all block preceding it (but not the point itself). /// Will refuse to purge if the point is not the TIP of the mithril chain. - fn purge(&self, network: Network, point: &Point) -> Result<()> { + fn purge(&self, chain: Network, point: &Point) -> Result<()> { // Make sure our first live block == the last mithril tip. // Ensures we are properly connected to the Mithril Chain. // But don't check this if we are about to purge the entire chain. // We do this before we bother locking the chain for update. if *point != Point::TIP { - let latest_mithril_tip = latest_mithril_snapshot_id(network).tip(); + let latest_mithril_tip = latest_mithril_snapshot_id(chain).tip(); if !point.strict_eq(&latest_mithril_tip) { return Err(Error::LiveSync(format!( "First Block of Live Purge {point} MUST be last block of Mithril Snapshot {latest_mithril_tip}." @@ -414,27 +414,27 @@ impl ProtectedLiveChainBlockList { } /// Get the `LiveChainBlockList` for a particular `Network`. -fn get_live_chain(network: Network) -> ProtectedLiveChainBlockList { +fn get_live_chain(chain: Network) -> ProtectedLiveChainBlockList { // Get a reference to our live chain storage. // This SHOULD always exist, because its initialized exhaustively. // If this FAILS, Recreate a blank chain, but log an error as its a serious UNRECOVERABLE // BUG. - let entry = if let Some(entry) = LIVE_CHAINS.get(&network) { + let entry = if let Some(entry) = LIVE_CHAINS.get(&chain) { entry } else { error!( - network = network.to_string(), - "Internal Error: Chain Sync Failed to find network in LIVE_CHAINS" + chain = chain.to_string(), + "Internal Error: Chain Sync Failed to find chain in LIVE_CHAINS" ); // Try and correct the error. - LIVE_CHAINS.insert(network, ProtectedLiveChainBlockList::new()); + LIVE_CHAINS.insert(chain, ProtectedLiveChainBlockList::new()); // This should NOT fail, because we just inserted it, its catastrophic failure if it does. #[allow(clippy::expect_used)] LIVE_CHAINS - .get(&network) - .expect("Internal Error: Chain Sync Failed to find network in LIVE_CHAINS") + .get(&chain) + .expect("Internal Error: Chain Sync Failed to find chain in LIVE_CHAINS") }; let value = entry.value(); @@ -442,17 +442,17 @@ fn get_live_chain(network: Network) -> ProtectedLiveChainBlockList { } /// Get the head `Point` currently in the live chain. -pub(crate) fn get_live_head_point(network: Network) -> Option { - let live_chain = get_live_chain(network); +pub(crate) fn get_live_head_point(chain: Network) -> Option { + let live_chain = get_live_chain(chain); live_chain.get_live_head_point() } /// Get the Live block relative to the specified point. /// The starting block must exist if the search is strict. pub(crate) fn get_live_block( - network: Network, point: &Point, advance: i64, strict: bool, + chain: Network, point: &Point, advance: i64, strict: bool, ) -> Option { - let live_chain = get_live_chain(network); + let live_chain = get_live_chain(chain); live_chain.get_block(point, advance, strict) } @@ -462,12 +462,12 @@ pub(crate) fn get_live_block( /// /// Note: It MAY change between calling this function and actually backfilling. /// This is expected and normal behavior. -pub(crate) async fn get_fill_to_point(network: Network) -> (Point, Fork) { - let live_chain = get_live_chain(network); +pub(crate) async fn get_fill_to_point(chain: Network) -> (Point, u64) { + let live_chain = get_live_chain(chain); loop { if let Some(earliest_block) = live_chain.get_earliest_block() { - return (earliest_block.point(), earliest_block.fork()); + return (earliest_block.point(), earliest_block.fork().into()); } // Nothing in the Live chain to sync to, so wait until there is. tokio::time::sleep(Duration::from_secs(DATA_RACE_BACKOFF_SECS)).await; @@ -479,43 +479,43 @@ pub(crate) async fn get_fill_to_point(network: Network) -> (Point, Fork) { /// `rollback_count` should be set to 1 on the very first connection, after that, /// it is maintained by this function, and MUST not be modified elsewhere. pub(crate) fn live_chain_add_block_to_tip( - network: Network, block: MultiEraBlock, fork: &mut Fork, tip: Point, + chain: Network, block: MultiEraBlock, fork: &mut Fork, tip: Point, ) -> Result<()> { - let live_chain = get_live_chain(network); - live_chain.add_block_to_tip(network, block, fork, tip) + let live_chain = get_live_chain(chain); + live_chain.add_block_to_tip(chain, block, fork, tip) } /// Backfill the live chain with the block set provided. -pub(crate) fn live_chain_backfill(network: Network, blocks: &[MultiEraBlock]) -> Result<()> { - let live_chain = get_live_chain(network); - live_chain.backfill(network, blocks) +pub(crate) fn live_chain_backfill(chain: Network, blocks: &[MultiEraBlock]) -> Result<()> { + let live_chain = get_live_chain(chain); + live_chain.backfill(chain, blocks) } /// Get the length of the live chain. /// Probably used by debug code only, so its ok if this is not use. -pub(crate) fn live_chain_length(network: Network) -> usize { - let live_chain = get_live_chain(network); +pub(crate) fn live_chain_length(chain: Network) -> usize { + let live_chain = get_live_chain(chain); live_chain.len() } -/// On an immutable update, purge the live chain up to the new immutable tip. +/// On an immutable update, purge the live-chain up to the new immutable tip. /// Will error if the point is not in the Live chain. -pub(crate) fn purge_live_chain(network: Network, point: &Point) -> Result<()> { - let live_chain = get_live_chain(network); - live_chain.purge(network, point) +pub(crate) fn purge_live_chain(chain: Network, point: &Point) -> Result<()> { + let live_chain = get_live_chain(chain); + live_chain.purge(chain, point) } /// Get intersection points to try and find best point to connect to the node on /// reconnect. -pub(crate) fn get_intersect_points(network: Network) -> Vec { - let live_chain = get_live_chain(network); +pub(crate) fn get_intersect_points(chain: Network) -> Vec { + let live_chain = get_live_chain(chain); live_chain.get_intersect_points() } /// Find best block from a fork relative to a point. pub(crate) fn find_best_fork_block( - network: Network, point: &Point, previous_point: &Point, fork: Fork, + chain: Network, point: &Point, previous_point: &Point, fork: Fork, ) -> Option<(MultiEraBlock, u64)> { - let live_chain = get_live_chain(network); + let live_chain = get_live_chain(chain); live_chain.find_best_fork_block(point, previous_point, fork) } diff --git a/rust/cardano-chain-follower/src/chain_sync_ready.rs b/rust/cardano-chain-follower/src/chain_sync_ready.rs index 102b24132..05dc61e8c 100644 --- a/rust/cardano-chain-follower/src/chain_sync_ready.rs +++ b/rust/cardano-chain-follower/src/chain_sync_ready.rs @@ -39,13 +39,13 @@ impl SyncReady { /// Sand a chain update to any subscribers that are listening. pub(crate) fn notify_follower( - network: Network, update_sender: Option<&broadcast::Sender>, + chain: Network, update_sender: Option<&broadcast::Sender>, kind: &chain_update::Kind, ) { if let Some(update_sender) = update_sender { if let Err(error) = update_sender.send(kind.clone()) { error!( - network = network.to_string(), + chain = chain.to_string(), "Failed to broadcast the Update {kind} : {error}" ); } @@ -84,14 +84,14 @@ static SYNC_READY: LazyLock>> = LazyLock::new /// Write Lock the `SYNC_READY` lock for a network. /// When we are signaled to be ready, set it to true and release the lock. -pub(crate) fn wait_for_sync_ready(network: Network) -> SyncReadyWaiter { +pub(crate) fn wait_for_sync_ready(chain: Network) -> SyncReadyWaiter { let (tx, rx) = oneshot::channel::<()>(); tokio::spawn(async move { // We are safe to use `expect` here because the SYNC_READY list is exhaustively // initialized. Its a Serious BUG if that not True, so panic is OK. #[allow(clippy::expect_used)] - let lock_entry = SYNC_READY.get(&network).expect("network should exist"); + let lock_entry = SYNC_READY.get(&chain).expect("network should exist"); let lock = lock_entry.value(); @@ -109,11 +109,11 @@ pub(crate) fn wait_for_sync_ready(network: Network) -> SyncReadyWaiter { } /// Get a Read lock on the Sync State, and return if we are ready or not. -async fn check_sync_ready(network: Network) -> bool { +async fn check_sync_ready(chain: Network) -> bool { // We are safe to use `expect` here because the SYNC_READY list is exhaustively // initialized. Its a Serious BUG if that not True, so panic is OK. #[allow(clippy::expect_used)] - let lock_entry = SYNC_READY.get(&network).expect("network should exist"); + let lock_entry = SYNC_READY.get(&chain).expect("network should exist"); let lock = lock_entry.value(); let status = lock.read().await; @@ -128,22 +128,22 @@ const SYNC_READY_RACE_BACKOFF_SECS: u64 = 1; /// Block until the chain is synced to TIP. /// This is necessary to ensure the Blockchain data is fully intact before attempting to /// consume it. -pub(crate) async fn block_until_sync_ready(network: Network) { +pub(crate) async fn block_until_sync_ready(chain: Network) { // There is a potential race where we haven't yet write locked the SYNC_READY lock when we // check it. So, IF the ready state returns as false, sleep a while and try again. - while !check_sync_ready(network).await { + while !check_sync_ready(chain).await { sleep(Duration::from_secs(SYNC_READY_RACE_BACKOFF_SECS)).await; } } /// Get the Broadcast Receive queue for the given chain updates. pub(crate) async fn get_chain_update_rx_queue( - network: Network, + chain: Network, ) -> broadcast::Receiver { // We are safe to use `expect` here because the SYNC_READY list is exhaustively // initialized. Its a Serious BUG if that not True, so panic is OK. #[allow(clippy::expect_used)] - let lock_entry = SYNC_READY.get(&network).expect("network should exist"); + let lock_entry = SYNC_READY.get(&chain).expect("network should exist"); let lock = lock_entry.value(); @@ -154,12 +154,12 @@ pub(crate) async fn get_chain_update_rx_queue( /// Get the Broadcast Transmit queue for the given chain updates. pub(crate) async fn get_chain_update_tx_queue( - network: Network, + chain: Network, ) -> Option> { // We are safe to use `expect` here because the SYNC_READY list is exhaustively // initialized. Its a Serious BUG if that not True, so panic is OK. #[allow(clippy::expect_used)] - let lock_entry = SYNC_READY.get(&network).expect("network should exist"); + let lock_entry = SYNC_READY.get(&chain).expect("network should exist"); let lock = lock_entry.value(); diff --git a/rust/cardano-chain-follower/src/chain_update.rs b/rust/cardano-chain-follower/src/chain_update.rs index 2efc6d699..4835efab9 100644 --- a/rust/cardano-chain-follower/src/chain_update.rs +++ b/rust/cardano-chain-follower/src/chain_update.rs @@ -42,7 +42,7 @@ impl ChainUpdate { /// Is the chain update immutable? #[must_use] - pub fn is_immutable(&self) -> bool { + pub fn immutable(&self) -> bool { self.data.is_immutable() } } diff --git a/rust/cardano-chain-follower/src/error.rs b/rust/cardano-chain-follower/src/error.rs index 1f7fe748d..761c42f91 100644 --- a/rust/cardano-chain-follower/src/error.rs +++ b/rust/cardano-chain-follower/src/error.rs @@ -21,7 +21,7 @@ pub enum Error { /// Chainsync protocol error. #[error("Chainsync error: {0:?}")] Chainsync(chainsync::ClientError), - /// Backfill Sync error. + /// Backfill Synch error. #[error("Backfill Sync error: {0}")] BackfillSync(String), /// Live Sync error. diff --git a/rust/cardano-chain-follower/src/follow.rs b/rust/cardano-chain-follower/src/follow.rs index 3c1d323ca..b1b2f79a1 100644 --- a/rust/cardano-chain-follower/src/follow.rs +++ b/rust/cardano-chain-follower/src/follow.rs @@ -20,7 +20,7 @@ use crate::{ /// The Chain Follower pub struct ChainFollower { /// The Blockchain network we are following. - network: Network, + chain: Network, /// Where we end following. end: Point, /// Point we processed most recently. @@ -44,7 +44,7 @@ impl ChainFollower { /// /// # Arguments /// - /// * `network` - The blockchain network to follow. + /// * `chain` - The blockchain network to follow. /// * `start` - The point or tip to start following from (inclusive). /// * `end` - The point or tip to stop following from (inclusive). /// @@ -67,16 +67,16 @@ impl ChainFollower { /// /// To ONLY follow from TIP, set BOTH start and end to TIP. #[must_use] - pub async fn new(network: Network, start: Point, end: Point) -> Self { - let rx = get_chain_update_rx_queue(network).await; + pub async fn new(chain: Network, start: Point, end: Point) -> Self { + let rx = get_chain_update_rx_queue(chain).await; ChainFollower { - network, + chain, end, previous: Point::UNKNOWN, current: start, fork: 1.into(), // This is correct, because Mithril is Fork 0. - snapshot: MithrilSnapshot::new(network), + snapshot: MithrilSnapshot::new(chain), mithril_follower: None, mithril_tip: None, sync_updates: rx, @@ -85,7 +85,7 @@ impl ChainFollower { /// If we can, get the next update from the mithril snapshot. async fn next_from_mithril(&mut self) -> Option { - let current_mithril_tip = latest_mithril_snapshot_id(self.network).tip(); + let current_mithril_tip = latest_mithril_snapshot_id(self.chain).tip(); if current_mithril_tip > self.current { if self.mithril_follower.is_none() { @@ -115,7 +115,7 @@ impl ChainFollower { }; if roll_forward_condition { - let snapshot = MithrilSnapshot::new(self.network); + let snapshot = MithrilSnapshot::new(self.chain); if let Some(block) = snapshot.read_block_at(¤t_mithril_tip).await { // The Mithril Tip has moved forwards. self.mithril_tip = Some(current_mithril_tip); @@ -143,7 +143,7 @@ impl ChainFollower { // Special Case: point = TIP_POINT. Just return the latest block in the live chain. if self.current == Point::TIP { next_block = { - let block = get_live_block(self.network, &self.current, -1, false)?; + let block = get_live_block(self.chain, &self.current, -1, false)?; Some(block) }; } @@ -152,7 +152,7 @@ impl ChainFollower { if next_block.is_none() { // If we don't know the previous block, get the block requested. let advance = i64::from(!self.previous.is_unknown()); - next_block = get_live_block(self.network, &self.current, advance, true); + next_block = get_live_block(self.chain, &self.current, advance, true); } // If we can't get the next consecutive block, then @@ -163,7 +163,7 @@ impl ChainFollower { // IF this is an update still, and not us having caught up, then it WILL be a rollback. update_type = chain_update::Kind::Rollback; next_block = if let Some((block, depth)) = - find_best_fork_block(self.network, &self.current, &self.previous, self.fork) + find_best_fork_block(self.chain, &self.current, &self.previous, self.fork) { debug!("Found fork block: {block}"); // IF the block is the same as our current previous, there has been no chain @@ -176,12 +176,12 @@ impl ChainFollower { } } else { debug!("No block to find, rewinding to latest mithril tip."); - let latest_mithril_point = latest_mithril_snapshot_id(self.network).tip(); - if let Some(block) = MithrilSnapshot::new(self.network) + let latest_mithril_point = latest_mithril_snapshot_id(self.chain).tip(); + if let Some(block) = MithrilSnapshot::new(self.chain) .read_block_at(&latest_mithril_point) .await { - rollback_depth = live_chain_length(self.network) as u64; + rollback_depth = live_chain_length(self.chain) as u64; Some(block) } else { return None; @@ -193,7 +193,7 @@ impl ChainFollower { // Update rollback stats for the follower if one is reported. if update_type == chain_update::Kind::Rollback { stats::rollback::rollback( - self.network, + self.chain, stats::rollback::RollbackType::Follower, rollback_depth, ); @@ -204,7 +204,7 @@ impl ChainFollower { self.current = next_block.point().clone(); self.fork = next_block.fork(); - let tip = point_at_tip(self.network, &self.current).await; + let tip = point_at_tip(self.chain, &self.current).await; let update = ChainUpdate::new(update_type, tip, next_block); return Some(update); } @@ -287,7 +287,7 @@ impl ChainFollower { } // Can't follow if SYNC is not ready. - block_until_sync_ready(self.network).await; + block_until_sync_ready(self.chain).await; // Get next block from the iteration. self.unprotected_next().await @@ -300,22 +300,22 @@ impl ChainFollower { /// /// This is a convenience function which just used `ChainFollower` to fetch a single /// block. - pub async fn get_block(network: Network, point: Point) -> Option { + pub async fn get_block(chain: Network, point: Point) -> Option { // Get the block from the chain. // This function suppose to run only once, so the end point // can be set to `TIP_POINT` - let mut follower = Self::new(network, point, Point::TIP).await; + let mut follower = Self::new(chain, point, Point::TIP).await; follower.next().await } /// Get the current Immutable and live tips. /// /// Note, this will block until the chain is synced, ready to be followed. - pub async fn get_tips(network: Network) -> (Point, Point) { + pub async fn get_tips(chain: Network) -> (Point, Point) { // Can't follow if SYNC is not ready. - block_until_sync_ready(network).await; + block_until_sync_ready(chain).await; - let tips = Statistics::tips(network); + let tips = Statistics::tips(chain); let mithril_tip = Point::fuzzy(tips.0); let live_tip = Point::fuzzy(tips.1); @@ -327,16 +327,16 @@ impl ChainFollower { /// /// # Arguments /// - /// * `network` - The blockchain network to post the transaction on. + /// * `chain` - The blockchain to post the transaction on. /// * `txn` - The transaction to be posted. /// /// # Returns /// /// `TxId` - The ID of the transaction that was queued. #[allow(clippy::unused_async)] - pub async fn post_txn(network: Network, txn: TxBody) -> TxId { + pub async fn post_txn(chain: Network, txn: TxBody) -> TxId { #[allow(clippy::no_effect_underscore_binding)] - let _unused = network; + let _unused = chain; #[allow(clippy::no_effect_underscore_binding)] let _unused = txn; @@ -349,9 +349,9 @@ impl ChainFollower { /// After which, it should be on the blockchain, and its the applications job to track /// if a transaction made it on-chain or not. #[allow(clippy::unused_async)] - pub async fn txn_sent(network: Network, id: TxId) -> bool { + pub async fn txn_sent(chain: Network, id: TxId) -> bool { #[allow(clippy::no_effect_underscore_binding)] - let _unused = network; + let _unused = chain; #[allow(clippy::no_effect_underscore_binding)] let _unused = id; @@ -393,13 +393,13 @@ mod tests { #[tokio::test] async fn test_chain_follower_new() { - let network = Network::Mainnet; + let chain = Network::Mainnet; let start = Point::new(100u64.into(), [0; 32].into()); let end = Point::fuzzy(999u64.into()); - let follower = ChainFollower::new(network, start.clone(), end.clone()).await; + let follower = ChainFollower::new(chain, start.clone(), end.clone()).await; - assert_eq!(follower.network, network); + assert_eq!(follower.chain, chain); assert_eq!(follower.end, end); assert_eq!(follower.previous, Point::UNKNOWN); assert_eq!(follower.current, start); @@ -410,11 +410,11 @@ mod tests { #[tokio::test] async fn test_chain_follower_update_current_none() { - let network = Network::Mainnet; + let chain = Network::Mainnet; let start = Point::new(100u64.into(), [0; 32].into()); let end = Point::fuzzy(999u64.into()); - let mut follower = ChainFollower::new(network, start.clone(), end.clone()).await; + let mut follower = ChainFollower::new(chain, start.clone(), end.clone()).await; let result = follower.update_current(None); @@ -423,11 +423,11 @@ mod tests { #[tokio::test] async fn test_chain_follower_update_current() { - let network = Network::Mainnet; + let chain = Network::Mainnet; let start = Point::new(100u64.into(), [0; 32].into()); let end = Point::fuzzy(999u64.into()); - let mut follower = ChainFollower::new(network, start.clone(), end.clone()).await; + let mut follower = ChainFollower::new(chain, start.clone(), end.clone()).await; let block_data = mock_block(); let update = ChainUpdate::new(chain_update::Kind::Block, false, block_data); diff --git a/rust/cardano-chain-follower/src/mithril_snapshot.rs b/rust/cardano-chain-follower/src/mithril_snapshot.rs index 4a0608b50..2d8c9d31a 100644 --- a/rust/cardano-chain-follower/src/mithril_snapshot.rs +++ b/rust/cardano-chain-follower/src/mithril_snapshot.rs @@ -21,13 +21,13 @@ use crate::{ #[derive(Clone)] pub(crate) struct MithrilSnapshot { /// Network that this snapshot is configured for - network: Network, + chain: Network, } impl MithrilSnapshot { /// Create a new Mithril Snapshot handler - pub(crate) fn new(network: Network) -> Self { - Self { network } + pub(crate) fn new(chain: Network) -> Self { + Self { chain } } /// Checks if the snapshot contains a given point. @@ -40,7 +40,7 @@ impl MithrilSnapshot { /// Returns true if the point exists within the Mithril snapshot for the specified /// network, false otherwise. pub(crate) fn contains_point(&self, point: &Point) -> bool { - let latest_id = latest_mithril_snapshot_id(self.network); + let latest_id = latest_mithril_snapshot_id(self.chain); point.slot_or_default() <= latest_id.tip().slot_or_default() } @@ -61,7 +61,7 @@ impl MithrilSnapshot { pub(crate) async fn try_read_blocks_from_point( &self, point: &Point, ) -> Option { - let snapshot_id = latest_mithril_snapshot_id(self.network); + let snapshot_id = latest_mithril_snapshot_id(self.chain); let snapshot_path = snapshot_id.immutable_path(); // Quick check if the block can be within the immutable data. @@ -70,7 +70,7 @@ impl MithrilSnapshot { } // We don't know the previous block, so we need to find it. - MithrilSnapshotIterator::new(self.network, &snapshot_path, point, None) + MithrilSnapshotIterator::new(self.chain, &snapshot_path, point, None) .await .ok() } diff --git a/rust/cardano-chain-follower/src/mithril_snapshot_config.rs b/rust/cardano-chain-follower/src/mithril_snapshot_config.rs index adefeb4e7..e4c95a091 100644 --- a/rust/cardano-chain-follower/src/mithril_snapshot_config.rs +++ b/rust/cardano-chain-follower/src/mithril_snapshot_config.rs @@ -55,7 +55,7 @@ pub(crate) struct MithrilUpdateMessage { #[derive(Clone, Debug)] pub struct MithrilSnapshotConfig { /// What Blockchain network are we configured for. - pub network: Network, + pub chain: Network, /// Path to the Mithril snapshot the follower should use. /// Note: this is a base directory. The Actual data will be stored under here. /// archive downloads -> `/dl` @@ -76,12 +76,12 @@ impl MithrilSnapshotConfig { /// Each network has a different set of defaults, so no single "default" can apply. /// This function is preferred to the `default()` standard function. #[must_use] - pub fn default_for(network: Network) -> Self { + pub fn default_for(chain: Network) -> Self { Self { - network, - path: network.default_mithril_path(), - aggregator_url: network.default_mithril_aggregator(), - genesis_key: network.default_mithril_genesis_key(), + chain, + path: chain.default_mithril_path(), + aggregator_url: chain.default_mithril_aggregator(), + genesis_key: chain.default_mithril_genesis_key(), dl_config: None, } } @@ -126,7 +126,7 @@ impl MithrilSnapshotConfig { } if latest_immutable_file > 0 { - return SnapshotId::try_new(self.network, &latest_path).await; + return SnapshotId::try_new(self.chain, &latest_path).await; } None @@ -136,7 +136,7 @@ impl MithrilSnapshotConfig { /// And then remove any left over files in download or the tmp path, or old snapshots. pub(crate) async fn activate(&self, snapshot_number: u64) -> io::Result { let new_path = self.mithril_path(snapshot_number); - let latest_id = latest_mithril_snapshot_id(self.network); + let latest_id = latest_mithril_snapshot_id(self.chain); debug!( "Activating snapshot: {} {} {:?}", @@ -190,7 +190,7 @@ impl MithrilSnapshotConfig { }, Ok(mut entries) => { // Get latest mithril snapshot path and number. - let latest_snapshot = latest_mithril_snapshot_id(self.network); + let latest_snapshot = latest_mithril_snapshot_id(self.chain); loop { // Get the next entry, stop on any error, or no entries left. @@ -332,7 +332,7 @@ impl MithrilSnapshotConfig { // hex. let vkey = remove_whitespace(&self.genesis_key); if !is_hex(&vkey) { - return Err(Error::MithrilGenesisVKeyNotHex(self.network)); + return Err(Error::MithrilGenesisVKeyNotHex(self.chain)); } Ok(()) @@ -349,22 +349,22 @@ impl MithrilSnapshotConfig { // We do this by trying to use it to get a list of snapshots. let client = mithril_client::ClientBuilder::aggregator(&url, &key) .build() - .map_err(|e| Error::MithrilClient(self.network, url.clone(), e))?; + .map_err(|e| Error::MithrilClient(self.chain, url.clone(), e))?; let snapshots = client .snapshot() .list() .await - .map_err(|e| Error::MithrilClient(self.network, url.clone(), e))?; + .map_err(|e| Error::MithrilClient(self.chain, url.clone(), e))?; // Check we have a snapshot, and its for our network. match snapshots.first().and_then(|s| s.beacon.network.as_ref()) { Some(network) => { let _aggregator_network = Network::from_str(network.as_str()).map_err(|_err| { - Error::MithrilClientNetworkMismatch(self.network, network.clone()) + Error::MithrilClientNetworkMismatch(self.chain, network.clone()) })?; }, - None => return Err(Error::MithrilClientNoSnapshots(self.network, url)), + None => return Err(Error::MithrilClientNoSnapshots(self.chain, url)), } Ok(()) @@ -385,17 +385,14 @@ impl MithrilSnapshotConfig { /// Run a Mithril Follower for the given network and configuration. pub(crate) async fn run(&self) -> Result> { debug!( - network = self.network.to_string(), + chain = self.chain.to_string(), "Mithril Auto-update : Starting" ); // Start the Mithril Sync - IFF its not already running. - let lock_entry = match SYNC_JOIN_HANDLE_MAP.get(&self.network) { + let lock_entry = match SYNC_JOIN_HANDLE_MAP.get(&self.chain) { None => { - error!( - "Join Map improperly initialized: Missing {}!!", - self.network - ); + error!("Join Map improperly initialized: Missing {}!!", self.chain); return Err(Error::Internal); // Should not get here. }, Some(entry) => entry, @@ -403,8 +400,8 @@ impl MithrilSnapshotConfig { let mut locked_handle = lock_entry.value().lock().await; if (*locked_handle).is_some() { - debug!("Mithril Already Running for {}", self.network); - return Err(Error::MithrilSnapshotSyncAlreadyRunning(self.network)); + debug!("Mithril Already Running for {}", self.chain); + return Err(Error::MithrilSnapshotSyncAlreadyRunning(self.chain)); } self.validate().await?; @@ -420,7 +417,7 @@ impl MithrilSnapshotConfig { // sync_map.insert(chain, handle); debug!( - network = self.network.to_string(), + chain = self.chain.to_string(), "Mithril Auto-update : Started" ); @@ -495,7 +492,7 @@ mod tests { let network = Network::Preprod; let config = MithrilSnapshotConfig::default_for(network); - assert_eq!(config.network, network); + assert_eq!(config.chain, network); assert_eq!(config.path, network.default_mithril_path()); assert_eq!(config.aggregator_url, network.default_mithril_aggregator()); assert_eq!(config.genesis_key, network.default_mithril_genesis_key()); @@ -504,7 +501,7 @@ mod tests { #[tokio::test] async fn test_validate_genesis_vkey() { let config = MithrilSnapshotConfig { - network: Network::Preprod, + chain: Network::Preprod, path: PathBuf::new(), aggregator_url: String::new(), genesis_key: "1234abcd".to_string(), @@ -514,7 +511,7 @@ mod tests { assert!(config.validate_genesis_vkey().is_ok()); let invalid_config = MithrilSnapshotConfig { - network: Network::Preprod, + chain: Network::Preprod, path: PathBuf::new(), aggregator_url: String::new(), genesis_key: "1234abcz".to_string(), diff --git a/rust/cardano-chain-follower/src/mithril_snapshot_data.rs b/rust/cardano-chain-follower/src/mithril_snapshot_data.rs index 4711a70d1..2dcdf912c 100644 --- a/rust/cardano-chain-follower/src/mithril_snapshot_data.rs +++ b/rust/cardano-chain-follower/src/mithril_snapshot_data.rs @@ -39,24 +39,24 @@ static CURRENT_MITHRIL_SNAPSHOT: LazyLock> = LazyLock::new(DashMap::new); /// Get the current latest snapshot data we have recorded. -pub(crate) fn latest_mithril_snapshot_data(network: Network) -> SnapshotData { +pub(crate) fn latest_mithril_snapshot_data(chain: Network) -> SnapshotData { // There should ALWAYS be a snapshot for the chain if this is called. - match CURRENT_MITHRIL_SNAPSHOT.get(&network) { + match CURRENT_MITHRIL_SNAPSHOT.get(&chain) { Some(snapshot_data) => snapshot_data.value().clone(), None => SnapshotData::default(), } } /// Get the latest Mithril Snapshot for a network. -pub(crate) fn latest_mithril_snapshot_id(network: Network) -> SnapshotId { - // There should ALWAYS be a snapshot for the network if this is called. - latest_mithril_snapshot_data(network).id +pub(crate) fn latest_mithril_snapshot_id(chain: Network) -> SnapshotId { + // There should ALWAYS be a snapshot for the chain if this is called. + latest_mithril_snapshot_data(chain).id } /// Update the latest snapshot data. -pub(crate) fn update_latest_mithril_snapshot(network: Network, snapshot_id: SnapshotId) { +pub(crate) fn update_latest_mithril_snapshot(chain: Network, snapshot_id: SnapshotId) { let snapshot_data = SnapshotData::new(snapshot_id); // Save the current snapshot - CURRENT_MITHRIL_SNAPSHOT.insert(network, snapshot_data); + CURRENT_MITHRIL_SNAPSHOT.insert(chain, snapshot_data); } diff --git a/rust/cardano-chain-follower/src/mithril_snapshot_iterator.rs b/rust/cardano-chain-follower/src/mithril_snapshot_iterator.rs index 580dc52ec..f7d7d9b64 100644 --- a/rust/cardano-chain-follower/src/mithril_snapshot_iterator.rs +++ b/rust/cardano-chain-follower/src/mithril_snapshot_iterator.rs @@ -23,9 +23,9 @@ const BACKWARD_SEARCH_SLOT_INTERVAL: u64 = 60; /// Synchronous Inner Iterator state struct MithrilSnapshotIteratorInner { - /// The blockchain network being iterated - network: Network, - /// Point we want to start iterating from + /// The chain being iterated + chain: Network, + /// Where we really want to start iterating from start: Point, /// Previous iteration point. previous: Point, @@ -37,8 +37,8 @@ impl Debug for MithrilSnapshotIteratorInner { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, - "MithrilSnapshotIteratorInner {{ network: {:?}, start: {:?}, previous: {:?} }}", - self.network, self.start, self.previous + "MithrilSnapshotIteratorInner {{ chain: {:?}, start: {:?}, previous: {:?} }}", + self.chain, self.start, self.previous ) } } @@ -68,7 +68,7 @@ pub(crate) fn probe_point(point: &Point, distance: u64) -> Point { impl MithrilSnapshotIterator { /// Try and probe to establish the iterator from the desired point. async fn try_fuzzy_iterator( - network: Network, path: &Path, from: &Point, search_interval: u64, + chain: Network, path: &Path, from: &Point, search_interval: u64, ) -> Option { let point = probe_point(from, search_interval); let Ok(mut iterator) = make_mithril_iterator(path, &point).await else { @@ -120,7 +120,7 @@ impl MithrilSnapshotIterator { Some(MithrilSnapshotIterator { inner: Arc::new(Mutex::new(MithrilSnapshotIteratorInner { - network, + chain, start: this, previous: previous?, inner: iterator, @@ -132,13 +132,11 @@ impl MithrilSnapshotIterator { /// We use this when we don't know the previous point, and need to find it. #[allow(clippy::indexing_slicing)] #[logcall("debug")] - async fn fuzzy_iterator( - network: Network, path: &Path, from: &Point, - ) -> MithrilSnapshotIterator { + async fn fuzzy_iterator(chain: Network, path: &Path, from: &Point) -> MithrilSnapshotIterator { let mut backwards_search = BACKWARD_SEARCH_SLOT_INTERVAL; loop { if let Some(iterator) = - Self::try_fuzzy_iterator(network, path, from, backwards_search).await + Self::try_fuzzy_iterator(chain, path, from, backwards_search).await { return iterator; } @@ -151,7 +149,7 @@ impl MithrilSnapshotIterator { /// /// # Arguments /// - /// `network`: The blockchain network to iterate. + /// `chain`: The blockchain network to iterate. /// `from`: The point to start iterating from. If the `Point` does not contain a /// hash, the iteration start is fuzzy. `previous`: The previous point we are /// iterating, if known. If the previous is NOT known, then the first block @@ -159,10 +157,10 @@ impl MithrilSnapshotIterator { #[allow(clippy::indexing_slicing)] #[logcall(ok = "debug", err = "error")] pub(crate) async fn new( - network: Network, path: &Path, from: &Point, previous_point: Option, + chain: Network, path: &Path, from: &Point, previous_point: Option, ) -> Result { if from.is_fuzzy() || (!from.is_origin() && previous_point.is_none()) { - return Ok(Self::fuzzy_iterator(network, path, from).await); + return Ok(Self::fuzzy_iterator(chain, path, from).await); } let previous = if from.is_origin() { @@ -180,7 +178,7 @@ impl MithrilSnapshotIterator { Ok(MithrilSnapshotIterator { inner: Arc::new(Mutex::new(MithrilSnapshotIteratorInner { - network, + chain, start: from.clone(), previous, inner: iterator, @@ -212,7 +210,7 @@ impl Iterator for MithrilSnapshotIteratorInner { if let Ok(block) = maybe_block { if !self.previous.is_unknown() { // We can safely fully decode this block. - match MultiEraBlock::new(self.network, block, &self.previous, 0.into()) { + match MultiEraBlock::new(self.chain, block, &self.previous, 0.into()) { Ok(block_data) => { // Update the previous point // debug!("Pre Previous update 1 : {:?}", self.previous); diff --git a/rust/cardano-chain-follower/src/mithril_snapshot_sync.rs b/rust/cardano-chain-follower/src/mithril_snapshot_sync.rs index 7979a7e57..624d1ce74 100644 --- a/rust/cardano-chain-follower/src/mithril_snapshot_sync.rs +++ b/rust/cardano-chain-follower/src/mithril_snapshot_sync.rs @@ -73,7 +73,7 @@ async fn get_latest_snapshots( Some((latest_snapshot.clone(), chronologically_previous.clone())) } -/// Given a particular snapshot ID, find the actual snapshot for it. +/// Given a particular snapshot ID, find the Actual Snapshot for it. async fn get_snapshot_by_id( client: &Client, network: Network, snapshot_id: &SnapshotId, ) -> Option { @@ -112,7 +112,7 @@ fn create_client(cfg: &MithrilSnapshotConfig) -> Option<(Client, Arc c, Err(err) => { - error!(chain=cfg.network.to_string(),"Unexpected Error [{}]: Unable to create Mithril Client. Mithril Snapshots can not update.", err); + error!(chain=cfg.chain.to_string(),"Unexpected Error [{}]: Unable to create Mithril Client. Mithril Snapshots can not update.", err); return None; }, }; @@ -234,7 +234,7 @@ pub(crate) const MITHRIL_IMMUTABLE_SUB_DIRECTORY: &str = "immutable"; /// /// # Arguments /// -/// * `network` - The network chain to get the tip block from. +/// * `chain` - The network chain to get the tip block from. /// * `path` - The path where the immutable chain is stored. /// /// # Returns @@ -243,7 +243,7 @@ pub(crate) const MITHRIL_IMMUTABLE_SUB_DIRECTORY: &str = "immutable"; /// it in a tuple. #[allow(clippy::indexing_slicing)] #[logcall(ok = "debug", err = "error")] -pub(crate) async fn get_mithril_tip(network: Network, path: &Path) -> Result { +pub(crate) async fn get_mithril_tip(chain: Network, path: &Path) -> Result { let mut path = path.to_path_buf(); path.push(MITHRIL_IMMUTABLE_SUB_DIRECTORY); @@ -259,7 +259,7 @@ pub(crate) async fn get_mithril_tip(network: Network, path: &Path) -> Result Result Option<(Snapshot, MithrilCertificate)> { - debug!( - "Mithril Snapshot background updater for: {network} : Download snapshot from aggregator." - ); + debug!("Mithril Snapshot background updater for: {chain} : Download snapshot from aggregator."); // Download the snapshot from the aggregator. - let Some(snapshot) = get_snapshot(client, item, network).await else { + let Some(snapshot) = get_snapshot(client, item, chain).await else { // If we couldn't get the snapshot then we don't need to do anything else, transient // error. return None; }; - debug!("Mithril Snapshot background updater for: {network} : Download/Verify certificate."); + debug!("Mithril Snapshot background updater for: {chain} : Download/Verify certificate."); // Download and Verify the certificate. - let certificate = download_and_verify_snapshot_certificate(client, &snapshot, network).await?; + let certificate = download_and_verify_snapshot_certificate(client, &snapshot, chain).await?; Some((snapshot, certificate)) } /// Validate that a Mithril Snapshot downloaded matches its certificate. async fn validate_mithril_snapshot( - network: Network, certificate: &MithrilCertificate, path: &Path, + chain: Network, certificate: &MithrilCertificate, path: &Path, ) -> bool { let cert = certificate.clone(); let mithril_path = path.to_path_buf(); @@ -313,7 +311,7 @@ async fn validate_mithril_snapshot( true } else { // If we couldn't match then assume its a transient error. - error!("Failed to Match Certificate and Computed Snapshot Message for {network}!"); + error!("Failed to Match Certificate and Computed Snapshot Message for {chain}!"); false } }, @@ -335,14 +333,14 @@ async fn validate_mithril_snapshot( /// 1. The actual latest mithril snapshot; AND /// 2. It must async fn get_latest_validated_mithril_snapshot( - network: Network, client: &Client, cfg: &MithrilSnapshotConfig, + chain: Network, client: &Client, cfg: &MithrilSnapshotConfig, ) -> Option { /// Purge a bad mithril snapshot from disk. - async fn purge_bad_mithril_snapshot(network: Network, latest_mithril: &SnapshotId) { + async fn purge_bad_mithril_snapshot(chain: Network, latest_mithril: &SnapshotId) { debug!("Purging Bad Mithril Snapshot: {latest_mithril}"); if let Err(error) = remove_dir_all(&latest_mithril).await { // This should NOT happen because we already checked the Mithril path is fully writable. - error!("Mithril Snapshot background updater for: {network}: Failed to remove old snapshot {latest_mithril}: {error}"); + error!("Mithril Snapshot background updater for: {chain}: Failed to remove old snapshot {latest_mithril}: {error}"); } } @@ -354,7 +352,7 @@ async fn get_latest_validated_mithril_snapshot( // Get the actual latest snapshot, shouldn't fail, but say the current is invalid if it // does. - let (actual_latest, _) = get_latest_snapshots(client, network).await?; + let (actual_latest, _) = get_latest_snapshots(client, chain).await?; // IF the mithril data we have is NOT the current latest (or the immediately previous), it // may as well be invalid. @@ -362,31 +360,31 @@ async fn get_latest_validated_mithril_snapshot( return None; } - let Some(snapshot) = get_snapshot_by_id(client, network, &latest_mithril).await else { + let Some(snapshot) = get_snapshot_by_id(client, chain, &latest_mithril).await else { // We have a latest snapshot, but the Aggregator does not know it. - error!("Mithril Snapshot background updater for: {network}: Latest snapshot {latest_mithril} does not exist on the Aggregator."); - purge_bad_mithril_snapshot(network, &latest_mithril).await; + error!("Mithril Snapshot background updater for: {chain}: Latest snapshot {latest_mithril} does not exist on the Aggregator."); + purge_bad_mithril_snapshot(chain, &latest_mithril).await; return None; }; // Download the snapshot/certificate from the aggregator. let Some((_, certificate)) = - get_mithril_snapshot_and_certificate(network, client, &snapshot).await + get_mithril_snapshot_and_certificate(chain, client, &snapshot).await else { error!("Mithril Snapshot : Failed to get Snapshot and certificate (Transient Error)."); // If we couldn't get the snapshot then we don't need to do anything else, transient // error. - // purge_bad_mithril_snapshot(network, &latest_mithril).await; + // purge_bad_mithril_snapshot(chain, &latest_mithril).await; return None; }; let path = latest_mithril.as_ref(); - let valid = validate_mithril_snapshot(network, &certificate, path).await; + let valid = validate_mithril_snapshot(chain, &certificate, path).await; if !valid { error!("Mithril Snapshot : Snapshot fails to validate, can not be recovered."); - purge_bad_mithril_snapshot(network, &latest_mithril).await; + purge_bad_mithril_snapshot(chain, &latest_mithril).await; return None; } @@ -398,7 +396,7 @@ async fn recover_existing_snapshot( cfg: &MithrilSnapshotConfig, tx: &Sender, ) -> Option { // This is a Mithril Validation, so record it. - mithril_validation_state(cfg.network, stats::MithrilValidationState::Start); + mithril_validation_state(cfg.chain, stats::MithrilValidationState::Start); // Note: we pre-validated connection before we ran, so failure here should be transient. // Just wait if we fail, and try again later. @@ -406,7 +404,7 @@ async fn recover_existing_snapshot( debug!( "Mithril Snapshot background updater for: {} : Client connected.", - cfg.network + cfg.chain ); let mut current_snapshot = None; @@ -414,15 +412,15 @@ async fn recover_existing_snapshot( // Check if we already have a Mithril snapshot downloaded, and IF we do validate it is // intact. if let Some(active_snapshot) = - get_latest_validated_mithril_snapshot(cfg.network, &client, cfg).await + get_latest_validated_mithril_snapshot(cfg.chain, &client, cfg).await { // Read the actual TIP block from the Mithril chain. - match get_mithril_tip(cfg.network, &active_snapshot.path()).await { + match get_mithril_tip(cfg.chain, &active_snapshot.path()).await { Ok(tip_block) => { // Validate the Snapshot ID matches the true TIP. if active_snapshot.tip() == tip_block.point() { current_snapshot = Some(active_snapshot.clone()); - update_latest_mithril_snapshot(cfg.network, active_snapshot); + update_latest_mithril_snapshot(cfg.chain, active_snapshot); // Tell the live sync service the current Mithril TIP. let update = MithrilUpdateMessage { @@ -432,7 +430,7 @@ async fn recover_existing_snapshot( if let Err(error) = tx.send(update).await { error!( "Failed to send new tip to the live updater for: {}: {error}", - cfg.network + cfg.chain ); }; } else { @@ -444,17 +442,17 @@ async fn recover_existing_snapshot( } }, Err(error) => { - error!("Mithril snapshot validation failed for: {}. Could not read the TIP Block : {}.", cfg.network, error); + error!("Mithril snapshot validation failed for: {}. Could not read the TIP Block : {}.", cfg.chain, error); }, } } else { - debug!("No latest validated snapshot for: {}", cfg.network); + debug!("No latest validated snapshot for: {}", cfg.chain); } if current_snapshot.is_none() { - mithril_validation_state(cfg.network, stats::MithrilValidationState::Failed); + mithril_validation_state(cfg.chain, stats::MithrilValidationState::Failed); } else { - mithril_validation_state(cfg.network, stats::MithrilValidationState::Finish); + mithril_validation_state(cfg.chain, stats::MithrilValidationState::Finish); } // Explicitly free the resources claimed by the Mithril Client and Downloader. @@ -474,19 +472,19 @@ enum SnapshotStatus { /// Check if we have a new snapshot to download, and if so, return its details. async fn check_snapshot_to_download( - network: Network, client: &Client, current_snapshot: Option<&SnapshotId>, + chain: Network, client: &Client, current_snapshot: Option<&SnapshotId>, ) -> SnapshotStatus { - debug!("Mithril Snapshot background updater for: {network} : Getting Latest Snapshot."); + debug!("Mithril Snapshot background updater for: {chain} : Getting Latest Snapshot."); // This should only fail if the Aggregator is offline. // Because we check we can talk to the aggregator before we create the downloader task. let Some((latest_snapshot, chronologically_previous_snapshot)) = - get_latest_snapshots(client, network).await + get_latest_snapshots(client, chain).await else { return SnapshotStatus::Sleep(DOWNLOAD_ERROR_RETRY_DURATION); }; - debug!("Mithril Snapshot background updater for: {network} : Checking if we are up-to-date {current_snapshot:?}."); + debug!("Mithril Snapshot background updater for: {chain} : Checking if we are up-to-date {current_snapshot:?}."); // Check if the latest snapshot is different from our actual previous one. if let Some(current_mithril_snapshot) = current_snapshot { @@ -502,7 +500,7 @@ async fn check_snapshot_to_download( // Download the snapshot/certificate from the aggregator. let Some((snapshot, certificate)) = - get_mithril_snapshot_and_certificate(network, client, &latest_snapshot).await + get_mithril_snapshot_and_certificate(chain, client, &latest_snapshot).await else { // If we couldn't get the snapshot then we don't need to do anything else, transient // error. @@ -516,30 +514,30 @@ async fn check_snapshot_to_download( /// Start Mithril Validation in the background, and return a handle so we can check when /// it finishes. fn background_validate_mithril_snapshot( - network: Network, certificate: MithrilCertificate, tmp_path: PathBuf, + chain: Network, certificate: MithrilCertificate, tmp_path: PathBuf, ) -> tokio::task::JoinHandle { tokio::spawn(async move { debug!( "Mithril Snapshot background updater for: {} : Check Certificate.", - network + chain ); - stats::mithril_validation_state(network, stats::MithrilValidationState::Start); + stats::mithril_validation_state(chain, stats::MithrilValidationState::Start); - if !validate_mithril_snapshot(network, &certificate, &tmp_path).await { - stats::mithril_validation_state(network, stats::MithrilValidationState::Failed); + if !validate_mithril_snapshot(chain, &certificate, &tmp_path).await { + stats::mithril_validation_state(chain, stats::MithrilValidationState::Failed); // If we couldn't build the message then assume its a transient error. error!( - network = %network, + chain = %chain, "Failed to Compute Snapshot Message" ); return false; } - stats::mithril_validation_state(network, stats::MithrilValidationState::Finish); + stats::mithril_validation_state(chain, stats::MithrilValidationState::Finish); debug!( "Mithril Snapshot background updater for: {} : Certificate Validated OK.", - network + chain ); true @@ -583,7 +581,7 @@ async fn download_and_validate_snapshot( ) -> bool { debug!( "Mithril Snapshot background updater for: {} : Download and unpack the Mithril snapshot.", - cfg.network + cfg.chain ); // Download and unpack the actual snapshot archive. @@ -599,21 +597,21 @@ async fn download_and_validate_snapshot( debug!( "Mithril Snapshot background updater for: {} : Add statistics for download.", - cfg.network + cfg.chain ); if let Err(error) = client.snapshot().add_statistics(snapshot).await { // Just log not fatal to anything. error!( "Could not increment snapshot download statistics for {}: {error}", - cfg.network + cfg.chain ); // We can process the download even after this fails. } debug!( "Mithril Snapshot background updater for: {} : Index and Check Certificate.", - cfg.network + cfg.chain ); let chunk_list = downloader.get_new_chunks(); @@ -622,10 +620,10 @@ async fn download_and_validate_snapshot( trim_chunk_list(&chunk_list, max_chunk); let validate_handle = - background_validate_mithril_snapshot(cfg.network, certificate, cfg.tmp_path()); + background_validate_mithril_snapshot(cfg.chain, certificate, cfg.tmp_path()); if !validate_handle.await.unwrap_or(false) { - error!("Failed to validate for {}", cfg.network); + error!("Failed to validate for {}", cfg.chain); return false; } @@ -638,7 +636,7 @@ async fn cleanup(cfg: &MithrilSnapshotConfig) { if let Err(error) = cfg.cleanup().await { error!( "Mithril Snapshot background updater for: {} : Error cleaning up: {:?}", - cfg.network, error + cfg.chain, error ); } } @@ -649,7 +647,7 @@ async fn sleep_until_next_probable_update( ) -> Duration { debug!( "Mithril Snapshot background updater for: {} : Sleeping for {}.", - cfg.network, + cfg.chain, format_duration(*next_sleep) ); // Wait until its likely we have a new snapshot ready to download. @@ -687,7 +685,7 @@ pub(crate) async fn background_mithril_update( ) { debug!( "Mithril Snapshot background updater for: {} from {} to {} : Starting", - cfg.network, + cfg.chain, cfg.aggregator_url, cfg.path.to_string_lossy() ); @@ -705,8 +703,7 @@ pub(crate) async fn background_mithril_update( let (client, downloader) = connect_client(&cfg).await; let (snapshot, certificate) = - match check_snapshot_to_download(cfg.network, &client, current_snapshot.as_ref()).await - { + match check_snapshot_to_download(cfg.chain, &client, current_snapshot.as_ref()).await { SnapshotStatus::Sleep(sleep) => { next_sleep = sleep; next_iteration!(client, downloader); @@ -724,24 +721,21 @@ pub(crate) async fn background_mithril_update( .await { error!("Failed to Download or Validate a snapshot."); - mithril_sync_failure( - cfg.network, - stats::MithrilSyncFailures::DownloadOrValidation, - ); + mithril_sync_failure(cfg.chain, stats::MithrilSyncFailures::DownloadOrValidation); next_iteration!(client, downloader); } // Download was A-OK - Update the new immutable tip. - let tip = match get_mithril_tip(cfg.network, &cfg.tmp_path()).await { + let tip = match get_mithril_tip(cfg.chain, &cfg.tmp_path()).await { Ok(tip) => tip, Err(error) => { // If we couldn't get the tip then assume its a transient error. error!( "Failed to Get Tip from Snapshot for {}: {error}", - cfg.network + cfg.chain ); - mithril_sync_failure(cfg.network, stats::MithrilSyncFailures::FailedToGetTip); + mithril_sync_failure(cfg.chain, stats::MithrilSyncFailures::FailedToGetTip); next_iteration!(client, downloader); }, @@ -754,9 +748,9 @@ pub(crate) async fn background_mithril_update( if tip <= active_snapshot.tip() { error!( "New Tip is not more advanced than the old tip for: {}", - cfg.network + cfg.chain ); - mithril_sync_failure(cfg.network, stats::MithrilSyncFailures::TipDidNotAdvance); + mithril_sync_failure(cfg.chain, stats::MithrilSyncFailures::TipDidNotAdvance); next_iteration!(client, downloader); } } @@ -766,13 +760,13 @@ pub(crate) async fn background_mithril_update( Ok(new_path) => { debug!( "Mithril Snapshot background updater for: {} : Updated TIP.", - cfg.network + cfg.chain ); current_snapshot = SnapshotId::new(&new_path, tip.point()); if let Some(latest_snapshot) = current_snapshot.clone() { // Update the latest snapshot data record - update_latest_mithril_snapshot(cfg.network, latest_snapshot); + update_latest_mithril_snapshot(cfg.chain, latest_snapshot); // Tell the live updater that the Immutable TIP has updated. if let Err(error) = tx @@ -784,10 +778,10 @@ pub(crate) async fn background_mithril_update( { error!( "Failed to send new tip to the live updater for: {}: {error}", - cfg.network + cfg.chain ); mithril_sync_failure( - cfg.network, + cfg.chain, stats::MithrilSyncFailures::TipFailedToSendToUpdater, ); next_iteration!(client, downloader); @@ -796,11 +790,11 @@ pub(crate) async fn background_mithril_update( }, Err(err) => { error!( - network = cfg.network.to_string(), + chain = cfg.chain.to_string(), "Failed to activate new snapshot : {err}" ); mithril_sync_failure( - cfg.network, + cfg.chain, stats::MithrilSyncFailures::FailedToActivateNewSnapshot, ); next_iteration!(client, downloader); diff --git a/rust/cardano-chain-follower/src/mithril_turbo_downloader.rs b/rust/cardano-chain-follower/src/mithril_turbo_downloader.rs index 0f389c3b1..f9b380b98 100644 --- a/rust/cardano-chain-follower/src/mithril_turbo_downloader.rs +++ b/rust/cardano-chain-follower/src/mithril_turbo_downloader.rs @@ -99,7 +99,7 @@ impl Inner { }; let tmp_dir = self.cfg.tmp_path(); - let latest_snapshot = latest_mithril_snapshot_data(self.cfg.network); + let latest_snapshot = latest_mithril_snapshot_data(self.cfg.chain); for entry in entries { let mut entry = match entry { @@ -164,13 +164,13 @@ impl Inner { } if let Err(error) = std::fs::write(&abs_file, buf) { - error!(network = %self.cfg.network, "Failed to write file {} got {}", abs_file.display(), error); + error!(chain = %self.cfg.chain, "Failed to write file {} got {}", abs_file.display(), error); bail!("Failed to write file {} got {}", abs_file.display(), error); } } else { // No dedup, just extract it into the tmp directory as-is. entry.unpack_in(&tmp_dir)?; - debug!(network = %self.cfg.network, "DeDup: Extracted file {rel_file:?}:{entry_size}"); + debug!(chain = %self.cfg.chain, "DeDup: Extracted file {rel_file:?}:{entry_size}"); } new_file!(self, rel_file, abs_file, entry_size); } @@ -179,9 +179,9 @@ impl Inner { bail!("Failed to get the Parallel Download processor!"); }; - debug!(network = %self.cfg.network, "Download {} bytes", dl_handler.dl_size()); + debug!(chain = %self.cfg.chain, "Download {} bytes", dl_handler.dl_size()); - stats::mithril_dl_finished(self.cfg.network, Some(dl_handler.dl_size())); + stats::mithril_dl_finished(self.cfg.chain, Some(dl_handler.dl_size())); Ok(()) } @@ -205,7 +205,7 @@ impl Inner { /// Check if we are supposed to extract this file from the archive or not. fn check_for_extract(&self, path: &Path, extract_type: EntryType) -> bool { if path.is_absolute() { - error!(network = %self.cfg.network, "DeDup : Cannot extract an absolute path: {:?}", path); + error!(chain = %self.cfg.chain, "DeDup : Cannot extract an absolute path: {:?}", path); return false; } @@ -215,7 +215,7 @@ impl Inner { } if !extract_type.is_file() { - error!(network = %self.cfg.network, "DeDup : Cannot extract a non-file: {:?}:{:?}", path, extract_type); + error!(chain = %self.cfg.chain, "DeDup : Cannot extract a non-file: {:?}:{:?}", path, extract_type); return false; } @@ -308,7 +308,7 @@ impl MithrilTurboDownloader { return result; } - stats::mithril_dl_finished(self.inner.cfg.network, None); + stats::mithril_dl_finished(self.inner.cfg.chain, None); bail!("Download and Dedup task failed"); } } @@ -351,7 +351,7 @@ impl SnapshotDownloader for MithrilTurboDownloader { let new_files = self.inner.new_files.load(Ordering::SeqCst); stats::mithril_extract_finished( - self.inner.cfg.network, + self.inner.cfg.chain, Some(self.inner.ext_size.load(Ordering::SeqCst)), self.inner.dedup_size.load(Ordering::SeqCst), tot_files - (chg_files + new_files), @@ -371,10 +371,10 @@ impl SnapshotDownloader for MithrilTurboDownloader { let dl_processor = ParallelDownloadProcessor::new(location, dl_config).await?; // Decompress and extract and de-dupe each file in the archive. - stats::mithril_extract_started(self.inner.cfg.network); + stats::mithril_extract_started(self.inner.cfg.chain); // We also immediately start downloading now. - stats::mithril_dl_started(self.inner.cfg.network); + stats::mithril_dl_started(self.inner.cfg.chain); // Save the DownloadProcessor in the inner struct for use to process the downloaded data. if let Err(_error) = self.inner.dl_handler.set(dl_processor) { diff --git a/rust/cardano-chain-follower/src/snapshot_id.rs b/rust/cardano-chain-follower/src/snapshot_id.rs index 0e7655280..876a39c91 100644 --- a/rust/cardano-chain-follower/src/snapshot_id.rs +++ b/rust/cardano-chain-follower/src/snapshot_id.rs @@ -14,16 +14,16 @@ use crate::mithril_snapshot_sync::{get_mithril_tip, MITHRIL_IMMUTABLE_SUB_DIRECT /// A representation of a Snapshot Path and its represented immutable file number. #[derive(Clone, Debug)] pub(crate) struct SnapshotId { - /// The snapshot path + /// The Snapshot Path path: PathBuf, - /// The largest immutable file number + /// The largest Immutable File Number file: u64, - /// The tip of the Snapshot + /// The Tip of the Snapshot tip: Point, } impl SnapshotId { - /// See if we can parse the path into an immutable file number. + /// See if we can Parse the path into an immutable file number. pub(crate) fn parse_path(path: &Path) -> Option { // Path must actually exist, and be a directory. if !path.is_dir() { @@ -42,7 +42,7 @@ impl SnapshotId { } /// Try and create a new `SnapshotID` from a given path. - /// Immutable tip must be provided. + /// Immutable TIP must be provided. pub(crate) fn new(path: &Path, tip: Point) -> Option { debug!("Trying to Get SnapshotID of: {}", path.to_string_lossy()); let immutable_file = SnapshotId::parse_path(path)?; @@ -56,16 +56,16 @@ impl SnapshotId { } /// Try and create a new `SnapshotID` from a given path. - /// Includes properly getting the immutable TIP. - pub(crate) async fn try_new(network: Network, path: &Path) -> Option { - let Ok(tip) = get_mithril_tip(network, path).await else { + /// Includes properly getting the Immutable TIP. + pub(crate) async fn try_new(chain: Network, path: &Path) -> Option { + let Ok(tip) = get_mithril_tip(chain, path).await else { return None; }; SnapshotId::new(path, tip.point()) } - /// Get the immutable blockchain path from this `SnapshotId` + /// Get the Immutable Blockchain path from this `SnapshotId` pub(crate) fn immutable_path(&self) -> PathBuf { let mut immutable = self.path.clone(); immutable.push(MITHRIL_IMMUTABLE_SUB_DIRECTORY); @@ -73,12 +73,12 @@ impl SnapshotId { immutable } - /// Get the blockchain path from this `SnapshotId` + /// Get the Blockchain path from this `SnapshotId` pub(crate) fn path(&self) -> PathBuf { self.path.clone() } - /// Get the blockchain path from this `SnapshotId` only if it actually exists. + /// Get the Blockchain path from this `SnapshotId` only if it actually exists. pub(crate) fn path_if_exists(&self) -> Option { if self.tip.is_unknown() { return None; @@ -86,7 +86,7 @@ impl SnapshotId { Some(self.path.clone()) } - /// Get the tip of the immutable blockchain from this `SnapshotId` + /// Get the Tip of the Immutable Blockchain from this `SnapshotId` pub(crate) fn tip(&self) -> Point { self.tip.clone() } @@ -122,16 +122,18 @@ impl Display for SnapshotId { } } -// Normal comparisons to simplify code. +// Normal Comparisons to simplify code. impl PartialEq for SnapshotId { - // Equality ONLY checks the `file` (immutable file number), not the path. + // Equality ONLY checks the Immutable File Number, not the path. + // This is because the Filename is already the ImmutableFileNumber fn eq(&self, other: &Self) -> bool { self.file == other.file } } impl PartialOrd for SnapshotId { - // Equality ONLY checks the `file` (immutable file number), not the path. + // Equality ONLY checks the Immutable File Number, not the path. + // This is because the Filename is already the ImmutableFileNumber fn partial_cmp(&self, other: &Self) -> Option { self.file.partial_cmp(&other.file) } @@ -139,7 +141,8 @@ impl PartialOrd for SnapshotId { // Allows us to compare a `SnapshotID` against Some(`SnapshotID`). impl PartialEq> for SnapshotId { - // Equality ONLY checks the `file` (immutable file number), not the path. + // Equality ONLY checks the Immutable File Number, not the path. + // This is because the Filename is already the ImmutableFileNumber fn eq(&self, other: &Option) -> bool { match other { None => false, @@ -149,7 +152,8 @@ impl PartialEq> for SnapshotId { } impl PartialOrd> for SnapshotId { - // Equality ONLY checks the `file` (immutable file number), not the path. + // Equality ONLY checks the Immutable File Number, not the path. + // This is because the Filename is already the ImmutableFileNumber fn partial_cmp(&self, other: &Option) -> Option { match other { None => Some(Ordering::Greater), // Anything is always greater than None. @@ -160,14 +164,16 @@ impl PartialOrd> for SnapshotId { // Allows us to compare a `SnapshotID` against u64 (just the immutable file number). impl PartialEq for SnapshotId { - // Equality ONLY checks the `file` (immutable file number), not the path. + // Equality ONLY checks the Immutable File Number, not the path. + // This is because the Filename is already the ImmutableFileNumber fn eq(&self, other: &u64) -> bool { self.file == *other } } impl PartialOrd for SnapshotId { - // Equality ONLY checks the `file` (immutable file number), not the path. + // Equality ONLY checks the Immutable File Number, not the path. + // This is because the Filename is already the ImmutableFileNumber fn partial_cmp(&self, other: &u64) -> Option { self.file.partial_cmp(other) } From 00e5cf73ea170487c6ae08bac93c3c55ac6da63a Mon Sep 17 00:00:00 2001 From: bkioshn <35752733+bkioshn@users.noreply.github.com> Date: Fri, 10 Jan 2025 13:51:42 +0700 Subject: [PATCH 36/40] Update rust/cardano-chain-follower/Cargo.toml Co-authored-by: Steven Johnson --- rust/cardano-chain-follower/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/cardano-chain-follower/Cargo.toml b/rust/cardano-chain-follower/Cargo.toml index 5b1709199..1bf3527bd 100644 --- a/rust/cardano-chain-follower/Cargo.toml +++ b/rust/cardano-chain-follower/Cargo.toml @@ -19,7 +19,7 @@ mithril-client = { version = "0.10.4", default-features = false, features = [ "full", "num-integer-backend", ] } -cardano-blockchain-types = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", branch = "fix/cip36" } +cardano-blockchain-types = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250108-00" } catalyst-types = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250108-00" } thiserror = "1.0.69" From 557e20c857f75bbd0ed95f6a84ddc95064caf4d1 Mon Sep 17 00:00:00 2001 From: bkioshn Date: Fri, 10 Jan 2025 13:59:45 +0700 Subject: [PATCH 37/40] fix(cardano-chain-follower): revert changes Signed-off-by: bkioshn --- rust/cardano-chain-follower/Cargo.toml | 2 +- rust/cardano-chain-follower/src/stats/mod.rs | 84 +++++++++---------- .../src/stats/rollback.rs | 16 ++-- 3 files changed, 51 insertions(+), 51 deletions(-) diff --git a/rust/cardano-chain-follower/Cargo.toml b/rust/cardano-chain-follower/Cargo.toml index 1bf3527bd..79f0293c1 100644 --- a/rust/cardano-chain-follower/Cargo.toml +++ b/rust/cardano-chain-follower/Cargo.toml @@ -19,7 +19,7 @@ mithril-client = { version = "0.10.4", default-features = false, features = [ "full", "num-integer-backend", ] } -cardano-blockchain-types = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250108-00" } +cardano-blockchain-types = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250109-00" } catalyst-types = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250108-00" } thiserror = "1.0.69" diff --git a/rust/cardano-chain-follower/src/stats/mod.rs b/rust/cardano-chain-follower/src/stats/mod.rs index 530f36a98..fa21e6381 100644 --- a/rust/cardano-chain-follower/src/stats/mod.rs +++ b/rust/cardano-chain-follower/src/stats/mod.rs @@ -42,8 +42,8 @@ static STATS_MAP: LazyLock = LazyLock::new(|| { }); /// Get the stats for a particular chain. -fn lookup_stats(network: Network) -> Option>> { - let Some(chain_entry) = STATS_MAP.get(&network) else { +fn lookup_stats(chain: Network) -> Option>> { + let Some(chain_entry) = STATS_MAP.get(&chain) else { error!("Stats MUST BE exhaustively pre-allocated."); return None; }; @@ -56,8 +56,8 @@ fn lookup_stats(network: Network) -> Option>> { impl Statistics { /// Get a new statistics struct for a given blockchain network. #[must_use] - pub fn new(network: Network) -> Self { - let Some(stats) = lookup_stats(network) else { + pub fn new(chain: Network) -> Self { + let Some(stats) = lookup_stats(chain) else { return Statistics::default(); }; @@ -67,9 +67,9 @@ impl Statistics { let mut this_stats = chain_stats.clone(); // Set the current rollback stats. - this_stats.live.rollbacks.live = rollbacks(network, RollbackType::LiveChain); - this_stats.live.rollbacks.peer = rollbacks(network, RollbackType::Peer); - this_stats.live.rollbacks.follower = rollbacks(network, RollbackType::Follower); + this_stats.live.rollbacks.live = rollbacks(chain, RollbackType::LiveChain); + this_stats.live.rollbacks.peer = rollbacks(chain, RollbackType::Peer); + this_stats.live.rollbacks.follower = rollbacks(chain, RollbackType::Follower); this_stats } @@ -81,9 +81,9 @@ impl Statistics { } /// Get the current tips of the immutable chain and live chain. - pub(crate) fn tips(network: Network) -> (Slot, Slot) { + pub(crate) fn tips(chain: Network) -> (Slot, Slot) { let zero_slot = Slot::from_saturating(0); - let Some(stats) = lookup_stats(network) else { + let Some(stats) = lookup_stats(chain) else { return (zero_slot, zero_slot); }; @@ -96,8 +96,8 @@ impl Statistics { /// Reset amd return cumulative counters contained in the statistics. #[must_use] - pub fn reset(network: Network) -> Self { - let Some(stats) = lookup_stats(network) else { + pub fn reset(chain: Network) -> Self { + let Some(stats) = lookup_stats(chain) else { return Statistics::default(); }; @@ -109,9 +109,9 @@ impl Statistics { let mut this_stats = chain_stats.clone(); // Reset the current rollback stats. - this_stats.live.rollbacks.live = rollbacks_reset(network, RollbackType::LiveChain); - this_stats.live.rollbacks.peer = rollbacks_reset(network, RollbackType::Peer); - this_stats.live.rollbacks.follower = rollbacks_reset(network, RollbackType::Follower); + this_stats.live.rollbacks.live = rollbacks_reset(chain, RollbackType::LiveChain); + this_stats.live.rollbacks.peer = rollbacks_reset(chain, RollbackType::Peer); + this_stats.live.rollbacks.follower = rollbacks_reset(chain, RollbackType::Follower); this_stats } @@ -136,9 +136,9 @@ impl Statistics { /// Count the invalidly deserialized blocks #[allow(dead_code)] -pub(crate) fn stats_invalid_block(network: Network, immutable: bool) { +pub(crate) fn stats_invalid_block(chain: Network, immutable: bool) { // This will actually always succeed. - let Some(stats) = lookup_stats(network) else { + let Some(stats) = lookup_stats(chain) else { return; }; @@ -157,10 +157,10 @@ pub(crate) fn stats_invalid_block(network: Network, immutable: bool) { /// Count the validly deserialized blocks pub(crate) fn new_live_block( - network: Network, total_live_blocks: u64, head_slot: Slot, tip_slot: Slot, + chain: Network, total_live_blocks: u64, head_slot: Slot, tip_slot: Slot, ) { // This will actually always succeed. - let Some(stats) = lookup_stats(network) else { + let Some(stats) = lookup_stats(chain) else { return; }; @@ -178,10 +178,10 @@ pub(crate) fn new_live_block( /// Track the end of the current mithril update pub(crate) fn new_mithril_update( - network: Network, mithril_tip: Slot, total_live_blocks: u64, tip_slot: Slot, + chain: Network, mithril_tip: Slot, total_live_blocks: u64, tip_slot: Slot, ) { // This will actually always succeed. - let Some(stats) = lookup_stats(network) else { + let Some(stats) = lookup_stats(chain) else { return; }; @@ -198,9 +198,9 @@ pub(crate) fn new_mithril_update( } /// When did we start the backfill. -pub(crate) fn backfill_started(network: Network) { +pub(crate) fn backfill_started(chain: Network) { // This will actually always succeed. - let Some(stats) = lookup_stats(network) else { + let Some(stats) = lookup_stats(chain) else { return; }; @@ -221,9 +221,9 @@ pub(crate) fn backfill_started(network: Network) { } /// When did we start the backfill. -pub(crate) fn backfill_ended(network: Network, backfill_size: u64) { +pub(crate) fn backfill_ended(chain: Network, backfill_size: u64) { // This will actually always succeed. - let Some(stats) = lookup_stats(network) else { + let Some(stats) = lookup_stats(chain) else { return; }; @@ -238,9 +238,9 @@ pub(crate) fn backfill_ended(network: Network, backfill_size: u64) { } /// Track statistics about connections to the cardano peer node. -pub(crate) fn peer_connected(network: Network, active: bool, peer_address: &str) { +pub(crate) fn peer_connected(chain: Network, active: bool, peer_address: &str) { // This will actually always succeed. - let Some(stats) = lookup_stats(network) else { + let Some(stats) = lookup_stats(chain) else { return; }; @@ -263,9 +263,9 @@ pub(crate) fn peer_connected(network: Network, active: bool, peer_address: &str) } /// Record when we started syncing -pub(crate) fn sync_started(network: Network) { +pub(crate) fn sync_started(chain: Network) { // This will actually always succeed. - let Some(stats) = lookup_stats(network) else { + let Some(stats) = lookup_stats(chain) else { return; }; @@ -280,9 +280,9 @@ pub(crate) fn sync_started(network: Network) { /// Record when we first reached tip. This can safely be called multiple times. /// Except for overhead, only the first call will actually record the time. -pub(crate) fn tip_reached(network: Network) { +pub(crate) fn tip_reached(chain: Network) { // This will actually always succeed. - let Some(stats) = lookup_stats(network) else { + let Some(stats) = lookup_stats(chain) else { return; }; @@ -298,9 +298,9 @@ pub(crate) fn tip_reached(network: Network) { } /// Record that a Mithril snapshot Download has started. -pub(crate) fn mithril_dl_started(network: Network) { +pub(crate) fn mithril_dl_started(chain: Network) { // This will actually always succeed. - let Some(stats) = lookup_stats(network) else { + let Some(stats) = lookup_stats(chain) else { return; }; @@ -315,9 +315,9 @@ pub(crate) fn mithril_dl_started(network: Network) { /// Record when DL finished, if it fails, set size to None, otherwise the size of the /// downloaded file. -pub(crate) fn mithril_dl_finished(network: Network, dl_size: Option) { +pub(crate) fn mithril_dl_finished(chain: Network, dl_size: Option) { // This will actually always succeed. - let Some(stats) = lookup_stats(network) else { + let Some(stats) = lookup_stats(chain) else { return; }; @@ -340,9 +340,9 @@ pub(crate) fn mithril_dl_finished(network: Network, dl_size: Option) { } /// Record that extracting the mithril snapshot archive has started. -pub(crate) fn mithril_extract_started(network: Network) { +pub(crate) fn mithril_extract_started(chain: Network) { // This will actually always succeed. - let Some(stats) = lookup_stats(network) else { + let Some(stats) = lookup_stats(chain) else { return; }; @@ -358,11 +358,11 @@ pub(crate) fn mithril_extract_started(network: Network) { /// Record when DL finished, if it fails, set size to None, otherwise the size of the /// downloaded file. pub(crate) fn mithril_extract_finished( - network: Network, extract_size: Option, deduplicated_size: u64, deduplicated_files: u64, + chain: Network, extract_size: Option, deduplicated_size: u64, deduplicated_files: u64, changed_files: u64, new_files: u64, ) { // This will actually always succeed. - let Some(stats) = lookup_stats(network) else { + let Some(stats) = lookup_stats(chain) else { return; }; @@ -396,9 +396,9 @@ pub(crate) enum MithrilValidationState { } /// Record when Mithril Cert validation starts, ends or fails). -pub(crate) fn mithril_validation_state(network: Network, mithril_state: MithrilValidationState) { +pub(crate) fn mithril_validation_state(chain: Network, mithril_state: MithrilValidationState) { // This will actually always succeed. - let Some(stats) = lookup_stats(network) else { + let Some(stats) = lookup_stats(chain) else { return; }; @@ -431,9 +431,9 @@ pub(crate) enum MithrilSyncFailures { } /// Record when Mithril Cert validation starts, ends or fails). -pub(crate) fn mithril_sync_failure(network: Network, failure: MithrilSyncFailures) { +pub(crate) fn mithril_sync_failure(chain: Network, failure: MithrilSyncFailures) { // This will actually always succeed. - let Some(stats) = lookup_stats(network) else { + let Some(stats) = lookup_stats(chain) else { return; }; diff --git a/rust/cardano-chain-follower/src/stats/rollback.rs b/rust/cardano-chain-follower/src/stats/rollback.rs index 646348480..e6b73d090 100644 --- a/rust/cardano-chain-follower/src/stats/rollback.rs +++ b/rust/cardano-chain-follower/src/stats/rollback.rs @@ -65,9 +65,9 @@ static ROLLBACKS_MAP: LazyLock = LazyLock::new(|| { /// Get the actual rollback map for a chain. fn lookup_rollback_map( - network: Network, rollback: RollbackType, + chain: Network, rollback: RollbackType, ) -> Option>> { - let Some(chain_rollback_map) = ROLLBACKS_MAP.get(&network) else { + let Some(chain_rollback_map) = ROLLBACKS_MAP.get(&chain) else { error!("Rollback stats SHOULD BE exhaustively pre-allocated."); return None; }; @@ -83,8 +83,8 @@ fn lookup_rollback_map( } /// Extract the current rollback stats as a vec. -pub(crate) fn rollbacks(network: Network, rollback: RollbackType) -> Vec { - let Some(rollback_map) = lookup_rollback_map(network, rollback) else { +pub(crate) fn rollbacks(chain: Network, rollback: RollbackType) -> Vec { + let Some(rollback_map) = lookup_rollback_map(chain, rollback) else { return Vec::new(); }; @@ -104,8 +104,8 @@ pub(crate) fn rollbacks(network: Network, rollback: RollbackType) -> Vec Vec { - let Some(rollback_map) = lookup_rollback_map(network, rollback) else { +pub(crate) fn rollbacks_reset(chain: Network, rollback: RollbackType) -> Vec { + let Some(rollback_map) = lookup_rollback_map(chain, rollback) else { return Vec::new(); }; @@ -120,8 +120,8 @@ pub(crate) fn rollbacks_reset(network: Network, rollback: RollbackType) -> Vec Date: Fri, 10 Jan 2025 18:08:54 +0700 Subject: [PATCH 38/40] fix(cardano-chain-follower): new fork Signed-off-by: bkioshn --- rust/cardano-chain-follower/Cargo.toml | 2 +- rust/cardano-chain-follower/examples/follow_chains.rs | 2 +- rust/cardano-chain-follower/src/chain_sync.rs | 4 ++-- rust/cardano-chain-follower/src/chain_sync_live_chains.rs | 7 +++++-- rust/cardano-chain-follower/src/follow.rs | 2 +- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/rust/cardano-chain-follower/Cargo.toml b/rust/cardano-chain-follower/Cargo.toml index 79f0293c1..aa1a54181 100644 --- a/rust/cardano-chain-follower/Cargo.toml +++ b/rust/cardano-chain-follower/Cargo.toml @@ -19,7 +19,7 @@ mithril-client = { version = "0.10.4", default-features = false, features = [ "full", "num-integer-backend", ] } -cardano-blockchain-types = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250109-00" } +cardano-blockchain-types = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", branch = "fix/fork" } catalyst-types = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250108-00" } thiserror = "1.0.69" diff --git a/rust/cardano-chain-follower/examples/follow_chains.rs b/rust/cardano-chain-follower/examples/follow_chains.rs index bab914bab..59268ede5 100644 --- a/rust/cardano-chain-follower/examples/follow_chains.rs +++ b/rust/cardano-chain-follower/examples/follow_chains.rs @@ -190,7 +190,7 @@ async fn follow_for(network: Network, matches: ArgMatches) { // If these become true, we will show all blocks from the follower. follow_all = follow_all || (!chain_update.immutable() && all_live_blocks) - || ((chain_update.data.fork() > 1.into()) && all_tip_blocks); + || (chain_update.data.fork().is_live() && all_tip_blocks); // Don't know if this update will show or not, so say it didn't. last_update_shown = false; diff --git a/rust/cardano-chain-follower/src/chain_sync.rs b/rust/cardano-chain-follower/src/chain_sync.rs index abccfb428..4bc624c2f 100644 --- a/rust/cardano-chain-follower/src/chain_sync.rs +++ b/rust/cardano-chain-follower/src/chain_sync.rs @@ -368,7 +368,7 @@ async fn live_sync_backfill( while let Some(block_data) = peer.blockfetch().recv_while_streaming().await? { // Backfilled blocks get placed in the oldest fork currently on the live-chain. - let block = MultiEraBlock::new(cfg.chain, block_data, &previous_point, 1.into()) + let block = MultiEraBlock::new(cfg.chain, block_data, &previous_point, Fork::BACKFILL) .with_context(|| { format!( "Failed to decode block data. previous: {previous_point:?}, range: {range_msg}" @@ -534,7 +534,7 @@ pub(crate) async fn chain_sync(cfg: ChainSyncConfig, rx: mpsc::Receiver> = LazyLock::new(|| { map }); +/// Initial slot age to probe. +const INITIAL_SLOT_PROBE_AGE: u64 = 40; + /// Set the last TIP received from the peer. fn update_peer_tip(chain: Network, tip: Point) { PEER_TIP.insert(chain, tip); @@ -207,7 +210,7 @@ impl ProtectedLiveChainBlockList { let mut rollback_size: u64 = 0; // We are NOT contiguous, so check if we can become contiguous with a rollback. - debug!("Detected non-contiguous block, rolling back. Fork: {fork_count:?}"); + debug!("Detected non-contiguous block, rolling back. Fork: {fork_count}"); // First check if the previous is >= the earliest block in the live chain. // This is because when we start syncing we could rollback earlier than our @@ -344,7 +347,7 @@ impl ProtectedLiveChainBlockList { } // Now find points based on an every increasing Slot age. - let mut slot_age: Slot = 40.into(); + let mut slot_age: Slot = INITIAL_SLOT_PROBE_AGE.into(); let reference_slot = entry.value().point().slot_or_default(); let mut previous_point = entry.value().point(); diff --git a/rust/cardano-chain-follower/src/follow.rs b/rust/cardano-chain-follower/src/follow.rs index b1b2f79a1..8e8d5bd6d 100644 --- a/rust/cardano-chain-follower/src/follow.rs +++ b/rust/cardano-chain-follower/src/follow.rs @@ -101,7 +101,7 @@ impl ChainFollower { self.previous = self.current.clone(); // debug!("Post Previous update 3 : {:?}", self.previous); self.current = next.point(); - self.fork = 0.into(); // Mithril Immutable data is always Fork 0. + self.fork = Fork::IMMUTABLE; // Mithril Immutable data is always Fork 0. let update = ChainUpdate::new(chain_update::Kind::Block, false, next); return Some(update); } From 2fbbe61a5df82ed97452a64bff88c3b05604c72f Mon Sep 17 00:00:00 2001 From: bkioshn Date: Mon, 13 Jan 2025 07:54:39 +0700 Subject: [PATCH 39/40] fix(cardano-chain-follower): add more function Signed-off-by: bkioshn --- .../examples/follow_chains.rs | 181 +++++++++++++++--- 1 file changed, 158 insertions(+), 23 deletions(-) diff --git a/rust/cardano-chain-follower/examples/follow_chains.rs b/rust/cardano-chain-follower/examples/follow_chains.rs index 59268ede5..a1aef7be9 100644 --- a/rust/cardano-chain-follower/examples/follow_chains.rs +++ b/rust/cardano-chain-follower/examples/follow_chains.rs @@ -5,7 +5,9 @@ // Allowing since this is example code. //#![allow(clippy::unwrap_used)] -use cardano_blockchain_types::{Cip36, Fork, MultiEraBlock, Network, Point}; +use cardano_blockchain_types::{ + Cip36, Fork, MetadatumLabel, MultiEraBlock, Network, Point, TxnIndex, +}; #[cfg(feature = "mimalloc")] use mimalloc::MiMalloc; @@ -39,6 +41,10 @@ fn process_argument() -> (Vec, ArgMatches) { .action(ArgAction::SetTrue), arg!(--"log-raw-aux" "Dump raw auxiliary data.") .action(ArgAction::SetTrue), + arg!(--"largest-metadata" "Dump The largest transaction metadata we find (as we find it).") + .action(ArgAction::SetTrue), + arg!(--"largest-aux" "Dump The largest auxiliary metadata we find (as we find it).") + .action(ArgAction::SetTrue), arg!(--"mithril-sync-workers" "The number of workers to use when downloading the blockchain snapshot.") .value_parser(clap::value_parser!(u16).range(1..)) .action(ArgAction::Set), @@ -57,6 +63,8 @@ fn process_argument() -> (Vec, ArgMatches) { // Metadata arg!(--"log-bad-cip36" "Dump Bad CIP36 registrations detected.") .action(ArgAction::SetTrue), + arg!(--"log-bad-cip509" "Dump Bad CIP509 detected.") + .action(ArgAction::SetTrue), ]) .get_matches(); @@ -145,9 +153,12 @@ async fn follow_for(network: Network, matches: ArgMatches) { let stop_at_tip = matches.get_flag("stop-at-tip"); let halt_on_error = matches.get_flag("halt-on-error"); let log_raw_aux = matches.get_flag("log-raw-aux"); + let largest_metadata = matches.get_flag("largest-metadata"); + let largest_aux = matches.get_flag("largest-aux"); // Metadata let log_bad_cip36 = matches.get_flag("log-bad-cip36"); + let log_bad_cip509 = matches.get_flag("log-bad-cip509"); let mut current_era = String::new(); let mut last_update: Option = None; @@ -161,6 +172,9 @@ async fn follow_for(network: Network, matches: ArgMatches) { let mut last_metrics_time = Instant::now(); + let mut largest_metadata_size: usize = 0; + let mut largest_aux_size: usize = 0; + while let Some(chain_update) = follower.next().await { updates += 1; @@ -168,8 +182,9 @@ async fn follow_for(network: Network, matches: ArgMatches) { reached_tip = true; } - let block = chain_update.block_data().decode(); - let this_era = block.era().to_string(); + let block = chain_update.block_data(); + let decoded_block = block.decode(); + let this_era = decoded_block.era().to_string(); // When we transition between important points, show the last block as well. if ((current_era != this_era) @@ -213,7 +228,7 @@ async fn follow_for(network: Network, matches: ArgMatches) { last_update_shown = true; } - let this_prev_hash = block.header().previous_hash(); + let this_prev_hash = decoded_block.header().previous_hash(); // We have no state, so can only check consistency with block updates. // But thats OK, the chain follower itself is also checking chain consistency. @@ -232,33 +247,33 @@ async fn follow_for(network: Network, matches: ArgMatches) { break; } - if log_raw_aux { - if let Some(x) = block.as_alonzo() { - info!( - chain = network.to_string(), - "Raw Aux Data: {:02x?}", x.auxiliary_data_set - ); - } else if let Some(x) = block.as_babbage() { - info!( - chain = network.to_string(), - "Raw Aux Data: {:02x?}", x.auxiliary_data_set - ); - } else if let Some(x) = block.as_conway() { - info!( - chain = network.to_string(), - "Raw Aux Data: {:02x?}", x.auxiliary_data_set - ); + // Update and log the largest metadata + if largest_metadata { + for (txn_idx, _tx) in decoded_block.txs().iter().enumerate() { + update_largest_metadata(block, network, txn_idx.into(), &mut largest_metadata_size); } } + // Update and log the largest transaction auxiliary data. + if largest_aux { + update_largest_aux(decoded_block, network, &mut largest_aux_size); + } + + // Log the raw auxiliary data. + if log_raw_aux { + raw_aux_info(decoded_block, network); + } // Illustrate how the chain-follower works with metadata. // Log bad CIP36. if log_bad_cip36 { - log_bad_cip36_info(chain_update.block_data(), network); + log_bad_cip36_info(block, network); + } + // Log bad CIP509. + if log_bad_cip509 { + log_bad_cip509_info(block, network); } - // TODO - Add CIP509 example. - prev_hash = Some(block.hash()); + prev_hash = Some(decoded_block.hash()); last_update = Some(chain_update); if reached_tip && stop_at_tip { @@ -297,6 +312,121 @@ async fn follow_for(network: Network, matches: ArgMatches) { info!(chain = network.to_string(), "Following Completed."); } +/// Helper function for updating the biggest metadata from a list of +/// interested metadata label. +fn update_largest_metadata( + block: &MultiEraBlock, network: Network, txn_idx: TxnIndex, largest_metadata_size: &mut usize, +) { + let labels = [ + MetadatumLabel::CIP509_RBAC, + MetadatumLabel::CIP036_AUXDATA, + MetadatumLabel::CIP020_MESSAGE, + ]; + + for label in &labels { + let metadata = block.txn_metadata(txn_idx, *label); + if let Some(data) = metadata { + let metadata_len = data.as_ref().len(); + if metadata_len > *largest_metadata_size { + *largest_metadata_size = metadata_len; + info!( + chain = network.to_string(), + "Largest Metadata updated, point: {:?}, tx index: {:?}, label: {:?}, size: {}", + block.point(), + txn_idx, + label, + largest_metadata_size + ); + } + } + } +} + +/// Helper function for logging the raw box auxiliary data. +fn raw_aux_info(block: &pallas::ledger::traverse::MultiEraBlock, network: Network) { + match block { + pallas::ledger::traverse::MultiEraBlock::AlonzoCompatible(b, _) => { + info!( + chain = network.to_string(), + "Raw Aux Data: {:02x?}", b.auxiliary_data_set + ); + }, + pallas::ledger::traverse::MultiEraBlock::Babbage(b) => { + info!( + chain = network.to_string(), + "Raw Aux Data: {:02x?}", b.auxiliary_data_set + ); + }, + pallas::ledger::traverse::MultiEraBlock::Conway(b) => { + info!( + chain = network.to_string(), + "Raw Aux Data: {:02x?}", b.auxiliary_data_set + ); + }, + _ => {}, + } +} + +/// Helper function for updating the largest auxiliary data. +fn update_largest_aux( + block: &pallas::ledger::traverse::MultiEraBlock, network: Network, + largest_metadata_size: &mut usize, +) { + match block { + pallas::ledger::traverse::MultiEraBlock::AlonzoCompatible(ref b, _) => { + b.auxiliary_data_set.iter().for_each(|(txn_idx, aux_data)| { + compare_and_log_aux( + aux_data.raw_cbor().len(), + block.number(), + *txn_idx, + network, + largest_metadata_size, + ); + }); + }, + pallas::ledger::traverse::MultiEraBlock::Babbage(ref b) => { + b.auxiliary_data_set.iter().for_each(|(txn_idx, aux_data)| { + compare_and_log_aux( + aux_data.raw_cbor().len(), + block.number(), + *txn_idx, + network, + largest_metadata_size, + ); + }); + }, + pallas::ledger::traverse::MultiEraBlock::Conway(ref b) => { + b.auxiliary_data_set.iter().for_each(|(txn_idx, aux_data)| { + compare_and_log_aux( + aux_data.raw_cbor().len(), + block.number(), + *txn_idx, + network, + largest_metadata_size, + ); + }); + }, + _ => {}, + } +} + +/// Helper function for comparing and logging the largest auxiliary data. +fn compare_and_log_aux( + aux_len: usize, block_no: u64, txn_idx: u32, network: Network, + largest_metadata_size: &mut usize, +) { + if aux_len > *largest_metadata_size { + *largest_metadata_size = aux_len; + info!( + chain = network.to_string(), + "Largest Aux Data updated, block: {}, tx index: {}, size: {}", + block_no, + txn_idx, + largest_metadata_size + ); + } +} + /// Function for logging bad CIP36. /// Bad CIP36 includes: /// - CIP36 that is valid decoded, but have problem. @@ -322,6 +452,11 @@ fn log_bad_cip36_info(block: &MultiEraBlock, network: Network) { } } +/// Function for logging bad CIP509. +fn log_bad_cip509_info(_block: &MultiEraBlock, _network: Network) { + // TODO - Implement this function. +} + #[tokio::main] async fn main() -> Result<(), Box> { tracing_subscriber::fmt() From 2283d97daab6894463bef226f11b5587ac3b44ef Mon Sep 17 00:00:00 2001 From: bkioshn Date: Tue, 14 Jan 2025 14:19:29 +0700 Subject: [PATCH 40/40] fix(cardano-chain-follower): tag cardano-blockchain-types Signed-off-by: bkioshn --- rust/cardano-chain-follower/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/cardano-chain-follower/Cargo.toml b/rust/cardano-chain-follower/Cargo.toml index aa1a54181..346138774 100644 --- a/rust/cardano-chain-follower/Cargo.toml +++ b/rust/cardano-chain-follower/Cargo.toml @@ -19,7 +19,7 @@ mithril-client = { version = "0.10.4", default-features = false, features = [ "full", "num-integer-backend", ] } -cardano-blockchain-types = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", branch = "fix/fork" } +cardano-blockchain-types = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250114-00" } catalyst-types = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250108-00" } thiserror = "1.0.69"