teliox 0.17.13

Library for the Transaction Event Log
Documentation
use crate::{
    error::Error,
    event::vc_event::{VCEventMessage, VCEventType},
};
use said::SelfAddressingIdentifier;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)]
pub enum TelState {
    #[default]
    NotIssued,
    Issued(SelfAddressingIdentifier),
    Revoked,
}

impl TelState {
    pub fn apply(&self, event: &VCEventMessage) -> Result<Self, Error> {
        let event_content = event.data.data.clone();
        match event_content.event_type {
            VCEventType::Bis(_iss) => match self {
                TelState::NotIssued => {
                    if event_content.sn == 0 {
                        Ok(TelState::Issued(event.digest()?))
                    } else {
                        Err(Error::Generic("Wrong sn".into()))
                    }
                }
                _ => Err(Error::EventAlreadySavedError),
            },
            VCEventType::Brv(rev) => match self {
                TelState::Issued(last) => {
                    if rev.prev_event_hash.eq(last) && event_content.sn == 1 {
                        Ok(TelState::Revoked)
                    } else {
                        Err(Error::Generic("Previous event doesn't match".to_string()))
                    }
                }
                TelState::NotIssued => Err(Error::OutOfOrderError),
                TelState::Revoked => Err(Error::Generic("Already revoked".into())),
            },
            VCEventType::Iss(_iss) => match self {
                TelState::NotIssued => Ok(TelState::Issued(event.digest()?)),
                _ => Err(Error::EventAlreadySavedError),
            },
            VCEventType::Rev(rev) => match self {
                TelState::Issued(last) => {
                    if &rev.prev_event_hash == last {
                        Ok(TelState::Revoked)
                    } else {
                        Err(Error::Generic("Previous event doesn't match".to_string()))
                    }
                }
                TelState::NotIssued => Err(Error::OutOfOrderError),
                TelState::Revoked => Err(Error::Generic("Already revoked".into())),
            },
        }
    }
}

#[test]
fn test_apply() -> Result<(), Error> {
    let bis_raw = r#"{"v":"KERI10JSON000162_","t":"bis","d":"EFXbFFjdUNRgg_blTx76RAdcIoRoLtPl5tA3yAw5vS9W","i":"EC8Oej-3HAUpBY_kxzBK3B-0RV9j4dXw1H0NRKxJg7g-","s":"0","ii":"EKKJ0FoLxO1TYmyuprguKO7kJ7Hbn0m0Wuk5aMtSrMtY","ra":{"i":"EIZlA3TANi3p8vEu4VQMjPnY0sPFAag1ekIwyyR6lAsq","s":"0","d":"EFSL6HebpbWsxKxfdS4t6NbKTdO4hAUIAxvhmWVf3Z8o"},"dt":"2023-01-10T10:36:50.842679+00:00"}"#;
    let bis_ev: VCEventMessage = serde_json::from_str(&bis_raw).unwrap();
    assert_eq!(serde_json::to_string(&bis_ev).unwrap(), bis_raw);

    let brv_raw = r#"{"v":"KERI10JSON000161_","t":"brv","d":"ENJrZygsUPsqzxjrmgXIjweuQX5I2lXbgcGFn7iEyDyG","i":"EC8Oej-3HAUpBY_kxzBK3B-0RV9j4dXw1H0NRKxJg7g-","s":"1","p":"EFXbFFjdUNRgg_blTx76RAdcIoRoLtPl5tA3yAw5vS9W","ra":{"i":"EIZlA3TANi3p8vEu4VQMjPnY0sPFAag1ekIwyyR6lAsq","s":"0","d":"EFSL6HebpbWsxKxfdS4t6NbKTdO4hAUIAxvhmWVf3Z8o"},"dt":"2023-01-10T10:36:50.843652+00:00"}"#;
    let brv_ev: VCEventMessage = serde_json::from_str(&brv_raw).unwrap();
    assert_eq!(serde_json::to_string(&brv_ev).unwrap(), brv_raw);

    let state = TelState::default();
    let state = state.apply(&bis_ev)?;
    assert!(matches!(state, TelState::Issued(_)));

    if let TelState::Issued(last) = state.clone() {
        match brv_ev.data.data.event_type {
            VCEventType::Brv(ref brv) => assert!(brv.prev_event_hash == last),
            _ => (),
        };
    }
    let state = state.apply(&brv_ev)?;
    assert_eq!(state, TelState::Revoked);

    let state = state.apply(&brv_ev);
    assert!(state.is_err());

    Ok(())
}