Skip to content

Commit 13239ef

Browse files
committed
Add Cardano chain EraReaderAdapter
1 parent f64ee9b commit 13239ef

File tree

3 files changed

+166
-1
lines changed

3 files changed

+166
-1
lines changed

mithril-common/src/chain_observer/fake_observer.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ pub struct FakeObserver {
1717
///
1818
/// [get_current_epoch]: ChainObserver::get_current_epoch
1919
pub current_beacon: RwLock<Option<Beacon>>,
20+
21+
/// A list of [TxDatum], used by [get_current_datums]
22+
///
23+
/// [get_current_datums]: ChainObserver::get_current_datums
24+
pub datums: RwLock<Vec<TxDatum>>,
2025
}
2126

2227
impl FakeObserver {
@@ -25,6 +30,7 @@ impl FakeObserver {
2530
Self {
2631
signers: RwLock::new(vec![]),
2732
current_beacon: RwLock::new(current_beacon),
33+
datums: RwLock::new(vec![]),
2834
}
2935
}
3036

@@ -45,6 +51,13 @@ impl FakeObserver {
4551
let mut signers = self.signers.write().await;
4652
*signers = new_signers;
4753
}
54+
55+
/// Set the datums that will used to compute the result of
56+
/// [get_current_datums][ChainObserver::get_current_datums].
57+
pub async fn set_datums(&self, new_datums: Vec<TxDatum>) {
58+
let mut datums = self.datums.write().await;
59+
*datums = new_datums;
60+
}
4861
}
4962

