Skip to content

Commit 22b5720

Browse files
committed
refactor(dmq): update the message builder and its KES signature
1 parent 812c798 commit 22b5720

File tree

2 files changed

+87
-59
lines changed

2 files changed

+87
-59
lines changed
Lines changed: 76 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,26 @@
11
use std::sync::Arc;
22

3-
use anyhow::{Context, anyhow};
3+
use anyhow::Context;
44
use blake2::{Blake2b, Digest, digest::consts::U64};
5-
use pallas_network::miniprotocols::localmsgsubmission::DmqMsg;
5+
use pallas_network::miniprotocols::localmsgsubmission::{DmqMsg, DmqMsgPayload};
66

77
use mithril_cardano_node_chain::chain_observer::ChainObserver;
88
use mithril_common::{
99
StdResult,
1010
crypto_helper::{KesSigner, TryToBytes},
1111
};
1212

13-
use crate::model::DmqMessage;
13+
use crate::model::{DmqMessage, SystemUnixTimestampProvider, UnixTimestampProvider};
1414

15-
/// The TTL (Time To Live) for DMQ messages in blocks.
16-
const DMQ_MESSAGE_TTL_IN_BLOCKS: u16 = 100;
15+
/// The TTL (Time To Live) for DMQ messages in seconds (default is 30 minutes).
16+
const DMQ_MESSAGE_TTL_IN_SECONDS: u16 = 1800;
1717

1818
/// A builder for creating DMQ messages.
1919
pub struct DmqMessageBuilder {
2020
kes_signer: Arc<dyn KesSigner>,
2121
chain_observer: Arc<dyn ChainObserver>,
22-
ttl_blocks: u16,
22+
timestamp_provider: Arc<dyn UnixTimestampProvider>,
23+
ttl_seconds: u16,
2324
}
2425

