Skip to content

Commit 1dd6495

Browse files
authored
Merge pull request input-output-hk#1680 from input-output-hk/jpraynaud/1590-chainsync-pallas
Implement `chainsync` `ChainReader` with `pallas`
2 parents 7b08974 + 968f0b9 commit 1dd6495

10 files changed

+542
-2
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ As a minor extension, we have adopted a slightly different versioning convention
1919

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

22+
- Implement a Chain Reader which retrieves blocks from the Cardano chain with Pallas through the `chainsync` mini-protocol.
23+
2224
- Crates versions:
2325

2426
| Crate | Version |

Cargo.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mithril-common/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mithril-common"
3-
version = "0.4.7"
3+
version = "0.4.8"
44
description = "Common types, interfaces, and utilities for Mithril nodes."
55
authors = { workspace = true }
66
edition = { workspace = true }
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
use crate::{cardano_block_scanner::ScannedBlock, entities::ChainPoint};
2+
3+
/// The action that indicates what to do next when scanning the chain
4+
#[derive(Debug, Clone, PartialEq)]
5+
pub enum ChainBlockNextAction {
6+
/// RollForward event (we are still on the correct fork)
7+
RollForward {
8+
/// The next point in the chain to read
9+
next_point: ChainPoint,
10+
/// The parsed chain block
11+
parsed_block: ScannedBlock,
12+
},
13+
/// RollBackward event (we are on an incorrect fork, we need to get back a point to roll forward again)
14+
RollBackward {
15+
/// 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)
16+
rollback_point: ChainPoint,
17+
},
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
use async_trait::async_trait;
2+
use std::{collections::VecDeque, sync::Mutex};
3+
4+
use crate::{entities::ChainPoint, StdResult};
5+
6+
use super::{ChainBlockNextAction, ChainBlockReader};
7+
8+
/// [FakeChainReader] is a fake implementation of [ChainBlockReader] for testing purposes.
9+
pub struct FakeChainReader {
10+
chain_point_next_actions: Mutex<VecDeque<ChainBlockNextAction>>,
11+
}
12+
13+
impl FakeChainReader {
14+
/// Creates a new [FakeChainReader] instance.
15+
pub fn new(chain_point_next_actions: Vec<ChainBlockNextAction>) -> Self {
16+
Self {
17+
chain_point_next_actions: Mutex::new(chain_point_next_actions.into()),
18+
}
19+
}
20+
}
21+
22+
#[async_trait]
23+
impl ChainBlockReader for FakeChainReader {
24+
async fn set_chain_point(&mut self, _point: &ChainPoint) -> StdResult<()> {
25+
Ok(())
26+
}
27+
28+
async fn get_next_chain_block(&mut self) -> StdResult<Option<ChainBlockNextAction>> {
29+
Ok(self.chain_point_next_actions.lock().unwrap().pop_front())
30+
}
31+
}
32+
33+
#[cfg(test)]
34+
mod tests {
35+
use crate::cardano_block_scanner::ScannedBlock;
36+
37+
use super::*;
38+
39+
fn build_chain_point(id: u64) -> ChainPoint {
40+
ChainPoint {
41+
slot_number: id,
42+
block_number: id,
43+
block_hash: format!("point-hash-{id}"),
44+
}
45+
}
46+
47+
#[tokio::test]
48+
async fn test_get_next_chain_block() {
49+
let expected_chain_point_next_actions = vec![
50+
ChainBlockNextAction::RollForward {
51+
next_point: build_chain_point(1),
52+
parsed_block: ScannedBlock::new("hash-1", 1, 10, 20, Vec::<&str>::new()),
53+
},
54+
ChainBlockNextAction::RollForward {
55+
next_point: build_chain_point(2),
56+
parsed_block: ScannedBlock::new("hash-2", 2, 11, 21, Vec::<&str>::new()),
57+
},
58+
ChainBlockNextAction::RollBackward {
59+
rollback_point: build_chain_point(1),
60+
},
61+
];
62+
63+
let mut chain_reader = FakeChainReader::new(expected_chain_point_next_actions.clone());
64+
65+
let mut chain_point_next_actions = vec![];
66+
while let Some(chain_block_next_action) = chain_reader.get_next_chain_block().await.unwrap()
67+
{
68+
chain_point_next_actions.push(chain_block_next_action);
69+
}
70+
71+
assert_eq!(expected_chain_point_next_actions, chain_point_next_actions);
72+
}
73+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
use async_trait::async_trait;
2+
3+
use crate::{entities::ChainPoint, StdResult};
4+
5+
use super::ChainBlockNextAction;
6+
7+
/// The trait that reads events to either:
8+
/// - read next block on the chain
9+
/// - rollback to another point in case of rollback
10+
/// - do nothing when tip of the chain is reached
11+
#[async_trait]
12+
pub trait ChainBlockReader {
13+
/// Sets the chain point
14+
async fn set_chain_point(&mut self, point: &ChainPoint) -> StdResult<()>;
15+
16+
/// Get the next chain block
17+
async fn get_next_chain_block(&mut self) -> StdResult<Option<ChainBlockNextAction>>;
18+
}
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//! Tools to read chain blocks sequentially
2+
3+
mod entity;
4+
mod fake_chain_reader;
5+
mod interface;
6+
mod pallas_chain_reader;
7+
8+
pub use entity::*;
9+
pub use fake_chain_reader::*;
10+
pub use interface::*;
11+
pub use pallas_chain_reader::*;

0 commit comments

Comments
 (0)