5063
impl Default for FakeObserver {
@@ -62,7 +75,8 @@ impl ChainObserver for FakeObserver {
6275
&self,
6376
_address: &ChainAddress,
6477
) -> Result<Vec<TxDatum>, ChainObserverError> {
65-
Ok(Vec::new())
78+
let datums = self.datums.read().await;
79+
Ok(datums.to_vec())
6680
}
6781

6882
async fn get_current_epoch(&self) -> Result<Option<Epoch>, ChainObserverError> {
@@ -124,4 +138,21 @@ mod tests {
124138
"get current stake distribution should not fail and should not be empty"
125139
);
126140
}
141+
142+
#[tokio::test]
143+
async fn test_get_current_datums() {
144+
let fake_address = "addr_test_123456".to_string();
145+
let fake_datums = vec![
146+
TxDatum("tx_datum_1".to_string()),
147+
TxDatum("tx_datum_2".to_string()),
148+
];
149+
let fake_observer = FakeObserver::new(None);
150+
fake_observer.set_datums(fake_datums.clone()).await;
151+
let datums = fake_observer
152+
.get_current_datums(&fake_address)
153+
.await
154+
.expect("get_current_datums should not fail");
155+
156+
assert_eq!(fake_datums, datums);
157+
}
127158
}
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
use crate::chain_observer::ChainAddress;
2+
use crate::crypto_helper::key_decode_hex;
3+
use crate::{chain_observer::ChainObserver, entities::Epoch};
4+
use async_trait::async_trait;
5+
use serde::{Deserialize, Serialize};
6+
use std::error::Error as StdError;
7+
use std::sync::Arc;
8+
use thiserror::Error;
9+
10+
// TODO: remove EraMarker & EraReaderAdapter w/ they are available
11+
12+
/// Value object that represents a tag of Era change.
13+
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
14+
pub struct EraMarker {
15+
/// Era name
16+
pub name: String,
17+
18+
/// Eventual information that advertises the Epoch of transition.
19+
pub epoch: Option<Epoch>,
20+
}
21+
22+
impl EraMarker {
23+
/// instanciate a new [EraMarker].
24+
pub fn new(name: &str, epoch: Option<Epoch>) -> Self {
25+
let name = name.to_string();
26+
27+
Self { name, epoch }
28+
}
29+
}
30+
31+
#[async_trait]
32+
pub trait EraReaderAdapter: Sync + Send {
33+
/// Read era markers from the underlying adapter.
34+
async fn read(&self) -> Result<Vec<EraMarker>, Box<dyn StdError + Sync + Send>>;
35+
}
36+
37+
// TODO: Keep Cardano Chain Adapter part below
38+
39+
type HexEncodeEraMarkerSignature = String;
40+
41+
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
42+
struct EraMarkersPayload {
43+
markers: Vec<EraMarker>,
44+
signature: HexEncodeEraMarkerSignature,
45+
}
46+
47+
/// Cardano Chain adapter retrieves era markers on chain
48+
pub struct CardanoChainAdapter {
49+
address: ChainAddress,
50+
chain_observer: Arc<dyn ChainObserver>,
51+
}
52+
53+
impl CardanoChainAdapter {
54+
/// CardanoChainAdapter factory
55+
pub fn new(address: ChainAddress, chain_observer: Arc<dyn ChainObserver>) -> Self {
56+
Self {
57+
address,
58+
chain_observer,
59+
}
60+
}
61+
}
62+
63+
#[async_trait]
64+
impl EraReaderAdapter for CardanoChainAdapter {
65+
async fn read(&self) -> Result<Vec<EraMarker>, Box<dyn StdError + Sync + Send>> {
66+
let tx_datums = self
67+
.chain_observer
68+
.get_current_datums(&self.address)
69+
.await?;
70+
let markers_list = tx_datums
71+
.into_iter()
72+
.filter_map(|datum| datum.get_field_raw_value("bytes", 0).ok())
73+
.filter_map(|field_value| field_value.as_str().map(|s| s.to_string()))
74+
.filter_map(|field_value_str| key_decode_hex(&field_value_str).ok())
75+
.map(|era_markers_payload: EraMarkersPayload| era_markers_payload.markers)
76+
.collect::<Vec<Vec<EraMarker>>>();
77+
Ok(markers_list.first().unwrap_or(&Vec::new()).to_owned())
78+
}
79+
}
80+
81+
#[cfg(test)]
82+
mod test {
83+
use crate::chain_observer::{FakeObserver, TxDatum};
84+
use crate::crypto_helper::key_encode_hex;
85+
86+
use super::*;
87+
88+
fn dummy_tx_datums_from_markers_payload(payloads: Vec<EraMarkersPayload>) -> Vec<TxDatum> {
89+
payloads
90+
.into_iter()
91+
.map(|payload| {
92+
TxDatum(format!(
93+
"{{\"constructor\":0,\"fields\":[{{\"bytes\":\"{}\"}}]}}",
94+
key_encode_hex(payload).unwrap()
95+
))
96+
})
97+
.collect()
98+
}
99+
100+
#[tokio::test]
101+
async fn test_cardano_chain_adapter() {
102+
let fake_address = "addr_test_123456".to_string();
103+
let era_marker_payload_1 = EraMarkersPayload {
104+
markers: vec![
105+
EraMarker::new("thales", Some(Epoch(1))),
106+
EraMarker::new("pythagors", None),
107+
],
108+
signature: "".to_string(),
109+
};
110+
let era_marker_payload_2 = EraMarkersPayload {
111+
markers: vec![
112+
EraMarker::new("thales", Some(Epoch(1))),
113+
EraMarker::new("pythagors", Some(Epoch(2))),
114+
],
115+
signature: "".to_string(),
116+
};
117+
let mut fake_datums = dummy_tx_datums_from_markers_payload(vec![
118+
era_marker_payload_1.clone(),
119+
era_marker_payload_2,
120+
]);
121+
fake_datums.push(TxDatum("not_valid_datum".to_string()));
122+
let chain_observer = FakeObserver::default();
123+
chain_observer.set_datums(fake_datums.clone()).await;
124+
let cardano_chain_adapter =
125+
CardanoChainAdapter::new(fake_address, Arc::new(chain_observer));
126+
let markers = cardano_chain_adapter
127+
.read()
128+
.await
129+
.expect("CardanoChainAdapter read should not fail");
130+
let expected_markers = era_marker_payload_1.markers.to_owned();
131+
assert_eq!(expected_markers, markers);
132+
}
133+
}

mithril-common/src/era/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! The module used for handling eras
22
33
pub mod adapters;
4+
mod cardano_chain_adapter;
45
mod era_checker;
56
mod era_reader;
67
mod supported_era;

0 commit comments

Comments
 (0)