use cesrox::primitives::codes::self_addressing::dummy_prefix;
use keri_core::actor::prelude::SerializationFormats;
use keri_core::event_message::msg::TypedEvent;
use said::{derivation::HashFunctionCode, SelfAddressingIdentifier};
use serde::{Deserialize, Serialize};
use serde_hex::{Compact, SerHex};
use keri_core::{event_message::Typeable, prefix::IdentifierPrefix};
use said::version::SerializationInfo;
use crate::error::Error;
pub type ManagerTelEventMessage = TypedEvent<ManagementTelType, ManagerTelEvent>;
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct ManagerTelEvent {
#[serde(rename = "i")]
pub prefix: IdentifierPrefix,
#[serde(rename = "s", with = "SerHex::<Compact>")]
pub sn: u64,
#[serde(flatten)]
pub event_type: ManagerEventType,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum ManagementTelType {
Vcp,
Vrt,
}
impl Typeable for ManagerTelEvent {
type TypeTag = ManagementTelType;
fn get_type(&self) -> ManagementTelType {
match self.event_type {
ManagerEventType::Vcp(_) => ManagementTelType::Vcp,
ManagerEventType::Vrt(_) => ManagementTelType::Vrt,
}
}
}
impl ManagerTelEvent {
pub fn new(prefix: &IdentifierPrefix, sn: u64, event_type: ManagerEventType) -> Self {
Self {
prefix: prefix.to_owned(),
sn,
event_type,
}
}
pub fn to_message(
self,
format: SerializationFormats,
derivation: HashFunctionCode,
) -> Result<ManagerTelEventMessage, Error> {
Ok(TypedEvent::<ManagementTelType, ManagerTelEvent>::new(
format,
derivation.into(),
self,
))
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
#[serde(untagged, rename_all = "lowercase")]
pub enum ManagerEventType {
Vcp(Inc),
Vrt(Rot),
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub enum Config {
#[serde(rename = "NB")]
NoBackers,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct Inc {
#[serde(rename = "ii")]
pub issuer_id: IdentifierPrefix,
#[serde(rename = "c")]
pub config: Vec<Config>,
#[serde(rename = "bt", with = "SerHex::<Compact>")]
pub backer_threshold: u64,
#[serde(rename = "b")]
pub backers: Vec<IdentifierPrefix>,
}
#[derive(Serialize, Debug, Clone)]
pub(crate) struct DummyEvent {
#[serde(rename = "v")]
serialization_info: SerializationInfo,
#[serde(rename = "i")]
prefix: String,
#[serde(rename = "s", with = "SerHex::<Compact>")]
sn: u8,
#[serde(flatten, rename = "t")]
data: ManagerEventType,
}
impl DummyEvent {
pub fn derive_inception_data(
vcp: Inc,
derivation: &HashFunctionCode,
format: SerializationFormats,
) -> Result<Vec<u8>, Error> {
Self::derive_data(ManagerEventType::Vcp(vcp), derivation, format)
}
fn derive_data(
data: ManagerEventType,
derivation: &HashFunctionCode,
format: SerializationFormats,
) -> Result<Vec<u8>, Error> {
Self {
serialization_info: SerializationInfo::new(
"KERI".to_string(),
1,
0,
format,
Self {
serialization_info: SerializationInfo::default(),
prefix: dummy_prefix(&derivation),
sn: 0,
data: data.clone(),
}
.encode()?
.len(),
),
prefix: dummy_prefix(&derivation),
sn: 0,
data,
}
.encode()
}
pub fn encode(&self) -> Result<Vec<u8>, Error> {
self.serialization_info
.serialize(&self)
.map_err(|e| Error::EncodingError(e.to_string()))
}
}
impl Inc {
pub fn incept_self_addressing(
self,
derivation: &said::derivation::HashFunction,
format: SerializationFormats,
) -> Result<ManagerTelEvent, Error> {
Ok(ManagerTelEvent::new(
&IdentifierPrefix::self_addressing(derivation.derive(
&DummyEvent::derive_inception_data(self.clone(), &derivation.into(), format)?,
)),
0,
ManagerEventType::Vcp(self),
))
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct Rot {
#[serde(rename = "p")]
pub prev_event: SelfAddressingIdentifier,
#[serde(rename = "ba")]
pub backers_to_add: Vec<IdentifierPrefix>,
#[serde(rename = "br")]
pub backers_to_remove: Vec<IdentifierPrefix>,
}
#[cfg(test)]
mod tests {
use keri_core::prefix::IdentifierPrefix;
use said::derivation::{HashFunction, HashFunctionCode};
use said::version::format::SerializationFormats;
use crate::{
error::Error,
event::manager_event::{
Config, Inc, ManagerEventType, ManagerTelEvent, ManagerTelEventMessage, Rot,
},
state::ManagerTelState,
};
#[test]
fn test_serialization() -> Result<(), keri_core::prefix::error::Error> {
let vcp_raw = r#"{"v":"KERI10JSON0000dc_","t":"vcp","d":"EIniznx8Vyltc0i-T7QwngvZkt_2xsT1PdsyRjq_1gAw","i":"EFohdnN33-vdNOTPYxeTQIWVzRKtzZzBoiBSGYSSnD0s","s":"0","ii":"DHtNTPnDFBnmlO6J44LXCrzZTAmpe-82b7BmQGtL4QhM","c":[],"bt":"1","b":[]}"#;
let vcp: ManagerTelEventMessage = serde_json::from_str(vcp_raw).unwrap();
assert_eq!(
vcp.data.prefix,
"EFohdnN33-vdNOTPYxeTQIWVzRKtzZzBoiBSGYSSnD0s".parse()?
);
assert_eq!(vcp.data.sn, 0);
let expected_event_type = ManagerEventType::Vcp(Inc {
issuer_id: "DHtNTPnDFBnmlO6J44LXCrzZTAmpe-82b7BmQGtL4QhM".parse()?,
config: vec![],
backer_threshold: 1,
backers: vec![],
});
assert_eq!(vcp.data.event_type, expected_event_type);
assert_eq!(String::from_utf8(vcp.encode().unwrap()).unwrap(), vcp_raw);
let vcp_raw = r#"{"v":"KERI10JSON0000e0_","t":"vcp","d":"EBK9Otzl6zxt55LF095coJH7EBqlPIdrDC0f8bjeZYC9","i":"EFohdnN33-vdNOTPYxeTQIWVzRKtzZzBoiBSGYSSnD0s","s":"0","ii":"DHtNTPnDFBnmlO6J44LXCrzZTAmpe-82b7BmQGtL4QhM","c":["NB"],"bt":"1","b":["EXvR3p8V95W8J7Ui4-mEzZ79S-A1esAnJo1Kmzq80Jkc"]}"#;
let vcp: ManagerTelEvent = serde_json::from_str(vcp_raw).unwrap();
assert_eq!(
vcp.prefix,
"EFohdnN33-vdNOTPYxeTQIWVzRKtzZzBoiBSGYSSnD0s".parse()?
);
assert_eq!(vcp.sn, 0);
let expected_event_type = ManagerEventType::Vcp(Inc {
issuer_id: "DHtNTPnDFBnmlO6J44LXCrzZTAmpe-82b7BmQGtL4QhM".parse()?,
config: vec![Config::NoBackers],
backer_threshold: 1,
backers: vec!["EXvR3p8V95W8J7Ui4-mEzZ79S-A1esAnJo1Kmzq80Jkc".parse()?],
});
assert_eq!(vcp.event_type, expected_event_type);
let vrt_raw = r#"{"v":"KERI10JSON000102_","t":"vrt","d":"EBt83eunp22Zingg0UXHKXddBLeYQSBovkbr5mtQnwmB","i":"EFohdnN33-vdNOTPYxeTQIWVzRKtzZzBoiBSGYSSnD0s","s":"1","p":"EIniznx8Vyltc0i-T7QwngvZkt_2xsT1PdsyRjq_1gAw","ba":["EHvR3p8V95W8J7Ui4-mEzZ79S-A1esAnJo1Kmzq80Jkc"],"br":[]}"#;
let vrt: ManagerTelEvent = serde_json::from_str(vrt_raw).unwrap();
assert_eq!(
vrt.prefix,
"EFohdnN33-vdNOTPYxeTQIWVzRKtzZzBoiBSGYSSnD0s".parse()?
);
assert_eq!(vrt.sn, 1);
let expected_event_type = ManagerEventType::Vrt(Rot {
prev_event: "EIniznx8Vyltc0i-T7QwngvZkt_2xsT1PdsyRjq_1gAw"
.parse()
.unwrap(),
backers_to_add: vec!["EHvR3p8V95W8J7Ui4-mEzZ79S-A1esAnJo1Kmzq80Jkc"
.parse()
.unwrap()],
backers_to_remove: vec![],
});
assert_eq!(vrt.event_type, expected_event_type);
Ok(())
}
#[test]
fn test_apply_to() -> Result<(), Error> {
let pref: IdentifierPrefix = "EVohdnN33-vdNOTPYxeTQIWVzRKtzZzBoiBSGYSSnD0s"
.parse()
.unwrap();
let issuer_pref: IdentifierPrefix = "DntNTPnDFBnmlO6J44LXCrzZTAmpe-82b7BmQGtL4QhM"
.parse()
.unwrap();
let event_type = ManagerEventType::Vcp(Inc {
issuer_id: issuer_pref.clone(),
config: vec![],
backer_threshold: 1,
backers: vec![],
});
let vcp = ManagerTelEvent::new(&pref, 0, event_type)
.to_message(SerializationFormats::JSON, HashFunctionCode::Blake3_256)?;
println!("\nvcp: {}", String::from_utf8(vcp.encode()?).unwrap());
let state = ManagerTelState::default();
let state = state.apply(&vcp)?;
assert_eq!(state.issuer, issuer_pref);
assert_eq!(state.backers.clone().unwrap(), vec![]);
let prev_event = vcp.digest()?;
let event_type = ManagerEventType::Vrt(Rot {
prev_event,
backers_to_add: vec!["EXvR3p8V95W8J7Ui4-mEzZ79S-A1esAnJo1Kmzq80Jkc"
.parse()
.unwrap()],
backers_to_remove: vec![],
});
let vrt = ManagerTelEvent::new(&pref, 1, event_type.clone()).to_message(
SerializationFormats::JSON,
HashFunctionCode::Blake3_256.into(),
)?;
println!("\nvrt: {}", String::from_utf8(vrt.encode()?).unwrap());
let state = state.apply(&vrt)?;
assert_eq!(state.backers.clone().unwrap().len(), 1);
assert_eq!(state.sn, 1);
let out_of_order_vrt = ManagerTelEvent::new(&pref, 10, event_type).to_message(
SerializationFormats::JSON,
HashFunctionCode::Blake3_256.into(),
)?;
let err_state = state.apply(&out_of_order_vrt);
assert!(err_state.is_err());
let prev_event =
HashFunction::from(HashFunctionCode::Blake3_256).derive("anything".as_bytes());
let event_type = ManagerEventType::Vrt(Rot {
prev_event,
backers_to_remove: vec![],
backers_to_add: vec![],
});
let bad_previous = ManagerTelEvent::new(&pref, 2, event_type)
.to_message(SerializationFormats::JSON, HashFunctionCode::Blake3_256)?;
let err_state = state.apply(&bad_previous);
assert!(err_state.is_err());
let prev_event = state.last.clone();
let event_type = ManagerEventType::Vrt(Rot {
prev_event,
backers_to_remove: vec!["EXvR3p8V95W8J7Ui4-mEzZ79S-A1esAnJo1Kmzq80Jkc"
.parse()
.unwrap()],
backers_to_add: vec![
"DSEpNJeSJjxo6oAxkNE8eCOJg2HRPstqkeHWBAvN9XNU"
.parse()
.unwrap(),
"Dvxo-P4W_Z0xXTfoA3_4DMPn7oi0mLCElOWJDpC0nQXw"
.parse()
.unwrap(),
],
});
let vrt = ManagerTelEvent::new(&pref, 2, event_type.clone())
.to_message(SerializationFormats::JSON, HashFunctionCode::Blake3_256)?;
let state = state.apply(&vrt)?;
assert_eq!(state.backers.clone().unwrap().len(), 2);
Ok(())
}
#[test]
fn test_no_backers() -> Result<(), Error> {
let pref: IdentifierPrefix = "EVohdnN33-vdNOTPYxeTQIWVzRKtzZzBoiBSGYSSnD0s"
.parse()
.unwrap();
let issuer_pref: IdentifierPrefix = "DntNTPnDFBnmlO6J44LXCrzZTAmpe-82b7BmQGtL4QhM"
.parse()
.unwrap();
let event_type = ManagerEventType::Vcp(Inc {
issuer_id: issuer_pref.clone(),
config: vec![Config::NoBackers],
backer_threshold: 1,
backers: vec![],
});
let vcp = ManagerTelEvent::new(&pref, 0, event_type)
.to_message(SerializationFormats::JSON, HashFunctionCode::Blake3_256)?;
println!("\nvcp: {}", String::from_utf8(vcp.encode()?).unwrap());
let state = ManagerTelState::default();
let state = state.apply(&vcp)?;
assert_eq!(state.issuer, issuer_pref);
assert_eq!(state.backers, None);
let prev_event = HashFunction::from(HashFunctionCode::Blake3_256).derive(&vcp.encode()?);
let event_type = ManagerEventType::Vrt(Rot {
prev_event,
backers_to_add: vec!["EXvR3p8V95W8J7Ui4-mEzZ79S-A1esAnJo1Kmzq80Jkc"
.parse()
.unwrap()],
backers_to_remove: vec![],
});
let vrt = ManagerTelEvent::new(&pref, 1, event_type.clone())
.to_message(SerializationFormats::JSON, HashFunctionCode::Blake3_256)?;
let state = state.apply(&vrt);
assert!(state.is_err());
Ok(())
}
}