2526
impl DmqMessageBuilder {
@@ -28,43 +29,45 @@ impl DmqMessageBuilder {
2829
Self {
2930
kes_signer,
3031
chain_observer,
31-
ttl_blocks: DMQ_MESSAGE_TTL_IN_BLOCKS,
32+
timestamp_provider: Arc::new(SystemUnixTimestampProvider),
33+
ttl_seconds: DMQ_MESSAGE_TTL_IN_SECONDS,
3234
}
3335
}
3436

35-
/// Set the TTL (Time To Live) for DMQ messages in blocks.
36-
pub fn set_ttl(mut self, ttl_blocks: u16) -> Self {
37-
self.ttl_blocks = ttl_blocks;
37+
/// Sets the timestamp provider for the DMQ message builder.
38+
pub fn set_timestamp_provider(
39+
mut self,
40+
timestamp_provider: Arc<dyn UnixTimestampProvider>,
41+
) -> Self {
42+
self.timestamp_provider = timestamp_provider;
43+
self
44+
}
45+
46+
/// Sets the TTL (Time To Live) for DMQ messages in seconds.
47+
pub fn set_ttl(mut self, ttl_seconds: u16) -> Self {
48+
self.ttl_seconds = ttl_seconds;
3849

3950
self
4051
}
4152

53+
/// Computes a message id for a DMQ message payload.
54+
fn compute_msg_id(dmq_message_payload: &DmqMsgPayload) -> Vec<u8> {
55+
let mut hasher = Blake2b::<U64>::new();
56+
hasher.update(&dmq_message_payload.msg_body);
57+
hasher.update(dmq_message_payload.kes_period.to_be_bytes());
58+
hasher.update(&dmq_message_payload.operational_certificate);
59+
hasher.update(&dmq_message_payload.cold_verification_key);
60+
hasher.update(dmq_message_payload.expires_at.to_be_bytes());
61+
62+
hasher.finalize().to_vec()
63+
}
64+
4265
/// Builds a DMQ message from the provided message bytes.
4366
pub async fn build(&self, message_bytes: &[u8]) -> StdResult<DmqMessage> {
44-
fn compute_msg_id(dmq_message: &DmqMsg) -> Vec<u8> {
45-
let mut hasher = Blake2b::<U64>::new();
46-
hasher.update(&dmq_message.msg_body);
47-
hasher.update(dmq_message.block_number.to_be_bytes());
48-
hasher.update(dmq_message.ttl.to_be_bytes());
49-
hasher.update(&dmq_message.kes_signature);
50-
hasher.update(&dmq_message.operational_certificate);
51-
hasher.update(dmq_message.kes_period.to_be_bytes());
52-
53-
hasher.finalize().to_vec()
54-
}
55-
56-
let block_number = self
57-
.chain_observer
58-
.get_current_chain_point()
59-
.await
60-
.with_context(|| "Failed to get current chain point while building DMQ message")?
61-
.ok_or(anyhow!(
62-
"No current chain point available while building DMQ message"
63-
))?
64-
.block_number;
65-
let block_number = (*block_number)
67+
let expires_at: u32 = (self.timestamp_provider.current_timestamp()?
68+
+ self.ttl_seconds as u64)
6669
.try_into()
67-
.with_context(|| "Failed to convert block number to u32")?;
70+
.with_context(|| "Failed to compute expires_at while building DMQ message")?;
6871
let kes_period = self
6972
.chain_observer
7073
.get_current_kes_period()
@@ -75,16 +78,23 @@ impl DmqMessageBuilder {
7578
.kes_signer
7679
.sign(message_bytes, kes_period)
7780
.with_context(|| "Failed to KES sign message while building DMQ message")?;
78-
let mut dmq_message = DmqMsg {
79-
msg_id: vec![],
80-
msg_body: message_bytes.to_vec(),
81-
block_number,
82-
ttl: self.ttl_blocks,
81+
82+
let dmq_message = DmqMsg {
83+
msg_payload: {
84+
let mut dmq_message_payload = DmqMsgPayload {
85+
msg_id: vec![],
86+
msg_body: message_bytes.to_vec(),
87+
kes_period: kes_period as u64,
88+
operational_certificate: operational_certificate.to_bytes_vec()?, // TODO: remove the cold verification key in the op cert
89+
cold_verification_key: vec![],
90+
expires_at,
91+
};
92+
dmq_message_payload.msg_id = Self::compute_msg_id(&dmq_message_payload);
93+
94+
dmq_message_payload
95+
},
8396
kes_signature: kes_signature.to_bytes_vec()?,
84-
operational_certificate: operational_certificate.to_bytes_vec()?,
85-
kes_period,
8697
};
87-
dmq_message.msg_id = compute_msg_id(&dmq_message);
8898

8999
Ok(dmq_message.into())
90100
}
@@ -100,6 +110,8 @@ mod tests {
100110
test::{crypto_helper::KesSignerFake, double::Dummy},
101111
};
102112

113+
use crate::model::MockUnixTimestampProvider;
114+
103115
use super::*;
104116

105117
mod test_utils {
@@ -131,28 +143,39 @@ mod tests {
131143
},
132144
..TimePoint::dummy()
133145
})));
134-
let builder = DmqMessageBuilder::new(kes_signer, chain_observer).set_ttl(100);
146+
let builder = DmqMessageBuilder::new(kes_signer, chain_observer)
147+
.set_ttl(1000)
148+
.set_timestamp_provider(Arc::new({
149+
let mut mock_timestamp_provider = MockUnixTimestampProvider::new();
150+
mock_timestamp_provider
151+
.expect_current_timestamp()
152+
.returning(|| Ok(234));
153+
154+
mock_timestamp_provider
155+
}));
135156
let message = test_utils::TestMessage {
136157
content: b"test".to_vec(),
137158
};
138159

139160
let dmq_message = builder.build(&message.to_bytes_vec().unwrap()).await.unwrap();
140161

141-
assert!(!dmq_message.msg_id.is_empty());
162+
let DmqMsg {
163+
msg_payload,
164+
kes_signature: _,
165+
} = &*dmq_message;
142166
assert_eq!(
143167
DmqMsg {
144-
msg_id: vec![],
145-
msg_body: b"test".to_vec(),
146-
block_number: 123,
147-
ttl: 100,
168+
msg_payload: DmqMsgPayload {
169+
msg_id: DmqMessageBuilder::compute_msg_id(msg_payload),
170+
msg_body: b"test".to_vec(),
171+
kes_period: 0,
172+
operational_certificate: operational_certificate.to_bytes_vec().unwrap(),
173+
cold_verification_key: vec![], // TODO: fix
174+
expires_at: 1234,
175+
},
148176
kes_signature: kes_signature.to_bytes_vec().unwrap(),
149-
operational_certificate: operational_certificate.to_bytes_vec().unwrap(),
150-
kes_period: 0,
151177
},
152-
DmqMsg {
153-
msg_id: vec![],
154-
..dmq_message.into()
155-
}
178+
dmq_message.into()
156179
);
157180
}
158181
}

internal/mithril-dmq/src/model/message.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,18 +72,23 @@ impl<'de> Deserialize<'de> for DmqMessage {
7272

7373
#[cfg(test)]
7474
mod tests {
75+
use pallas_network::miniprotocols::localmsgsubmission::DmqMsgPayload;
76+
7577
use super::*;
7678

7779
#[test]
7880
fn test_dmq_message_serialize_deserialize() {
7981
let dmq_msg = DmqMsg {
80-
msg_id: vec![0, 1],
81-
msg_body: vec![0, 1, 2],
82+
msg_payload: DmqMsgPayload {
83+
msg_id: vec![0, 1],
84+
msg_body: vec![0, 1, 2],
85+
86+
kes_period: 10,
87+
operational_certificate: vec![0, 1, 2, 3, 4],
88+
cold_verification_key: vec![0, 1, 2, 3, 4, 5],
89+
expires_at: 100,
90+
},
8291
kes_signature: vec![0, 1, 2, 3],
83-
kes_period: 10,
84-
operational_certificate: vec![0, 1, 2, 3, 4],
85-
cold_verification_key: vec![0, 1, 2, 3, 4, 5],
86-
expires_at: 100,
8792
};
8893

8994
let dmq_message = DmqMessage::from(dmq_msg.clone());

0 commit comments

Comments
 (0)