Skip to main content

aleph_types/message/
aggregate.rs

1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4pub struct AggregateKeyDict {
5    name: String,
6}
7
8#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
9#[serde(untagged)]
10pub enum AggregateKey {
11    String(String),
12    Dict(AggregateKeyDict),
13}
14
15impl AggregateKey {
16    pub fn key(&self) -> &str {
17        match self {
18            AggregateKey::String(key) => key,
19            AggregateKey::Dict(dict) => dict.name.as_str(),
20        }
21    }
22}
23
24#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
25pub struct AggregateContent {
26    /// The aggregate key can be either a string of a dict containing the key in field 'name'.
27    pub key: AggregateKey,
28    /// The content of the aggregate, always a JSON object.
29    pub content: serde_json::Map<String, serde_json::Value>,
30}
31
32impl AggregateContent {
33    pub fn key(&self) -> &str {
34        self.key.key()
35    }
36}
37
38#[cfg(test)]
39mod tests {
40    use crate::chain::Chain;
41    use crate::message::base_message::MessageContentEnum;
42    use crate::message::{ContentSource, Message, MessageType};
43    use crate::timestamp::Timestamp;
44    use crate::{address, channel, item_hash, signature};
45    use assert_matches::assert_matches;
46
47    const AGGREGATE_FIXTURE: &str = include_str!(concat!(
48        env!("CARGO_MANIFEST_DIR"),
49        "/../../fixtures/messages/aggregate/aggregate.json"
50    ));
51
52    #[test]
53    fn test_deserialize_aggregate() {
54        let message: Message = serde_json::from_str(AGGREGATE_FIXTURE).unwrap();
55
56        assert_eq!(
57            message.sender,
58            address!("0xa1B3bb7d2332383D96b7796B908fB7f7F3c2Be10")
59        );
60        assert_eq!(message.chain, Chain::Ethereum);
61        assert_eq!(
62            message.signature,
63            signature!(
64                "0x7d14b66772d97f5a7f9915875b34eae3df117f0a2cd6ffada3bfee09313441e853c1fdf813158b3109e1f85aacb8410894e7d76b552a7821d2280aac956528591c"
65            )
66        );
67        assert_matches!(message.message_type, MessageType::Aggregate);
68        assert_matches!(
69            message.content_source,
70            ContentSource::Storage,
71            "Expected content_source to be ContentSource::Storage"
72        );
73        assert_eq!(
74            message.item_hash,
75            item_hash!("3ad7f29b5b451b3e49d6054a8966aa7e728ac0f07dd7ef25f3bd2455f1408190")
76        );
77        assert_eq!(message.time, Timestamp::from(1762518461.524221));
78        assert_eq!(message.channel, Some(channel!("FOUNDATION")));
79
80        // Check content fields
81        assert_eq!(
82            &message.content.address,
83            &address!("0xa1B3bb7d2332383D96b7796B908fB7f7F3c2Be10")
84        );
85        assert_eq!(&message.content.time, &Timestamp::from(1762518461.4893668));
86        assert_eq!(message.sent_at(), &message.content.time);
87
88        // Check aggregate content fields
89        let aggregate_content = match message.content() {
90            MessageContentEnum::Aggregate(content) => content,
91            other => {
92                panic!("Expected MessageContentEnum::Aggregate, got {:?}", other);
93            }
94        };
95        assert_eq!(aggregate_content.key(), "corechannel");
96        assert!(aggregate_content.content.contains_key("nodes"));
97        assert!(aggregate_content.content.contains_key("resource_nodes"));
98
99        // No confirmation on this fixture
100        assert!(!message.confirmed());
101        assert!(message.confirmations.is_empty());
102    }
103}