Skip to content

Commit

Permalink
Merge pull request input-output-hk#1680 from input-output-hk/jpraynau…
Browse files Browse the repository at this point in the history
…d/1590-chainsync-pallas

Implement `chainsync` `ChainReader` with `pallas`
  • Loading branch information
jpraynaud authored May 28, 2024
2 parents 7b08974 + 968f0b9 commit 1dd6495
Show file tree
Hide file tree
Showing 10 changed files with 542 additions and 2 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ As a minor extension, we have adopted a slightly different versioning convention

- Update website and explorer user interface to use the new mithril logo.

- Implement a Chain Reader which retrieves blocks from the Cardano chain with Pallas through the `chainsync` mini-protocol.

- Crates versions:

| Crate | Version |
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion mithril-common/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mithril-common"
version = "0.4.7"
version = "0.4.8"
description = "Common types, interfaces, and utilities for Mithril nodes."
authors = { workspace = true }
edition = { workspace = true }
Expand Down
18 changes: 18 additions & 0 deletions mithril-common/src/chain_reader/entity.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use crate::{cardano_block_scanner::ScannedBlock, entities::ChainPoint};

/// The action that indicates what to do next when scanning the chain
#[derive(Debug, Clone, PartialEq)]
pub enum ChainBlockNextAction {
/// RollForward event (we are still on the correct fork)
RollForward {
/// The next point in the chain to read
next_point: ChainPoint,
/// The parsed chain block
parsed_block: ScannedBlock,
},
/// RollBackward event (we are on an incorrect fork, we need to get back a point to roll forward again)
RollBackward {
/// The rollback point in the chain to read (as a new valid point to read from on the main chain, which has already been seen)
rollback_point: ChainPoint,
},
}
73 changes: 73 additions & 0 deletions mithril-common/src/chain_reader/fake_chain_reader.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use async_trait::async_trait;
use std::{collections::VecDeque, sync::Mutex};

use crate::{entities::ChainPoint, StdResult};

use super::{ChainBlockNextAction, ChainBlockReader};

/// [FakeChainReader] is a fake implementation of [ChainBlockReader] for testing purposes.
pub struct FakeChainReader {
chain_point_next_actions: Mutex<VecDeque<ChainBlockNextAction>>,
}

impl FakeChainReader {
/// Creates a new [FakeChainReader] instance.
pub fn new(chain_point_next_actions: Vec<ChainBlockNextAction>) -> Self {
Self {
chain_point_next_actions: Mutex::new(chain_point_next_actions.into()),
}
}
}

#[async_trait]
impl ChainBlockReader for FakeChainReader {
async fn set_chain_point(&mut self, _point: &ChainPoint) -> StdResult<()> {
Ok(())
}

async fn get_next_chain_block(&mut self) -> StdResult<Option<ChainBlockNextAction>> {
Ok(self.chain_point_next_actions.lock().unwrap().pop_front())
}
}

#[cfg(test)]
mod tests {
use crate::cardano_block_scanner::ScannedBlock;

use super::*;

fn build_chain_point(id: u64) -> ChainPoint {
ChainPoint {
slot_number: id,
block_number: id,
block_hash: format!("point-hash-{id}"),
}
}

#[tokio::test]
async fn test_get_next_chain_block() {
let expected_chain_point_next_actions = vec![
ChainBlockNextAction::RollForward {
next_point: build_chain_point(1),
parsed_block: ScannedBlock::new("hash-1", 1, 10, 20, Vec::<&str>::new()),
},
ChainBlockNextAction::RollForward {
next_point: build_chain_point(2),
parsed_block: ScannedBlock::new("hash-2", 2, 11, 21, Vec::<&str>::new()),
},
ChainBlockNextAction::RollBackward {
rollback_point: build_chain_point(1),
},
];

let mut chain_reader = FakeChainReader::new(expected_chain_point_next_actions.clone());

let mut chain_point_next_actions = vec![];
while let Some(chain_block_next_action) = chain_reader.get_next_chain_block().await.unwrap()
{
chain_point_next_actions.push(chain_block_next_action);
}

assert_eq!(expected_chain_point_next_actions, chain_point_next_actions);
}
}
18 changes: 18 additions & 0 deletions mithril-common/src/chain_reader/interface.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use async_trait::async_trait;

use crate::{entities::ChainPoint, StdResult};

use super::ChainBlockNextAction;

/// The trait that reads events to either:
/// - read next block on the chain
/// - rollback to another point in case of rollback
/// - do nothing when tip of the chain is reached
#[async_trait]
pub trait ChainBlockReader {
/// Sets the chain point
async fn set_chain_point(&mut self, point: &ChainPoint) -> StdResult<()>;

/// Get the next chain block
async fn get_next_chain_block(&mut self) -> StdResult<Option<ChainBlockNextAction>>;
}
11 changes: 11 additions & 0 deletions mithril-common/src/chain_reader/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//! Tools to read chain blocks sequentially

mod entity;
mod fake_chain_reader;
mod interface;
mod pallas_chain_reader;

pub use entity::*;
pub use fake_chain_reader::*;
pub use interface::*;
pub use pallas_chain_reader::*;
Loading

0 comments on commit 1dd6495

Please sign in to comment.