keri_core/event_message/
cesr_adapter.rs

1use std::convert::{TryFrom, TryInto};
2
3use cesrox::{
4    group::Group,
5    payload::{parse_payload, Payload},
6    primitives::IndexedSignature as CesrIndexedSignature,
7    ParsedData,
8};
9use said::{version::format::SerializationFormats, SelfAddressingIdentifier};
10use serde::{Deserialize, Serialize};
11
12use crate::event::{
13    event_data::EventData,
14    receipt::Receipt,
15    sections::seal::{EventSeal, SourceSeal},
16    KeyEvent,
17};
18
19#[cfg(feature = "query")]
20use crate::event_message::signed_event_message::Op;
21
22#[cfg(feature = "query")]
23use super::signature::signatures_into_groups;
24#[cfg(feature = "query")]
25use crate::query::{
26    query_event::SignedQueryMessage,
27    query_event::{QueryEvent, SignedKelQuery},
28    reply_event::{ReplyEvent, SignedReply},
29};
30
31#[cfg(feature = "mailbox")]
32use crate::{
33    event_message::signature,
34    mailbox::exchange::{ExchangeMessage, SignedExchange},
35    query::mailbox::{MailboxQuery, SignedMailboxQuery},
36};
37
38use super::{
39    msg::{KeriEvent, TypedEvent},
40    signature::Nontransferable,
41    signed_event_message::{
42        Message, Notice, SignedEventMessage, SignedNontransferableReceipt,
43        SignedTransferableReceipt,
44    },
45    Typeable,
46};
47
48#[derive(Debug, thiserror::Error, Serialize, Deserialize)]
49pub enum ParseError {
50    #[error("Cesr error")]
51    CesrError(String),
52    #[error("Deserialize error: {0}")]
53    DeserializeError(String),
54    #[error("Wrong attachment: {0}")]
55    AttachmentError(String),
56    #[error("Wrong event type: {0}")]
57    WrongEventType(String),
58}
59
60pub fn parse_event_type(input: &[u8]) -> Result<EventType, ParseError> {
61    parse_payload(input)
62        .map_err(|e| ParseError::CesrError(e.to_string()))?
63        .1
64        .try_into()
65}
66
67#[derive(Clone, Debug, PartialEq, Deserialize)]
68#[serde(untagged)]
69pub enum EventType {
70    KeyEvent(KeriEvent<KeyEvent>),
71    Receipt(Receipt),
72    #[cfg(feature = "mailbox")]
73    Exn(ExchangeMessage),
74    #[cfg(feature = "query")]
75    Qry(QueryEvent),
76    #[cfg(feature = "mailbox")]
77    MailboxQry(MailboxQuery),
78    #[cfg(any(feature = "query", feature = "oobi"))]
79    Rpy(ReplyEvent),
80}
81
82impl EventType {
83    pub fn serialize(&self) -> Result<Vec<u8>, crate::error::Error> {
84        match self {
85            EventType::KeyEvent(event) => event.encode(),
86            EventType::Receipt(rcp) => rcp.encode(),
87            #[cfg(feature = "query")]
88            EventType::Qry(qry) => qry.encode(),
89            #[cfg(feature = "query")]
90            EventType::Rpy(rpy) => rpy.encode(),
91            #[cfg(feature = "mailbox")]
92            EventType::Exn(exn) => exn.encode(),
93            #[cfg(feature = "mailbox")]
94            EventType::MailboxQry(qry) => qry.encode(),
95        }
96    }
97}
98
99impl From<&SignedEventMessage> for ParsedData {
100    fn from(ev: &SignedEventMessage) -> Self {
101        let mut attachments = if let Some(SourceSeal { sn, digest }) = ev.delegator_seal.clone() {
102            vec![Group::SourceSealCouples(vec![(sn, digest.said.into())])]
103        } else {
104            vec![]
105        };
106        let sigs = ev
107            .signatures
108            .clone()
109            .into_iter()
110            .map(|sig| sig.into())
111            .collect();
112        let signatures = Group::IndexedControllerSignatures(sigs);
113        attachments.push(signatures);
114
115        if let Some(witness_rcts) = &ev.witness_receipts {
116            witness_rcts.iter().for_each(|rcts| match rcts {
117                Nontransferable::Indexed(indexed) => {
118                    let witness_sigs: Vec<CesrIndexedSignature> =
119                        indexed.iter().map(|sig| sig.clone().into()).collect();
120                    attachments.push(Group::IndexedWitnessSignatures(witness_sigs))
121                }
122                Nontransferable::Couplet(couplets) => {
123                    let couples = couplets
124                        .iter()
125                        .map(|(bp, sp)| (bp.clone().into(), sp.clone().into()))
126                        .collect();
127                    attachments.push(Group::NontransReceiptCouples(couples))
128                }
129            });
130        };
131
132        ParsedData {
133            payload: ev.event_message.clone().into(),
134            attachments,
135        }
136    }
137}
138
139impl<T: Serialize + Clone, D: Typeable<TypeTag = T> + Serialize + Clone> From<TypedEvent<T, D>>
140    for Payload
141{
142    fn from(pd: TypedEvent<T, D>) -> Self {
143        match pd.serialization_info.kind {
144            SerializationFormats::JSON => Payload::JSON(pd.encode().unwrap()),
145            SerializationFormats::MGPK => Payload::MGPK(pd.encode().unwrap()),
146            SerializationFormats::CBOR => Payload::CBOR(pd.encode().unwrap()),
147        }
148    }
149}
150
151impl From<SignedNontransferableReceipt> for ParsedData {
152    fn from(rcp: SignedNontransferableReceipt) -> ParsedData {
153        let attachments: Vec<Group> = rcp.signatures.into_iter().map(|sig| sig.into()).collect();
154        ParsedData {
155            payload: rcp.body.into(),
156            attachments,
157        }
158    }
159}
160
161impl From<SignedTransferableReceipt> for ParsedData {
162    fn from(rcp: SignedTransferableReceipt) -> ParsedData {
163        let seal = rcp.validator_seal;
164        let event_digest = seal.event_digest();
165        let signatures = rcp.signatures.into_iter().map(|sig| sig.into()).collect();
166        let quadruple = (seal.prefix.into(), seal.sn, event_digest.into(), signatures);
167        let group = Group::TransIndexedSigGroups(vec![quadruple]);
168
169        ParsedData {
170            payload: rcp.body.into(),
171            attachments: vec![group],
172        }
173    }
174}
175
176#[cfg(feature = "query")]
177impl From<SignedReply> for ParsedData {
178    fn from(ev: SignedReply) -> Self {
179        let attachments = vec![ev.signature.into()];
180        ParsedData {
181            payload: ev.reply.into(),
182            attachments,
183        }
184    }
185}
186
187#[cfg(feature = "query")]
188impl From<SignedKelQuery> for ParsedData {
189    fn from(ev: SignedKelQuery) -> Self {
190        let groups = signatures_into_groups(&[ev.signature]);
191
192        ParsedData {
193            payload: ev.query.into(),
194            attachments: groups,
195        }
196    }
197}
198
199#[cfg(feature = "mailbox")]
200impl From<SignedMailboxQuery> for ParsedData {
201    fn from(ev: SignedMailboxQuery) -> Self {
202        let groups = signatures_into_groups(&[ev.signature]);
203
204        ParsedData {
205            payload: ev.query.into(),
206            attachments: groups,
207        }
208    }
209}
210
211#[cfg(feature = "query")]
212impl From<SignedQueryMessage> for ParsedData {
213    fn from(ev: SignedQueryMessage) -> Self {
214        match ev {
215            SignedQueryMessage::KelQuery(kqry) => ParsedData::from(kqry),
216            #[cfg(feature = "mailbox")]
217            SignedQueryMessage::MailboxQuery(mqry) => ParsedData::from(mqry),
218        }
219    }
220}
221
222#[cfg(feature = "mailbox")]
223impl From<SignedExchange> for ParsedData {
224    fn from(ev: SignedExchange) -> Self {
225        let mut attachments = signature::signatures_into_groups(&ev.signature);
226
227        let data_signatures = signature::signatures_into_groups(&ev.data_signature.1);
228
229        let data_attachment = Group::PathedMaterialQuadruplet(ev.data_signature.0, data_signatures);
230        attachments.push(data_attachment);
231        ParsedData {
232            payload: ev.exchange_message.into(),
233            attachments,
234        }
235    }
236}
237
238impl TryFrom<Payload> for EventType {
239    type Error = ParseError;
240
241    fn try_from(value: Payload) -> Result<Self, Self::Error> {
242        let event: Result<EventType, _> = match value {
243            Payload::JSON(event) => serde_json::from_slice(&event),
244            Payload::CBOR(_event) => todo!(),
245            Payload::MGPK(_event) => todo!(),
246        };
247        event.map_err(|e| ParseError::DeserializeError(e.to_string()))
248    }
249}
250
251impl TryFrom<ParsedData> for Message {
252    type Error = ParseError;
253
254    fn try_from(value: ParsedData) -> Result<Self, Self::Error> {
255        let msg = match value.payload.try_into()? {
256            EventType::KeyEvent(ev) => Message::Notice(signed_key_event(ev, value.attachments)?),
257            EventType::Receipt(rct) => Message::Notice(signed_receipt(rct, value.attachments)?),
258            #[cfg(feature = "query")]
259            EventType::Qry(qry) => Message::Op(signed_query(qry, value.attachments)?),
260            #[cfg(feature = "query")]
261            EventType::Rpy(rpy) => Message::Op(signed_reply(rpy, value.attachments)?),
262            #[cfg(feature = "mailbox")]
263            EventType::Exn(exn) => Message::Op(signed_exchange(exn, value.attachments)?),
264            #[cfg(feature = "mailbox")]
265            EventType::MailboxQry(qry) => {
266                Message::Op(signed_management_query(qry, value.attachments)?)
267            }
268        };
269        Ok(msg)
270    }
271}
272
273impl TryFrom<ParsedData> for Notice {
274    type Error = ParseError;
275
276    fn try_from(value: ParsedData) -> Result<Self, Self::Error> {
277        match Message::try_from(value)? {
278            Message::Notice(notice) => Ok(notice),
279            #[cfg(feature = "query")]
280            _ => Err(ParseError::WrongEventType(
281                "Cannot convert SignedEventData to Notice".to_string(),
282            )),
283        }
284    }
285}
286
287#[cfg(any(feature = "query", feature = "oobi"))]
288impl TryFrom<ParsedData> for Op {
289    type Error = ParseError;
290
291    fn try_from(value: ParsedData) -> Result<Self, Self::Error> {
292        let et: EventType = value.payload.try_into()?;
293        match et {
294            #[cfg(feature = "query")]
295            EventType::Qry(qry) => signed_query(qry, value.attachments),
296            #[cfg(feature = "mailbox")]
297            EventType::MailboxQry(qry) => signed_management_query(qry, value.attachments),
298            #[cfg(feature = "oobi")]
299            EventType::Rpy(rpy) => signed_reply(rpy, value.attachments),
300            #[cfg(feature = "mailbox")]
301            EventType::Exn(exn) => signed_exchange(exn, value.attachments),
302            _ => Err(ParseError::WrongEventType(
303                "Cannot convert SignedEventData to Op".to_string(),
304            )),
305        }
306    }
307}
308
309#[cfg(feature = "query")]
310impl TryFrom<ParsedData> for SignedQueryMessage {
311    type Error = ParseError;
312
313    fn try_from(value: ParsedData) -> Result<Self, Self::Error> {
314        match Op::try_from(value)? {
315            Op::Query(qry) => Ok(qry),
316            // Op::MailboxQuery(qry) => Ok(SignedQueryMessage::MailboxQuery(qry)),
317            _ => Err(ParseError::WrongEventType(
318                "Cannot convert SignedEventData to SignedQuery".to_string(),
319            )),
320        }
321    }
322}
323
324#[cfg(feature = "query")]
325impl TryFrom<ParsedData> for SignedReply {
326    type Error = ParseError;
327
328    fn try_from(value: ParsedData) -> Result<Self, Self::Error> {
329        match Op::try_from(value)? {
330            Op::Reply(rpy) => Ok(rpy),
331            _ => Err(ParseError::WrongEventType(
332                "Cannot convert SignedEventData to SignedReply".to_string(),
333            )),
334        }
335    }
336}
337
338#[cfg(feature = "mailbox")]
339impl TryFrom<ParsedData> for SignedExchange {
340    type Error = ParseError;
341
342    fn try_from(value: ParsedData) -> Result<Self, Self::Error> {
343        match Op::try_from(value)? {
344            Op::Exchange(exn) => Ok(exn),
345            _ => Err(ParseError::WrongEventType(
346                "Cannot convert SignedEventData to SignedExchange".to_string(),
347            )),
348        }
349    }
350}
351
352#[cfg(feature = "query")]
353fn signed_reply(rpy: ReplyEvent, mut attachments: Vec<Group>) -> Result<Op, ParseError> {
354    use said::SelfAddressingIdentifier;
355
356    match attachments
357        .pop()
358        .ok_or_else(|| ParseError::AttachmentError("Missing attachment".into()))?
359    {
360        Group::NontransReceiptCouples(couplets) => {
361            let signer = couplets[0].0.clone();
362            let signature = couplets[0].1.clone();
363            Ok(Op::Reply(SignedReply::new_nontrans(
364                rpy,
365                signer.into(),
366                signature.into(),
367            )))
368        }
369        Group::TransIndexedSigGroups(data) => {
370            let (prefix, sn, digest, sigs) = data
371                // TODO what if more than one?
372                .last()
373                .ok_or_else(|| ParseError::AttachmentError("More than one seal".into()))?
374                .to_owned();
375            let seal = EventSeal::new(
376                prefix.into(),
377                sn,
378                SelfAddressingIdentifier::from(digest).into(),
379            );
380            let sigs = sigs.into_iter().map(|sig| sig.into()).collect();
381            Ok(Op::Reply(SignedReply::new_trans(rpy, seal, sigs)))
382        }
383        Group::Frame(atts) => signed_reply(rpy, atts),
384        _ => {
385            // Improper payload type
386            Err(ParseError::AttachmentError("Improper payload type".into()))
387        }
388    }
389}
390
391#[cfg(feature = "query")]
392fn signed_query(qry: QueryEvent, mut attachments: Vec<Group>) -> Result<Op, ParseError> {
393    use super::signature::get_signatures;
394
395    let att = attachments
396        .pop()
397        .ok_or_else(|| ParseError::AttachmentError("Missing attachment".into()))?;
398    let sigs = get_signatures(att)?;
399    let qry = SignedQueryMessage::KelQuery(SignedKelQuery {
400        query: qry,
401        // TODO what if more than one?
402        signature: sigs
403            .get(0)
404            .ok_or(ParseError::AttachmentError("Missing attachment".into()))?
405            .clone(),
406    });
407    Ok(Op::Query(qry))
408}
409
410#[cfg(feature = "mailbox")]
411fn signed_management_query(
412    qry: MailboxQuery,
413    mut attachments: Vec<Group>,
414) -> Result<Op, ParseError> {
415    use super::signature::get_signatures;
416
417    let att = attachments
418        .pop()
419        .ok_or_else(|| ParseError::AttachmentError("Missing attachment".into()))?;
420    let sigs = get_signatures(att)?;
421    let qry = SignedQueryMessage::MailboxQuery(SignedMailboxQuery {
422        query: qry,
423        // TODO what if more than one?
424        signature: sigs
425            .get(0)
426            .ok_or(ParseError::AttachmentError("Missing attachment".into()))?
427            .clone(),
428    });
429    Ok(Op::Query(qry))
430}
431
432fn signed_key_event(
433    event_message: KeriEvent<KeyEvent>,
434    mut attachments: Vec<Group>,
435) -> Result<Notice, ParseError> {
436    match event_message.data.get_event_data() {
437        EventData::Dip(_) | EventData::Drt(_) => {
438            let (att1, att2) = (
439                attachments
440                    .pop()
441                    .ok_or_else(|| ParseError::AttachmentError("Missing attachment".into()))?,
442                attachments.pop(),
443            );
444
445            let (seals, sigs) = match (att1, att2) {
446                (
447                    Group::SourceSealCouples(seals),
448                    Some(Group::IndexedControllerSignatures(sigs)),
449                ) => Ok((Some(seals), sigs)),
450                (
451                    Group::IndexedControllerSignatures(sigs),
452                    Some(Group::SourceSealCouples(seals)),
453                ) => Ok((Some(seals), sigs)),
454                (Group::IndexedControllerSignatures(sigs), None) => Ok((None, sigs)),
455                _ => {
456                    // Improper attachment type
457                    Err(ParseError::AttachmentError(
458                        "Improper attachment type".into(),
459                    ))
460                }
461            }?;
462
463            let delegator_seal = if let Some(seal) = seals {
464                match seal.len() {
465                    0 => Err(ParseError::AttachmentError("Missing delegator seal".into())),
466                    1 => Ok(seal.first().map(|seal| seal.clone().into())),
467                    _ => Err(ParseError::AttachmentError("Too many seals".into())),
468                }
469            } else {
470                Ok(None)
471            };
472            let signatures = sigs.into_iter().map(|sig| sig.into()).collect();
473
474            Ok(Notice::Event(SignedEventMessage::new(
475                &event_message,
476                signatures,
477                None,
478                delegator_seal?,
479            )))
480        }
481        _ => {
482            let signatures = if let Group::Frame(atts) = attachments
483                .first()
484                .cloned()
485                .ok_or_else(|| ParseError::AttachmentError("Missing attachment".into()))?
486            {
487                atts
488            } else {
489                attachments
490            };
491            let controller_sigs = signatures
492                .iter()
493                .cloned()
494                .find_map(|att| {
495                    if let Group::IndexedControllerSignatures(sigs) = att {
496                        Some(sigs.into_iter().map(|sig| sig.into()).collect())
497                    } else {
498                        None
499                    }
500                })
501                .ok_or_else(|| {
502                    ParseError::AttachmentError("Missing controller signatures attachment".into())
503                })?;
504            let witness_sigs: Vec<_> = signatures
505                .into_iter()
506                .filter_map(|att| match att {
507                    Group::IndexedWitnessSignatures(indexed) => Some(Nontransferable::Indexed(
508                        indexed.into_iter().map(|sig| sig.into()).collect(),
509                    )),
510                    Group::NontransReceiptCouples(couples) => Some(Nontransferable::Couplet(
511                        couples
512                            .into_iter()
513                            .map(|(bp, sp)| (bp.into(), sp.into()))
514                            .collect(),
515                    )),
516                    _ => None,
517                })
518                .collect();
519
520            Ok(Notice::Event(SignedEventMessage::new(
521                &event_message,
522                controller_sigs,
523                if witness_sigs.is_empty() {
524                    None
525                } else {
526                    Some(witness_sigs)
527                },
528                // TODO parse delegator seal attachment
529                None,
530            )))
531        }
532    }
533}
534
535fn signed_receipt(
536    event_message: Receipt,
537    mut attachments: Vec<Group>,
538) -> Result<Notice, ParseError> {
539    let nontransferable = attachments
540        .iter()
541        .filter_map(|att| match att {
542            Group::IndexedWitnessSignatures(sigs) => {
543                let converted_signatures = sigs.iter().map(|sig| sig.clone().into()).collect();
544                Some(Nontransferable::Indexed(converted_signatures))
545            }
546            Group::NontransReceiptCouples(couples) => Some(Nontransferable::Couplet(
547                couples
548                    .into_iter()
549                    .map(|(bp, sp)| (bp.clone().into(), sp.clone().into()))
550                    .collect(),
551            )),
552            _ => None,
553        })
554        .collect();
555    let att = attachments
556        .pop()
557        .ok_or_else(|| ParseError::AttachmentError("Missing attachment".into()))?;
558
559    match att {
560        // Should be nontransferable receipt
561        Group::NontransReceiptCouples(_) | Group::IndexedWitnessSignatures(_) => {
562            Ok(Notice::NontransferableRct(SignedNontransferableReceipt {
563                body: event_message,
564                signatures: nontransferable,
565            }))
566        }
567        Group::TransIndexedSigGroups(data) => {
568            // Should be transferable receipt
569            let (prefix, sn, event_digest, sigs) = data
570                // TODO what if more than one?
571                .last()
572                .ok_or_else(|| ParseError::AttachmentError("Empty seals".into()))?;
573            let seal = EventSeal::new(
574                prefix.clone().into(),
575                *sn,
576                SelfAddressingIdentifier::from(event_digest.clone()).into(),
577            );
578            let converted_signatures = sigs.iter().map(|sig| sig.clone().into()).collect();
579            Ok(Notice::TransferableRct(SignedTransferableReceipt::new(
580                event_message,
581                seal,
582                converted_signatures,
583            )))
584        }
585        Group::Frame(atts) => signed_receipt(event_message, atts),
586        _ => {
587            // Improper payload type
588            Err(ParseError::AttachmentError("Improper payload type".into()))
589        }
590    }
591}
592
593#[cfg(feature = "mailbox")]
594pub fn signed_exchange(exn: ExchangeMessage, attachments: Vec<Group>) -> Result<Op, ParseError> {
595    use crate::event_message::signature::get_signatures;
596
597    use super::signature::Signature;
598
599    let mut atts = attachments.into_iter();
600    let att1 = atts
601        .next()
602        .ok_or_else(|| ParseError::AttachmentError("Missing attachment".into()))?;
603    let att2 = atts
604        .next()
605        .ok_or_else(|| ParseError::AttachmentError("Missing attachment".into()))?;
606    let (path, data_sigs, signatures): (_, _, Vec<Signature>) = match (att1, att2) {
607        (Group::PathedMaterialQuadruplet(path, sigs), anything)
608        | (anything, Group::PathedMaterialQuadruplet(path, sigs)) => {
609            (path, sigs, get_signatures(anything)?)
610        }
611        _ => return Err(ParseError::AttachmentError("Wrong attachment".into())),
612    };
613    let data_signatures: Result<Vec<Signature>, ParseError> =
614        data_sigs.into_iter().fold(Ok(vec![]), |acc, group| {
615            let mut signatures: Vec<Signature> = get_signatures(group)?;
616            let mut sigs = acc?;
617            sigs.append(&mut signatures);
618            Ok(sigs)
619        });
620
621    Ok(Op::Exchange(SignedExchange {
622        exchange_message: exn,
623        signature: signatures,
624        data_signature: (path, data_signatures?),
625    }))
626}
627
628#[cfg(test)]
629pub mod test {
630    use cesrox::{parse, parse_many};
631
632    use crate::{
633        event::{receipt::Receipt, KeyEvent},
634        event_message::msg::KeriEvent,
635    };
636
637    #[test]
638    fn test_signed_event() {
639        // taken from KERIPY: tests/core/test_eventing.py::test_multisig_digprefix#2255
640        let stream = br#"{"v":"KERI10JSON0001e7_","t":"icp","d":"EBfxc4RiVY6saIFmUfEtETs1FcqmktZW88UkbnOg0Qen","i":"EBfxc4RiVY6saIFmUfEtETs1FcqmktZW88UkbnOg0Qen","s":"0","kt":"2","k":["DErocgXD2RGSyvn3MObcx59jeOsEQhv2TqHirVkzrp0Q","DFXLiTjiRdSBPLL6hLa0rskIxk3dh4XwJLfctkJFLRSS","DE9YgIQVgpLwocTVrG8tidKScsQSMWwLWywNC48fhq4f"],"nt":"2","n":["EDJk5EEpC4-tQ7YDwBiKbpaZahh1QCyQOnZRF7p2i8k8","EAXfDjKvUFRj-IEB_o4y-Y_qeJAjYfZtOMD9e7vHNFss","EN8l6yJC2PxribTN0xfri6bLz34Qvj-x3cNwcV3DvT2m"],"bt":"0","b":[],"c":[],"a":[]}-AADAAD4SyJSYlsQG22MGXzRGz2PTMqpkgOyUfq7cS99sC2BCWwdVmEMKiTEeWe5kv-l_d9auxdadQuArLtAGEArW8wEABD0z_vQmFImZXfdR-0lclcpZFfkJJJNXDcUNrf7a-mGsxNLprJo-LROwDkH5m7tVrb-a1jcor2dHD9Jez-r4bQIACBFeU05ywfZycLdR0FxCvAR9BfV9im8tWe1DglezqJLf-vHRQSChY1KafbYNc96hYYpbuN90WzuCRMgV8KgRsEC"#;
641        let parsed = parse(stream);
642        assert!(parsed.is_ok());
643        assert_eq!(parsed.unwrap().1.to_cesr().unwrap(), stream);
644    }
645
646    #[test]
647    fn test_key_event_parsing() {
648        // Inception event.
649        let stream = br#"{"v":"KERI10JSON0000fd_","t":"icp","d":"EMW0zK3bagYPO6gx3w7Ua90f-I7x5kGIaI4Xeq9W8_As","i":"BFs8BBx86uytIM0D2BhsE5rrqVIT8ef8mflpNceHo4XH","s":"0","kt":"1","k":["BFs8BBx86uytIM0D2BhsE5rrqVIT8ef8mflpNceHo4XH"],"nt":"0","n":[],"bt":"0","b":[],"c":[],"a":[]}"#;
650        let event: KeriEvent<KeyEvent> = serde_json::from_slice(stream).unwrap();
651        assert_eq!(event.encode().unwrap(), stream);
652
653        // Rotation event.
654        let stream = br#"{"v":"KERI10JSON000160_","t":"rot","d":"EFl8nvRCbN2xQJI75nBXp-gaXuHJw8zheVjwMN_rB-pb","i":"DFs8BBx86uytIM0D2BhsE5rrqVIT8ef8mflpNceHo4XH","s":"1","p":"EJQUyxnzIAtmZPoq9f4fExeGN0qfJmaFnUEKTwIiTBPj","kt":"1","k":["DB4GWvru73jWZKpNgMQp8ayDRin0NG0Ymn_RXQP_v-PQ"],"nt":"1","n":["EIsKL3B6Zz5ICGxCQp-SoLXjwOrdlSbLJrEn21c2zVaU"],"bt":"0","br":[],"ba":[],"a":[]}"#;
655        let event: KeriEvent<KeyEvent> = serde_json::from_slice(stream).unwrap();
656        assert_eq!(event.encode().unwrap(), stream);
657
658        // Interaction event without seals.
659        let stream = br#"{"v":"KERI10JSON0000cb_","t":"ixn","d":"EKKccCumVQdgxvsrSXvuTtjmS28Xqf3zRJ8T6peKgl9J","i":"DFs8BBx86uytIM0D2BhsE5rrqVIT8ef8mflpNceHo4XH","s":"2","p":"ECauhEzA4DJDXVDnNQiGQ0sKXa6sx_GgS8Ebdzm4E-kQ","a":[]}"#;
660        let event: KeriEvent<KeyEvent> = serde_json::from_slice(stream).unwrap();
661        assert_eq!(event.encode().unwrap(), stream);
662
663        // Interaction event with seal.
664        let stream = br#"{"v":"KERI10JSON00013a_","t":"ixn","d":"EJtQndkvwnMpVGE5oVVbLWSCm-jLviGw1AOOkzBvNwsS","i":"EA_SbBUZYwqLVlAAn14d6QUBQCSReJlZ755JqTgmRhXH","s":"1","p":"EA_SbBUZYwqLVlAAn14d6QUBQCSReJlZ755JqTgmRhXH","a":[{"i":"EHng2fV42DdKb5TLMIs6bbjFkPNmIdQ5mSFn6BTnySJj","s":"0","d":"EHng2fV42DdKb5TLMIs6bbjFkPNmIdQ5mSFn6BTnySJj"}]}"#;
665        let event: KeriEvent<KeyEvent> = serde_json::from_slice(stream).unwrap();
666        assert_eq!(event.encode().unwrap(), stream);
667
668        // Delegated inception event.
669        let stream = br#"{"v":"KERI10JSON00015f_","t":"dip","d":"EHng2fV42DdKb5TLMIs6bbjFkPNmIdQ5mSFn6BTnySJj","i":"EHng2fV42DdKb5TLMIs6bbjFkPNmIdQ5mSFn6BTnySJj","s":"0","kt":"1","k":["DLitcfMnabnLt-PNCaXdVwX45wsG93Wd8eW9QiZrlKYQ"],"nt":"1","n":["EDjXvWdaNJx7pAIr72Va6JhHxc7Pf4ScYJG496ky8lK8"],"bt":"0","b":[],"c":[],"a":[],"di":"EA_SbBUZYwqLVlAAn14d6QUBQCSReJlZ755JqTgmRhXH"}"#;
670        let event: KeriEvent<KeyEvent> = serde_json::from_slice(stream).unwrap();
671        assert_eq!(event.encode().unwrap(), stream);
672
673        // Delegated rotation event.
674        let stream = br#"{"v":"KERI10JSON000160_","t":"drt","d":"EMBBBkaLV7i6wNgfz3giib2ItrHsr548mtIflW0Hrbuv","i":"EN3PglLbr4mJblS4dyqbqlpUa735hVmLOhYUbUztxaiH","s":"4","p":"EANkcl_QewzrRSKH2p9zUskHI462CuIMS_HQIO132Z30","kt":"1","k":["DPLt4YqQsWZ5DPztI32mSyTJPRESONvE9KbETtCVYIeH"],"nt":"1","n":["EIsKL3B6Zz5ICGxCQp-SoLXjwOrdlSbLJrEn21c2zVaU"],"bt":"0","br":[],"ba":[],"a":[]}"#;
675        let event: KeriEvent<KeyEvent> = serde_json::from_slice(stream).unwrap();
676        assert_eq!(event.encode().unwrap(), stream);
677    }
678
679    #[test]
680    fn test_receipt_parsing() {
681        // Receipt event
682        let stream = br#"{"v":"KERI10JSON000091_","t":"rct","d":"EKKccCumVQdgxvsrSXvuTtjmS28Xqf3zRJ8T6peKgl9J","i":"DFs8BBx86uytIM0D2BhsE5rrqVIT8ef8mflpNceHo4XH","s":"0"}"#;
683        let event = parse(stream).unwrap().1;
684        assert_eq!(event.to_cesr().unwrap(), stream);
685
686        let event: Receipt = serde_json::from_slice(stream).unwrap();
687        assert_eq!(event.encode().unwrap(), stream.to_vec());
688    }
689
690    #[cfg(feature = "query")]
691    #[test]
692    fn test_qry() {
693        use std::convert::TryInto;
694
695        use crate::event_message::cesr_adapter::EventType;
696        // taken from keripy keripy/tests/core/test_eventing.py::test_messegize
697        let qry_event = br#"{"v":"KERI10JSON000105_","t":"qry","d":"EHtaQHsKzezkQUEYjMjEv6nIf4AhhR9Zy6AvcfyGCXkI","dt":"2021-01-01T00:00:00.000000+00:00","r":"logs","rr":"","q":{"s":0,"i":"EIaGMMWJFPmtXznY1IIiKDIrg-vIyge6mBl2QV8dDjI3","src":"BGKVzj4ve0VSd8z_AmvhLg4lqcC_9WYX90k03q-R_Ydo"}}"#;
698        let rest = "something more".as_bytes();
699        let stream = [qry_event, rest].concat();
700
701        let (_extra, event) = parse(&stream).unwrap();
702        assert!(matches!(
703            event.payload.clone().try_into().unwrap(),
704            EventType::Qry(_)
705        ));
706        assert_eq!(&event.to_cesr().unwrap(), qry_event);
707    }
708
709    #[cfg(feature = "mailbox")]
710    #[test]
711    fn test_exn() {
712        use crate::event_message::cesr_adapter::EventType;
713        use std::convert::TryInto;
714        let exn_event = br#"{"v":"KERI10JSON0002f1_","t":"exn","d":"EBLqTGJXK8ViUGXMOO8_LXbetpjJX8CY_SbA134RIZmf","dt":"2022-10-25T09:53:04.119676+00:00","r":"/fwd","q":{"pre":"EKYLUMmNPZeEs77Zvclf0bSN5IN-mLfLpx2ySb-HDlk4","topic":"multisig"},"a":{"v":"KERI10JSON000215_","t":"icp","d":"EC61gZ9lCKmHAS7U5ehUfEbGId5rcY0D7MirFZHDQcE2","i":"EC61gZ9lCKmHAS7U5ehUfEbGId5rcY0D7MirFZHDQcE2","s":"0","kt":"2","k":["DOZlWGPfDHLMf62zSFzE8thHmnQUOgA3_Y-KpOyF9ScG","DHGb2qY9WwZ1sBnC9Ip0F-M8QjTM27ftI-3jTGF9mc6K"],"nt":"2","n":["EBvD5VIVvf6NpP9GRmTqu_Cd1KN0RKrKNfPJ-uhIxurj","EHlpcaxffvtcpoUUMTc6tpqAVtb2qnOYVk_3HRsZ34PH"],"bt":"3","b":["BBilc4-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha","BLskRTInXnMxWaGqcpSyMgo0nYbalW99cGZESrz3zapM","BIKKuvBwpmDVA4Ds-EpL5bt9OqPzWPja2LigFYZN2YfX"],"c":[],"a":[]}}-HABEJccSRTfXYF6wrUVuenAIHzwcx3hJugeiJsEKmndi5q1-AABAAArUSuSpts5zDQ7CgPcy305IxhAG8lOjf-r_d5yYQXp18OD9No_gd2McOOjGWMfjyLVjDK529pQcbvNv9Uwc6gH-LAZ5AABAA-a-AABAABYHc_lpuYF3SPNWvyPjzek7yquw69Csc6pLv5vrXHkFAFDcwNNTVxq7ZpxpqOO0CAIS-9Qj1zMor-cwvMHAmkE')"#;
715
716        let (_extra, event) = parse(exn_event).unwrap();
717        assert!(matches!(
718            event.payload.try_into().unwrap(),
719            EventType::Exn(_)
720        ));
721    }
722
723    #[cfg(feature = "query")]
724    #[test]
725    fn test_reply() {
726        use crate::event_message::cesr_adapter::EventType;
727        use std::convert::TryInto;
728        let rpy = br#"{"v":"KERI10JSON00029d_","t":"rpy","d":"EYFMuK9IQmHvq9KaJ1r67_MMCq5GnQEgLyN9YPamR3r0","dt":"2021-01-01T00:00:00.000000+00:00","r":"/ksn/E7YbTIkWWyNwOxZQTTnrs6qn8jFbu2A8zftQ33JYQFQ0","a":{"v":"KERI10JSON0001e2_","i":"E7YbTIkWWyNwOxZQTTnrs6qn8jFbu2A8zftQ33JYQFQ0","s":"3","p":"EF7f4gNFCbJz6ZHLacIi_bbIq7kaWAFOzX7ncU_vs5Qg","d":"EOPSPvHHVmU9IIdHa5ksisoVrOnmHRps_tx3OsZSQQ30","f":"3","dt":"2021-01-01T00:00:00.000000+00:00","et":"rot","kt":"1","k":["DrcAz_gmDTuWIHn_mOQDeSK_aJIRiw5IMzPD7igzEDb0"],"nt":"1","n":["EK7ZUmFebD2st48Yvtzc9LajV3Yg2mkeeDzVRL-7uKrU"],"bt":"0","b":[],"c":[],"ee":{"s":"3","d":"EOPSPvHHVmU9IIdHa5ksisoVrOnmHRps_tx3OsZSQQ30","br":[],"ba":[]},"di":""}}-VA0-FABE7YbTIkWWyNwOxZQTTnrs6qn8jFbu2A8zftQ33JYQFQ00AAAAAAAAAAAAAAAAAAAAAAwEOPSPvHHVmU9IIdHa5ksisoVrOnmHRps_tx3OsZSQQ30-AABAAYsqumzPM0bIo04gJ4Ln0zAOsGVnjHZrFjjjS49hGx_nQKbXuD1D4J_jNoEa4TPtPDnQ8d0YcJ4TIRJb-XouJBg"#;
729        let rest = "something more".as_bytes();
730        let stream = [rpy, rest].concat();
731
732        let (_extra, event) = parse(&stream).unwrap();
733        assert!(matches!(
734            event.payload.try_into().unwrap(),
735            EventType::Rpy(_)
736        ));
737    }
738
739    #[cfg(feature = "query")]
740    #[test]
741    fn test_signed_qry() {
742        // Taken from keripy/tests/core/test_eventing.py::test_messagize (line 1471)
743        let stream = br#"{"v":"KERI10JSON0000c9_","t":"qry","d":"E-WvgxrllmjGFhpn0oOiBkAVz3-dEm3bbiV_5qwj81xo","dt":"2021-01-01T00:00:00.000000+00:00","r":"log","rr":"","q":{"i":"DyvCLRr5luWmp7keDvDuLP0kIqcyBYq79b3Dho1QvrjI"}}-VAj-HABEZOIsLsfrVdBvULlg3Hg_Y1r-hadS82ZpglBLojPIQhg-AABAAuISeZIVO_wXjIrGJ-VcVMxr285OkKzAqVEQqVPFx8Ht2A9GQFB-zRA18J1lpqVphOnnXbTc51WR4uAvK90EHBg"#;
744        let se = parse(&stream[..stream.len() - 1]);
745        assert!(se.is_err());
746        let se = parse(stream);
747        assert!(se.is_ok());
748    }
749
750    #[test]
751    fn test_signed_events_stream() {
752        // Taken from keripy/tests/core/test_kevery.py::test kevery
753        let kerl_str= br#"{"v":"KERI10JSON000120_","t":"icp","d":"EG4EuTsxPiRM7soX10XXzNsS1KqXKUp8xsQ-kW_tWHoI","i":"DSuhyBcPZEZLK-fcw5tzHn2N46wRCG_ZOoeKtWTOunRA","s":"0","kt":"1","k":["DSuhyBcPZEZLK-fcw5tzHn2N46wRCG_ZOoeKtWTOunRA"],"n":"EPYuj8mq_PYYsoBKkzX1kxSPGYBWaIya3slgCOyOtlqU","bt":"0","b":[],"c":[],"a":[]}-AABAA0aSisI4ZZTH_6JCqsvAsEpuf_Jq6bDbvPWj_eCDnAGbSARqYHipNs-9W7MHnwnMfIXwLpcoJkKGrQ-SiaklhAw{"v":"KERI10JSON000155_","t":"rot","d":"Ej30AgJV14mTTs427F3kILLrP_l03a27APg2FBO0-QtA","i":"DSuhyBcPZEZLK-fcw5tzHn2N46wRCG_ZOoeKtWTOunRA","s":"1","p":"EG4EuTsxPiRM7soX10XXzNsS1KqXKUp8xsQ-kW_tWHoI","kt":"1","k":["DVcuJOOJF1IE8svqEtrSuyQjGTd2HhfAkt9y2QkUtFJI"],"n":"E-dapdcC6XR1KWmWDsNl4J_OxcGxNZw1Xd95JH5a34fI","bt":"0","br":[],"ba":[],"a":[]}-AABAAwoiqt07w2UInzzo2DmtwkBfqX1-tTO4cYk_7YdlbJ95qA7PO5sEUkER8fZySQMNCVh64ruAh1yoew3TikwVGAQ{"v":"KERI10JSON000155_","t":"rot","d":"EmtXXRjyz6IdeX4201BgXKRDBm74gGqJF2r2umMMAL6I","i":"DSuhyBcPZEZLK-fcw5tzHn2N46wRCG_ZOoeKtWTOunRA","s":"2","p":"Ej30AgJV14mTTs427F3kILLrP_l03a27APg2FBO0-QtA","kt":"1","k":["DT1iAhBWCkvChxNWsby2J0pJyxBIxbAtbLA0Ljx-Grh8"],"n":"EKrLE2h2nh3ClyJNEjKaikHWT7G-ngimNpK-QgVQv9As","bt":"0","br":[],"ba":[],"a":[]}-AABAAW_RsDfAcHkknyzh9oeliH90KGPJEI8AP3rJPyuTnpVg8yOVtSIp_JFlyRwjV5SEQOqddAcRV6JtaQO8oXtWFCQ{"v":"KERI10JSON0000cb_","t":"ixn","d":"EY7E4RJXPe7FF1zQPbpSMIY-TYz9eAmNIhuprPYqTQ5o","i":"DSuhyBcPZEZLK-fcw5tzHn2N46wRCG_ZOoeKtWTOunRA","s":"3","p":"EmtXXRjyz6IdeX4201BgXKRDBm74gGqJF2r2umMMAL6I","a":[]}-AABAAlB0Ui5NHJpcifXUB6bAutmpZkhSgwxyI5jEZ2JGVBgTI02sC0Ugbq3q0EpOae7ruXW-eabUz2s0FAs26jGwVBg{"v":"KERI10JSON0000cb_","t":"ixn","d":"ENVzbZieVIjYLYkPWQy0gfua11KqdRG-oku5Ut8Dl6hU","i":"DSuhyBcPZEZLK-fcw5tzHn2N46wRCG_ZOoeKtWTOunRA","s":"4","p":"EY7E4RJXPe7FF1zQPbpSMIY-TYz9eAmNIhuprPYqTQ5o","a":[]}-AABAAWITFg460TXvYvxxzN62vpqpLs-vGgeGAbd-onY3DYxd5e3AljHh85pTum4Ha48F5dui9IVYqYvuYJCG8p8KvDw{"v":"KERI10JSON000155_","t":"rot","d":"E6wrLhilpPo4ePq7m7ZccEcKjwPD2q9mqzLUb_aO2Hi0","i":"DSuhyBcPZEZLK-fcw5tzHn2N46wRCG_ZOoeKtWTOunRA","s":"5","p":"ENVzbZieVIjYLYkPWQy0gfua11KqdRG-oku5Ut8Dl6hU","kt":"1","k":["DKPE5eeJRzkRTMOoRGVd2m18o8fLqM2j9kaxLhV3x8AQ"],"n":"EhVTfJFfl6L0Z0432mDUxeaqB_hlWPJ2qUuzG95gEyJU","bt":"0","br":[],"ba":[],"a":[]}-AABAAnqz-vnMx1cqe_SkcIrlx092UhbYzvvkHXjtxfuNDDcqnVtH11_8ZPaWomn3n963_bFTjjRhJaAH1SK8LU7s1DA{"v":"KERI10JSON0000cb_","t":"ixn","d":"Ek9gvRbkCt-wlgQBoV1PGm2iI__gaPURtJ3YrNFsXLzE","i":"DSuhyBcPZEZLK-fcw5tzHn2N46wRCG_ZOoeKtWTOunRA","s":"6","p":"E6wrLhilpPo4ePq7m7ZccEcKjwPD2q9mqzLUb_aO2Hi0","a":[]}-AABAAwGGWMNDpu8t4NuF_3M0jnkn3P063oUHmluwRwsyCg5tIvu-BfwIJRruAsCKry4LaI84dJAfAT5KJnG8xz9lJCw"#;
754        let (rest, messages) = parse_many(kerl_str).unwrap();
755
756        assert!(rest.is_empty());
757        assert_eq!(messages.len(), 7);
758    }
759}