mithril_common/era/adapters/
builder.rs

1use serde::{Deserialize, Serialize};
2use std::{fmt::Display, path::PathBuf, sync::Arc};
3use thiserror::Error;
4
5use crate::{
6    chain_observer::{ChainAddress, ChainObserver},
7    crypto_helper::EraMarkersVerifierVerificationKey,
8    era::{
9        adapters::{
10            EraReaderBootstrapAdapter, EraReaderCardanoChainAdapter, EraReaderDummyAdapter,
11            EraReaderFileAdapter,
12        },
13        EraMarker, EraReaderAdapter,
14    },
15    StdError,
16};
17
18/// Type of era reader adapters available
19#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
20#[serde(rename_all = "lowercase")]
21pub enum AdapterType {
22    /// Cardano chain adapter.
23    #[serde(rename = "cardano-chain")]
24    CardanoChain,
25    /// File adapter.
26    File,
27    /// Dummy adapter.
28    Dummy,
29    /// Bootstrap adapter.
30    Bootstrap,
31}
32
33impl Display for AdapterType {
34    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35        match self {
36            Self::Bootstrap => write!(f, "bootstrap"),
37            Self::CardanoChain => write!(f, "cardano chain"),
38            Self::Dummy => write!(f, "dummy"),
39            Self::File => write!(f, "file"),
40        }
41    }
42}
43
44/// Error type for era adapter builder service.
45#[derive(Error, Debug)]
46pub enum AdapterBuilderError {
47    /// Missing parameters error.
48    #[error("era reader adapter parameters are missing")]
49    MissingParameters(),
50
51    /// Parameters parse error.
52    #[error("era reader adapter parameters parse error")]
53    ParseParameters(#[source] serde_json::Error),
54
55    /// Parameters decode error.
56    #[error("era reader adapter parameters decode error")]
57    Decode(#[source] StdError),
58}
59
60/// Era adapter builder
61pub struct AdapterBuilder {
62    adapter_type: AdapterType,
63    adapter_params: Option<String>,
64}
65
66impl AdapterBuilder {
67    /// Era reader adapter builder factory
68    pub fn new(adapter_type: &AdapterType, adapter_params: &Option<String>) -> Self {
69        Self {
70            adapter_type: adapter_type.to_owned(),
71            adapter_params: adapter_params.to_owned(),
72        }
73    }
74
75    /// Create era reader adapter from configuration settings.
76    pub fn build(
77        &self,
78        chain_observer: Arc<dyn ChainObserver>,
79    ) -> Result<Arc<dyn EraReaderAdapter>, AdapterBuilderError> {
80        match self.adapter_type {
81            AdapterType::CardanoChain => {
82                #[derive(Deserialize)]
83                struct CardanoChainAdapterConfig {
84                    address: ChainAddress,
85                    verification_key: EraMarkersVerifierVerificationKey,
86                }
87
88                let adapter_config: CardanoChainAdapterConfig = serde_json::from_str(
89                    self.adapter_params
90                        .as_ref()
91                        .ok_or_else(AdapterBuilderError::MissingParameters)?,
92                )
93                .map_err(AdapterBuilderError::ParseParameters)?;
94
95                Ok(Arc::new(EraReaderCardanoChainAdapter::new(
96                    adapter_config.address,
97                    chain_observer,
98                    adapter_config.verification_key,
99                )))
100            }
101            AdapterType::File => {
102                #[derive(Deserialize)]
103                struct EraReaderFileAdapterConfig {
104                    markers_file: PathBuf,
105                }
106
107                let adapter_config: EraReaderFileAdapterConfig = serde_json::from_str(
108                    self.adapter_params
109                        .as_ref()
110                        .ok_or_else(AdapterBuilderError::MissingParameters)?,
111                )
112                .map_err(AdapterBuilderError::ParseParameters)?;
113                let file_adapter = EraReaderFileAdapter::new(adapter_config.markers_file);
114
115                Ok(Arc::new(file_adapter))
116            }
117            AdapterType::Dummy => {
118                #[derive(Deserialize)]
119                struct EraReaderDummyAdapterConfig {
120                    markers: Vec<EraMarker>,
121                }
122
123                let adapter_config: EraReaderDummyAdapterConfig = serde_json::from_str(
124                    self.adapter_params
125                        .as_ref()
126                        .ok_or_else(AdapterBuilderError::MissingParameters)?,
127                )
128                .map_err(AdapterBuilderError::ParseParameters)?;
129                let dummy_adapter = EraReaderDummyAdapter::default();
130                dummy_adapter.set_markers(adapter_config.markers);
131
132                Ok(Arc::new(dummy_adapter))
133            }
134            AdapterType::Bootstrap => Ok(Arc::new(EraReaderBootstrapAdapter)),
135        }
136    }
137}
138
139#[cfg(test)]
140mod test {
141    use crate::chain_observer::MockChainObserver;
142
143    use super::*;
144
145    const GOLDEN_ADAPTER_PARAMS: &str = r#"{
146        "address":"addr_test1qrv5xfwh043mlc3vk5d97s4nmhxu7cmleyssvhx37gkfyejfe8d38v3vsfgetjafgrsdc49krug8wf04h5rmtengtejqlxrksk",
147        "verification_key":"5b35352c3232382c3134342c38372c3133382c3133362c34382c382c31342c3138372c38352c3134382c39372c3233322c3235352c3232392c33382c3234342c3234372c3230342c3139382c31332c33312c3232322c32352c3136342c35322c3130322c39312c3132302c3230382c3134375d"
148    }"#;
149
150    #[test]
151    fn golden_test_for_cardano_chain() {
152        AdapterBuilder::new(
153            &AdapterType::CardanoChain,
154            &Some(GOLDEN_ADAPTER_PARAMS.to_owned()),
155        )
156        .build(Arc::new(MockChainObserver::new()))
157        .expect("building an cardano chain era reader with golden params should not fail");
158    }
159}