tangle


git clone https://radroots.dev/git/tangle.git
Log | Files | Refs | README | LICENSE

lib.rs (98806B)


      1 #![forbid(unsafe_code)]
      2 
      3 use core::fmt;
      4 use core::str::FromStr;
      5 use serde::de::{self, Deserialize, Deserializer, MapAccess, SeqAccess, Visitor};
      6 use std::collections::BTreeMap;
      7 
      8 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
      9 pub struct EventId(String);
     10 
     11 impl EventId {
     12     pub const HEX_LENGTH: usize = 64;
     13 
     14     pub fn new(value: &str) -> Result<Self, String> {
     15         require_lowercase_hex("event id", value, Self::HEX_LENGTH)?;
     16         Ok(Self(value.to_owned()))
     17     }
     18 
     19     pub fn as_str(&self) -> &str {
     20         &self.0
     21     }
     22 }
     23 
     24 impl fmt::Display for EventId {
     25     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
     26         formatter.write_str(self.as_str())
     27     }
     28 }
     29 
     30 impl FromStr for EventId {
     31     type Err = String;
     32 
     33     fn from_str(value: &str) -> Result<Self, Self::Err> {
     34         Self::new(value)
     35     }
     36 }
     37 
     38 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
     39 pub struct PublicKeyHex(String);
     40 
     41 impl PublicKeyHex {
     42     pub const HEX_LENGTH: usize = 64;
     43 
     44     pub fn new(value: &str) -> Result<Self, String> {
     45         require_lowercase_hex("public key", value, Self::HEX_LENGTH)?;
     46         Ok(Self(value.to_owned()))
     47     }
     48 
     49     pub fn as_str(&self) -> &str {
     50         &self.0
     51     }
     52 }
     53 
     54 impl fmt::Display for PublicKeyHex {
     55     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
     56         formatter.write_str(self.as_str())
     57     }
     58 }
     59 
     60 impl FromStr for PublicKeyHex {
     61     type Err = String;
     62 
     63     fn from_str(value: &str) -> Result<Self, Self::Err> {
     64         Self::new(value)
     65     }
     66 }
     67 
     68 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
     69 pub struct SignatureHex(String);
     70 
     71 impl SignatureHex {
     72     pub const HEX_LENGTH: usize = 128;
     73 
     74     pub fn new(value: &str) -> Result<Self, String> {
     75         require_lowercase_hex("signature", value, Self::HEX_LENGTH)?;
     76         Ok(Self(value.to_owned()))
     77     }
     78 
     79     pub fn as_str(&self) -> &str {
     80         &self.0
     81     }
     82 }
     83 
     84 impl fmt::Display for SignatureHex {
     85     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
     86         formatter.write_str(self.as_str())
     87     }
     88 }
     89 
     90 impl FromStr for SignatureHex {
     91     type Err = String;
     92 
     93     fn from_str(value: &str) -> Result<Self, Self::Err> {
     94         Self::new(value)
     95     }
     96 }
     97 
     98 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
     99 pub struct SubscriptionId(String);
    100 
    101 impl SubscriptionId {
    102     pub const MAX_LENGTH: usize = 64;
    103 
    104     pub fn new(value: &str) -> Result<Self, String> {
    105         let actual = value.chars().count();
    106         if actual == 0 {
    107             return Err(empty_error("subscription id"));
    108         }
    109         if actual > Self::MAX_LENGTH {
    110             return Err(too_long_error("subscription id", Self::MAX_LENGTH, actual));
    111         }
    112         Ok(Self(value.to_owned()))
    113     }
    114 
    115     pub fn as_str(&self) -> &str {
    116         &self.0
    117     }
    118 }
    119 
    120 impl fmt::Display for SubscriptionId {
    121     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    122         formatter.write_str(self.as_str())
    123     }
    124 }
    125 
    126 impl FromStr for SubscriptionId {
    127     type Err = String;
    128 
    129     fn from_str(value: &str) -> Result<Self, Self::Err> {
    130         Self::new(value)
    131     }
    132 }
    133 
    134 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
    135 pub struct UnixTimestamp(u64);
    136 
    137 impl UnixTimestamp {
    138     pub fn new(value: u64) -> Self {
    139         Self(value)
    140     }
    141 
    142     pub fn as_u64(self) -> u64 {
    143         self.0
    144     }
    145 }
    146 
    147 impl fmt::Display for UnixTimestamp {
    148     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    149         write!(formatter, "{}", self.0)
    150     }
    151 }
    152 
    153 impl From<u64> for UnixTimestamp {
    154     fn from(value: u64) -> Self {
    155         Self::new(value)
    156     }
    157 }
    158 
    159 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
    160 pub struct Kind(u32);
    161 
    162 impl Kind {
    163     pub fn new(value: u64) -> Result<Self, String> {
    164         let value = u32::try_from(value).map_err(|_| kind_out_of_range_error(value))?;
    165         Ok(Self(value))
    166     }
    167 
    168     pub fn as_u32(self) -> u32 {
    169         self.0
    170     }
    171 
    172     pub fn class(self) -> KindClass {
    173         match self.0 {
    174             0 | 3 | 10_000..=19_999 => KindClass::Replaceable,
    175             20_000..=29_999 => KindClass::Ephemeral,
    176             30_000..=39_999 => KindClass::Addressable,
    177             _ => KindClass::Regular,
    178         }
    179     }
    180 
    181     pub fn is_regular(self) -> bool {
    182         self.class() == KindClass::Regular
    183     }
    184 
    185     pub fn is_replaceable(self) -> bool {
    186         self.class() == KindClass::Replaceable
    187     }
    188 
    189     pub fn is_ephemeral(self) -> bool {
    190         self.class() == KindClass::Ephemeral
    191     }
    192 
    193     pub fn is_addressable(self) -> bool {
    194         self.class() == KindClass::Addressable
    195     }
    196 }
    197 
    198 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
    199 pub enum KindClass {
    200     Regular,
    201     Replaceable,
    202     Ephemeral,
    203     Addressable,
    204 }
    205 
    206 impl fmt::Display for Kind {
    207     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    208         write!(formatter, "{}", self.0)
    209     }
    210 }
    211 
    212 impl TryFrom<u64> for Kind {
    213     type Error = String;
    214 
    215     fn try_from(value: u64) -> Result<Self, Self::Error> {
    216         Self::new(value)
    217     }
    218 }
    219 
    220 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
    221 pub struct Tag {
    222     values: Vec<String>,
    223 }
    224 
    225 impl Tag {
    226     pub fn new(values: Vec<String>) -> Result<Self, String> {
    227         let Some(name) = values.first() else {
    228             return Err(empty_error("tag"));
    229         };
    230         TagName::new(name)?;
    231         Ok(Self { values })
    232     }
    233 
    234     pub fn from_parts(name: &str, values: &[&str]) -> Result<Self, String> {
    235         let values = core::iter::once(name)
    236             .chain(values.iter().copied())
    237             .map(str::to_owned)
    238             .collect();
    239         Self::new(values)
    240     }
    241 
    242     pub fn name(&self) -> TagName {
    243         TagName(self.values[0].clone())
    244     }
    245 
    246     pub fn value(&self) -> Option<TagValue> {
    247         self.values.get(1).map(|value| TagValue(value.clone()))
    248     }
    249 
    250     pub fn values(&self) -> &[String] {
    251         &self.values
    252     }
    253 
    254     pub fn indexed_pair(&self) -> Option<(&str, &str)> {
    255         let name = self.values[0].as_str();
    256         if !TagName::is_indexable_name(name) {
    257             return None;
    258         }
    259         self.values.get(1).map(|value| (name, value.as_str()))
    260     }
    261 }
    262 
    263 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    264 pub struct TagName(String);
    265 
    266 impl TagName {
    267     pub fn new(value: &str) -> Result<Self, String> {
    268         if value.is_empty() {
    269             return Err(empty_error("tag name"));
    270         }
    271         Ok(Self(value.to_owned()))
    272     }
    273 
    274     pub fn as_str(&self) -> &str {
    275         &self.0
    276     }
    277 
    278     pub fn is_indexable(&self) -> bool {
    279         Self::is_indexable_name(self.as_str())
    280     }
    281 
    282     pub fn is_indexable_name(value: &str) -> bool {
    283         let mut bytes = value.bytes();
    284         let Some(byte) = bytes.next() else {
    285             return false;
    286         };
    287         bytes.next().is_none() && byte.is_ascii_alphabetic()
    288     }
    289 }
    290 
    291 impl fmt::Display for TagName {
    292     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    293         formatter.write_str(self.as_str())
    294     }
    295 }
    296 
    297 impl FromStr for TagName {
    298     type Err = String;
    299 
    300     fn from_str(value: &str) -> Result<Self, Self::Err> {
    301         Self::new(value)
    302     }
    303 }
    304 
    305 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    306 pub struct TagValue(String);
    307 
    308 impl TagValue {
    309     pub fn new(value: &str) -> Self {
    310         Self(value.to_owned())
    311     }
    312 
    313     pub fn as_str(&self) -> &str {
    314         &self.0
    315     }
    316 }
    317 
    318 impl fmt::Display for TagValue {
    319     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    320         formatter.write_str(self.as_str())
    321     }
    322 }
    323 
    324 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    325 pub struct DTag(String);
    326 
    327 impl DTag {
    328     pub fn new(value: &str) -> Self {
    329         Self(value.to_owned())
    330     }
    331 
    332     pub fn as_str(&self) -> &str {
    333         &self.0
    334     }
    335 }
    336 
    337 impl fmt::Display for DTag {
    338     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    339         formatter.write_str(self.as_str())
    340     }
    341 }
    342 
    343 impl FromStr for DTag {
    344     type Err = String;
    345 
    346     fn from_str(value: &str) -> Result<Self, Self::Err> {
    347         Ok(Self::new(value))
    348     }
    349 }
    350 
    351 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    352 pub struct AddressKey(String);
    353 
    354 impl AddressKey {
    355     pub fn as_str(&self) -> &str {
    356         &self.0
    357     }
    358 }
    359 
    360 impl fmt::Display for AddressKey {
    361     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    362         formatter.write_str(self.as_str())
    363     }
    364 }
    365 
    366 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    367 pub struct AddressCoordinate {
    368     kind: Kind,
    369     pubkey: PublicKeyHex,
    370     d: DTag,
    371 }
    372 
    373 impl AddressCoordinate {
    374     pub fn new(kind: Kind, pubkey: PublicKeyHex, d: DTag) -> Result<Self, String> {
    375         if !kind.is_addressable() {
    376             return Err(format!(
    377                 "address coordinate kind must be addressable, got {}",
    378                 kind.as_u32()
    379             ));
    380         }
    381         Ok(Self { kind, pubkey, d })
    382     }
    383 
    384     pub fn from_event(event: &Event) -> Result<Option<Self>, String> {
    385         let kind = event.unsigned().kind();
    386         if !kind.is_addressable() {
    387             return Ok(None);
    388         }
    389         let d = event
    390             .unsigned()
    391             .tags()
    392             .iter()
    393             .find_map(|tag| {
    394                 tag.indexed_pair().and_then(|(name, value)| {
    395                     if name == "d" {
    396                         Some(DTag::new(value))
    397                     } else {
    398                         None
    399                     }
    400                 })
    401             })
    402             .ok_or_else(|| "addressable event must include a d tag".to_owned())?;
    403         Self::new(kind, event.unsigned().pubkey().clone(), d).map(Some)
    404     }
    405 
    406     pub fn kind(&self) -> Kind {
    407         self.kind
    408     }
    409 
    410     pub fn pubkey(&self) -> &PublicKeyHex {
    411         &self.pubkey
    412     }
    413 
    414     pub fn d(&self) -> &DTag {
    415         &self.d
    416     }
    417 
    418     pub fn key(&self) -> AddressKey {
    419         AddressKey(self.to_string())
    420     }
    421 }
    422 
    423 impl fmt::Display for AddressCoordinate {
    424     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    425         write!(
    426             formatter,
    427             "{}:{}:{}",
    428             self.kind.as_u32(),
    429             self.pubkey.as_str(),
    430             self.d.as_str()
    431         )
    432     }
    433 }
    434 
    435 impl FromStr for AddressCoordinate {
    436     type Err = String;
    437 
    438     fn from_str(value: &str) -> Result<Self, Self::Err> {
    439         let mut parts = value.splitn(3, ':');
    440         let kind = parts
    441             .next()
    442             .unwrap_or_default()
    443             .parse::<u64>()
    444             .map_err(|_| "address coordinate kind must be an unsigned integer".to_owned())
    445             .and_then(Kind::new)?;
    446         let pubkey = parts
    447             .next()
    448             .ok_or_else(|| "address coordinate pubkey is missing".to_owned())
    449             .and_then(PublicKeyHex::new)?;
    450         let d = parts
    451             .next()
    452             .ok_or_else(|| "address coordinate d tag is missing".to_owned())
    453             .map(DTag::new)?;
    454         Self::new(kind, pubkey, d)
    455     }
    456 }
    457 
    458 #[derive(Debug, Clone, PartialEq, Eq)]
    459 pub struct UnsignedEvent {
    460     pubkey: PublicKeyHex,
    461     created_at: UnixTimestamp,
    462     kind: Kind,
    463     tags: Vec<Tag>,
    464     content: String,
    465 }
    466 
    467 impl UnsignedEvent {
    468     pub fn new(
    469         pubkey: PublicKeyHex,
    470         created_at: UnixTimestamp,
    471         kind: Kind,
    472         tags: Vec<Tag>,
    473         content: &str,
    474     ) -> Self {
    475         Self {
    476             pubkey,
    477             created_at,
    478             kind,
    479             tags,
    480             content: content.to_owned(),
    481         }
    482     }
    483 
    484     pub fn pubkey(&self) -> &PublicKeyHex {
    485         &self.pubkey
    486     }
    487 
    488     pub fn created_at(&self) -> UnixTimestamp {
    489         self.created_at
    490     }
    491 
    492     pub fn kind(&self) -> Kind {
    493         self.kind
    494     }
    495 
    496     pub fn tags(&self) -> &[Tag] {
    497         &self.tags
    498     }
    499 
    500     pub fn content(&self) -> &str {
    501         &self.content
    502     }
    503 }
    504 
    505 #[derive(Debug, Clone, PartialEq, Eq)]
    506 pub struct Event {
    507     id: EventId,
    508     unsigned: UnsignedEvent,
    509     sig: SignatureHex,
    510 }
    511 
    512 impl Event {
    513     pub fn new(id: EventId, unsigned: UnsignedEvent, sig: SignatureHex) -> Self {
    514         Self { id, unsigned, sig }
    515     }
    516 
    517     pub fn id(&self) -> &EventId {
    518         &self.id
    519     }
    520 
    521     pub fn unsigned(&self) -> &UnsignedEvent {
    522         &self.unsigned
    523     }
    524 
    525     pub fn sig(&self) -> &SignatureHex {
    526         &self.sig
    527     }
    528 }
    529 
    530 #[derive(Debug, Clone, PartialEq, Eq)]
    531 pub struct RawEventJson(String);
    532 
    533 impl RawEventJson {
    534     pub fn new(value: &str) -> Result<Self, EventShapeError> {
    535         if value.is_empty() {
    536             return Err(EventShapeError::empty_raw_json());
    537         }
    538         Ok(Self(value.to_owned()))
    539     }
    540 
    541     pub fn as_str(&self) -> &str {
    542         &self.0
    543     }
    544 
    545     pub fn into_string(self) -> String {
    546         self.0
    547     }
    548 }
    549 
    550 pub struct EventShapeError {
    551     message: String,
    552 }
    553 
    554 impl EventShapeError {
    555     pub fn missing_field(field: &'static str) -> Self {
    556         Self {
    557             message: format!("event field `{field}` is missing"),
    558         }
    559     }
    560 
    561     pub fn invalid_field(field: &'static str, reason: &str) -> Self {
    562         Self {
    563             message: format!("event field `{field}` is invalid: {reason}"),
    564         }
    565     }
    566 
    567     fn empty_raw_json() -> Self {
    568         Self {
    569             message: "raw event JSON must not be empty".to_owned(),
    570         }
    571     }
    572 }
    573 
    574 impl fmt::Display for EventShapeError {
    575     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    576         formatter.write_str(&self.message)
    577     }
    578 }
    579 
    580 impl fmt::Debug for EventShapeError {
    581     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    582         formatter
    583             .debug_struct("EventShapeError")
    584             .field("message", &self.message)
    585             .finish()
    586     }
    587 }
    588 
    589 impl std::error::Error for EventShapeError {}
    590 
    591 pub fn canonical_event_json(event: &UnsignedEvent) -> String {
    592     let tags: Vec<serde_json::Value> = event
    593         .tags()
    594         .iter()
    595         .map(|tag| {
    596             serde_json::Value::Array(
    597                 tag.values()
    598                     .iter()
    599                     .map(|value| serde_json::Value::String(value.clone()))
    600                     .collect(),
    601             )
    602         })
    603         .collect();
    604     serde_json::json!([
    605         0,
    606         event.pubkey().as_str(),
    607         event.created_at().as_u64(),
    608         event.kind().as_u32(),
    609         tags,
    610         event.content()
    611     ])
    612     .to_string()
    613 }
    614 
    615 impl UnsignedEvent {
    616     pub fn canonical_json(&self) -> String {
    617         canonical_event_json(self)
    618     }
    619 }
    620 
    621 #[derive(Debug, Clone, PartialEq)]
    622 pub enum ClientMessage {
    623     Event(Event),
    624     Req {
    625         subscription_id: SubscriptionId,
    626         filters: Vec<Filter>,
    627     },
    628     Count {
    629         subscription_id: SubscriptionId,
    630         filters: Vec<Filter>,
    631     },
    632     Close(SubscriptionId),
    633     Auth(Event),
    634     NegOpen {
    635         subscription_id: SubscriptionId,
    636         filter: Filter,
    637         message: String,
    638     },
    639     NegMsg {
    640         subscription_id: SubscriptionId,
    641         message: String,
    642     },
    643     NegClose(SubscriptionId),
    644 }
    645 
    646 #[derive(Debug, Clone, PartialEq, Eq)]
    647 pub struct Filter {
    648     ids: Vec<EventId>,
    649     authors: Vec<PublicKeyHex>,
    650     kinds: Vec<Kind>,
    651     tag_filters: BTreeMap<TagName, Vec<TagValue>>,
    652     since: Option<UnixTimestamp>,
    653     until: Option<UnixTimestamp>,
    654     limit: Option<u64>,
    655     search: Option<String>,
    656 }
    657 
    658 impl Filter {
    659     pub fn empty() -> Self {
    660         Self {
    661             ids: Vec::new(),
    662             authors: Vec::new(),
    663             kinds: Vec::new(),
    664             tag_filters: BTreeMap::new(),
    665             since: None,
    666             until: None,
    667             limit: None,
    668             search: None,
    669         }
    670     }
    671 
    672     #[allow(clippy::too_many_arguments)]
    673     pub fn from_parts(
    674         ids: Vec<EventId>,
    675         authors: Vec<PublicKeyHex>,
    676         kinds: Vec<Kind>,
    677         tag_filters: BTreeMap<TagName, Vec<TagValue>>,
    678         since: Option<UnixTimestamp>,
    679         until: Option<UnixTimestamp>,
    680         limit: Option<u64>,
    681         search: Option<String>,
    682     ) -> Result<Self, String> {
    683         for (name, values) in &tag_filters {
    684             if !name.is_indexable() {
    685                 return Err(format!(
    686                     "filter field `#{}` is invalid: tag name must be a single ASCII letter",
    687                     name.as_str()
    688                 ));
    689             }
    690             if values.is_empty() {
    691                 return Err(filter_array_error(&format!("#{}", name.as_str())));
    692             }
    693         }
    694         Ok(Self {
    695             ids,
    696             authors,
    697             kinds,
    698             tag_filters,
    699             since,
    700             until,
    701             limit,
    702             search,
    703         })
    704     }
    705 
    706     pub fn ids(&self) -> &[EventId] {
    707         &self.ids
    708     }
    709 
    710     pub fn authors(&self) -> &[PublicKeyHex] {
    711         &self.authors
    712     }
    713 
    714     pub fn kinds(&self) -> &[Kind] {
    715         &self.kinds
    716     }
    717 
    718     pub fn tag_filters(&self) -> &BTreeMap<TagName, Vec<TagValue>> {
    719         &self.tag_filters
    720     }
    721 
    722     pub fn since(&self) -> Option<UnixTimestamp> {
    723         self.since
    724     }
    725 
    726     pub fn until(&self) -> Option<UnixTimestamp> {
    727         self.until
    728     }
    729 
    730     pub fn limit(&self) -> Option<u64> {
    731         self.limit
    732     }
    733 
    734     pub fn without_limit(&self) -> Self {
    735         let mut filter = self.clone();
    736         filter.limit = None;
    737         filter
    738     }
    739 
    740     pub fn with_limit(&self, limit: u64) -> Self {
    741         let mut filter = self.clone();
    742         filter.limit = Some(limit);
    743         filter
    744     }
    745 
    746     pub fn search(&self) -> Option<&str> {
    747         self.search.as_deref()
    748     }
    749 
    750     pub fn is_complete(&self) -> bool {
    751         !self.ids.is_empty()
    752     }
    753 
    754     pub fn matches(&self, event: &Event) -> bool {
    755         if !self.ids.is_empty() && !self.ids.iter().any(|id| id == event.id()) {
    756             return false;
    757         }
    758         if !self.authors.is_empty()
    759             && !self
    760                 .authors
    761                 .iter()
    762                 .any(|author| author == event.unsigned().pubkey())
    763         {
    764             return false;
    765         }
    766         if !self.kinds.is_empty()
    767             && !self
    768                 .kinds
    769                 .iter()
    770                 .any(|kind| *kind == event.unsigned().kind())
    771         {
    772             return false;
    773         }
    774         if let Some(since) = self.since
    775             && event.unsigned().created_at().as_u64() < since.as_u64()
    776         {
    777             return false;
    778         }
    779         if let Some(until) = self.until
    780             && event.unsigned().created_at().as_u64() > until.as_u64()
    781         {
    782             return false;
    783         }
    784         for (name, values) in &self.tag_filters {
    785             let matched = event.unsigned().tags().iter().any(|tag| {
    786                 tag.indexed_pair().is_some_and(|(tag_name, tag_value)| {
    787                     tag_name == name.as_str()
    788                         && values.iter().any(|value| value.as_str() == tag_value)
    789                 })
    790             });
    791             if !matched {
    792                 return false;
    793             }
    794         }
    795         true
    796     }
    797 }
    798 
    799 #[derive(Debug, Clone, PartialEq)]
    800 pub enum RelayMessage {
    801     Event {
    802         subscription_id: SubscriptionId,
    803         event: Event,
    804     },
    805     Ok {
    806         event_id: EventId,
    807         accepted: bool,
    808         message: String,
    809     },
    810     Eose(SubscriptionId),
    811     Closed {
    812         subscription_id: SubscriptionId,
    813         message: String,
    814     },
    815     Count {
    816         subscription_id: SubscriptionId,
    817         count: u64,
    818         hll: Option<String>,
    819     },
    820     Notice(String),
    821     Auth(String),
    822     NegErr {
    823         subscription_id: SubscriptionId,
    824         message: String,
    825     },
    826     NegMsg {
    827         subscription_id: SubscriptionId,
    828         message: String,
    829     },
    830 }
    831 
    832 impl RelayMessage {
    833     pub fn encode(&self) -> String {
    834         encode_relay_message(self)
    835     }
    836 }
    837 
    838 pub fn encode_relay_message(message: &RelayMessage) -> String {
    839     relay_message_to_value(message).to_string()
    840 }
    841 
    842 pub fn relay_message_to_value(message: &RelayMessage) -> serde_json::Value {
    843     match message {
    844         RelayMessage::Event {
    845             subscription_id,
    846             event,
    847         } => serde_json::json!(["EVENT", subscription_id.as_str(), event_to_value(event)]),
    848         RelayMessage::Ok {
    849             event_id,
    850             accepted,
    851             message,
    852         } => serde_json::json!(["OK", event_id.as_str(), accepted, message]),
    853         RelayMessage::Eose(subscription_id) => {
    854             serde_json::json!(["EOSE", subscription_id.as_str()])
    855         }
    856         RelayMessage::Closed {
    857             subscription_id,
    858             message,
    859         } => serde_json::json!(["CLOSED", subscription_id.as_str(), message]),
    860         RelayMessage::Count {
    861             subscription_id,
    862             count,
    863             hll,
    864         } => {
    865             let mut payload = serde_json::Map::new();
    866             payload.insert(
    867                 "count".to_owned(),
    868                 serde_json::Value::Number((*count).into()),
    869             );
    870             if let Some(hll) = hll {
    871                 payload.insert("hll".to_owned(), serde_json::Value::String(hll.clone()));
    872             }
    873             serde_json::json!(["COUNT", subscription_id.as_str(), payload])
    874         }
    875         RelayMessage::Notice(message) => serde_json::json!(["NOTICE", message]),
    876         RelayMessage::Auth(challenge) => serde_json::json!(["AUTH", challenge]),
    877         RelayMessage::NegErr {
    878             subscription_id,
    879             message,
    880         } => serde_json::json!(["NEG-ERR", subscription_id.as_str(), message]),
    881         RelayMessage::NegMsg {
    882             subscription_id,
    883             message,
    884         } => serde_json::json!(["NEG-MSG", subscription_id.as_str(), message]),
    885     }
    886 }
    887 
    888 pub fn event_to_value(event: &Event) -> serde_json::Value {
    889     let tags = event
    890         .unsigned()
    891         .tags()
    892         .iter()
    893         .map(|tag| {
    894             serde_json::Value::Array(
    895                 tag.values()
    896                     .iter()
    897                     .map(|value| serde_json::Value::String(value.clone()))
    898                     .collect(),
    899             )
    900         })
    901         .collect::<Vec<_>>();
    902     serde_json::json!({
    903         "id": event.id().as_str(),
    904         "pubkey": event.unsigned().pubkey().as_str(),
    905         "created_at": event.unsigned().created_at().as_u64(),
    906         "kind": event.unsigned().kind().as_u32(),
    907         "tags": tags,
    908         "content": event.unsigned().content(),
    909         "sig": event.sig().as_str()
    910     })
    911 }
    912 
    913 pub fn filter_to_value(filter: &Filter) -> serde_json::Value {
    914     let mut object = serde_json::Map::new();
    915     if !filter.ids().is_empty() {
    916         object.insert(
    917             "ids".to_owned(),
    918             serde_json::Value::Array(
    919                 filter
    920                     .ids()
    921                     .iter()
    922                     .map(|id| serde_json::Value::String(id.as_str().to_owned()))
    923                     .collect(),
    924             ),
    925         );
    926     }
    927     if !filter.authors().is_empty() {
    928         object.insert(
    929             "authors".to_owned(),
    930             serde_json::Value::Array(
    931                 filter
    932                     .authors()
    933                     .iter()
    934                     .map(|author| serde_json::Value::String(author.as_str().to_owned()))
    935                     .collect(),
    936             ),
    937         );
    938     }
    939     if !filter.kinds().is_empty() {
    940         object.insert(
    941             "kinds".to_owned(),
    942             serde_json::Value::Array(
    943                 filter
    944                     .kinds()
    945                     .iter()
    946                     .map(|kind| serde_json::Value::Number(kind.as_u32().into()))
    947                     .collect(),
    948             ),
    949         );
    950     }
    951     for (name, values) in filter.tag_filters() {
    952         object.insert(
    953             format!("#{}", name.as_str()),
    954             serde_json::Value::Array(
    955                 values
    956                     .iter()
    957                     .map(|value| serde_json::Value::String(value.as_str().to_owned()))
    958                     .collect(),
    959             ),
    960         );
    961     }
    962     if let Some(since) = filter.since() {
    963         object.insert(
    964             "since".to_owned(),
    965             serde_json::Value::Number(since.as_u64().into()),
    966         );
    967     }
    968     if let Some(until) = filter.until() {
    969         object.insert(
    970             "until".to_owned(),
    971             serde_json::Value::Number(until.as_u64().into()),
    972         );
    973     }
    974     if let Some(limit) = filter.limit() {
    975         object.insert("limit".to_owned(), serde_json::Value::Number(limit.into()));
    976     }
    977     if let Some(search) = filter.search() {
    978         object.insert(
    979             "search".to_owned(),
    980             serde_json::Value::String(search.to_owned()),
    981         );
    982     }
    983     serde_json::Value::Object(object)
    984 }
    985 
    986 pub fn filter_from_value(value: &serde_json::Value) -> Result<Filter, String> {
    987     let object = value
    988         .as_object()
    989         .ok_or_else(|| "filter must be a JSON object".to_owned())?;
    990     let mut filter = Filter::empty();
    991     for (field, raw) in object {
    992         match field.as_str() {
    993             "ids" => filter.ids = parse_event_id_filter_array(field, raw)?,
    994             "authors" => filter.authors = parse_pubkey_filter_array(field, raw)?,
    995             "kinds" => filter.kinds = parse_kind_filter_array(field, raw)?,
    996             "since" => filter.since = Some(UnixTimestamp::new(parse_u64_filter_field(field, raw)?)),
    997             "until" => filter.until = Some(UnixTimestamp::new(parse_u64_filter_field(field, raw)?)),
    998             "limit" => filter.limit = Some(parse_u64_filter_field(field, raw)?),
    999             "search" => filter.search = Some(parse_string_filter_field(field, raw)?.to_owned()),
   1000             tag_field if tag_field.starts_with('#') => {
   1001                 let (name, values) = parse_tag_filter_field(tag_field, raw)?;
   1002                 filter.tag_filters.insert(name, values);
   1003             }
   1004             unsupported => return Err(format!("filter field `{unsupported}` is unsupported")),
   1005         }
   1006     }
   1007     Ok(filter)
   1008 }
   1009 
   1010 pub fn parse_client_message(raw: &str) -> Result<ClientMessage, String> {
   1011     let value = json_value_without_duplicate_fields(raw)
   1012         .map_err(|source| format!("client message JSON is invalid: {source}"))?;
   1013     let array = value
   1014         .as_array()
   1015         .ok_or_else(|| "client message must be an array".to_owned())?;
   1016     let command_value = array
   1017         .first()
   1018         .ok_or_else(|| "client message command is missing".to_owned())?;
   1019     let command = command_value
   1020         .as_str()
   1021         .ok_or_else(|| "client message command must be a string".to_owned())?;
   1022     match command {
   1023         "EVENT" => parse_event_client_message(array),
   1024         "REQ" => parse_req_client_message(array),
   1025         "COUNT" => parse_count_client_message(array),
   1026         "CLOSE" => parse_close_client_message(array),
   1027         "AUTH" => parse_auth_client_message(array),
   1028         unsupported => Err(format!(
   1029             "client message command `{unsupported}` is unsupported"
   1030         )),
   1031     }
   1032 }
   1033 
   1034 pub fn parse_event_json(raw: &RawEventJson) -> Result<Event, EventShapeError> {
   1035     let value = json_value_without_duplicate_fields(raw.as_str()).map_err(|source| {
   1036         EventShapeError::invalid_field("event", &format!("invalid JSON: {source}"))
   1037     })?;
   1038     event_from_value(&value)
   1039 }
   1040 
   1041 fn json_value_without_duplicate_fields(raw: &str) -> Result<serde_json::Value, serde_json::Error> {
   1042     let mut deserializer = serde_json::Deserializer::from_str(raw);
   1043     let value = UniqueJsonValue::deserialize(&mut deserializer)?.0;
   1044     deserializer.end()?;
   1045     Ok(value)
   1046 }
   1047 
   1048 struct UniqueJsonValue(serde_json::Value);
   1049 
   1050 impl<'de> Deserialize<'de> for UniqueJsonValue {
   1051     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
   1052     where
   1053         D: Deserializer<'de>,
   1054     {
   1055         deserializer
   1056             .deserialize_any(UniqueJsonValueVisitor)
   1057             .map(Self)
   1058     }
   1059 }
   1060 
   1061 struct UniqueJsonValueVisitor;
   1062 
   1063 impl<'de> Visitor<'de> for UniqueJsonValueVisitor {
   1064     type Value = serde_json::Value;
   1065 
   1066     fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
   1067         formatter.write_str("a JSON value without duplicate object fields")
   1068     }
   1069 
   1070     fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E> {
   1071         Ok(serde_json::Value::Bool(value))
   1072     }
   1073 
   1074     fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E> {
   1075         Ok(serde_json::Value::Number(value.into()))
   1076     }
   1077 
   1078     fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E> {
   1079         Ok(serde_json::Value::Number(value.into()))
   1080     }
   1081 
   1082     fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E>
   1083     where
   1084         E: de::Error,
   1085     {
   1086         serde_json::Number::from_f64(value)
   1087             .map(serde_json::Value::Number)
   1088             .ok_or_else(|| E::custom("JSON number must be finite"))
   1089     }
   1090 
   1091     fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> {
   1092         Ok(serde_json::Value::String(value.to_owned()))
   1093     }
   1094 
   1095     fn visit_borrowed_str<E>(self, value: &'de str) -> Result<Self::Value, E> {
   1096         Ok(serde_json::Value::String(value.to_owned()))
   1097     }
   1098 
   1099     fn visit_string<E>(self, value: String) -> Result<Self::Value, E> {
   1100         Ok(serde_json::Value::String(value))
   1101     }
   1102 
   1103     fn visit_none<E>(self) -> Result<Self::Value, E> {
   1104         Ok(serde_json::Value::Null)
   1105     }
   1106 
   1107     fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
   1108     where
   1109         D: Deserializer<'de>,
   1110     {
   1111         UniqueJsonValue::deserialize(deserializer).map(|value| value.0)
   1112     }
   1113 
   1114     fn visit_unit<E>(self) -> Result<Self::Value, E> {
   1115         Ok(serde_json::Value::Null)
   1116     }
   1117 
   1118     fn visit_seq<A>(self, mut sequence: A) -> Result<Self::Value, A::Error>
   1119     where
   1120         A: SeqAccess<'de>,
   1121     {
   1122         let mut values = Vec::new();
   1123         while let Some(value) = sequence.next_element::<UniqueJsonValue>()? {
   1124             values.push(value.0);
   1125         }
   1126         Ok(serde_json::Value::Array(values))
   1127     }
   1128 
   1129     fn visit_map<A>(self, mut object: A) -> Result<Self::Value, A::Error>
   1130     where
   1131         A: MapAccess<'de>,
   1132     {
   1133         let mut values = serde_json::Map::new();
   1134         while let Some(field) = object.next_key::<String>()? {
   1135             if values.contains_key(&field) {
   1136                 return Err(de::Error::custom(format!(
   1137                     "duplicate object field `{field}`"
   1138                 )));
   1139             }
   1140             let value = object.next_value::<UniqueJsonValue>()?;
   1141             values.insert(field, value.0);
   1142         }
   1143         Ok(serde_json::Value::Object(values))
   1144     }
   1145 }
   1146 
   1147 pub fn event_from_value(value: &serde_json::Value) -> Result<Event, EventShapeError> {
   1148     let object = value
   1149         .as_object()
   1150         .ok_or_else(|| EventShapeError::invalid_field("event", "must be an object"))?;
   1151     let id = EventId::new(field_string(object, "id")?)
   1152         .map_err(|reason| EventShapeError::invalid_field("id", &reason))?;
   1153     let pubkey = PublicKeyHex::new(field_string(object, "pubkey")?)
   1154         .map_err(|reason| EventShapeError::invalid_field("pubkey", &reason))?;
   1155     let created_at = UnixTimestamp::new(field_u64(object, "created_at")?);
   1156     let kind = Kind::new(field_u64(object, "kind")?)
   1157         .map_err(|reason| EventShapeError::invalid_field("kind", &reason))?;
   1158     let tags = tags_from_value(field_value(object, "tags")?)?;
   1159     let content = field_string(object, "content")?;
   1160     let sig = SignatureHex::new(field_string(object, "sig")?)
   1161         .map_err(|reason| EventShapeError::invalid_field("sig", &reason))?;
   1162     Ok(Event::new(
   1163         id,
   1164         UnsignedEvent::new(pubkey, created_at, kind, tags, content),
   1165         sig,
   1166     ))
   1167 }
   1168 
   1169 fn parse_event_client_message(array: &[serde_json::Value]) -> Result<ClientMessage, String> {
   1170     if array.len() != 2 {
   1171         return Err("EVENT client message must contain exactly 2 elements".to_owned());
   1172     }
   1173     event_from_value(&array[1])
   1174         .map(ClientMessage::Event)
   1175         .map_err(|source| source.to_string())
   1176 }
   1177 
   1178 fn parse_auth_client_message(array: &[serde_json::Value]) -> Result<ClientMessage, String> {
   1179     if array.len() != 2 {
   1180         return Err("AUTH client message must contain exactly 2 elements".to_owned());
   1181     }
   1182     event_from_value(&array[1])
   1183         .map(ClientMessage::Auth)
   1184         .map_err(|source| source.to_string())
   1185 }
   1186 
   1187 fn parse_req_client_message(array: &[serde_json::Value]) -> Result<ClientMessage, String> {
   1188     if array.len() < 3 {
   1189         return Err("REQ client message must contain a subscription id and filters".to_owned());
   1190     }
   1191     let subscription_id = array[1]
   1192         .as_str()
   1193         .ok_or_else(|| "REQ subscription id must be a string".to_owned())
   1194         .and_then(SubscriptionId::new)?;
   1195     let filters = array[2..]
   1196         .iter()
   1197         .map(filter_from_value)
   1198         .collect::<Result<Vec<_>, _>>()?;
   1199     Ok(ClientMessage::Req {
   1200         subscription_id,
   1201         filters,
   1202     })
   1203 }
   1204 
   1205 fn parse_count_client_message(array: &[serde_json::Value]) -> Result<ClientMessage, String> {
   1206     if array.len() < 3 {
   1207         return Err("COUNT client message must contain a subscription id and filters".to_owned());
   1208     }
   1209     let subscription_id = array[1]
   1210         .as_str()
   1211         .ok_or_else(|| "COUNT subscription id must be a string".to_owned())
   1212         .and_then(SubscriptionId::new)?;
   1213     let filters = array[2..]
   1214         .iter()
   1215         .map(filter_from_value)
   1216         .collect::<Result<Vec<_>, _>>()?;
   1217     Ok(ClientMessage::Count {
   1218         subscription_id,
   1219         filters,
   1220     })
   1221 }
   1222 
   1223 fn parse_close_client_message(array: &[serde_json::Value]) -> Result<ClientMessage, String> {
   1224     if array.len() != 2 {
   1225         return Err("CLOSE client message must contain exactly 2 elements".to_owned());
   1226     }
   1227     array[1]
   1228         .as_str()
   1229         .ok_or_else(|| "CLOSE subscription id must be a string".to_owned())
   1230         .and_then(SubscriptionId::new)
   1231         .map(ClientMessage::Close)
   1232 }
   1233 
   1234 fn field_value<'a>(
   1235     object: &'a serde_json::Map<String, serde_json::Value>,
   1236     field: &'static str,
   1237 ) -> Result<&'a serde_json::Value, EventShapeError> {
   1238     object
   1239         .get(field)
   1240         .ok_or_else(|| EventShapeError::missing_field(field))
   1241 }
   1242 
   1243 fn field_string<'a>(
   1244     object: &'a serde_json::Map<String, serde_json::Value>,
   1245     field: &'static str,
   1246 ) -> Result<&'a str, EventShapeError> {
   1247     field_value(object, field)?
   1248         .as_str()
   1249         .ok_or_else(|| EventShapeError::invalid_field(field, "must be a string"))
   1250 }
   1251 
   1252 fn field_u64(
   1253     object: &serde_json::Map<String, serde_json::Value>,
   1254     field: &'static str,
   1255 ) -> Result<u64, EventShapeError> {
   1256     field_value(object, field)?
   1257         .as_u64()
   1258         .ok_or_else(|| EventShapeError::invalid_field(field, "must be an unsigned integer"))
   1259 }
   1260 
   1261 fn tags_from_value(value: &serde_json::Value) -> Result<Vec<Tag>, EventShapeError> {
   1262     let array = value
   1263         .as_array()
   1264         .ok_or_else(|| EventShapeError::invalid_field("tags", "must be an array"))?;
   1265     array
   1266         .iter()
   1267         .map(|tag| {
   1268             let values = tag
   1269                 .as_array()
   1270                 .ok_or_else(|| EventShapeError::invalid_field("tags", "tag must be an array"))?
   1271                 .iter()
   1272                 .map(|part| {
   1273                     part.as_str().map(str::to_owned).ok_or_else(|| {
   1274                         EventShapeError::invalid_field("tags", "tag elements must be strings")
   1275                     })
   1276                 })
   1277                 .collect::<Result<Vec<_>, _>>()?;
   1278             Tag::new(values).map_err(|reason| EventShapeError::invalid_field("tags", &reason))
   1279         })
   1280         .collect()
   1281 }
   1282 
   1283 fn parse_event_id_filter_array(
   1284     field: &str,
   1285     value: &serde_json::Value,
   1286 ) -> Result<Vec<EventId>, String> {
   1287     parse_string_filter_array(field, value, |item| {
   1288         EventId::new(item).map_err(|reason| format!("filter field `{field}` is invalid: {reason}"))
   1289     })
   1290 }
   1291 
   1292 fn parse_pubkey_filter_array(
   1293     field: &str,
   1294     value: &serde_json::Value,
   1295 ) -> Result<Vec<PublicKeyHex>, String> {
   1296     parse_string_filter_array(field, value, |item| {
   1297         PublicKeyHex::new(item)
   1298             .map_err(|reason| format!("filter field `{field}` is invalid: {reason}"))
   1299     })
   1300 }
   1301 
   1302 fn parse_kind_filter_array(field: &str, value: &serde_json::Value) -> Result<Vec<Kind>, String> {
   1303     parse_u64_filter_array(field, value, |item| {
   1304         Kind::new(item).map_err(|reason| format!("filter field `{field}` is invalid: {reason}"))
   1305     })
   1306 }
   1307 
   1308 fn parse_tag_filter_field(
   1309     field: &str,
   1310     value: &serde_json::Value,
   1311 ) -> Result<(TagName, Vec<TagValue>), String> {
   1312     let name = &field[1..];
   1313     let tag_name = TagName::new(name)
   1314         .map_err(|reason| format!("filter field `{field}` is invalid: {reason}"))?;
   1315     if !tag_name.is_indexable() {
   1316         return Err(format!(
   1317             "filter field `{field}` is invalid: tag name must be a single ASCII letter"
   1318         ));
   1319     }
   1320     let values = parse_string_filter_array(field, value, |item| {
   1321         if name == "e" {
   1322             EventId::new(item)
   1323                 .map(|_| TagValue::new(item))
   1324                 .map_err(|reason| format!("filter field `{field}` is invalid: {reason}"))
   1325         } else if name == "p" {
   1326             PublicKeyHex::new(item)
   1327                 .map(|_| TagValue::new(item))
   1328                 .map_err(|reason| format!("filter field `{field}` is invalid: {reason}"))
   1329         } else {
   1330             Ok(TagValue::new(item))
   1331         }
   1332     })?;
   1333     Ok((tag_name, values))
   1334 }
   1335 
   1336 fn parse_string_filter_array<T>(
   1337     field: &str,
   1338     value: &serde_json::Value,
   1339     parse_item: impl Fn(&str) -> Result<T, String>,
   1340 ) -> Result<Vec<T>, String> {
   1341     let array = value.as_array().ok_or_else(|| filter_array_error(field))?;
   1342     if array.is_empty() {
   1343         return Err(filter_array_error(field));
   1344     }
   1345     array
   1346         .iter()
   1347         .map(|item| {
   1348             item.as_str()
   1349                 .ok_or_else(|| format!("filter field `{field}` values must be strings"))
   1350                 .and_then(&parse_item)
   1351         })
   1352         .collect()
   1353 }
   1354 
   1355 fn parse_u64_filter_array<T>(
   1356     field: &str,
   1357     value: &serde_json::Value,
   1358     parse_item: impl Fn(u64) -> Result<T, String>,
   1359 ) -> Result<Vec<T>, String> {
   1360     let array = value.as_array().ok_or_else(|| filter_array_error(field))?;
   1361     if array.is_empty() {
   1362         return Err(filter_array_error(field));
   1363     }
   1364     array
   1365         .iter()
   1366         .map(|item| {
   1367             item.as_u64()
   1368                 .ok_or_else(|| format!("filter field `{field}` values must be unsigned integers"))
   1369                 .and_then(&parse_item)
   1370         })
   1371         .collect()
   1372 }
   1373 
   1374 fn parse_u64_filter_field(field: &str, value: &serde_json::Value) -> Result<u64, String> {
   1375     value
   1376         .as_u64()
   1377         .ok_or_else(|| format!("filter field `{field}` must be an unsigned integer"))
   1378 }
   1379 
   1380 fn parse_string_filter_field<'a>(
   1381     field: &str,
   1382     value: &'a serde_json::Value,
   1383 ) -> Result<&'a str, String> {
   1384     value
   1385         .as_str()
   1386         .ok_or_else(|| format!("filter field `{field}` must be a string"))
   1387 }
   1388 
   1389 fn filter_array_error(field: &str) -> String {
   1390     format!("filter field `{field}` must be a non-empty array")
   1391 }
   1392 
   1393 fn require_lowercase_hex(scalar: &'static str, value: &str, expected: usize) -> Result<(), String> {
   1394     let actual = value.chars().count();
   1395     if actual != expected {
   1396         return Err(invalid_length_error(scalar, expected, actual));
   1397     }
   1398     if value
   1399         .bytes()
   1400         .any(|byte| !byte.is_ascii_hexdigit() || byte.is_ascii_uppercase())
   1401     {
   1402         return Err(non_lowercase_hex_error(scalar));
   1403     }
   1404     Ok(())
   1405 }
   1406 
   1407 fn empty_error(scalar: &'static str) -> String {
   1408     format!("{scalar} must not be empty")
   1409 }
   1410 
   1411 fn invalid_length_error(scalar: &'static str, expected: usize, actual: usize) -> String {
   1412     format!("{scalar} must be {expected} characters, got {actual}")
   1413 }
   1414 
   1415 fn too_long_error(scalar: &'static str, max: usize, actual: usize) -> String {
   1416     format!("{scalar} must be at most {max} characters, got {actual}")
   1417 }
   1418 
   1419 fn non_lowercase_hex_error(scalar: &'static str) -> String {
   1420     format!("{scalar} must be lowercase hex")
   1421 }
   1422 
   1423 fn kind_out_of_range_error(value: u64) -> String {
   1424     format!("kind must fit in u32, got {value}")
   1425 }
   1426 
   1427 #[cfg(test)]
   1428 mod tests {
   1429     use super::{
   1430         AddressCoordinate, AddressKey, ClientMessage, DTag, Event, EventId, EventShapeError,
   1431         Filter, Kind, KindClass, PublicKeyHex, RawEventJson, RelayMessage, SignatureHex,
   1432         SubscriptionId, Tag, TagName, TagValue, UnixTimestamp, UnsignedEvent, canonical_event_json,
   1433         empty_error, encode_relay_message, event_from_value, event_to_value, filter_from_value,
   1434         filter_to_value, invalid_length_error, kind_out_of_range_error, non_lowercase_hex_error,
   1435         parse_client_message, parse_event_json, relay_message_to_value, too_long_error,
   1436     };
   1437     use core::str::FromStr;
   1438     use std::collections::{BTreeMap, hash_map::DefaultHasher};
   1439     use std::hash::{Hash, Hasher};
   1440 
   1441     #[test]
   1442     fn event_id_accepts_lowercase_hex() {
   1443         let value = "0".repeat(EventId::HEX_LENGTH);
   1444         let event_id = EventId::new(&value).expect("event id");
   1445 
   1446         assert_eq!(event_id.as_str(), value);
   1447         assert_eq!(event_id.to_string(), value);
   1448         let cloned = event_id.clone();
   1449         let mut hasher = DefaultHasher::new();
   1450         cloned.hash(&mut hasher);
   1451         assert_ne!(hasher.finish(), 0);
   1452         assert_eq!(format!("{cloned:?}"), format!("EventId(\"{value}\")"));
   1453         assert!(cloned <= event_id);
   1454         assert_eq!(EventId::from_str(&value), Ok(event_id));
   1455     }
   1456 
   1457     #[test]
   1458     fn fixed_hex_scalars_reject_bad_lengths_and_characters() {
   1459         assert_eq!(
   1460             EventId::new(&"0".repeat(EventId::HEX_LENGTH - 1)),
   1461             Err(format!(
   1462                 "event id must be {} characters, got {}",
   1463                 EventId::HEX_LENGTH,
   1464                 EventId::HEX_LENGTH - 1
   1465             ))
   1466         );
   1467         assert_eq!(
   1468             EventId::new("bad"),
   1469             Err("event id must be 64 characters, got 3".to_owned())
   1470         );
   1471         let invalid_public_key = format!("{}G", "0".repeat(PublicKeyHex::HEX_LENGTH - 1));
   1472         assert_eq!(
   1473             PublicKeyHex::new(&invalid_public_key),
   1474             Err("public key must be lowercase hex".to_owned())
   1475         );
   1476         let invalid_signature = format!("{}A", "0".repeat(SignatureHex::HEX_LENGTH - 1));
   1477         assert_eq!(
   1478             SignatureHex::new(&invalid_signature),
   1479             Err("signature must be lowercase hex".to_owned())
   1480         );
   1481     }
   1482 
   1483     #[test]
   1484     fn public_key_and_signature_display_values() {
   1485         let public_key_value = "1".repeat(PublicKeyHex::HEX_LENGTH);
   1486         let signature_value = "2".repeat(SignatureHex::HEX_LENGTH);
   1487         let public_key = PublicKeyHex::new(&public_key_value).expect("pubkey");
   1488         let signature = SignatureHex::new(&signature_value).expect("sig");
   1489 
   1490         assert_eq!(public_key.as_str(), "1".repeat(PublicKeyHex::HEX_LENGTH));
   1491         assert_eq!(signature.as_str(), "2".repeat(SignatureHex::HEX_LENGTH));
   1492         assert_eq!(public_key.to_string(), public_key.as_str());
   1493         assert_eq!(signature.to_string(), signature.as_str());
   1494         assert_eq!(PublicKeyHex::from_str(public_key.as_str()), Ok(public_key));
   1495         assert_eq!(SignatureHex::from_str(signature.as_str()), Ok(signature));
   1496     }
   1497 
   1498     #[test]
   1499     fn subscription_id_rejects_empty_and_overlong_values() {
   1500         assert_eq!(
   1501             SubscriptionId::new(""),
   1502             Err("subscription id must not be empty".to_owned())
   1503         );
   1504         assert_eq!(
   1505             SubscriptionId::new(&"x".repeat(SubscriptionId::MAX_LENGTH + 1)),
   1506             Err(format!(
   1507                 "subscription id must be at most {} characters, got {}",
   1508                 SubscriptionId::MAX_LENGTH,
   1509                 SubscriptionId::MAX_LENGTH + 1
   1510             ))
   1511         );
   1512         let subscription = SubscriptionId::new("radroots").expect("subscription");
   1513         assert_eq!(subscription.as_str(), "radroots");
   1514         assert_eq!(subscription.to_string(), "radroots");
   1515         assert_eq!(SubscriptionId::from_str("radroots"), Ok(subscription));
   1516     }
   1517 
   1518     #[test]
   1519     fn timestamp_and_kind_expose_numeric_values() {
   1520         let timestamp = UnixTimestamp::new(1_714_124_433);
   1521         let kind = Kind::new(30_402).expect("kind");
   1522 
   1523         assert_eq!(timestamp.as_u64(), 1_714_124_433);
   1524         assert_eq!(timestamp.to_string(), "1714124433");
   1525         assert_eq!(UnixTimestamp::from(7).as_u64(), 7);
   1526         assert_eq!(kind.as_u32(), 30_402);
   1527         assert_eq!(kind.to_string(), "30402");
   1528         assert_eq!(Kind::try_from(30_402), Ok(kind));
   1529     }
   1530 
   1531     #[test]
   1532     fn kind_rejects_values_outside_u32() {
   1533         let value = u64::from(u32::MAX) + 1;
   1534 
   1535         assert_eq!(
   1536             Kind::new(value),
   1537             Err(format!("kind must fit in u32, got {value}"))
   1538         );
   1539         assert_eq!(
   1540             kind_out_of_range_error(value),
   1541             format!("kind must fit in u32, got {value}")
   1542         );
   1543     }
   1544 
   1545     #[test]
   1546     fn event_kind_classification_matches_nip01_ranges() {
   1547         for value in [1, 2, 4, 44, 1_000, 9_999, 45, 40_000] {
   1548             let kind = Kind::new(value).expect("regular");
   1549             assert_eq!(kind.class(), KindClass::Regular);
   1550             assert!(kind.is_regular());
   1551             assert!(!kind.is_replaceable());
   1552             assert!(!kind.is_ephemeral());
   1553             assert!(!kind.is_addressable());
   1554         }
   1555 
   1556         for value in [0, 3, 10_000, 19_999] {
   1557             let kind = Kind::new(value).expect("replaceable");
   1558             assert_eq!(kind.class(), KindClass::Replaceable);
   1559             assert!(kind.is_replaceable());
   1560         }
   1561 
   1562         for value in [20_000, 29_999] {
   1563             let kind = Kind::new(value).expect("ephemeral");
   1564             assert_eq!(kind.class(), KindClass::Ephemeral);
   1565             assert!(kind.is_ephemeral());
   1566         }
   1567 
   1568         for value in [30_000, 39_999] {
   1569             let kind = Kind::new(value).expect("addressable");
   1570             assert_eq!(kind.class(), KindClass::Addressable);
   1571             assert!(kind.is_addressable());
   1572         }
   1573 
   1574         assert_eq!(format!("{:?}", KindClass::Regular), "Regular");
   1575         assert_eq!(KindClass::Regular, KindClass::Regular);
   1576     }
   1577 
   1578     #[test]
   1579     fn address_coordinate_parses_formats_and_extracts_from_events() {
   1580         let pubkey = PublicKeyHex::new(&"1".repeat(PublicKeyHex::HEX_LENGTH)).expect("pubkey");
   1581         let coordinate = AddressCoordinate::new(
   1582             Kind::new(30_402).expect("kind"),
   1583             pubkey.clone(),
   1584             DTag::new("market-stall"),
   1585         )
   1586         .expect("coordinate");
   1587         let key: AddressKey = coordinate.key();
   1588         let parsed = AddressCoordinate::from_str(&coordinate.to_string()).expect("parsed");
   1589         let empty_d =
   1590             AddressCoordinate::from_str(&format!("30000:{}:", pubkey.as_str())).expect("empty d");
   1591         let event = addressable_event("market-stall", 30_402);
   1592 
   1593         assert_eq!(coordinate.kind().as_u32(), 30_402);
   1594         assert_eq!(coordinate.pubkey(), &pubkey);
   1595         assert_eq!(coordinate.d().as_str(), "market-stall");
   1596         assert_eq!(
   1597             coordinate.to_string(),
   1598             format!("30402:{}:market-stall", pubkey.as_str())
   1599         );
   1600         assert_eq!(key.as_str(), coordinate.to_string());
   1601         assert_eq!(key.to_string(), coordinate.to_string());
   1602         assert_eq!(parsed, coordinate);
   1603         assert_eq!(empty_d.d().as_str(), "");
   1604         assert_eq!(
   1605             AddressCoordinate::from_event(&event).expect("event"),
   1606             Some(coordinate)
   1607         );
   1608         assert_eq!(
   1609             AddressCoordinate::from_event(&event_for_filter(
   1610                 &"e".repeat(EventId::HEX_LENGTH),
   1611                 50,
   1612                 1
   1613             ))
   1614             .expect("regular"),
   1615             None
   1616         );
   1617         assert_eq!(format!("{:?}", DTag::new("d")), "DTag(\"d\")");
   1618         assert_eq!(DTag::new("d").to_string(), "d");
   1619         assert_eq!(DTag::from_str("d"), Ok(DTag::new("d")));
   1620     }
   1621 
   1622     #[test]
   1623     fn address_coordinate_rejects_invalid_coordinates() {
   1624         let pubkey = "1".repeat(PublicKeyHex::HEX_LENGTH);
   1625 
   1626         assert_eq!(
   1627             AddressCoordinate::new(
   1628                 Kind::new(1).expect("kind"),
   1629                 PublicKeyHex::new(&pubkey).expect("pubkey"),
   1630                 DTag::new("d")
   1631             )
   1632             .expect_err("regular kind"),
   1633             "address coordinate kind must be addressable, got 1"
   1634         );
   1635         assert_eq!(
   1636             AddressCoordinate::from_str("bad").expect_err("kind parse"),
   1637             "address coordinate kind must be an unsigned integer"
   1638         );
   1639         assert_eq!(
   1640             AddressCoordinate::from_str(&format!("{}:{pubkey}:d", u64::from(u32::MAX) + 1))
   1641                 .expect_err("kind range"),
   1642             format!("kind must fit in u32, got {}", u64::from(u32::MAX) + 1)
   1643         );
   1644         assert_eq!(
   1645             AddressCoordinate::from_str("1").expect_err("missing pubkey"),
   1646             "address coordinate pubkey is missing"
   1647         );
   1648         assert_eq!(
   1649             AddressCoordinate::from_str("30000:bad").expect_err("bad pubkey"),
   1650             "public key must be 64 characters, got 3"
   1651         );
   1652         assert_eq!(
   1653             AddressCoordinate::from_str(&format!("30000:{pubkey}")).expect_err("missing d"),
   1654             "address coordinate d tag is missing"
   1655         );
   1656         assert_eq!(
   1657             AddressCoordinate::from_str(&format!("1:{pubkey}:d")).expect_err("regular parse"),
   1658             "address coordinate kind must be addressable, got 1"
   1659         );
   1660         assert_eq!(
   1661             AddressCoordinate::from_event(&addressable_event_without_d())
   1662                 .expect_err("missing event d"),
   1663             "addressable event must include a d tag"
   1664         );
   1665     }
   1666 
   1667     #[test]
   1668     fn scalar_errors_have_stable_messages() {
   1669         assert_eq!(empty_error("id"), "id must not be empty");
   1670         assert_eq!(
   1671             invalid_length_error("id", 64, 63),
   1672             "id must be 64 characters, got 63"
   1673         );
   1674         assert_eq!(
   1675             too_long_error("id", 64, 65),
   1676             "id must be at most 64 characters, got 65"
   1677         );
   1678         assert_eq!(non_lowercase_hex_error("id"), "id must be lowercase hex");
   1679     }
   1680 
   1681     #[test]
   1682     fn tag_model_preserves_tag_arrays_and_extracts_first_values() {
   1683         let tag = Tag::from_parts("e", &["event-id", "wss://relay.example"]).expect("tag");
   1684 
   1685         assert_eq!(tag.name(), TagName::new("e").expect("name"));
   1686         assert_eq!(tag.value(), Some(TagValue::new("event-id")));
   1687         assert_eq!(
   1688             tag.values(),
   1689             &[
   1690                 "e".to_owned(),
   1691                 "event-id".to_owned(),
   1692                 "wss://relay.example".to_owned()
   1693             ]
   1694         );
   1695         assert_eq!(tag.indexed_pair(), Some(("e", "event-id")));
   1696         assert_eq!(tag.name().to_string(), "e");
   1697         assert_eq!(tag.value().expect("value").to_string(), "event-id");
   1698     }
   1699 
   1700     #[test]
   1701     fn tag_model_rejects_empty_arrays_and_names() {
   1702         assert_eq!(
   1703             Tag::new(Vec::new()),
   1704             Err("tag must not be empty".to_owned())
   1705         );
   1706         assert_eq!(
   1707             Tag::new(vec![String::new()]),
   1708             Err("tag name must not be empty".to_owned())
   1709         );
   1710         assert_eq!(
   1711             TagName::new(""),
   1712             Err("tag name must not be empty".to_owned())
   1713         );
   1714     }
   1715 
   1716     #[test]
   1717     fn tag_indexing_is_limited_to_single_ascii_letters() {
   1718         let uppercase = Tag::from_parts("E", &["root"]).expect("uppercase");
   1719         let missing_value = Tag::from_parts("p", &[]).expect("missing value");
   1720         let long_name = Tag::from_parts("alt", &["reply"]).expect("long name");
   1721         let non_ascii = Tag::from_parts("é", &["value"]).expect("non ascii");
   1722 
   1723         assert!(TagName::from_str("A").expect("name").is_indexable());
   1724         assert!(TagName::is_indexable_name("z"));
   1725         assert_eq!(uppercase.indexed_pair(), Some(("E", "root")));
   1726         assert_eq!(missing_value.indexed_pair(), None);
   1727         assert_eq!(long_name.indexed_pair(), None);
   1728         assert_eq!(non_ascii.indexed_pair(), None);
   1729         assert!(!TagName::is_indexable_name(""));
   1730         assert!(!TagName::is_indexable_name("aa"));
   1731         assert!(!TagName::is_indexable_name("1"));
   1732         assert_eq!(TagValue::new("").as_str(), "");
   1733     }
   1734 
   1735     #[test]
   1736     fn unsigned_event_exposes_nostr_event_shape() {
   1737         let pubkey = PublicKeyHex::new(&"1".repeat(PublicKeyHex::HEX_LENGTH)).expect("pubkey");
   1738         let tag = Tag::from_parts("p", &["peer"]).expect("tag");
   1739         let event = UnsignedEvent::new(
   1740             pubkey.clone(),
   1741             UnixTimestamp::new(1_714_124_433),
   1742             Kind::new(1).expect("kind"),
   1743             vec![tag.clone()],
   1744             "hello",
   1745         );
   1746 
   1747         assert_eq!(event.pubkey(), &pubkey);
   1748         assert_eq!(event.created_at().as_u64(), 1_714_124_433);
   1749         assert_eq!(event.kind().as_u32(), 1);
   1750         assert_eq!(event.tags(), &[tag]);
   1751         assert_eq!(event.content(), "hello");
   1752         assert!(format!("{event:?}").contains("UnsignedEvent"));
   1753     }
   1754 
   1755     #[test]
   1756     fn signed_event_wraps_id_unsigned_shape_and_signature() {
   1757         let id = EventId::new(&"a".repeat(EventId::HEX_LENGTH)).expect("id");
   1758         let sig = SignatureHex::new(&"b".repeat(SignatureHex::HEX_LENGTH)).expect("sig");
   1759         let unsigned = UnsignedEvent::new(
   1760             PublicKeyHex::new(&"c".repeat(PublicKeyHex::HEX_LENGTH)).expect("pubkey"),
   1761             UnixTimestamp::new(1),
   1762             Kind::new(1).expect("kind"),
   1763             Vec::new(),
   1764             "",
   1765         );
   1766         let event = Event::new(id.clone(), unsigned.clone(), sig.clone());
   1767 
   1768         assert_eq!(event.id(), &id);
   1769         assert_eq!(event.unsigned(), &unsigned);
   1770         assert_eq!(event.sig(), &sig);
   1771         assert_eq!(event.clone(), Event::new(id, unsigned, sig));
   1772         assert!(format!("{event:?}").contains("Event"));
   1773     }
   1774 
   1775     #[test]
   1776     fn raw_event_json_rejects_empty_input_and_preserves_bytes() {
   1777         assert_eq!(
   1778             RawEventJson::new("").expect_err("empty").to_string(),
   1779             "raw event JSON must not be empty"
   1780         );
   1781         let raw = RawEventJson::new("{\"kind\":1}").expect("raw");
   1782 
   1783         assert_eq!(raw.as_str(), "{\"kind\":1}");
   1784         assert_eq!(raw.clone().into_string(), "{\"kind\":1}");
   1785         assert_eq!(format!("{raw:?}"), "RawEventJson(\"{\\\"kind\\\":1}\")");
   1786     }
   1787 
   1788     #[test]
   1789     fn event_shape_errors_have_stable_messages() {
   1790         let missing = EventShapeError::missing_field("pubkey");
   1791         let invalid = EventShapeError::invalid_field("kind", "must be unsigned integer");
   1792 
   1793         assert_eq!(missing.to_string(), "event field `pubkey` is missing");
   1794         assert_eq!(
   1795             invalid.to_string(),
   1796             "event field `kind` is invalid: must be unsigned integer"
   1797         );
   1798         assert_eq!(
   1799             format!("{missing:?}"),
   1800             "EventShapeError { message: \"event field `pubkey` is missing\" }"
   1801         );
   1802     }
   1803 
   1804     #[test]
   1805     fn parse_event_json_builds_typed_event_shape() {
   1806         let raw = RawEventJson::new(&event_json("a", "b", 1, tags_json())).expect("raw");
   1807         let event = parse_event_json(&raw).expect("event");
   1808 
   1809         assert_eq!(event.id().as_str(), "a".repeat(EventId::HEX_LENGTH));
   1810         assert_eq!(
   1811             event.unsigned().pubkey().as_str(),
   1812             "1".repeat(PublicKeyHex::HEX_LENGTH)
   1813         );
   1814         assert_eq!(event.unsigned().created_at().as_u64(), 1_714_124_433);
   1815         assert_eq!(event.unsigned().kind().as_u32(), 1);
   1816         assert_eq!(event.unsigned().tags().len(), 2);
   1817         assert_eq!(event.unsigned().content(), "hello");
   1818         assert_eq!(event.sig().as_str(), "b".repeat(SignatureHex::HEX_LENGTH));
   1819     }
   1820 
   1821     #[test]
   1822     fn parse_client_message_accepts_event_auth_req_count_and_close() {
   1823         let event_payload = event_json("a", "b", 1, tags_json());
   1824         let auth_event_json = event_json("c", "d", 22242, "[]");
   1825         let event_message = format!("[\"EVENT\",{event_payload}]");
   1826         let auth_message = format!("[\"AUTH\",{auth_event_json}]");
   1827         let req_message = "[\"REQ\",\"sub-a\",{\"ids\":[\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"]},{\"kinds\":[1]}]";
   1828         let count_message = "[\"COUNT\",\"sub-a\",{\"kinds\":[1]}]";
   1829         let close_message = "[\"CLOSE\",\"sub-a\"]";
   1830         let event =
   1831             parse_event_json(&RawEventJson::new(&event_payload).expect("raw")).expect("event");
   1832         let auth_event =
   1833             parse_event_json(&RawEventJson::new(&auth_event_json).expect("raw")).expect("auth");
   1834 
   1835         assert_eq!(
   1836             parse_client_message(&event_message),
   1837             Ok(ClientMessage::Event(event))
   1838         );
   1839         assert_eq!(
   1840             parse_client_message(&auth_message),
   1841             Ok(ClientMessage::Auth(auth_event))
   1842         );
   1843         assert_eq!(
   1844             parse_client_message(req_message),
   1845             Ok(ClientMessage::Req {
   1846                 subscription_id: SubscriptionId::new("sub-a").expect("sub"),
   1847                 filters: vec![
   1848                     filter_from_value(&serde_json::json!({"ids":["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]})).expect("ids"),
   1849                     filter_from_value(&serde_json::json!({"kinds":[1]})).expect("kinds")
   1850                 ]
   1851             })
   1852         );
   1853         assert_eq!(
   1854             parse_client_message(count_message),
   1855             Ok(ClientMessage::Count {
   1856                 subscription_id: SubscriptionId::new("sub-a").expect("sub"),
   1857                 filters: vec![filter_from_value(&serde_json::json!({"kinds":[1]})).expect("kinds")]
   1858             })
   1859         );
   1860         assert_eq!(
   1861             parse_client_message(close_message).expect("close"),
   1862             ClientMessage::Close(SubscriptionId::new("sub-a").expect("sub"))
   1863         );
   1864     }
   1865 
   1866     #[test]
   1867     fn parser_rejects_duplicate_json_object_fields() {
   1868         let duplicate_filter_field =
   1869             parse_client_message(r#"["REQ","sub-a",{"limit":1,"limit":2,"kinds":[1]}]"#)
   1870                 .expect_err("duplicate filter field");
   1871         let duplicate_event_field = parse_event_json(
   1872             &RawEventJson::new(&format!(
   1873                 r#"{{"id":"{}","pubkey":"{}","created_at":1714124433,"kind":1,"tags":[],"content":"one","content":"two","sig":"{}"}}"#,
   1874                 "a".repeat(EventId::HEX_LENGTH),
   1875                 "1".repeat(PublicKeyHex::HEX_LENGTH),
   1876                 "b".repeat(SignatureHex::HEX_LENGTH)
   1877             ))
   1878             .expect("raw"),
   1879         )
   1880         .expect_err("duplicate event field")
   1881         .to_string();
   1882 
   1883         assert!(
   1884             duplicate_filter_field.contains("duplicate object field `limit`"),
   1885             "{duplicate_filter_field}"
   1886         );
   1887         assert!(
   1888             duplicate_event_field.contains("duplicate object field `content`"),
   1889             "{duplicate_event_field}"
   1890         );
   1891     }
   1892 
   1893     #[test]
   1894     fn nip01_client_and_relay_message_conformance_vectors_are_exact() {
   1895         let event_payload = event_json("a", "b", 1, tags_json());
   1896         let event =
   1897             parse_event_json(&RawEventJson::new(&event_payload).expect("raw")).expect("event");
   1898         let subscription_id = SubscriptionId::new("sub-vector").expect("sub");
   1899         let event_id = EventId::new(&"c".repeat(EventId::HEX_LENGTH)).expect("id");
   1900         let client_vectors = [
   1901             (
   1902                 format!("[\"EVENT\",{event_payload}]"),
   1903                 ClientMessage::Event(event.clone()),
   1904             ),
   1905             (
   1906                 format!("[\"AUTH\",{event_payload}]"),
   1907                 ClientMessage::Auth(event.clone()),
   1908             ),
   1909             (
   1910                 "[\"REQ\",\"sub-vector\",{\"kinds\":[1]}]".to_owned(),
   1911                 ClientMessage::Req {
   1912                     subscription_id: subscription_id.clone(),
   1913                     filters: vec![
   1914                         filter_from_value(&serde_json::json!({"kinds":[1]})).expect("filter"),
   1915                     ],
   1916                 },
   1917             ),
   1918             (
   1919                 "[\"COUNT\",\"sub-vector\",{\"kinds\":[1]}]".to_owned(),
   1920                 ClientMessage::Count {
   1921                     subscription_id: subscription_id.clone(),
   1922                     filters: vec![
   1923                         filter_from_value(&serde_json::json!({"kinds":[1]})).expect("filter"),
   1924                     ],
   1925                 },
   1926             ),
   1927             (
   1928                 "[\"CLOSE\",\"sub-vector\"]".to_owned(),
   1929                 ClientMessage::Close(subscription_id.clone()),
   1930             ),
   1931         ];
   1932         for (raw, expected) in client_vectors {
   1933             assert_eq!(parse_client_message(&raw), Ok(expected));
   1934         }
   1935         let relay_vectors = [
   1936             (
   1937                 RelayMessage::Event {
   1938                     subscription_id: subscription_id.clone(),
   1939                     event: event.clone(),
   1940                 },
   1941                 serde_json::json!(["EVENT", "sub-vector", event_to_value(&event)]),
   1942             ),
   1943             (
   1944                 RelayMessage::Ok {
   1945                     event_id: event_id.clone(),
   1946                     accepted: true,
   1947                     message: String::new(),
   1948                 },
   1949                 serde_json::json!(["OK", event_id.as_str(), true, ""]),
   1950             ),
   1951             (
   1952                 RelayMessage::Eose(subscription_id.clone()),
   1953                 serde_json::json!(["EOSE", "sub-vector"]),
   1954             ),
   1955             (
   1956                 RelayMessage::Closed {
   1957                     subscription_id: subscription_id.clone(),
   1958                     message: "unsupported: search filters are not supported".to_owned(),
   1959                 },
   1960                 serde_json::json!([
   1961                     "CLOSED",
   1962                     "sub-vector",
   1963                     "unsupported: search filters are not supported"
   1964                 ]),
   1965             ),
   1966             (
   1967                 RelayMessage::Count {
   1968                     subscription_id: subscription_id.clone(),
   1969                     count: 3,
   1970                     hll: None,
   1971                 },
   1972                 serde_json::json!(["COUNT", "sub-vector", {"count": 3}]),
   1973             ),
   1974             (
   1975                 RelayMessage::Notice("invalid: bad envelope".to_owned()),
   1976                 serde_json::json!(["NOTICE", "invalid: bad envelope"]),
   1977             ),
   1978             (
   1979                 RelayMessage::Auth("challenge".to_owned()),
   1980                 serde_json::json!(["AUTH", "challenge"]),
   1981             ),
   1982         ];
   1983         for (message, expected) in relay_vectors {
   1984             assert_eq!(relay_message_to_value(&message), expected);
   1985             assert_eq!(
   1986                 serde_json::from_str::<serde_json::Value>(&message.encode()).expect("encoded"),
   1987                 expected
   1988             );
   1989         }
   1990     }
   1991 
   1992     #[test]
   1993     fn protocol_conformance_fixtures_cover_dense_envelopes_and_parser_stress() {
   1994         let event_payload = event_json(
   1995             "a",
   1996             "b",
   1997             30_023,
   1998             r#"[["e","aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","wss://relay.example","root"],["e","bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"],["p","2222222222222222222222222222222222222222222222222222222222222222"],["h","Farm"],["emoji","🌱"]]"#,
   1999         );
   2000         let parsed_event =
   2001             parse_client_message(&format!("[\"EVENT\",{event_payload}]")).expect("event envelope");
   2002         let ClientMessage::Event(event) = parsed_event else {
   2003             panic!("expected event")
   2004         };
   2005         assert_eq!(event.unsigned().kind().as_u32(), 30_023);
   2006         assert_eq!(event.unsigned().tags().len(), 5);
   2007 
   2008         let req = serde_json::json!([
   2009             "REQ",
   2010             "sub-dense",
   2011             {
   2012                 "ids": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"],
   2013                 "authors": ["1111111111111111111111111111111111111111111111111111111111111111"],
   2014                 "kinds": [1, 30023],
   2015                 "#e": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"],
   2016                 "#p": ["2222222222222222222222222222222222222222222222222222222222222222"],
   2017                 "#h": ["Farm"],
   2018                 "since": 0,
   2019                 "until": 4102444800_u64,
   2020                 "limit": 500,
   2021                 "search": "radroots"
   2022             },
   2023             {
   2024                 "#t": ["radroots", "market", "farm"],
   2025                 "limit": 1
   2026             }
   2027         ])
   2028         .to_string();
   2029         let ClientMessage::Req {
   2030             subscription_id,
   2031             filters,
   2032         } = parse_client_message(&req).expect("req")
   2033         else {
   2034             panic!("expected req")
   2035         };
   2036         assert_eq!(subscription_id.as_str(), "sub-dense");
   2037         assert_eq!(filters.len(), 2);
   2038         assert_eq!(filters[0].kinds().len(), 2);
   2039         assert_eq!(filters[0].tag_filters().len(), 3);
   2040         assert_eq!(filters[1].limit(), Some(1));
   2041 
   2042         let count = serde_json::json!([
   2043             "COUNT",
   2044             "sub-count",
   2045             {"#h": ["Farm"], "kinds": [1], "limit": 1}
   2046         ])
   2047         .to_string();
   2048         let ClientMessage::Count {
   2049             subscription_id,
   2050             filters,
   2051         } = parse_client_message(&count).expect("count")
   2052         else {
   2053             panic!("expected count")
   2054         };
   2055         assert_eq!(subscription_id.as_str(), "sub-count");
   2056         assert_eq!(filters.len(), 1);
   2057         assert_eq!(filters[0].limit(), Some(1));
   2058 
   2059         for raw in [
   2060             "",
   2061             "[",
   2062             "[\"REQ\",\"sub\",{}",
   2063             "[\"REQ\",\"sub\",{\"#h\":[{}]}]",
   2064             "[\"REQ\",\"sub\",{\"ids\":[\"short\"]}]",
   2065             "[\"COUNT\",\"sub\",{\"kinds\":[4294967296]}]",
   2066             "[\"COUNT\",1,{}]",
   2067             "[\"EVENT\",{\"tags\":[[1]]}]",
   2068             "[\"AUTH\",{\"kind\":\"bad\"}]",
   2069             "[\"CLOSE\",\"\"]",
   2070         ] {
   2071             std::panic::catch_unwind(|| {
   2072                 assert!(parse_client_message(raw).is_err());
   2073             })
   2074             .expect("parser must not panic");
   2075         }
   2076     }
   2077 
   2078     #[test]
   2079     fn parser_preserves_addressable_events_and_weird_tag_shapes() {
   2080         let p_tag = "2".repeat(PublicKeyHex::HEX_LENGTH);
   2081         let event_payload = format!(
   2082             r#"{{"id":"{}","pubkey":"{}","created_at":1714124433,"kind":30023,"tags":[["emoji","🌱","https://example.invalid/seed.png"],["d","market-stall"],["d","shadow"],["é","not-indexed"],["h","Farm","extra"],["p","{}","wss://relay.example","mention"]],"content":"addressable 🌱","sig":"{}"}}"#,
   2083             "a".repeat(EventId::HEX_LENGTH),
   2084             "1".repeat(PublicKeyHex::HEX_LENGTH),
   2085             p_tag,
   2086             "b".repeat(SignatureHex::HEX_LENGTH)
   2087         );
   2088         let event =
   2089             parse_event_json(&RawEventJson::new(&event_payload).expect("raw")).expect("event");
   2090         let coordinate = AddressCoordinate::from_event(&event)
   2091             .expect("coordinate")
   2092             .expect("addressable");
   2093         let filter = filter_from_value(&serde_json::json!({
   2094             "#d": ["market-stall"],
   2095             "#h": ["Farm"],
   2096             "#p": [p_tag],
   2097             "limit": u64::MAX
   2098         }))
   2099         .expect("filter");
   2100 
   2101         assert_eq!(event.unsigned().tags().len(), 6);
   2102         assert_eq!(
   2103             event.unsigned().tags()[0].values(),
   2104             &[
   2105                 "emoji".to_owned(),
   2106                 "🌱".to_owned(),
   2107                 "https://example.invalid/seed.png".to_owned()
   2108             ]
   2109         );
   2110         assert_eq!(event.unsigned().tags()[3].indexed_pair(), None);
   2111         assert_eq!(coordinate.d().as_str(), "market-stall");
   2112         assert_eq!(filter.limit(), Some(u64::MAX));
   2113         assert!(filter.matches(&event));
   2114         assert_eq!(
   2115             filter_from_value(&serde_json::json!({"#é": ["value"]}))
   2116                 .expect_err("non ascii tag filter"),
   2117             "filter field `#é` is invalid: tag name must be a single ASCII letter"
   2118         );
   2119     }
   2120 
   2121     #[test]
   2122     fn parse_client_message_rejects_malformed_envelopes() {
   2123         assert!(
   2124             parse_client_message("{")
   2125                 .expect_err("json")
   2126                 .starts_with("client message JSON is invalid")
   2127         );
   2128         assert_eq!(
   2129             parse_client_message("{}").expect_err("object"),
   2130             "client message must be an array"
   2131         );
   2132         assert_eq!(
   2133             parse_client_message("[]").expect_err("empty"),
   2134             "client message command is missing"
   2135         );
   2136         assert_eq!(
   2137             parse_client_message("[1]").expect_err("command type"),
   2138             "client message command must be a string"
   2139         );
   2140         assert_eq!(
   2141             parse_client_message("[\"BOGUS\"]").expect_err("unsupported"),
   2142             "client message command `BOGUS` is unsupported"
   2143         );
   2144         assert_eq!(
   2145             parse_client_message("[\"EVENT\"]").expect_err("event length"),
   2146             "EVENT client message must contain exactly 2 elements"
   2147         );
   2148         assert_eq!(
   2149             parse_client_message("[\"EVENT\",{}]").expect_err("event shape"),
   2150             "event field `id` is missing"
   2151         );
   2152         assert_eq!(
   2153             parse_client_message("[\"AUTH\"]").expect_err("auth length"),
   2154             "AUTH client message must contain exactly 2 elements"
   2155         );
   2156         assert_eq!(
   2157             parse_client_message("[\"AUTH\",{}]").expect_err("auth shape"),
   2158             "event field `id` is missing"
   2159         );
   2160         assert_eq!(
   2161             parse_client_message("[\"REQ\",\"sub-a\"]").expect_err("req length"),
   2162             "REQ client message must contain a subscription id and filters"
   2163         );
   2164         assert_eq!(
   2165             parse_client_message("[\"REQ\",1,{}]").expect_err("req sub type"),
   2166             "REQ subscription id must be a string"
   2167         );
   2168         assert_eq!(
   2169             parse_client_message("[\"REQ\",\"\",{}]").expect_err("req sub empty"),
   2170             "subscription id must not be empty"
   2171         );
   2172         assert_eq!(
   2173             parse_client_message("[\"REQ\",\"sub-a\",1]").expect_err("req filter"),
   2174             "filter must be a JSON object"
   2175         );
   2176         assert_eq!(
   2177             parse_client_message("[\"COUNT\"]").expect_err("count length"),
   2178             "COUNT client message must contain a subscription id and filters"
   2179         );
   2180         assert_eq!(
   2181             parse_client_message("[\"COUNT\",1,{}]").expect_err("count sub type"),
   2182             "COUNT subscription id must be a string"
   2183         );
   2184         assert_eq!(
   2185             parse_client_message("[\"COUNT\",\"\",{}]").expect_err("count sub empty"),
   2186             "subscription id must not be empty"
   2187         );
   2188         assert_eq!(
   2189             parse_client_message("[\"COUNT\",\"sub-a\",1]").expect_err("count filter"),
   2190             "filter must be a JSON object"
   2191         );
   2192         assert_eq!(
   2193             parse_client_message("[\"CLOSE\"]").expect_err("close length"),
   2194             "CLOSE client message must contain exactly 2 elements"
   2195         );
   2196         assert_eq!(
   2197             parse_client_message("[\"CLOSE\",1]").expect_err("close sub type"),
   2198             "CLOSE subscription id must be a string"
   2199         );
   2200     }
   2201 
   2202     #[test]
   2203     fn malformed_client_message_corpus_is_rejected_or_parsed_without_panic() {
   2204         let valid_event = event_json("a", "b", 1, tags_json());
   2205         let long_sub = "x".repeat(SubscriptionId::MAX_LENGTH + 1);
   2206         let oversized_kind = u64::from(u32::MAX) + 1;
   2207         let corpus = [
   2208             String::new(),
   2209             "[".to_owned(),
   2210             "null".to_owned(),
   2211             "[null]".to_owned(),
   2212             "[\"EVENT\",null]".to_owned(),
   2213             format!("[\"EVENT\",{valid_event},{}]", serde_json::json!({})),
   2214             "[\"REQ\",{},{}]".to_owned(),
   2215             "[\"REQ\",\"sub\",{\"ids\":[]}]".to_owned(),
   2216             "[\"REQ\",\"sub\",{\"ids\":[1]}]".to_owned(),
   2217             "[\"REQ\",\"sub\",{\"#aa\":[\"value\"]}]".to_owned(),
   2218             format!("[\"REQ\",\"sub\",{{\"kinds\":[{oversized_kind}]}}]"),
   2219             format!("[\"REQ\",\"{long_sub}\",{{}}]"),
   2220             "[\"COUNT\",\"sub\",{\"authors\":[\"BAD\"]}]".to_owned(),
   2221             "[\"COUNT\",\"sub\",{\"unknown\":true}]".to_owned(),
   2222             "[\"CLOSE\",\"sub\",{}]".to_owned(),
   2223             "[\"AUTH\",[]]".to_owned(),
   2224             "[\"NOTICE\",\"not a client command\"]".to_owned(),
   2225         ];
   2226         for raw in corpus {
   2227             std::panic::catch_unwind(|| {
   2228                 let _ = parse_client_message(&raw);
   2229             })
   2230             .expect("parser must not panic");
   2231         }
   2232     }
   2233 
   2234     #[test]
   2235     fn parse_event_json_rejects_invalid_event_shapes() {
   2236         assert_eq!(
   2237             parse_event_json(&RawEventJson::new("{").expect("raw"))
   2238                 .expect_err("invalid json")
   2239                 .to_string(),
   2240             "event field `event` is invalid: invalid JSON: EOF while parsing an object at line 1 column 1"
   2241         );
   2242         assert_eq!(
   2243             event_from_value(&serde_json::json!(1))
   2244                 .expect_err("not object")
   2245                 .to_string(),
   2246             "event field `event` is invalid: must be an object"
   2247         );
   2248         assert_eq!(
   2249             event_from_value(&serde_json::json!({}))
   2250                 .expect_err("missing id")
   2251                 .to_string(),
   2252             "event field `id` is missing"
   2253         );
   2254         assert_eq!(
   2255             event_from_value(&event_value_without("created_at"))
   2256                 .expect_err("missing created_at")
   2257                 .to_string(),
   2258             "event field `created_at` is missing"
   2259         );
   2260         assert_eq!(
   2261             event_from_value(&event_value_with("id", serde_json::json!(1)))
   2262                 .expect_err("id type")
   2263                 .to_string(),
   2264             "event field `id` is invalid: must be a string"
   2265         );
   2266         assert_eq!(
   2267             event_from_value(&event_value_with("id", serde_json::json!("bad")))
   2268                 .expect_err("id scalar")
   2269                 .to_string(),
   2270             "event field `id` is invalid: event id must be 64 characters, got 3"
   2271         );
   2272         assert_eq!(
   2273             event_from_value(&event_value_with("pubkey", serde_json::json!("bad")))
   2274                 .expect_err("pubkey scalar")
   2275                 .to_string(),
   2276             "event field `pubkey` is invalid: public key must be 64 characters, got 3"
   2277         );
   2278         assert_eq!(
   2279             event_from_value(&event_value_with("created_at", serde_json::json!("now")))
   2280                 .expect_err("created type")
   2281                 .to_string(),
   2282             "event field `created_at` is invalid: must be an unsigned integer"
   2283         );
   2284         assert_eq!(
   2285             event_from_value(&event_value_with(
   2286                 "kind",
   2287                 serde_json::json!(u64::from(u32::MAX) + 1)
   2288             ))
   2289             .expect_err("kind range")
   2290             .to_string(),
   2291             format!(
   2292                 "event field `kind` is invalid: kind must fit in u32, got {}",
   2293                 u64::from(u32::MAX) + 1
   2294             )
   2295         );
   2296         assert_eq!(
   2297             event_from_value(&event_value_with("tags", serde_json::json!(1)))
   2298                 .expect_err("tags type")
   2299                 .to_string(),
   2300             "event field `tags` is invalid: must be an array"
   2301         );
   2302         assert_eq!(
   2303             event_from_value(&event_value_with("tags", serde_json::json!([1])))
   2304                 .expect_err("tag type")
   2305                 .to_string(),
   2306             "event field `tags` is invalid: tag must be an array"
   2307         );
   2308         assert_eq!(
   2309             event_from_value(&event_value_with("tags", serde_json::json!([[1]])))
   2310                 .expect_err("tag part type")
   2311                 .to_string(),
   2312             "event field `tags` is invalid: tag elements must be strings"
   2313         );
   2314         assert_eq!(
   2315             event_from_value(&event_value_with("tags", serde_json::json!([[]])))
   2316                 .expect_err("tag empty")
   2317                 .to_string(),
   2318             "event field `tags` is invalid: tag must not be empty"
   2319         );
   2320         assert_eq!(
   2321             event_from_value(&event_value_with("content", serde_json::json!(1)))
   2322                 .expect_err("content type")
   2323                 .to_string(),
   2324             "event field `content` is invalid: must be a string"
   2325         );
   2326         assert_eq!(
   2327             event_from_value(&event_value_with("sig", serde_json::json!("bad")))
   2328                 .expect_err("sig scalar")
   2329                 .to_string(),
   2330             "event field `sig` is invalid: signature must be 128 characters, got 3"
   2331         );
   2332     }
   2333 
   2334     #[test]
   2335     fn filter_model_parses_core_fields_and_matches_events() {
   2336         let event_tag = "e".repeat(EventId::HEX_LENGTH);
   2337         let event = event_for_filter(&event_tag, 50, 1);
   2338         let filter = filter_from_value(&serde_json::json!({
   2339             "ids": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"],
   2340             "authors": ["1111111111111111111111111111111111111111111111111111111111111111"],
   2341             "kinds": [1],
   2342             "#e": [event_tag],
   2343             "#p": ["1111111111111111111111111111111111111111111111111111111111111111"],
   2344             "#t": ["radroots"],
   2345             "since": 40,
   2346             "until": 60,
   2347             "limit": 5,
   2348             "search": "fresh carrots"
   2349         }))
   2350         .expect("filter");
   2351 
   2352         assert_eq!(filter.ids()[0].as_str(), "a".repeat(EventId::HEX_LENGTH));
   2353         assert_eq!(
   2354             filter.authors()[0].as_str(),
   2355             "1".repeat(PublicKeyHex::HEX_LENGTH)
   2356         );
   2357         assert_eq!(filter.kinds()[0].as_u32(), 1);
   2358         assert_eq!(filter.since().expect("since").as_u64(), 40);
   2359         assert_eq!(filter.until().expect("until").as_u64(), 60);
   2360         assert_eq!(filter.limit(), Some(5));
   2361         assert_eq!(filter.search(), Some("fresh carrots"));
   2362         assert_eq!(
   2363             filter
   2364                 .tag_filters()
   2365                 .get(&TagName::new("t").expect("tag"))
   2366                 .expect("tag")[0]
   2367                 .as_str(),
   2368             "radroots"
   2369         );
   2370         assert!(filter.matches(&event));
   2371         assert!(Filter::empty().matches(&event));
   2372         assert_eq!(Filter::empty().limit(), None);
   2373         assert_eq!(Filter::empty().search(), None);
   2374         let without_limit = filter.without_limit();
   2375         assert_eq!(without_limit.limit(), None);
   2376         assert_eq!(without_limit.search(), filter.search());
   2377         assert!(without_limit.matches(&event));
   2378         let with_limit = without_limit.with_limit(2);
   2379         assert_eq!(with_limit.limit(), Some(2));
   2380         assert_eq!(with_limit.search(), filter.search());
   2381         assert!(with_limit.matches(&event));
   2382         assert_eq!(
   2383             filter_from_value(&filter_to_value(&filter)).expect("encoded"),
   2384             filter
   2385         );
   2386     }
   2387 
   2388     #[test]
   2389     fn filter_from_parts_builds_validated_filter_components() {
   2390         let name = TagName::new("t").expect("tag name");
   2391         let value = TagValue::new("market");
   2392         let filter = Filter::from_parts(
   2393             vec![EventId::new(&"a".repeat(EventId::HEX_LENGTH)).expect("id")],
   2394             vec![PublicKeyHex::new(&"b".repeat(PublicKeyHex::HEX_LENGTH)).expect("author")],
   2395             vec![Kind::new(1).expect("kind")],
   2396             BTreeMap::from([(name.clone(), vec![value.clone()])]),
   2397             Some(UnixTimestamp::new(10)),
   2398             Some(UnixTimestamp::new(20)),
   2399             Some(30),
   2400             Some("carrots".to_owned()),
   2401         )
   2402         .expect("filter");
   2403 
   2404         assert_eq!(filter.ids().len(), 1);
   2405         assert_eq!(filter.authors().len(), 1);
   2406         assert_eq!(filter.kinds(), &[Kind::new(1).expect("kind")]);
   2407         assert_eq!(filter.tag_filters().get(&name), Some(&vec![value]));
   2408         assert_eq!(filter.since(), Some(UnixTimestamp::new(10)));
   2409         assert_eq!(filter.until(), Some(UnixTimestamp::new(20)));
   2410         assert_eq!(filter.limit(), Some(30));
   2411         assert_eq!(filter.search(), Some("carrots"));
   2412         assert_eq!(
   2413             Filter::from_parts(
   2414                 Vec::new(),
   2415                 Vec::new(),
   2416                 Vec::new(),
   2417                 BTreeMap::from([(TagName::new("ab").expect("tag"), Vec::new())]),
   2418                 None,
   2419                 None,
   2420                 None,
   2421                 None
   2422             )
   2423             .expect_err("invalid tag"),
   2424             "filter field `#ab` is invalid: tag name must be a single ASCII letter"
   2425         );
   2426     }
   2427 
   2428     #[test]
   2429     fn filter_complete_semantics_are_exact_id_only() {
   2430         assert!(
   2431             filter_from_value(&serde_json::json!({
   2432                 "ids": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]
   2433             }))
   2434             .expect("id filter")
   2435             .is_complete()
   2436         );
   2437         assert!(
   2438             !filter_from_value(&serde_json::json!({"kinds": [1]}))
   2439                 .expect("kind filter")
   2440                 .is_complete()
   2441         );
   2442         assert!(!Filter::empty().is_complete());
   2443     }
   2444 
   2445     #[test]
   2446     fn filter_model_rejects_non_matching_events() {
   2447         let event_tag = "e".repeat(EventId::HEX_LENGTH);
   2448         let event = event_for_filter(&event_tag, 50, 1);
   2449 
   2450         assert!(
   2451             !filter_from_value(&serde_json::json!({
   2452                 "ids": ["bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"]
   2453             }))
   2454             .expect("id filter")
   2455             .matches(&event)
   2456         );
   2457         assert!(
   2458             !filter_from_value(&serde_json::json!({
   2459                 "authors": ["2222222222222222222222222222222222222222222222222222222222222222"]
   2460             }))
   2461             .expect("author filter")
   2462             .matches(&event)
   2463         );
   2464         assert!(
   2465             !filter_from_value(&serde_json::json!({"kinds": [2]}))
   2466                 .expect("kind filter")
   2467                 .matches(&event)
   2468         );
   2469         assert!(
   2470             !filter_from_value(&serde_json::json!({"since": 51}))
   2471                 .expect("since filter")
   2472                 .matches(&event)
   2473         );
   2474         assert!(
   2475             !filter_from_value(&serde_json::json!({"until": 49}))
   2476                 .expect("until filter")
   2477                 .matches(&event)
   2478         );
   2479         assert!(
   2480             !filter_from_value(&serde_json::json!({"#e": [
   2481                 "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
   2482             ]}))
   2483             .expect("tag filter")
   2484             .matches(&event)
   2485         );
   2486     }
   2487 
   2488     #[test]
   2489     fn filter_model_rejects_invalid_filter_shapes() {
   2490         assert_eq!(
   2491             filter_from_value(&serde_json::json!(1)).expect_err("object"),
   2492             "filter must be a JSON object"
   2493         );
   2494         assert_eq!(
   2495             filter_from_value(&serde_json::json!({"ids": 1})).expect_err("ids array"),
   2496             "filter field `ids` must be a non-empty array"
   2497         );
   2498         assert_eq!(
   2499             filter_from_value(&serde_json::json!({"ids": []})).expect_err("ids empty"),
   2500             "filter field `ids` must be a non-empty array"
   2501         );
   2502         assert_eq!(
   2503             filter_from_value(&serde_json::json!({"ids": [1]})).expect_err("ids string"),
   2504             "filter field `ids` values must be strings"
   2505         );
   2506         assert_eq!(
   2507             filter_from_value(&serde_json::json!({"ids": ["bad"]})).expect_err("ids hex"),
   2508             "filter field `ids` is invalid: event id must be 64 characters, got 3"
   2509         );
   2510         assert_eq!(
   2511             filter_from_value(&serde_json::json!({"authors": ["bad"]})).expect_err("author hex"),
   2512             "filter field `authors` is invalid: public key must be 64 characters, got 3"
   2513         );
   2514         assert_eq!(
   2515             filter_from_value(&serde_json::json!({"authors": 1})).expect_err("authors array"),
   2516             "filter field `authors` must be a non-empty array"
   2517         );
   2518         assert_eq!(
   2519             filter_from_value(&serde_json::json!({"authors": []})).expect_err("authors empty"),
   2520             "filter field `authors` must be a non-empty array"
   2521         );
   2522         assert_eq!(
   2523             filter_from_value(&serde_json::json!({"authors": [1]})).expect_err("authors string"),
   2524             "filter field `authors` values must be strings"
   2525         );
   2526         assert_eq!(
   2527             filter_from_value(&serde_json::json!({"kinds": 1})).expect_err("kinds array"),
   2528             "filter field `kinds` must be a non-empty array"
   2529         );
   2530         assert_eq!(
   2531             filter_from_value(&serde_json::json!({"kinds": []})).expect_err("kinds empty"),
   2532             "filter field `kinds` must be a non-empty array"
   2533         );
   2534         assert_eq!(
   2535             filter_from_value(&serde_json::json!({"kinds": ["one"]})).expect_err("kind integer"),
   2536             "filter field `kinds` values must be unsigned integers"
   2537         );
   2538         assert_eq!(
   2539             filter_from_value(&serde_json::json!({"kinds": [u64::from(u32::MAX) + 1]}))
   2540                 .expect_err("kind range"),
   2541             format!(
   2542                 "filter field `kinds` is invalid: kind must fit in u32, got {}",
   2543                 u64::from(u32::MAX) + 1
   2544             )
   2545         );
   2546         assert_eq!(
   2547             filter_from_value(&serde_json::json!({"since": "now"})).expect_err("since"),
   2548             "filter field `since` must be an unsigned integer"
   2549         );
   2550         assert_eq!(
   2551             filter_from_value(&serde_json::json!({"until": "then"})).expect_err("until"),
   2552             "filter field `until` must be an unsigned integer"
   2553         );
   2554         assert_eq!(
   2555             filter_from_value(&serde_json::json!({"limit": "ten"})).expect_err("limit"),
   2556             "filter field `limit` must be an unsigned integer"
   2557         );
   2558         assert_eq!(
   2559             filter_from_value(&serde_json::json!({"search": 1})).expect_err("search"),
   2560             "filter field `search` must be a string"
   2561         );
   2562         assert_eq!(
   2563             filter_from_value(&serde_json::json!({"#": ["value"]})).expect_err("tag empty"),
   2564             "filter field `#` is invalid: tag name must not be empty"
   2565         );
   2566         assert_eq!(
   2567             filter_from_value(&serde_json::json!({"#aa": ["value"]})).expect_err("tag long"),
   2568             "filter field `#aa` is invalid: tag name must be a single ASCII letter"
   2569         );
   2570         assert_eq!(
   2571             filter_from_value(&serde_json::json!({"#t": 1})).expect_err("tag array"),
   2572             "filter field `#t` must be a non-empty array"
   2573         );
   2574         assert_eq!(
   2575             filter_from_value(&serde_json::json!({"#t": []})).expect_err("tag empty array"),
   2576             "filter field `#t` must be a non-empty array"
   2577         );
   2578         assert_eq!(
   2579             filter_from_value(&serde_json::json!({"#t": [1]})).expect_err("tag string"),
   2580             "filter field `#t` values must be strings"
   2581         );
   2582         assert_eq!(
   2583             filter_from_value(&serde_json::json!({"#e": ["bad"]})).expect_err("tag event id"),
   2584             "filter field `#e` is invalid: event id must be 64 characters, got 3"
   2585         );
   2586         assert_eq!(
   2587             filter_from_value(&serde_json::json!({"#p": ["bad"]})).expect_err("tag pubkey"),
   2588             "filter field `#p` is invalid: public key must be 64 characters, got 3"
   2589         );
   2590         assert_eq!(
   2591             filter_from_value(&serde_json::json!({"unknown": true})).expect_err("unknown"),
   2592             "filter field `unknown` is unsupported"
   2593         );
   2594     }
   2595 
   2596     #[test]
   2597     fn relay_message_encoder_emits_nip01_and_nip42_messages() {
   2598         let event = parse_event_json(
   2599             &RawEventJson::new(&event_json("a", "b", 1, tags_json())).expect("raw"),
   2600         )
   2601         .expect("event");
   2602         let subscription_id = SubscriptionId::new("sub-a").expect("sub");
   2603         let accepted_id = EventId::new(&"c".repeat(EventId::HEX_LENGTH)).expect("id");
   2604         let rejected_id = EventId::new(&"d".repeat(EventId::HEX_LENGTH)).expect("id");
   2605 
   2606         assert_eq!(
   2607             relay_message_to_value(&RelayMessage::Event {
   2608                 subscription_id: subscription_id.clone(),
   2609                 event: event.clone()
   2610             }),
   2611             serde_json::json!(["EVENT", "sub-a", event_to_value(&event)])
   2612         );
   2613         assert_eq!(
   2614             serde_json::from_str::<serde_json::Value>(&encode_relay_message(&RelayMessage::Ok {
   2615                 event_id: accepted_id,
   2616                 accepted: true,
   2617                 message: String::new()
   2618             }))
   2619             .expect("ok"),
   2620             serde_json::json!([
   2621                 "OK",
   2622                 "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
   2623                 true,
   2624                 ""
   2625             ])
   2626         );
   2627         assert_eq!(
   2628             serde_json::from_str::<serde_json::Value>(
   2629                 &RelayMessage::Ok {
   2630                     event_id: rejected_id,
   2631                     accepted: false,
   2632                     message: "invalid: event id mismatch".to_owned()
   2633                 }
   2634                 .encode()
   2635             )
   2636             .expect("rejected"),
   2637             serde_json::json!([
   2638                 "OK",
   2639                 "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
   2640                 false,
   2641                 "invalid: event id mismatch"
   2642             ])
   2643         );
   2644         assert_eq!(
   2645             relay_message_to_value(&RelayMessage::Eose(subscription_id.clone())),
   2646             serde_json::json!(["EOSE", "sub-a"])
   2647         );
   2648         assert_eq!(
   2649             relay_message_to_value(&RelayMessage::Closed {
   2650                 subscription_id: subscription_id.clone(),
   2651                 message: "unsupported: filter contains unknown elements".to_owned()
   2652             }),
   2653             serde_json::json!([
   2654                 "CLOSED",
   2655                 "sub-a",
   2656                 "unsupported: filter contains unknown elements"
   2657             ])
   2658         );
   2659         assert_eq!(
   2660             relay_message_to_value(&RelayMessage::Count {
   2661                 subscription_id,
   2662                 count: 7,
   2663                 hll: None
   2664             }),
   2665             serde_json::json!(["COUNT", "sub-a", {"count": 7}])
   2666         );
   2667         assert_eq!(
   2668             relay_message_to_value(&RelayMessage::Notice("maintenance window".to_owned())),
   2669             serde_json::json!(["NOTICE", "maintenance window"])
   2670         );
   2671         assert_eq!(
   2672             relay_message_to_value(&RelayMessage::Auth("challenge-a".to_owned())),
   2673             serde_json::json!(["AUTH", "challenge-a"])
   2674         );
   2675     }
   2676 
   2677     #[test]
   2678     fn relay_message_encoder_emits_negentropy_messages() {
   2679         let subscription_id = SubscriptionId::new("neg-sub").expect("sub");
   2680 
   2681         assert_eq!(
   2682             relay_message_to_value(&RelayMessage::NegErr {
   2683                 subscription_id: subscription_id.clone(),
   2684                 message: "blocked: Negentropy sync is disabled".to_owned()
   2685             }),
   2686             serde_json::json!(["NEG-ERR", "neg-sub", "blocked: Negentropy sync is disabled"])
   2687         );
   2688         assert_eq!(
   2689             relay_message_to_value(&RelayMessage::NegMsg {
   2690                 subscription_id,
   2691                 message: "00ff".to_owned()
   2692             }),
   2693             serde_json::json!(["NEG-MSG", "neg-sub", "00ff"])
   2694         );
   2695     }
   2696 
   2697     #[test]
   2698     fn relay_message_encoder_emits_count_hll_when_present() {
   2699         let subscription_id = SubscriptionId::new("count-hll").expect("sub");
   2700         let hll = "0a".repeat(256);
   2701 
   2702         assert_eq!(
   2703             relay_message_to_value(&RelayMessage::Count {
   2704                 subscription_id,
   2705                 count: 42,
   2706                 hll: Some(hll.clone())
   2707             }),
   2708             serde_json::json!(["COUNT", "count-hll", {"count": 42, "hll": hll}])
   2709         );
   2710     }
   2711 
   2712     #[test]
   2713     fn event_to_value_round_trips_with_event_parser() {
   2714         let event = parse_event_json(
   2715             &RawEventJson::new(&event_json("e", "f", 30402, tags_json())).expect("raw"),
   2716         )
   2717         .expect("event");
   2718 
   2719         assert_eq!(
   2720             event_from_value(&event_to_value(&event)).expect("parsed"),
   2721             event
   2722         );
   2723     }
   2724 
   2725     #[test]
   2726     fn canonical_event_json_serializes_empty_content_and_tags() {
   2727         let event = unsigned_event(Vec::new(), "");
   2728 
   2729         assert_eq!(
   2730             event.canonical_json(),
   2731             include_str!("../tests/fixtures/canonical_empty_event.json").trim_end()
   2732         );
   2733         assert_eq!(canonical_event_json(&event), event.canonical_json());
   2734     }
   2735 
   2736     #[test]
   2737     fn canonical_event_json_serializes_escaped_content() {
   2738         let event = unsigned_event(
   2739             vec![Tag::from_parts("alt", &["quote"]).expect("tag")],
   2740             "quote \" slash \\ newline\n",
   2741         );
   2742 
   2743         assert_eq!(
   2744             event.canonical_json(),
   2745             include_str!("../tests/fixtures/canonical_escaped_event.json").trim_end()
   2746         );
   2747     }
   2748 
   2749     #[test]
   2750     fn canonical_event_json_serializes_unicode_content() {
   2751         let event = unsigned_event(
   2752             vec![Tag::from_parts("t", &["radroots"]).expect("tag")],
   2753             "radroots 🌱 café",
   2754         );
   2755 
   2756         assert_eq!(
   2757             event.canonical_json(),
   2758             include_str!("../tests/fixtures/canonical_unicode_event.json").trim_end()
   2759         );
   2760     }
   2761 
   2762     #[test]
   2763     fn canonical_event_json_preserves_repeated_tags() {
   2764         let event = unsigned_event(
   2765             vec![
   2766                 Tag::from_parts("e", &["one"]).expect("first e"),
   2767                 Tag::from_parts("e", &["two"]).expect("second e"),
   2768                 Tag::from_parts("p", &["peer", "wss://relay.example"]).expect("p"),
   2769             ],
   2770             "with repeated tags",
   2771         );
   2772 
   2773         assert_eq!(
   2774             event.canonical_json(),
   2775             include_str!("../tests/fixtures/canonical_repeated_tags_event.json").trim_end()
   2776         );
   2777     }
   2778 
   2779     #[test]
   2780     fn canonical_event_json_preserves_large_tags_without_shape_drift() {
   2781         let tags = (0..64)
   2782             .map(|index| Tag::from_parts("t", &[&format!("topic-{index}")]).expect("tag"))
   2783             .collect::<Vec<_>>();
   2784         let event = unsigned_event(tags, "large tag set");
   2785         let value =
   2786             serde_json::from_str::<serde_json::Value>(&event.canonical_json()).expect("json");
   2787 
   2788         assert_eq!(value[0], 0);
   2789         assert_eq!(value[4].as_array().expect("tags").len(), 64);
   2790         assert_eq!(value[5], "large tag set");
   2791     }
   2792 
   2793     #[test]
   2794     fn parser_fuzz_style_scalar_corpus_is_total() {
   2795         let ids = ["0", "a", "f", "g", "A", "00", "ff"];
   2796         for id_seed in ids {
   2797             let id = id_seed.repeat(EventId::HEX_LENGTH);
   2798             let raw = serde_json::json!([
   2799                 "EVENT",
   2800                 {
   2801                     "id": id,
   2802                     "pubkey": "1".repeat(PublicKeyHex::HEX_LENGTH),
   2803                     "created_at": 1_714_124_433_u64,
   2804                     "kind": 1,
   2805                     "tags": [["e", "a".repeat(EventId::HEX_LENGTH)]],
   2806                     "content": "fuzz",
   2807                     "sig": "2".repeat(SignatureHex::HEX_LENGTH)
   2808                 }
   2809             ])
   2810             .to_string();
   2811             std::panic::catch_unwind(|| {
   2812                 let _ = parse_client_message(&raw);
   2813             })
   2814             .expect("event parser must not panic");
   2815         }
   2816         for size in [1_usize, 2, 4, 8, 16, 32, 64, 128] {
   2817             let values = (0..size)
   2818                 .map(|index| serde_json::Value::String(format!("topic-{index}")))
   2819                 .collect::<Vec<_>>();
   2820             let raw = serde_json::json!(["REQ", "fuzz", {"#t": values}]).to_string();
   2821             assert!(parse_client_message(&raw).is_ok());
   2822         }
   2823     }
   2824 
   2825     fn unsigned_event(tags: Vec<Tag>, content: &str) -> UnsignedEvent {
   2826         UnsignedEvent::new(
   2827             PublicKeyHex::new(&"1".repeat(PublicKeyHex::HEX_LENGTH)).expect("pubkey"),
   2828             UnixTimestamp::new(1_714_124_433),
   2829             Kind::new(1).expect("kind"),
   2830             tags,
   2831             content,
   2832         )
   2833     }
   2834 
   2835     fn event_for_filter(event_tag: &str, created_at: u64, kind: u64) -> Event {
   2836         Event::new(
   2837             EventId::new(&"a".repeat(EventId::HEX_LENGTH)).expect("id"),
   2838             UnsignedEvent::new(
   2839                 PublicKeyHex::new(&"1".repeat(PublicKeyHex::HEX_LENGTH)).expect("pubkey"),
   2840                 UnixTimestamp::new(created_at),
   2841                 Kind::new(kind).expect("kind"),
   2842                 vec![
   2843                     Tag::from_parts("e", &[event_tag]).expect("event tag"),
   2844                     Tag::from_parts(
   2845                         "p",
   2846                         &["1111111111111111111111111111111111111111111111111111111111111111"],
   2847                     )
   2848                     .expect("pubkey tag"),
   2849                     Tag::from_parts("t", &["radroots"]).expect("topic tag"),
   2850                 ],
   2851                 "hello",
   2852             ),
   2853             SignatureHex::new(&"b".repeat(SignatureHex::HEX_LENGTH)).expect("sig"),
   2854         )
   2855     }
   2856 
   2857     fn addressable_event(d: &str, kind: u64) -> Event {
   2858         Event::new(
   2859             EventId::new(&"a".repeat(EventId::HEX_LENGTH)).expect("id"),
   2860             UnsignedEvent::new(
   2861                 PublicKeyHex::new(&"1".repeat(PublicKeyHex::HEX_LENGTH)).expect("pubkey"),
   2862                 UnixTimestamp::new(50),
   2863                 Kind::new(kind).expect("kind"),
   2864                 vec![
   2865                     Tag::from_parts(
   2866                         "p",
   2867                         &["1111111111111111111111111111111111111111111111111111111111111111"],
   2868                     )
   2869                     .expect("pubkey tag"),
   2870                     Tag::from_parts("d", &[d]).expect("d tag"),
   2871                 ],
   2872                 "hello",
   2873             ),
   2874             SignatureHex::new(&"b".repeat(SignatureHex::HEX_LENGTH)).expect("sig"),
   2875         )
   2876     }
   2877 
   2878     fn addressable_event_without_d() -> Event {
   2879         Event::new(
   2880             EventId::new(&"a".repeat(EventId::HEX_LENGTH)).expect("id"),
   2881             UnsignedEvent::new(
   2882                 PublicKeyHex::new(&"1".repeat(PublicKeyHex::HEX_LENGTH)).expect("pubkey"),
   2883                 UnixTimestamp::new(50),
   2884                 Kind::new(30_402).expect("kind"),
   2885                 vec![
   2886                     Tag::from_parts(
   2887                         "p",
   2888                         &["1111111111111111111111111111111111111111111111111111111111111111"],
   2889                     )
   2890                     .expect("pubkey tag"),
   2891                 ],
   2892                 "hello",
   2893             ),
   2894             SignatureHex::new(&"b".repeat(SignatureHex::HEX_LENGTH)).expect("sig"),
   2895         )
   2896     }
   2897 
   2898     fn tags_json() -> &'static str {
   2899         "[[\"e\",\"root\"],[\"p\",\"peer\",\"wss://relay.example\"]]"
   2900     }
   2901 
   2902     fn event_json(id_char: &str, sig_char: &str, kind: u64, tags: &str) -> String {
   2903         format!(
   2904             "{{\"id\":\"{}\",\"pubkey\":\"{}\",\"created_at\":1714124433,\"kind\":{},\"tags\":{},\"content\":\"hello\",\"sig\":\"{}\"}}",
   2905             id_char.repeat(EventId::HEX_LENGTH),
   2906             "1".repeat(PublicKeyHex::HEX_LENGTH),
   2907             kind,
   2908             tags,
   2909             sig_char.repeat(SignatureHex::HEX_LENGTH)
   2910         )
   2911     }
   2912 
   2913     fn event_value_with(field: &'static str, value: serde_json::Value) -> serde_json::Value {
   2914         let mut event =
   2915             serde_json::from_str::<serde_json::Value>(&event_json("a", "b", 1, tags_json()))
   2916                 .expect("event value");
   2917         event
   2918             .as_object_mut()
   2919             .expect("event object")
   2920             .insert(field.to_owned(), value);
   2921         event
   2922     }
   2923 
   2924     fn event_value_without(field: &'static str) -> serde_json::Value {
   2925         let mut event =
   2926             serde_json::from_str::<serde_json::Value>(&event_json("a", "b", 1, tags_json()))
   2927                 .expect("event value");
   2928         event.as_object_mut().expect("event object").remove(field);
   2929         event
   2930     }
   2931 }