Skip to content

Commit f3a5e39

Browse files
authored
Merge pull request #788 from input-output-hk/jpraynaud/786-fix-datum-generation-era-markers
Fix Datum generation for era markers
2 parents fa2cf90 + ba013af commit f3a5e39

File tree

9 files changed

+81
-110
lines changed

9 files changed

+81
-110
lines changed

Cargo.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mithril-aggregator/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mithril-aggregator"
3-
version = "0.2.26"
3+
version = "0.2.27"
44
description = "A Mithril Aggregator server"
55
authors = { workspace = true }
66
edition = { workspace = true }

mithril-aggregator/src/tools/era.rs

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@ use mithril_common::{
44
chain_observer::{TxDatumBuilder, TxDatumFieldValue},
55
crypto_helper::{key_encode_hex, EraMarkersSigner},
66
entities::Epoch,
7-
era::{
8-
adapters::{EraMarkerItemCardanoChain, EraMarkersPayloadCardanoChain},
9-
SupportedEra,
10-
},
7+
era::{adapters::EraMarkersPayloadCardanoChain, EraMarker, SupportedEra},
118
};
129

1310
type EraToolsResult<R> = Result<R, Box<dyn Error>>;
@@ -40,8 +37,8 @@ impl EraTools {
4037
let mut era_markers = Vec::new();
4138
for (index, era) in SupportedEra::eras().iter().enumerate() {
4239
let era_marker = match index {
43-
0 => EraMarkerItemCardanoChain::new(&era.to_string(), Some(current_era_epoch)),
44-
1 => EraMarkerItemCardanoChain::new(&era.to_string(), maybe_next_era_epoch),
40+
0 => EraMarker::new(&era.to_string(), Some(current_era_epoch)),
41+
1 => EraMarker::new(&era.to_string(), maybe_next_era_epoch),
4542
_ => Err("too many eras retrieved, can't generate tx datum".to_string())?,
4643
};
4744
era_markers.push(era_marker);
@@ -54,15 +51,10 @@ impl EraTools {
5451

5552
let tx_datum = TxDatumBuilder::new()
5653
.add_field(TxDatumFieldValue::Bytes(
57-
key_encode_hex(era_markers_payload.markers).map_err(|e| {
58-
format!("era markers payload markers could not be hex encoded: {e}")
59-
})?,
60-
))
61-
.add_field(TxDatumFieldValue::Bytes(
62-
era_markers_payload.signature.unwrap_or_default(),
54+
key_encode_hex(era_markers_payload)
55+
.map_err(|e| format!("era markerspayload could not be hex encoded: {e}"))?,
6356
))
6457
.build()?;
65-
6658
Ok(tx_datum.0)
6759
}
6860
}

mithril-common/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mithril-common"
3-
version = "0.2.21"
3+
version = "0.2.22"
44
authors = { workspace = true }
55
edition = { workspace = true }
66
documentation = { workspace = true }

mithril-common/src/chain_observer/model.rs

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,11 @@ pub enum TxDatumError {
2424
pub struct TxDatum(pub String);
2525

2626
impl TxDatum {
27-
/// Retrieves the nth field of the datum with given type
28-
pub fn get_nth_field_by_type(
27+
/// Retrieves the fields of the datum with given type
28+
pub fn get_fields_by_type(
2929
&self,
3030
type_name: &TxDatumFieldTypeName,
31-
index: usize,
32-
) -> Result<Value, Box<dyn StdError>> {
31+
) -> Result<Vec<Value>, Box<dyn StdError>> {
3332
let tx_datum_raw = &self.0;
3433
// 1- Parse the Utxo raw data to a hashmap
3534
let v: HashMap<String, Value> = serde_json::from_str(tx_datum_raw).map_err(|e| {
@@ -48,22 +47,28 @@ impl TxDatum {
4847
)
4948
})?;
5049
// 3- Filter the vec (keep the ones that match the given type), and retrieve the nth entry of this filtered vec
51-
let field_value = fields
50+
Ok(fields
5251
.iter()
5352
.filter(|&field| field.get(type_name.to_string()).is_some())
54-
.nth(index)
53+
.map(|field| field.get(type_name.to_string()).unwrap().to_owned())
54+
.collect::<_>())
55+
}
56+
57+
/// Retrieves the nth field of the datum with given type
58+
pub fn get_nth_field_by_type(
59+
&self,
60+
type_name: &TxDatumFieldTypeName,
61+
index: usize,
62+
) -> Result<Value, Box<dyn StdError>> {
63+
Ok(self
64+
.get_fields_by_type(type_name)?
65+
.get(index)
5566
.ok_or_else(|| {
5667
TxDatumError::InvalidContent(
57-
format!(
58-
"Error: missing field at index {index}, tx datum was = '{tx_datum_raw}'"
59-
)
60-
.into(),
68+
format!("Error: missing field at index {index}").into(),
6169
)
6270
})?
63-
.get(type_name.to_string())
64-
.unwrap();
65-
66-
Ok(field_value.to_owned())
71+
.to_owned())
6772
}
6873
}
6974

@@ -101,9 +106,29 @@ impl TxDatumBuilder {
101106

102107
/// Add a field to the builder
103108
pub fn add_field(&mut self, field_value: TxDatumFieldValue) -> &mut TxDatumBuilder {
104-
let mut field = HashMap::new();
105-
field.insert(TxDatumFieldTypeName::from(&field_value), field_value);
106-
self.fields.push(field);
109+
match &field_value {
110+
TxDatumFieldValue::Bytes(datum_str) => {
111+
// TODO: Remove this chunking of the bytes fields once the cardano-cli 1.36.0+ is released
112+
// The bytes fields are currently limited to 128 bytes and need to be chunked in multiple fields
113+
let field_type = TxDatumFieldTypeName::from(&field_value);
114+
let field_value_chunks = datum_str.as_bytes().chunks(128);
115+
for field_value_chunk in field_value_chunks {
116+
let mut field = HashMap::new();
117+
field.insert(
118+
field_type,
119+
TxDatumFieldValue::Bytes(
120+
std::str::from_utf8(field_value_chunk).unwrap().to_string(),
121+
),
122+
);
123+
self.fields.push(field);
124+
}
125+
}
126+
_ => {
127+
let mut field = HashMap::new();
128+
field.insert(TxDatumFieldTypeName::from(&field_value), field_value);
129+
self.fields.push(field);
130+
}
131+
}
107132

108133
self
109134
}
@@ -135,6 +160,7 @@ mod test {
135160
.add_field(TxDatumFieldValue::Bytes("bytes1".to_string()))
136161
.add_field(TxDatumFieldValue::Bytes("bytes2".to_string()))
137162
.add_field(TxDatumFieldValue::Int(2))
163+
.add_field(TxDatumFieldValue::Bytes("012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789".to_string()))
138164
.build()
139165
.expect("tx_datum build should not fail");
140166
tx_datum
@@ -143,7 +169,7 @@ mod test {
143169
#[test]
144170
fn test_build_tx_datum() {
145171
let tx_datum = dummy_tx_datum();
146-
let tx_datum_expected = TxDatum(r#"{"constructor":0,"fields":[{"bytes":"bytes0"},{"int":0},{"int":1},{"bytes":"bytes1"},{"bytes":"bytes2"},{"int":2}]}"#.to_string());
172+
let tx_datum_expected = TxDatum(r#"{"constructor":0,"fields":[{"bytes":"bytes0"},{"int":0},{"int":1},{"bytes":"bytes1"},{"bytes":"bytes2"},{"int":2},{"bytes":"01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567"},{"bytes":"8901234567890123456789"}]}"#.to_string());
147173
assert_eq!(tx_datum_expected, tx_datum);
148174
}
149175

mithril-common/src/era/adapters/cardano_chain.rs

Lines changed: 22 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::{
44
key_decode_hex, EraMarkersSigner, EraMarkersVerifier, EraMarkersVerifierSignature,
55
EraMarkersVerifierVerificationKey,
66
},
7-
entities::{Epoch, HexEncodedEraMarkersSignature},
7+
entities::HexEncodedEraMarkersSignature,
88
era::{EraMarker, EraReaderAdapter},
99
};
1010
use async_trait::async_trait;
@@ -40,45 +40,11 @@ pub enum EraMarkersPayloadError {
4040
CreateSignature(GeneralError),
4141
}
4242

43-
/// Era marker item
44-
/// Value object that represents a tag of Era change.
45-
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
46-
pub struct EraMarkerItem {
47-
/// Era name
48-
#[serde(rename = "n")]
49-
pub name: String,
50-
51-
/// Eventual information that advertises the Epoch of transition.
52-
#[serde(rename = "e")]
53-
pub epoch: Option<Epoch>,
54-
}
55-
56-
impl EraMarkerItem {
57-
/// Instantiate a new [EraMarkerItem].
58-
pub fn new(name: &str, epoch: Option<Epoch>) -> Self {
59-
let name = name.to_string();
60-
61-
Self { name, epoch }
62-
}
63-
}
64-
65-
impl From<EraMarker> for EraMarkerItem {
66-
fn from(other: EraMarker) -> EraMarkerItem {
67-
EraMarkerItem::new(&other.name, other.epoch)
68-
}
69-
}
70-
71-
impl From<EraMarkerItem> for EraMarker {
72-
fn from(other: EraMarkerItem) -> EraMarker {
73-
EraMarker::new(&other.name, other.epoch)
74-
}
75-
}
76-
7743
/// Era markers payload
7844
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
7945
pub struct EraMarkersPayload {
8046
/// List of Era markers
81-
pub markers: Vec<EraMarkerItem>,
47+
pub markers: Vec<EraMarker>,
8248

8349
/// Era markers signature
8450
pub signature: Option<HexEncodedEraMarkersSignature>,
@@ -162,27 +128,20 @@ impl EraReaderAdapter for CardanoChainAdapter {
162128
.await?;
163129
let markers_list = tx_datums
164130
.into_iter()
165-
.filter_map(|datum| {
166-
match (
167-
datum.get_nth_field_by_type(&TxDatumFieldTypeName::Bytes, 0),
168-
datum.get_nth_field_by_type(&TxDatumFieldTypeName::Bytes, 1),
169-
) {
170-
(Ok(markers), Ok(signature)) => {
171-
let markers = markers.as_str().map(|s| s.to_string()).unwrap_or_default();
172-
let signature = signature.as_str().map(|s| s.to_string());
173-
match key_decode_hex::<Vec<_>>(&markers) {
174-
Ok(markers) => EraMarkersPayload {
175-
markers: markers.clone(),
176-
signature,
177-
}
178-
.verify_signature(self.verification_key)
179-
.ok()
180-
.map(|_| markers.into_iter().map(|em| em.into()).collect()),
181-
Err(_) => None,
182-
}
183-
}
184-
_ => None,
185-
}
131+
.filter_map(|datum| datum.get_fields_by_type(&TxDatumFieldTypeName::Bytes).ok())
132+
.map(|fields| {
133+
fields
134+
.iter()
135+
.filter_map(|field_value| field_value.as_str().map(|s| s.to_string()))
136+
.collect::<Vec<String>>()
137+
.join("")
138+
})
139+
.filter_map(|field_value_str| key_decode_hex(&field_value_str).ok())
140+
.filter_map(|era_markers_payload: EraMarkersPayload| {
141+
era_markers_payload
142+
.verify_signature(self.verification_key)
143+
.ok()
144+
.map(|_| era_markers_payload.markers)
186145
})
187146
.collect::<Vec<Vec<EraMarker>>>();
188147

@@ -203,12 +162,7 @@ mod test {
203162
.into_iter()
204163
.map(|payload| {
205164
TxDatumBuilder::new()
206-
.add_field(TxDatumFieldValue::Bytes(
207-
key_encode_hex(payload.markers).unwrap(),
208-
))
209-
.add_field(TxDatumFieldValue::Bytes(
210-
payload.signature.unwrap_or_default(),
211-
))
165+
.add_field(TxDatumFieldValue::Bytes(key_encode_hex(payload).unwrap()))
212166
.build()
213167
.unwrap()
214168
})
@@ -221,15 +175,15 @@ mod test {
221175
let fake_address = "addr_test_123456".to_string();
222176
let era_marker_payload_1 = EraMarkersPayload {
223177
markers: vec![
224-
EraMarkerItem::new("thales", Some(Epoch(1))),
225-
EraMarkerItem::new("pythagoras", None),
178+
EraMarker::new("thales", Some(Epoch(1))),
179+
EraMarker::new("pythagoras", None),
226180
],
227181
signature: None,
228182
};
229183
let era_marker_payload_2 = EraMarkersPayload {
230184
markers: vec![
231-
EraMarkerItem::new("thales", Some(Epoch(1))),
232-
EraMarkerItem::new("pythagoras", Some(Epoch(2))),
185+
EraMarker::new("thales", Some(Epoch(1))),
186+
EraMarker::new("pythagoras", Some(Epoch(2))),
233187
],
234188
signature: None,
235189
};
@@ -252,11 +206,7 @@ mod test {
252206
.read()
253207
.await
254208
.expect("CardanoChainAdapter read should not fail");
255-
let expected_markers = era_marker_payload_2
256-
.markers
257-
.into_iter()
258-
.map(|em| em.into())
259-
.collect::<Vec<EraMarker>>();
209+
let expected_markers = era_marker_payload_2.markers.to_owned();
260210
assert_eq!(expected_markers, markers);
261211
}
262212
}

mithril-common/src/era/adapters/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ pub use bootstrap::BootstrapAdapter as EraReaderBootstrapAdapter;
99
pub use builder::{AdapterBuilder as EraReaderAdapterBuilder, AdapterType as EraReaderAdapterType};
1010
pub use cardano_chain::{
1111
CardanoChainAdapter as EraReaderCardanoChainAdapter,
12-
EraMarkerItem as EraMarkerItemCardanoChain, EraMarkersPayload as EraMarkersPayloadCardanoChain,
12+
EraMarkersPayload as EraMarkersPayloadCardanoChain,
1313
};
1414
pub use dummy::DummyAdapter as EraReaderDummyAdapter;
1515
pub use file::FileAdapter as EraReaderFileAdapter;

mithril-infra/variables.tf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,15 +132,18 @@ variable "mithril_era_reader_adapter_type" {
132132
variable "mithril_era_reader_address_url" {
133133
type = string
134134
description = "The url of the Mithril era reader address used to query the on chain Utxo containing the era markers payload"
135+
default = ""
135136
}
136137

137138
variable "mithril_era_reader_verification_key_url" {
138139
type = string
139140
description = "The url of the Mithril era reader verification key used by to verify an era markers payload"
141+
default = ""
140142
}
141143
variable "mithril_era_reader_secret_key" {
142144
type = string
143145
description = "The Mithril genesis secret key used by the aggregator to generate an era marker payload TxDatum file (test only)"
146+
default = ""
144147
}
145148

146149
variable "mithril_signers" {

mithril-signer/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mithril-signer"
3-
version = "0.2.18"
3+
version = "0.2.19"
44
description = "A Mithril Signer"
55
authors = { workspace = true }
66
edition = { workspace = true }

0 commit comments

Comments
 (0)