lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

commit 8c54865ac4eee33f584d3cd821535435ca6f9eed
parent 1abdfa1b493b07b7e56faef6ed0448b91b6b6e40
Author: triesap <tyson@radroots.org>
Date:   Tue, 28 Jul 2026 22:24:55 +0000

event: replace identifier strings with canonical owned types

- store fixed-width event signature trade and pointer IDs as typed bytes
- remove semantic string deref behavior and require explicit boundary encoding
- migrate codec storage transport and trade consumers to canonical identifiers
- refresh successor contract evidence and verify package and workspace gates

Diffstat:
Mcrates/authority/src/authorization.rs | 7+++----
Mcrates/authority/src/local_signer.rs | 2+-
Mcrates/authority/src/signer.rs | 7+++----
Mcrates/event/src/calendar.rs | 4++--
Mcrates/event/src/comment.rs | 12++++++------
Mcrates/event/src/contract/registry_v7.rs | 2+-
Mcrates/event/src/deletion.rs | 11++++++-----
Mcrates/event/src/draft.rs | 89+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Mcrates/event/src/envelope.rs | 28++++++++++++++--------------
Mcrates/event/src/event_head/v1.rs | 4++--
Mcrates/event/src/id.rs | 17+++++++++++------
Mcrates/event/src/ids.rs | 321++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Mcrates/event/src/order.rs | 26+++++++++++++-------------
Mcrates/event/src/relay_hint.rs | 18+-----------------
Mcrates/event/src/reply.rs | 10++++++----
Mcrates/event/src/trade.rs | 12++++++------
Mcrates/event/src/wire/v1/tests.rs | 4++--
Mcrates/event/tests/package_boundary.rs | 24++++++++++++++++++++++++
Mcrates/event_codec/src/admission.rs | 2+-
Mcrates/event_codec/src/calendar/encode.rs | 2+-
Mcrates/event_codec/src/comment/authored.rs | 6+++---
Mcrates/event_codec/src/comment/inbound/registry_v7/tests.rs | 4++--
Mcrates/event_codec/src/deletion/authored.rs | 2+-
Mcrates/event_codec/src/deletion/reconciliation_v1/admission/tests.rs | 2+-
Mcrates/event_codec/src/deletion/reconciliation_v1/evaluator/tests.rs | 20++++++++++----------
Mcrates/event_codec/src/deletion/reconciliation_v1/inbound/tests.rs | 4++--
Mcrates/event_codec/src/farm/mod.rs | 2+-
Mcrates/event_codec/src/farm_crdt/mod.rs | 2+-
Mcrates/event_codec/src/farm_file/mod.rs | 2+-
Mcrates/event_codec/src/farm_workspace/mod.rs | 2+-
Mcrates/event_codec/src/food_availability/revision.rs | 2+-
Mcrates/event_codec/src/http_auth/mod.rs | 2+-
Mcrates/event_codec/src/job/traits.rs | 23++++++++++++++---------
Mcrates/event_codec/src/knowledge/decode.rs | 2+-
Mcrates/event_codec/src/operational_listing/decode.rs | 8++++----
Mcrates/event_codec/src/order/decode.rs | 14+++++++-------
Mcrates/event_codec/src/order/encode.rs | 18++++++++++--------
Mcrates/event_codec/src/order/tags.rs | 4++--
Mcrates/event_codec/src/parsed.rs | 4++--
Mcrates/event_codec/src/relay_auth/mod.rs | 2+-
Mcrates/event_codec/src/reply/authored.rs | 2+-
Mcrates/event_codec/src/reply/inbound/registry_v7/tests.rs | 12++++++------
Mcrates/event_codec/src/trade/mod.rs | 2+-
Mcrates/event_codec/src/verification/v1.rs | 20+++++++++-----------
Mcrates/event_codec/src/verification/v1/tests.rs | 2+-
Mcrates/event_codec/tests/app_data.rs | 4++--
Mcrates/event_codec/tests/article.rs | 4++--
Mcrates/event_codec/tests/calendar.rs | 6+++---
Mcrates/event_codec/tests/calendar_conformance.rs | 4++--
Mcrates/event_codec/tests/file_metadata.rs | 2+-
Mcrates/event_codec/tests/follow.rs | 2+-
Mcrates/event_codec/tests/food_availability_conformance.rs | 8++++----
Mcrates/event_codec/tests/geochat.rs | 2+-
Mcrates/event_codec/tests/gift_wrap.rs | 2+-
Mcrates/event_codec/tests/job_traits.rs | 30+++++++++++++++++-------------
Mcrates/event_codec/tests/knowledge.rs | 4++--
Mcrates/event_codec/tests/knowledge_fixtures.rs | 6+++---
Mcrates/event_codec/tests/list.rs | 2+-
Mcrates/event_codec/tests/list_set.rs | 2+-
Mcrates/event_codec/tests/message.rs | 2+-
Mcrates/event_codec/tests/message_file.rs | 2+-
Mcrates/event_codec/tests/nip09_suppression_conformance.rs | 4++--
Mcrates/event_codec/tests/operational_listing.rs | 6+++---
Mcrates/event_codec/tests/profile.rs | 4++--
Mcrates/event_codec/tests/reaction.rs | 2+-
Mcrates/event_codec/tests/report.rs | 2+-
Mcrates/event_codec/tests/repost.rs | 2+-
Mcrates/event_codec/tests/seal.rs | 2+-
Mcrates/event_codec/tests/structured_decode.rs | 6+++---
Mcrates/event_codec/tests/verified_admission_conformance.rs | 6+++---
Mcrates/event_codec/tests/verified_comment_conformance.rs | 8++++----
Mcrates/event_codec/tests/verified_deletion_conformance.rs | 2+-
Mcrates/event_codec/tests/verified_post_conformance.rs | 2+-
Mcrates/event_codec/tests/verified_profile_conformance.rs | 8++++----
Mcrates/event_codec/tests/wire.rs | 2+-
Mcrates/event_store/contracts/source_maintenance_v1.manifest.json | 97++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Mcrates/event_store/contracts/source_maintenance_v1.manifest.sha256 | 2+-
Mcrates/event_store/src/generated/source_maintenance_manifest.rs | 6+++---
Mcrates/event_store/src/nip09/reconciliation_v1.rs | 95++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mcrates/event_store/src/source_maintenance_v1.rs | 8+++++---
Mcrates/event_store/src/store.rs | 482++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mcrates/event_store/src/store/addressable_transition_feed_v1.rs | 14+++++++-------
Mcrates/event_store/src/store/current_visibility_v1.rs | 14+++++---------
Mcrates/event_store/src/store/food_availability_projection_v1.rs | 22+++++++++++-----------
Mcrates/event_store/src/store/post_core_extensions_v1.rs | 12++++++------
Mcrates/event_store/src/store/post_core_storage_v1.rs | 53+++++++++++++++++++++++++++--------------------------
Mcrates/event_store/src/store/protocol_reconciliation_v1.rs | 18+++++++++---------
Mcrates/event_store/tests/food_availability_projection_v1_result_vector.rs | 22+++++++++++-----------
Mcrates/nostr/src/draft_signing.rs | 7++++---
Mcrates/nostr/src/event_verify.rs | 10+++++-----
Mcrates/nostr/src/job_adapter.rs | 4++--
Mcrates/nostr/tests/nip10_reply_profile.rs | 6+++---
Mcrates/outbox/src/store.rs | 104++++++++++++++++++++++++++++++++++++++++----------------------------------------
Mcrates/replica_sync/src/ingest.rs | 18+++++++++---------
Mcrates/trade/src/operational_listing/mutation.rs | 13+++++++++----
Mcrates/trade/src/operational_listing/validation.rs | 10+++++-----
Mcrates/trade/src/validation_receipt.rs | 2+-
Mtools/xtask/src/contract/food_availability_projection.rs | 8++++----
Mtools/xtask/src/contract/nip09_reconciliation.rs | 4++--
Mtools/xtask/src/contract/source_maintenance.rs | 15++++++++++-----
100 files changed, 1069 insertions(+), 880 deletions(-)

diff --git a/crates/authority/src/authorization.rs b/crates/authority/src/authorization.rs @@ -282,9 +282,8 @@ mod tests { id: self .overrides .event_id - .as_deref() - .unwrap_or(draft.expected_event_id_str()) - .to_owned(), + .clone() + .unwrap_or_else(|| draft.expected_event_id_hex()), pubkey: self.pubkey.to_string(), created_at: self.overrides.created_at.unwrap_or(draft.created_at_u64()), kind: self.overrides.kind.unwrap_or(draft.kind_u32()), @@ -643,7 +642,7 @@ mod tests { let signed = sign_authorized_draft(&actor, &signer, &draft).expect("signed"); - assert_eq!(signed.id_str(), draft.expected_event_id_str()); + assert_eq!(signed.id_str(), draft.expected_event_id_hex()); assert_eq!(signed.pubkey().to_hex(), draft.expected_pubkey().to_hex()); assert_eq!(signed.kind(), KIND_CLASSIFIED_LISTING); } diff --git a/crates/authority/src/local_signer.rs b/crates/authority/src/local_signer.rs @@ -85,7 +85,7 @@ mod tests { let signed = signer.sign_frozen_draft(&draft).expect("signed"); - assert_eq!(signed.id_str(), draft.expected_event_id_str()); + assert_eq!(signed.id_str(), draft.expected_event_id_hex()); assert_eq!(signed.pubkey().to_hex(), draft.expected_pubkey().to_hex()); assert_eq!( radroots_nostr_verify_event(&verification_event(&signed)), diff --git a/crates/authority/src/signer.rs b/crates/authority/src/signer.rs @@ -111,9 +111,8 @@ mod tests { } let id = self .event_id - .as_deref() - .unwrap_or(draft.expected_event_id_str()) - .to_owned(); + .clone() + .unwrap_or_else(|| draft.expected_event_id_hex()); let wire = RadrootsNip01EventWire { id, pubkey: self.pubkey.to_string(), @@ -174,7 +173,7 @@ mod tests { let signed = signer.sign_frozen_draft(&draft).expect("signed"); - assert_eq!(signed.id_str(), draft.expected_event_id_str()); + assert_eq!(signed.id_str(), draft.expected_event_id_hex()); assert_eq!(signed.pubkey().to_hex(), pubkey); assert_eq!(signed.kind(), KIND_GEOCHAT); } diff --git a/crates/event/src/calendar.rs b/crates/event/src/calendar.rs @@ -389,7 +389,7 @@ impl RadrootsCalendarEventRevisionReference { pub fn is_canonical(&self) -> bool { // Relay hints use strict Radroots syntax; their raw URL spelling is not normalized. - self.raw_event_id == self.event_id.as_str() + self.raw_event_id == self.event_id.to_hex() && self .relay() .is_none_or(|relay| RadrootsRelayUrl::parse(relay).is_ok()) @@ -2983,7 +2983,7 @@ mod tests { ) .unwrap(); assert_eq!(revision.raw_event_id(), "B".repeat(64)); - assert_eq!(revision.event_id().as_str(), "b".repeat(64)); + assert_eq!(revision.event_id().to_hex(), "b".repeat(64)); assert!(!revision.is_canonical()); let author = RadrootsCalendarEventAuthorReference::parse( diff --git a/crates/event/src/comment.rs b/crates/event/src/comment.rs @@ -627,7 +627,7 @@ fn validate_authored_comment_wire_size( &mut tag_count, &[ "E", - reference.event_id().as_str(), + reference.event_id().to_hex().as_str(), reference.relay_or_empty(), reference.author().to_hex().as_str(), ], @@ -672,7 +672,7 @@ fn validate_authored_comment_wire_size( &mut tag_count, &[ "e", - reference.event_id().as_str(), + reference.event_id().to_hex().as_str(), reference.relay_or_empty(), reference.author().to_hex().as_str(), ], @@ -710,7 +710,7 @@ fn validate_authored_comment_wire_size( &mut tags_json_bytes, &mut tag_count, "e", - current_revision.as_str(), + current_revision.to_hex().as_str(), reference.relay(), ); add_tag( @@ -736,7 +736,7 @@ fn validate_authored_comment_wire_size( &mut tag_count, &[ "e", - parent.event_id().as_str(), + parent.event_id().to_hex().as_str(), parent.relay_or_empty(), parent.author().to_hex().as_str(), ], @@ -911,7 +911,7 @@ mod tests { let root = event_root(KIND_CLASSIFIED_LISTING); let parent = RadrootsNip22CommentParentReference::parse( - root.event_id().as_str(), + root.event_id().to_hex(), "d".repeat(64), None, ) @@ -944,7 +944,7 @@ mod tests { assert!(matches!( comment.position(), RadrootsNip22CommentPosition::TopLevelAddress { current_revision } - if current_revision.as_str() == "e".repeat(64) + if current_revision.to_hex() == "e".repeat(64) )); } diff --git a/crates/event/src/contract/registry_v7.rs b/crates/event/src/contract/registry_v7.rs @@ -4388,7 +4388,7 @@ fn validate_calendar_rsvp_pointer_tag( { let value_is_canonical = tag.get(1).is_some_and(|value| { if event_id { - RadrootsEventId::parse(value).is_ok_and(|parsed| parsed.as_str() == value) + RadrootsEventId::parse(value).is_ok_and(|parsed| parsed.to_hex() == *value) } else { parse_public_key(value).is_ok_and(|parsed| parsed.to_hex() == *value) } diff --git a/crates/event/src/deletion.rs b/crates/event/src/deletion.rs @@ -275,7 +275,7 @@ impl RadrootsAuthoredNip09DeletionRequest { &kind_hints, )?; - event_targets.sort_by(|left, right| left.event_id.cmp(&right.event_id)); + event_targets.sort_by_key(|target| target.event_id); if let Some(duplicates) = event_targets .windows(2) .find(|targets| targets[0].event_id == targets[1].event_id) @@ -403,12 +403,13 @@ fn validate_authored_deletion_wire_size( let mut tags_json_bytes = 2usize; let mut visited_tags = 0usize; for target in event_targets { + let event_id = target.event_id().to_hex(); add_tag_size( &mut tag_bytes, &mut tags_json_bytes, &mut visited_tags, "e", - target.event_id().as_str(), + event_id.as_str(), )?; } for target in address_targets { @@ -533,7 +534,7 @@ mod tests { fn target_constructors_validate_identity_and_kind_hint() { let target = RadrootsNip09DeletionEventTarget::parse("A".repeat(64), u16::MAX as u32) .expect("event target"); - assert_eq!(target.event_id().as_str(), "a".repeat(64)); + assert_eq!(target.event_id().to_hex(), "a".repeat(64)); assert_eq!(target.kind_hint(), u16::MAX as u32); assert_eq!( RadrootsNip09DeletionEventTarget::parse("5".repeat(64), 5) @@ -625,11 +626,11 @@ mod tests { .expect("canonical request"); assert_eq!( - request.event_targets()[0].event_id().as_str(), + request.event_targets()[0].event_id().to_hex(), "a".repeat(64) ); assert_eq!( - request.event_targets()[1].event_id().as_str(), + request.event_targets()[1].event_id().to_hex(), "f".repeat(64) ); assert_eq!( diff --git a/crates/event/src/draft.rs b/crates/event/src/draft.rs @@ -318,8 +318,8 @@ impl RadrootsEventDraft { ); if actual_event_id != self.expected_event_id { return Err(RadrootsDraftError::DraftExpectedEventIdMismatch { - expected_event_id: actual_event_id.as_str().to_owned(), - actual_event_id: self.expected_event_id_str().to_owned(), + expected_event_id: actual_event_id.to_hex(), + actual_event_id: self.expected_event_id.to_hex(), }); } Ok(()) @@ -380,8 +380,8 @@ impl RadrootsEventDraft { } #[inline] - pub fn expected_event_id_str(&self) -> &str { - self.expected_event_id.as_str() + pub fn expected_event_id_hex(&self) -> String { + self.expected_event_id.to_hex() } } @@ -436,8 +436,8 @@ impl<'de> serde::Deserialize<'de> for RadrootsEventDraft { if draft.expected_event_id != value.expected_event_id { return Err(serde::de::Error::custom( RadrootsDraftError::DraftExpectedEventIdMismatch { - expected_event_id: draft.expected_event_id_str().to_owned(), - actual_event_id: value.expected_event_id.as_str().to_owned(), + expected_event_id: draft.expected_event_id.to_hex(), + actual_event_id: value.expected_event_id.to_hex(), }, )); } @@ -655,9 +655,15 @@ impl RadrootsSignedEvent { self.envelope.id() } + /// Returns the canonical NIP-01 event-id encoding retained by the wire boundary. #[inline] pub fn id_str(&self) -> &str { - self.envelope.id_str() + self.wire.id.as_str() + } + + #[inline] + pub fn id_hex(&self) -> String { + self.envelope.id().to_hex() } #[inline] @@ -689,9 +695,15 @@ impl RadrootsSignedEvent { self.envelope.sig() } + /// Returns the canonical NIP-01 signature encoding retained by the wire boundary. #[inline] pub fn sig_str(&self) -> &str { - self.envelope.sig_str() + self.wire.sig.as_str() + } + + #[inline] + pub fn signature_hex(&self) -> String { + self.envelope.sig().to_hex() } #[cfg(feature = "signature")] @@ -753,10 +765,10 @@ pub fn validate_signed_nostr_event_matches_draft( actual_len: signed_event.content().len(), }); } - if signed_event.id_str() != draft.expected_event_id_str() { + if signed_event.id() != draft.expected_event_id() { return Err(RadrootsDraftError::SignedEventIdMismatch { - expected_event_id: draft.expected_event_id_str().to_owned(), - actual_event_id: signed_event.id_str().to_owned(), + expected_event_id: draft.expected_event_id.to_hex(), + actual_event_id: signed_event.id().to_hex(), }); } let signed_pubkey = signed_event.pubkey().to_hex(); @@ -766,12 +778,11 @@ pub fn validate_signed_nostr_event_matches_draft( signed_event.kind(), &signed_tags, signed_event.content(), - ) - .into_string(); - if computed_event_id.as_str() != signed_event.id_str() { + ); + if computed_event_id != *signed_event.id() { return Err(RadrootsDraftError::SignedEventComputedIdMismatch { - expected_event_id: signed_event.id_str().to_owned(), - computed_event_id, + expected_event_id: signed_event.id().to_hex(), + computed_event_id: computed_event_id.to_hex(), }); } Ok(()) @@ -783,13 +794,9 @@ fn verify_bip340_signature( ) -> Result<(), RadrootsSignatureVerificationError> { use secp256k1::{Message, Secp256k1, XOnlyPublicKey, schnorr::Signature}; - let mut event_id = [0u8; 32]; - hex::decode_to_slice(signed_event.id_str(), &mut event_id) - .map_err(|_| RadrootsSignatureVerificationError::InvalidEventId)?; + let event_id = *signed_event.id().as_bytes(); let pubkey = signed_event.pubkey().into_bytes(); - let mut sig = [0u8; 64]; - hex::decode_to_slice(signed_event.sig_str(), &mut sig) - .map_err(|_| RadrootsSignatureVerificationError::InvalidSignature)?; + let sig = *signed_event.sig().as_bytes(); let message = Message::from_digest(event_id); let pubkey = XOnlyPublicKey::from_slice(&pubkey) .map_err(|_| RadrootsSignatureVerificationError::InvalidPubkey)?; @@ -975,7 +982,7 @@ mod tests { "[0,\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",1700000000,20000,[],\"hello\"]" ); assert_eq!( - draft.expected_event_id_str(), + draft.expected_event_id_hex(), "07643222c33091b20114d5baf1a32288e808177eac7d87acb2c4f610363a2a7d" ); } @@ -1022,7 +1029,7 @@ mod tests { .expect("event id"); assert_eq!( - event_id.as_str(), + event_id.to_hex(), "679ee570a933961d4f5ee95ed60cbc34d85c9c24a8da5e92f6036462ee0fc852" ); } @@ -1274,15 +1281,15 @@ mod tests { let decoded: RadrootsSignedEvent = serde_json::from_str(&json).expect("deserialize"); assert_eq!(decoded, signed); - assert_eq!(decoded.envelope().id_str(), decoded.id_str()); - assert_eq!(decoded.wire().id, decoded.id_str()); - assert_eq!(decoded.id().as_str(), decoded.id_str()); + assert_eq!(decoded.envelope().id_hex(), decoded.id_hex()); + assert_eq!(decoded.wire().id, decoded.id_hex()); + assert_eq!(decoded.id().to_hex(), decoded.id_hex()); assert_eq!(decoded.pubkey().to_hex(), hex_64('e')); assert_eq!(decoded.created_at(), 10); assert_eq!(decoded.kind(), KIND_POST); assert_eq!(decoded.tags_as_vec(), wire.tags); assert_eq!(decoded.content(), "hello"); - assert_eq!(decoded.sig().as_str(), decoded.sig_str()); + assert_eq!(decoded.sig().to_hex(), decoded.signature_hex()); assert_eq!(decoded.raw_json(), raw_json); } @@ -1300,9 +1307,9 @@ mod tests { let signed = RadrootsSignedEvent::from_wire_verified_id(wire.clone(), raw_json.clone()) .expect("signed event"); - assert_eq!(signed.id_str(), wire.id); + assert_eq!(signed.id_hex(), wire.id); assert_eq!(signed.pubkey().to_hex(), hex_64('2')); - assert_eq!(signed.sig_str(), hex_128('3')); + assert_eq!(signed.signature_hex(), hex_128('3')); assert_eq!(signed.raw_json(), raw_json); let invalid = RadrootsSignedEvent::new(RadrootsSignedEventParts { @@ -1375,7 +1382,7 @@ mod tests { let signed = RadrootsSignedEvent::from_wire_unchecked( unchecked_wire( - draft.expected_event_id_str().to_string(), + draft.expected_event_id_hex(), hex_64('c'), draft.created_at_u64(), draft.kind_u32(), @@ -1415,7 +1422,7 @@ mod tests { let signed = RadrootsSignedEvent::from_wire_unchecked( unchecked_wire( - draft.expected_event_id_str().to_string(), + draft.expected_event_id_hex(), draft.expected_pubkey().to_hex(), draft.created_at_u64() + 1, draft.kind_u32(), @@ -1435,7 +1442,7 @@ mod tests { let signed = RadrootsSignedEvent::from_wire_unchecked( unchecked_wire( - draft.expected_event_id_str().to_string(), + draft.expected_event_id_hex(), draft.expected_pubkey().to_hex(), draft.created_at_u64(), KIND_PROFILE, @@ -1457,7 +1464,7 @@ mod tests { tags.push(vec!["p".to_owned(), hex_64('e')]); let signed = RadrootsSignedEvent::from_wire_unchecked( unchecked_wire( - draft.expected_event_id_str().to_string(), + draft.expected_event_id_hex(), draft.expected_pubkey().to_hex(), draft.created_at_u64(), draft.kind_u32(), @@ -1477,7 +1484,7 @@ mod tests { let signed = RadrootsSignedEvent::from_wire_unchecked( unchecked_wire( - draft.expected_event_id_str().to_string(), + draft.expected_event_id_hex(), draft.expected_pubkey().to_hex(), draft.created_at_u64(), draft.kind_u32(), @@ -1603,16 +1610,16 @@ mod tests { assert_eq!(draft.tags().to_vec(), draft.tags_as_vec()); assert_eq!(draft.expected_pubkey().to_hex(), hex_64('a')); assert_eq!( - draft.expected_event_id().as_str(), - draft.expected_event_id_str() + draft.expected_event_id().to_hex(), + draft.expected_event_id_hex() ); let signed = signed_event_for_draft(&draft); - assert_eq!(signed.envelope().id_str(), signed.id_str()); - assert_eq!(signed.wire().id, signed.id_str()); - assert_eq!(signed.id().as_str(), signed.id_str()); + assert_eq!(signed.envelope().id_hex(), signed.id_hex()); + assert_eq!(signed.wire().id, signed.id_hex()); + assert_eq!(signed.id().to_hex(), signed.id_hex()); assert_eq!(signed.pubkey(), draft.expected_pubkey()); - assert_eq!(signed.sig().as_str(), signed.sig_str()); + assert_eq!(signed.sig().to_hex(), signed.signature_hex()); for error in [ RadrootsSignedEventError::Wire(RadrootsEventWireError::NonCanonicalIdentifier { diff --git a/crates/event/src/envelope.rs b/crates/event/src/envelope.rs @@ -1,7 +1,7 @@ #![forbid(unsafe_code)] #[cfg(all(not(feature = "std"), not(test)))] -use alloc::{string::String, string::ToString, vec::Vec}; +use alloc::{string::String, vec::Vec}; #[cfg(any(feature = "std", test))] use std::{string::String, vec::Vec}; @@ -453,7 +453,7 @@ impl RadrootsEventEnvelope { ) -> Result<Self, RadrootsEventEnvelopeError> { let id = RadrootsEventId::parse(parts.id.as_str()) .map_err(RadrootsEventEnvelopeError::InvalidId)?; - if id.as_str() != parts.id.as_str() { + if id.to_hex() != parts.id { return Err(RadrootsEventEnvelopeError::NonCanonicalId); } let author = parse_public_key(parts.author.as_str()) @@ -463,7 +463,7 @@ impl RadrootsEventEnvelope { } let sig = RadrootsEventSignature::parse(parts.sig.as_str()) .map_err(RadrootsEventEnvelopeError::InvalidSignature)?; - if sig.as_str() != parts.sig.as_str() { + if sig.to_hex() != parts.sig { return Err(RadrootsEventEnvelopeError::NonCanonicalSignature); } let content_len = parts.content.len(); @@ -491,8 +491,8 @@ impl RadrootsEventEnvelope { } #[inline] - pub fn id_str(&self) -> &str { - self.id.as_str() + pub fn id_hex(&self) -> String { + self.id.to_hex() } #[inline] @@ -550,19 +550,19 @@ impl RadrootsEventEnvelope { } #[inline] - pub fn sig_str(&self) -> &str { - self.sig.as_str() + pub fn signature_hex(&self) -> String { + self.sig.to_hex() } pub fn to_nip01_wire(&self) -> RadrootsNip01EventWire { RadrootsNip01EventWire { - id: self.id.as_str().to_string(), + id: self.id.to_hex(), pubkey: self.author.to_hex(), created_at: self.created_at.as_u64(), kind: self.kind.as_u32(), tags: self.tags.to_vec(), content: self.content.clone(), - sig: self.sig.as_str().to_string(), + sig: self.sig.to_hex(), extra: Default::default(), } } @@ -630,13 +630,13 @@ mod tests { fn envelope_uses_private_typed_state_and_getters() { let envelope = RadrootsEventEnvelope::new(event_parts()).expect("envelope"); - assert_eq!(envelope.id_str(), hex_64('1')); + assert_eq!(envelope.id_hex(), hex_64('1')); assert_eq!(envelope.author().to_hex(), hex_64('a')); assert_eq!(envelope.created_at_u64(), u64::from(u32::MAX) + 1); assert_eq!(envelope.kind_u32(), 30_023); assert_eq!(envelope.kind_class(), RadrootsEventKindClass::Addressable); assert_eq!(envelope.content(), "hello"); - assert_eq!(envelope.sig_str(), hex_128('b')); + assert_eq!(envelope.signature_hex(), hex_128('b')); assert_eq!( envelope.tags_as_vec(), vec![vec!["d".to_owned(), "article".to_owned()]] @@ -932,15 +932,15 @@ mod tests { assert!(serde_json::from_str::<RadrootsEventTags>("[[]]").is_err()); let envelope = RadrootsEventEnvelope::new(event_parts()).expect("envelope"); - assert_eq!(envelope.id().as_str(), envelope.id_str()); + assert_eq!(envelope.id().to_hex(), envelope.id_hex()); assert_eq!(envelope.author().to_hex(), hex_64('a')); assert_eq!(envelope.created_at().as_u64(), envelope.created_at_u64()); assert_eq!(envelope.kind().as_u32(), envelope.kind_u32()); assert_eq!(envelope.tags().to_vec(), envelope.tags_as_vec()); assert_eq!(envelope.tag_slices(), envelope.tags().as_slice()); - assert_eq!(envelope.sig().as_str(), envelope.sig_str()); + assert_eq!(envelope.sig().to_hex(), envelope.signature_hex()); let wire = envelope.to_nip01_wire(); - assert_eq!(wire.id, envelope.id_str()); + assert_eq!(wire.id, envelope.id_hex()); let encoded = serde_json::to_string(&envelope).expect("envelope json"); assert_eq!( serde_json::from_str::<RadrootsEventEnvelope>(&encoded).expect("envelope"), diff --git a/crates/event/src/event_head/v1.rs b/crates/event/src/event_head/v1.rs @@ -82,7 +82,7 @@ pub fn event_head_candidate_for_class( RadrootsEventClass::Regular => RadrootsEventHeadCandidateResult::NotHeadSelected, RadrootsEventClass::Ephemeral => RadrootsEventHeadCandidateResult::NotPersisted, RadrootsEventClass::Replaceable | RadrootsEventClass::Addressable => { - let event_id = event.id().clone(); + let event_id = *event.id(); let pubkey = *event.author(); let coordinate = if class == RadrootsEventClass::Replaceable { RadrootsEventHeadCoordinate::Replaceable { @@ -152,7 +152,7 @@ pub fn event_head_candidate_for_nip01_event_v1( }; RadrootsEventHeadCandidateResult::Candidate(RadrootsEventHeadCandidate { coordinate, - event_id: event.id().clone(), + event_id: *event.id(), created_at: event.created_at_u64(), }) } diff --git a/crates/event/src/id.rs b/crates/event/src/id.rs @@ -1,7 +1,12 @@ -//! Canonical event identifier types. -//! -//! Identifier ownership is consolidated here by the ordered identifier refactor. +//! Canonical owned event identifiers and explicit boundary encoders. -/// Internal marker for the target module while identifier types are migrated. -#[allow(dead_code)] -pub(crate) struct ModuleScaffold; +pub use crate::ids::{ + RadrootsAddressableCoordinate as AddressableCoordinate, + RadrootsAddressableCoordinateParts as AddressableCoordinateParts, + RadrootsClassifiedListingAddress as ClassifiedListingAddress, RadrootsDTag as DTag, + RadrootsEventEnvelopePointer as EventEnvelopePointer, RadrootsEventId as EventId, + RadrootsEventPointer as EventPointer, RadrootsEventSignature as EventSignature, + RadrootsIdParseError as ParseError, RadrootsNip01Coordinate as Nip01Coordinate, + RadrootsNip01CoordinateParseError as Nip01CoordinateParseError, + RadrootsNip01CoordinateParts as Nip01CoordinateParts, +}; diff --git a/crates/event/src/ids.rs b/crates/event/src/ids.rs @@ -6,7 +6,10 @@ use alloc::{format, string::String, string::ToString, vec::Vec}; #[cfg(feature = "std")] use std::{string::String, vec::Vec}; -use core::{borrow::Borrow, fmt, ops::Deref, str::FromStr}; +use core::{ + fmt::{self, Write as _}, + str::FromStr, +}; pub(crate) use radroots_identity::PublicKey; use url_nostd::Url; @@ -84,60 +87,127 @@ macro_rules! validated_string_id { } } - impl Deref for $name { - type Target = str; - + impl From<$name> for String { #[inline] - fn deref(&self) -> &Self::Target { - self.as_str() + fn from(value: $name) -> Self { + value.into_string() } } - impl Borrow<str> for $name { - #[inline] - fn borrow(&self) -> &str { - self.as_str() + impl fmt::Display for $name { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) } } - impl From<$name> for String { - #[inline] - fn from(value: $name) -> Self { - value.into_string() + impl FromStr for $name { + type Err = RadrootsIdParseError; + + fn from_str(value: &str) -> Result<Self, Self::Err> { + Self::parse(value) } } - impl PartialEq<&str> for $name { + impl TryFrom<&str> for $name { + type Error = RadrootsIdParseError; + + fn try_from(value: &str) -> Result<Self, Self::Error> { + Self::parse(value) + } + } + + impl TryFrom<String> for $name { + type Error = RadrootsIdParseError; + + fn try_from(value: String) -> Result<Self, Self::Error> { + Self::parse(value) + } + } + + #[cfg(any(feature = "serde", test))] + impl serde::Serialize for $name { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: serde::Serializer, + { + serializer.serialize_str(self.as_str()) + } + } + + #[cfg(any(feature = "serde", test))] + impl<'de> serde::Deserialize<'de> for $name { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: serde::Deserializer<'de>, + { + let value = String::deserialize(deserializer)?; + Self::parse(value).map_err(serde::de::Error::custom) + } + } + }; +} + +macro_rules! validated_hex_id { + ($name:ident, $byte_len:expr) => { + #[cfg_attr(feature = "dto-bindgen", derive(dto_bindgen::Dto))] + #[cfg_attr(feature = "dto-bindgen", dto(as = "string"))] + #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct $name([u8; $byte_len]); + + impl $name { + pub fn parse(value: impl AsRef<str>) -> Result<Self, RadrootsIdParseError> { + decode_hex::<$byte_len>(value.as_ref()).map(Self) + } + + #[inline] + pub const fn from_bytes(bytes: [u8; $byte_len]) -> Self { + Self(bytes) + } + + #[inline] + pub const fn as_bytes(&self) -> &[u8; $byte_len] { + &self.0 + } + + #[inline] + pub const fn into_bytes(self) -> [u8; $byte_len] { + self.0 + } + + pub fn to_hex(&self) -> String { + encode_hex(self.0.as_slice()) + } + #[inline] - fn eq(&self, other: &&str) -> bool { - self.as_str() == *other + pub fn into_string(self) -> String { + self.to_hex() } } - impl PartialEq<$name> for &str { + impl AsRef<[u8]> for $name { #[inline] - fn eq(&self, other: &$name) -> bool { - *self == other.as_str() + fn as_ref(&self) -> &[u8] { + self.0.as_slice() } } - impl PartialEq<String> for $name { + impl From<[u8; $byte_len]> for $name { #[inline] - fn eq(&self, other: &String) -> bool { - self.as_str() == other.as_str() + fn from(bytes: [u8; $byte_len]) -> Self { + Self::from_bytes(bytes) } } - impl PartialEq<$name> for String { + impl From<$name> for [u8; $byte_len] { #[inline] - fn eq(&self, other: &$name) -> bool { - self.as_str() == other.as_str() + fn from(value: $name) -> Self { + value.into_bytes() } } impl fmt::Display for $name { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.as_str()) + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + write_hex(formatter, self.0.as_slice()) } } @@ -171,7 +241,7 @@ macro_rules! validated_string_id { where S: serde::Serializer, { - serializer.serialize_str(self.as_str()) + serializer.collect_str(self) } } @@ -188,11 +258,11 @@ macro_rules! validated_string_id { }; } -validated_string_id!(RadrootsEventId, validate_hex_64); -validated_string_id!(RadrootsEventSignature, validate_hex_128); -validated_string_id!(RadrootsTradeId, validate_hex_32); -validated_string_id!(RadrootsTradeCandidateId, validate_hex_64); -validated_string_id!(RadrootsTradeMutationId, validate_hex_64); +validated_hex_id!(RadrootsEventId, 32); +validated_hex_id!(RadrootsEventSignature, 64); +validated_hex_id!(RadrootsTradeId, 16); +validated_hex_id!(RadrootsTradeCandidateId, 32); +validated_hex_id!(RadrootsTradeMutationId, 32); validated_string_id!(RadrootsDTag, validate_d_tag); validated_string_id!( RadrootsAddressableCoordinate, @@ -206,7 +276,7 @@ validated_string_id!(RadrootsOrderId, validate_commercial_id); validated_string_id!(RadrootsOrderQuoteId, validate_commercial_id); validated_string_id!(RadrootsInventoryBinId, validate_commercial_id); validated_string_id!(RadrootsEconomicsDigest, validate_economics_digest); -validated_string_id!(RadrootsEventPointer, validate_hex_64); +validated_hex_id!(RadrootsEventPointer, 32); validated_string_id!(RadrootsRelayUrl, validate_relay_url); pub(crate) fn parse_public_key(value: impl AsRef<str>) -> Result<PublicKey, RadrootsIdParseError> { @@ -390,22 +460,6 @@ impl AsRef<str> for RadrootsNip01Coordinate { } } -impl Deref for RadrootsNip01Coordinate { - type Target = str; - - #[inline] - fn deref(&self) -> &Self::Target { - self.as_str() - } -} - -impl Borrow<str> for RadrootsNip01Coordinate { - #[inline] - fn borrow(&self) -> &str { - self.as_str() - } -} - impl From<RadrootsNip01Coordinate> for String { #[inline] fn from(value: RadrootsNip01Coordinate) -> Self { @@ -502,16 +556,54 @@ impl RadrootsEventEnvelopePointer { } } -fn validate_hex_64(value: &str) -> Result<String, RadrootsIdParseError> { - validate_hex(value, 64) +fn decode_hex<const N: usize>(value: &str) -> Result<[u8; N], RadrootsIdParseError> { + let expected = N * 2; + if value.len() != expected { + return Err(RadrootsIdParseError::InvalidLength { + expected, + actual: value.len(), + }); + } + + let mut decoded = [0_u8; N]; + for (index, pair) in value.as_bytes().chunks_exact(2).enumerate() { + decoded[index] = (decode_hex_nibble(pair[0])? << 4) | decode_hex_nibble(pair[1])?; + } + Ok(decoded) +} + +fn decode_hex_nibble(value: u8) -> Result<u8, RadrootsIdParseError> { + match value { + b'0'..=b'9' => Ok(value - b'0'), + b'a'..=b'f' => Ok(value - b'a' + 10), + b'A'..=b'F' => Ok(value - b'A' + 10), + _ => Err(RadrootsIdParseError::InvalidCharacter), + } } -fn validate_hex_32(value: &str) -> Result<String, RadrootsIdParseError> { - validate_hex(value, 32) +fn encode_hex(bytes: &[u8]) -> String { + const LOWER_HEX: &[u8; 16] = b"0123456789abcdef"; + let mut encoded = String::with_capacity(bytes.len() * 2); + for byte in bytes { + encoded.push(LOWER_HEX[usize::from(byte >> 4)] as char); + encoded.push(LOWER_HEX[usize::from(byte & 0x0f)] as char); + } + encoded } -fn validate_hex_128(value: &str) -> Result<String, RadrootsIdParseError> { - validate_hex(value, 128) +fn write_hex(formatter: &mut fmt::Formatter<'_>, bytes: &[u8]) -> fmt::Result { + for byte in bytes { + formatter.write_char(lower_hex_digit(byte >> 4))?; + formatter.write_char(lower_hex_digit(byte & 0x0f))?; + } + Ok(()) +} + +const fn lower_hex_digit(value: u8) -> char { + match value { + 0..=9 => (b'0' + value) as char, + _ => (b'a' + value - 10) as char, + } } fn validate_hex(value: &str, expected_len: usize) -> Result<String, RadrootsIdParseError> { @@ -655,7 +747,7 @@ fn validate_relay_url(value: &str) -> Result<String, RadrootsIdParseError> { mod tests { use super::*; - macro_rules! assert_identifier_impls { + macro_rules! assert_string_identifier_impls { ($ty:ty, $value:expr) => {{ let value = $value.to_owned(); let value = value.as_str(); @@ -663,8 +755,6 @@ mod tests { assert_eq!(id.as_str(), value); assert_eq!(id.as_ref(), value); - assert_eq!(&*id, value); - assert_eq!(<$ty as core::borrow::Borrow<str>>::borrow(&id), value); assert_eq!(id.to_string(), value); assert_eq!( <$ty as core::str::FromStr>::from_str(value).expect("from str"), @@ -678,11 +768,6 @@ mod tests { <$ty as TryFrom<String>>::try_from(value.to_owned()).expect("try from string"), id ); - assert_eq!(id, value); - assert_eq!(value, id); - assert_eq!(id, value.to_owned()); - assert_eq!(value.to_owned(), id); - let id = <$ty>::parse(value).expect("parse"); let converted: String = String::from(id.clone()); assert_eq!(converted, value); @@ -698,6 +783,42 @@ mod tests { }}; } + macro_rules! assert_hex_identifier_impls { + ($ty:ty, $value:expr, $byte_len:expr) => {{ + let value = $value.to_owned(); + let value = value.as_str(); + let id = <$ty>::parse(value).expect("parse"); + + assert_eq!(id.to_hex(), value); + assert_eq!(id.as_bytes().len(), $byte_len); + assert_eq!(id.as_ref(), id.as_bytes()); + assert_eq!(id.to_string(), value); + assert_eq!( + <$ty as core::str::FromStr>::from_str(value).expect("from str"), + id + ); + assert_eq!( + <$ty as TryFrom<&str>>::try_from(value).expect("try from str"), + id + ); + assert_eq!( + <$ty as TryFrom<String>>::try_from(value.to_owned()).expect("try from string"), + id + ); + + let bytes = id.into_bytes(); + assert_eq!(<$ty>::from_bytes(bytes), id); + assert_eq!(id.into_string(), value.to_owned()); + + #[cfg(any(feature = "serde", test))] + { + let encoded = serde_json::to_string(&id).expect("serialize"); + let decoded: $ty = serde_json::from_str(&encoded).expect("deserialize"); + assert_eq!(decoded.to_hex(), value); + } + }}; + } + fn hex_64(character: char) -> String { crate::test_valid_hex_64(character) } @@ -720,7 +841,7 @@ mod tests { ); let event_id = RadrootsEventId::parse(hex_64('f')).expect("event id"); - assert_eq!(event_id.as_str(), hex_64('f')); + assert_eq!(event_id.to_hex(), hex_64('f')); assert_eq!( RadrootsEventId::parse(" ".repeat(64)).unwrap_err(), RadrootsIdParseError::InvalidCharacter @@ -771,7 +892,7 @@ mod tests { #[test] fn signatures_require_128_hex_chars() { let signature = RadrootsEventSignature::parse(hex_128('B')).expect("signature"); - assert_eq!(signature.as_str(), "b".repeat(128)); + assert_eq!(signature.to_hex(), "b".repeat(128)); assert_eq!( RadrootsEventSignature::parse(hex_64('b')).unwrap_err(), RadrootsIdParseError::InvalidLength { @@ -784,7 +905,7 @@ mod tests { #[test] fn trade_semantic_ids_use_protocol_sized_hex() { let trade_id = RadrootsTradeId::parse(hex_32('A')).expect("trade id"); - assert_eq!(trade_id.as_str(), hex_32('a')); + assert_eq!(trade_id.to_hex(), hex_32('a')); assert_eq!( RadrootsTradeId::parse(hex_64('a')).unwrap_err(), RadrootsIdParseError::InvalidLength { @@ -792,9 +913,9 @@ mod tests { actual: 64 } ); - assert_identifier_impls!(RadrootsTradeId, &hex_32('a')); - assert_identifier_impls!(RadrootsTradeCandidateId, &hex_64('b')); - assert_identifier_impls!(RadrootsTradeMutationId, &hex_64('c')); + assert_hex_identifier_impls!(RadrootsTradeId, &hex_32('a'), 16); + assert_hex_identifier_impls!(RadrootsTradeCandidateId, &hex_64('b'), 32); + assert_hex_identifier_impls!(RadrootsTradeMutationId, &hex_64('c'), 32); } #[test] @@ -869,6 +990,29 @@ mod tests { .unwrap_err(), RadrootsIdParseError::InvalidCharacter ); + + let noncanonical = format!("030402:{}:listing-1", hex_64('A')); + assert_eq!( + RadrootsAddressableCoordinate::parse(&noncanonical) + .expect("validated addressable coordinate") + .as_str(), + noncanonical + ); + } + + #[test] + fn binary_identifier_order_matches_canonical_hex_order() { + let lower = RadrootsEventId::from_bytes([0_u8; 32]); + let mut upper_bytes = [0_u8; 32]; + upper_bytes[31] = 1; + let upper = RadrootsEventId::from_bytes(upper_bytes); + + assert!(lower < upper); + assert!(lower.to_hex() < upper.to_hex()); + + let mut identifiers = [upper, lower]; + identifiers.sort(); + assert_eq!(identifiers, [lower, upper]); } #[test] @@ -1024,15 +1168,10 @@ mod tests { } #[test] - fn nip01_coordinate_exposes_string_traits_and_validating_serde() { + fn nip01_coordinate_exposes_explicit_text_and_validating_serde() { let value = format!("30000:{}:farm:victoria", hex_64('a')); let coordinate = RadrootsNip01Coordinate::parse(&value).expect("coordinate"); assert_eq!(coordinate.as_ref(), value); - assert_eq!(&*coordinate, value); - assert_eq!( - <RadrootsNip01Coordinate as Borrow<str>>::borrow(&coordinate), - value - ); assert_eq!(coordinate.to_string(), value); assert_eq!( RadrootsNip01Coordinate::from_str(&value).expect("from str"), @@ -1098,24 +1237,24 @@ mod tests { let id = RadrootsOrderQuoteId::try_from(String::from("quote-1")).expect("quote id"); assert_eq!(id.as_ref(), "quote-1"); let parsed: RadrootsEventPointer = hex_64('d').parse().expect("event pointer"); - assert_eq!(parsed.as_str(), hex_64('d')); + assert_eq!(parsed.to_hex(), hex_64('d')); } #[test] fn validated_identifier_wrappers_expose_consistent_traits() { let addressable = format!("30402:{}:listing-1", hex_64('0')); - assert_identifier_impls!(RadrootsEventId, hex_64('b').as_str()); - assert_identifier_impls!(RadrootsEventSignature, hex_128('c').as_str()); - assert_identifier_impls!(RadrootsDTag, "listing-1"); - assert_identifier_impls!(RadrootsAddressableCoordinate, addressable.as_str()); - assert_identifier_impls!(RadrootsClassifiedListingAddress, addressable.as_str()); - assert_identifier_impls!(RadrootsOrderId, "order-1"); - assert_identifier_impls!(RadrootsOrderQuoteId, "quote-1"); - assert_identifier_impls!(RadrootsInventoryBinId, "bin-1"); - assert_identifier_impls!(RadrootsEconomicsDigest, "digest-1"); - assert_identifier_impls!(RadrootsEventPointer, hex_64('d').as_str()); - assert_identifier_impls!(RadrootsRelayUrl, "wss://relay.example.com"); + assert_hex_identifier_impls!(RadrootsEventId, hex_64('b').as_str(), 32); + assert_hex_identifier_impls!(RadrootsEventSignature, hex_128('c').as_str(), 64); + assert_string_identifier_impls!(RadrootsDTag, "listing-1"); + assert_string_identifier_impls!(RadrootsAddressableCoordinate, addressable.as_str()); + assert_string_identifier_impls!(RadrootsClassifiedListingAddress, addressable.as_str()); + assert_string_identifier_impls!(RadrootsOrderId, "order-1"); + assert_string_identifier_impls!(RadrootsOrderQuoteId, "quote-1"); + assert_string_identifier_impls!(RadrootsInventoryBinId, "bin-1"); + assert_string_identifier_impls!(RadrootsEconomicsDigest, "digest-1"); + assert_hex_identifier_impls!(RadrootsEventPointer, hex_64('d').as_str(), 32); + assert_string_identifier_impls!(RadrootsRelayUrl, "wss://relay.example.com"); } #[test] @@ -1189,7 +1328,7 @@ mod tests { fn nostr_event_pointers_validate_relay_values() { let event_id = RadrootsEventId::parse(hex_64('e')).expect("event id"); let pointer = RadrootsEventEnvelopePointer::new( - event_id.clone(), + event_id, ["wss://relay.one.example", "wss://relay.two.example"], ) .expect("pointer"); @@ -1242,7 +1381,7 @@ mod tests { fn serde_deserialization_validates_identifiers() { let encoded = format!("\"{}\"", hex_64('E')); let event_id: RadrootsEventId = serde_json::from_str(&encoded).expect("event id"); - assert_eq!(event_id.as_str(), hex_64('e')); + assert_eq!(event_id.to_hex(), hex_64('e')); let invalid = serde_json::from_str::<RadrootsOrderId>("\"bad id\""); assert!(invalid.is_err()); diff --git a/crates/event/src/order.rs b/crates/event/src/order.rs @@ -103,7 +103,7 @@ impl RadrootsOrderEconomics { } pub fn validate(&self) -> Result<(), RadrootsOrderPayloadError> { - validate_required_field(&self.quote_id, "quote_id")?; + validate_required_field(self.quote_id.as_str(), "quote_id")?; if self.quote_version == 0 { return Err(RadrootsOrderPayloadError::InvalidQuoteVersion); } @@ -152,8 +152,8 @@ pub struct RadrootsOrderRequest { impl RadrootsOrderRequest { pub fn validate(&self) -> Result<(), RadrootsOrderPayloadError> { - validate_required_field(&self.order_id, "order_id")?; - validate_required_field(&self.listing_addr, "listing_addr")?; + validate_required_field(self.order_id.as_str(), "order_id")?; + validate_required_field(self.listing_addr.as_str(), "listing_addr")?; validate_order_items(&self.items)?; self.economics.validate()?; validate_order_economics_binding(&self.items, &self.economics) @@ -231,8 +231,8 @@ pub struct RadrootsOrderDecision { impl RadrootsOrderDecision { pub fn validate(&self) -> Result<(), RadrootsOrderPayloadError> { - validate_required_field(&self.order_id, "order_id")?; - validate_required_field(&self.listing_addr, "listing_addr")?; + validate_required_field(self.order_id.as_str(), "order_id")?; + validate_required_field(self.listing_addr.as_str(), "listing_addr")?; self.decision.validate() } } @@ -257,8 +257,8 @@ pub struct RadrootsOrderCancellation { impl RadrootsOrderCancellation { pub fn validate(&self) -> Result<(), RadrootsOrderPayloadError> { - validate_required_field(&self.order_id, "order_id")?; - validate_required_field(&self.listing_addr, "listing_addr")?; + validate_required_field(self.order_id.as_str(), "order_id")?; + validate_required_field(self.listing_addr.as_str(), "listing_addr")?; validate_required_field(&self.reason, "reason") } } @@ -517,7 +517,7 @@ fn validate_order_items(items: &[RadrootsOrderItem]) -> Result<(), RadrootsOrder return Err(RadrootsOrderPayloadError::MissingItems); } for (index, item) in items.iter().enumerate() { - validate_required_field(&item.bin_id, "bin_id")?; + validate_required_field(item.bin_id.as_str(), "bin_id")?; if item.bin_count == 0 { return Err(RadrootsOrderPayloadError::InvalidItemBinCount { index }); } @@ -530,7 +530,7 @@ fn validate_economic_item( expected_currency: Currency, index: usize, ) -> Result<Money, RadrootsOrderPayloadError> { - validate_required_field(&item.bin_id, "economics.items.bin_id")?; + validate_required_field(item.bin_id.as_str(), "economics.items.bin_id")?; if item.bin_count == 0 { return Err(RadrootsOrderPayloadError::InvalidEconomicItemBinCount { index }); } @@ -574,7 +574,7 @@ fn validate_order_economics_binding( return Err(RadrootsOrderPayloadError::InvalidOrderEconomicsBinding { field: "items" }); } for (item, economic_item) in order_items.iter().zip(economics.items.iter()) { - if item.bin_id != economic_item.bin_id { + if item.bin_id != economic_item.bin_id.as_str() { return Err(RadrootsOrderPayloadError::InvalidOrderEconomicsBinding { field: "items.bin_id", }); @@ -599,7 +599,7 @@ fn normalized_order_item_counts( ) -> Option<Vec<NormalizedOrderItemCount>> { let mut counts: Vec<NormalizedOrderItemCount> = Vec::new(); for item in items { - let bin_id = item.bin_id.trim(); + let bin_id = item.bin_id.as_str(); if item.bin_count == 0 { return None; } @@ -736,7 +736,7 @@ fn validate_inventory_commitments( return Err(RadrootsOrderPayloadError::MissingInventoryCommitments); } for (index, commitment) in commitments.iter().enumerate() { - validate_required_field(&commitment.bin_id, "bin_id")?; + validate_required_field(commitment.bin_id.as_str(), "bin_id")?; if commitment.bin_count == 0 { return Err(RadrootsOrderPayloadError::InvalidInventoryCommitmentCount { index }); } @@ -1099,7 +1099,7 @@ mod tests { ); let canonical = economics.canonicalized(); - assert_eq!(canonical.items[0].bin_id, "bin-a"); + assert_eq!(canonical.items[0].bin_id.as_str(), "bin-a"); assert_eq!(canonical.discounts[0].id, "discount-a"); assert_eq!(canonical.adjustments[0].id, "adjustment-a"); assert_eq!(canonical.subtotal, usd("18")); diff --git a/crates/event/src/relay_hint.rs b/crates/event/src/relay_hint.rs @@ -1,6 +1,6 @@ #[cfg(not(feature = "std"))] use alloc::string::{String, ToString}; -use core::{borrow::Borrow, fmt, net::Ipv6Addr, ops::Deref, str::FromStr}; +use core::{fmt, net::Ipv6Addr, str::FromStr}; use crate::ids::RadrootsIdParseError; @@ -37,22 +37,6 @@ impl AsRef<str> for RadrootsNostrRelayHint { } } -impl Deref for RadrootsNostrRelayHint { - type Target = str; - - #[inline] - fn deref(&self) -> &Self::Target { - self.as_str() - } -} - -impl Borrow<str> for RadrootsNostrRelayHint { - #[inline] - fn borrow(&self) -> &str { - self.as_str() - } -} - impl From<RadrootsNostrRelayHint> for String { #[inline] fn from(value: RadrootsNostrRelayHint) -> Self { diff --git a/crates/event/src/reply.rs b/crates/event/src/reply.rs @@ -271,21 +271,23 @@ fn validate_authored_reply_wire_size( let mut tag_bytes = 0usize; let mut tags_json_bytes = 2usize; let mut tag_count = 0usize; + let root_event_id = root.event_id.to_hex(); add_tag( &mut tag_bytes, &mut tags_json_bytes, &mut tag_count, - &["e", root.event_id.as_str(), root.relay_or_empty(), "root"], + &["e", root_event_id.as_str(), root.relay_or_empty(), "root"], ); if let Some(parent) = parent { + let parent_event_id = parent.event_id.to_hex(); add_tag( &mut tag_bytes, &mut tags_json_bytes, &mut tag_count, &[ "e", - parent.event_id.as_str(), + parent_event_id.as_str(), parent.relay_or_empty(), "reply", ], @@ -379,7 +381,7 @@ mod tests { .expect("nested"); assert!(!nested.is_direct()); assert_eq!( - nested.parent().expect("parent").event_id().as_str(), + nested.parent().expect("parent").event_id().to_hex(), "c".repeat(64) ); } @@ -407,7 +409,7 @@ mod tests { Some("wss://relay.example"), ) .expect("reference"); - assert_eq!(reference.event_id().as_str(), "a".repeat(64)); + assert_eq!(reference.event_id().to_hex(), "a".repeat(64)); assert_eq!(reference.author().to_hex(), crate::test_valid_hex_64('b')); assert_eq!( reference.relay().expect("relay").as_str(), diff --git a/crates/event/src/trade.rs b/crates/event/src/trade.rs @@ -674,7 +674,7 @@ pub fn canonical_trade_mutation_content( finalize_body_candidate_ids(&mut envelope.body)?; envelope.validate()?; let mutation_id = canonical_trade_mutation_id(&envelope)?; - envelope.mutation_id = Some(mutation_id.clone()); + envelope.mutation_id = Some(mutation_id); let value = serialize_trade_value(&envelope); let content = canonical_jcs_value(&value)?; if content.len() > RADROOTS_TRADE_MAX_PUBLIC_CONTENT_BYTES { @@ -896,13 +896,13 @@ fn validate_parent_mutation_ids( actual: parents.len(), }); } - let mut previous: Option<&str> = None; + let mut previous: Option<&RadrootsTradeMutationId> = None; for parent in parents { if Some(parent) == mutation_id { return Err(RadrootsTradeProtocolError::SelfParent); } if let Some(previous) = previous { - match previous.cmp(parent.as_str()) { + match previous.cmp(parent) { core::cmp::Ordering::Greater => { return Err(RadrootsTradeProtocolError::UnsortedParents); } @@ -912,7 +912,7 @@ fn validate_parent_mutation_ids( core::cmp::Ordering::Less => {} } } - previous = Some(parent.as_str()); + previous = Some(parent); } Ok(()) } @@ -1244,7 +1244,7 @@ mod tests { assert!(canonical.envelope.mutation_id.is_some()); assert_eq!( canonical.mutation_id, - canonical.envelope.mutation_id.clone().unwrap() + canonical.envelope.mutation_id.unwrap() ); let parsed = trade_mutation_from_canonical_content(&canonical.content).unwrap(); assert_eq!(parsed.mutation_id, Some(canonical.mutation_id)); @@ -1633,7 +1633,7 @@ mod tests { .expect("candidate id"), match &canonical.envelope.body { RadrootsTradeMutationBodyV1::Proposal { candidate } => { - candidate.candidate_id.clone().expect("candidate id") + candidate.candidate_id.expect("candidate id") } _ => unreachable!("proposal"), } diff --git a/crates/event/src/wire/v1/tests.rs b/crates/event/src/wire/v1/tests.rs @@ -110,7 +110,7 @@ fn into_envelope_verifies_id_before_domain_conversion() { .expect("wire"); let envelope = wire.clone().into_envelope().expect("envelope"); - assert_eq!(envelope.id_str(), wire.id); + assert_eq!(envelope.id_hex(), wire.id); assert_eq!(envelope.content(), "hello"); let mut tampered_id = wire.clone(); @@ -522,7 +522,7 @@ fn checked_in_conformance_vectors_match_wire_behavior() { .expect("expected preimage") ); assert_eq!( - wire.computed_event_id().expect("event id").as_str(), + wire.computed_event_id().expect("event id").to_hex(), expected .get("computed_event_id") .and_then(Value::as_str) diff --git a/crates/event/tests/package_boundary.rs b/crates/event/tests/package_boundary.rs @@ -1,5 +1,6 @@ use std::collections::BTreeSet; +use radroots_event::id::{DTag, EventId, EventSignature, Nip01Coordinate}; #[cfg(feature = "knowledge")] #[allow(unused_imports)] use radroots_event::knowledge as _; @@ -12,6 +13,8 @@ use radroots_event::{ const MANIFEST: &str = include_str!("../Cargo.toml"); const ROOT: &str = include_str!("../src/lib.rs"); +const IDENTIFIERS: &str = include_str!("../src/ids.rs"); +const RELAY_HINT: &str = include_str!("../src/relay_hint.rs"); #[test] fn manifest_has_final_identity_and_required_radroots_dependencies() { @@ -66,6 +69,27 @@ fn crate_root_declares_every_approved_module() { } } +#[test] +fn canonical_identifier_api_owns_bytes_and_requires_explicit_text_encoding() { + let event_id = EventId::parse("A".repeat(64)).expect("event id"); + let signature = EventSignature::parse("B".repeat(128)).expect("event signature"); + let d_tag = DTag::parse("listing-1").expect("d tag"); + let coordinate = Nip01Coordinate::parse(format!("30000:{}:listing-1", event_id.to_hex())) + .expect("coordinate"); + + assert_eq!(core::mem::size_of::<EventId>(), 32); + assert_eq!(core::mem::size_of::<EventSignature>(), 64); + assert_eq!(event_id.to_hex(), "a".repeat(64)); + assert_eq!(EventId::from_bytes(event_id.into_bytes()), event_id); + assert_eq!(signature.to_hex(), "b".repeat(128)); + assert_eq!(d_tag.as_str(), "listing-1"); + assert_eq!(coordinate.identifier(), "listing-1"); + assert!(!IDENTIFIERS.contains("impl Deref")); + assert!(!IDENTIFIERS.contains("impl Borrow<str>")); + assert!(!RELAY_HINT.contains("impl Deref")); + assert!(!RELAY_HINT.contains("impl Borrow<str>")); +} + fn table_keys<'a>(manifest: &'a str, heading: &str) -> BTreeSet<&'a str> { let Some((_, table)) = manifest.split_once(heading) else { return BTreeSet::new(); diff --git a/crates/event_codec/src/admission.rs b/crates/event_codec/src/admission.rs @@ -489,7 +489,7 @@ mod tests { let author = keys.public_key().to_string(); let id = compute_canonical_nip01_event_id(&author, created_at, kind, &tags, content) .expect("canonical event id"); - let nostr_id = nostr::EventId::from_hex(id.as_str()).expect("Nostr event id"); + let nostr_id = nostr::EventId::from_hex(&id.to_hex()).expect("Nostr event id"); let message = Message::from_digest(nostr_id.to_bytes()); let signature = SECP256K1.sign_schnorr_no_aux_rand(&message, keys.key_pair(SECP256K1)); diff --git a/crates/event_codec/src/calendar/encode.rs b/crates/event_codec/src/calendar/encode.rs @@ -277,7 +277,7 @@ fn push_calendar_revision_reference( tags: &mut Vec<Vec<String>>, reference: &RadrootsCalendarEventRevisionReference, ) { - let mut tag = vec![TAG_E.to_string(), reference.event_id().as_str().to_string()]; + let mut tag = vec![TAG_E.to_string(), reference.event_id().to_hex()]; if let Some(relay) = reference.relay() { tag.push(relay.to_string()); } diff --git a/crates/event_codec/src/comment/authored.rs b/crates/event_codec/src/comment/authored.rs @@ -52,7 +52,7 @@ pub fn authored_nip22_comment_to_wire_parts( tags.push(address_reference_tag("a", reference)); tags.push(optional_relay_tag( "e", - current_revision.as_str(), + current_revision.to_hex().as_str(), reference.relay(), )); tags.push(vec!["k".to_string(), root.kind().as_u32().to_string()]); @@ -76,7 +76,7 @@ pub fn authored_nip22_comment_to_wire_parts( fn event_reference_tag(name: &str, reference: &RadrootsNip22EventRootReference) -> Vec<String> { vec![ name.to_string(), - reference.event_id().as_str().to_string(), + reference.event_id().to_hex(), reference.relay_or_empty().to_string(), reference.author().to_hex(), ] @@ -89,7 +89,7 @@ fn address_reference_tag(name: &str, reference: &RadrootsNip22AddressRootReferen fn parent_reference_tag(reference: &RadrootsNip22CommentParentReference) -> Vec<String> { vec![ "e".to_string(), - reference.event_id().as_str().to_string(), + reference.event_id().to_hex(), reference.relay_or_empty().to_string(), reference.author().to_hex(), ] diff --git a/crates/event_codec/src/comment/inbound/registry_v7/tests.rs b/crates/event_codec/src/comment/inbound/registry_v7/tests.rs @@ -63,7 +63,7 @@ fn projects_top_address_with_distinct_optional_relay_hints() { else { panic!("top-level address"); }; - assert_eq!(current_revision.event_id().as_str(), h('e')); + assert_eq!(current_revision.event_id().to_hex(), h('e')); assert!(reference.relay().is_none()); assert_eq!( current_revision.relay().expect("relay").as_str(), @@ -110,7 +110,7 @@ fn nested_parent_uses_author_hint_and_keeps_mentions() { let RadrootsInboundNip22CommentPosition::Nested { parent } = projection.position() else { panic!("nested"); }; - assert_eq!(parent.event_id().as_str(), h('c')); + assert_eq!(parent.event_id().to_hex(), h('c')); assert_eq!(parent.author().pubkey().to_hex(), h('d')); assert_eq!(projection.mentions().len(), 1); assert_eq!(projection.mentions()[0].pubkey().to_hex(), h('e')); diff --git a/crates/event_codec/src/deletion/authored.rs b/crates/event_codec/src/deletion/authored.rs @@ -24,7 +24,7 @@ pub fn authored_nip09_deletion_request_to_wire_parts( request .event_targets() .iter() - .map(|target| vec!["e".to_string(), target.event_id().as_str().to_string()]), + .map(|target| vec!["e".to_string(), target.event_id().to_hex()]), ); tags.extend( request diff --git a/crates/event_codec/src/deletion/reconciliation_v1/admission/tests.rs b/crates/event_codec/src/deletion/reconciliation_v1/admission/tests.rs @@ -25,7 +25,7 @@ fn admitted_contract_resolves_registry_entry() { content, ) .expect("canonical deletion request id"); - let nostr_id = nostr::EventId::from_hex(id.as_str()).expect("Nostr event id"); + let nostr_id = nostr::EventId::from_hex(&id.to_hex()).expect("Nostr event id"); let message = Message::from_digest(nostr_id.to_bytes()); let signature = SECP256K1.sign_schnorr_no_aux_rand(&message, keys.key_pair(SECP256K1)); let event = RadrootsEventEnvelope::new(RadrootsEventEnvelopeParts { diff --git a/crates/event_codec/src/deletion/reconciliation_v1/evaluator/tests.rs b/crates/event_codec/src/deletion/reconciliation_v1/evaluator/tests.rs @@ -69,7 +69,7 @@ fn nip09_evaluator_deletion_requests_are_immune() { let request = admitted_request( FIXTURE_ALICE_SECRET_KEY_HEX, TARGET_TIME + 1, - vec![event_reference(target.event().id_str())], + vec![event_reference(target.event().id_hex().as_str())], "attempt", ); @@ -96,7 +96,7 @@ fn nip09_evaluator_exact_event_reference_is_time_independent() { let request = admitted_request( FIXTURE_ALICE_SECRET_KEY_HEX, TARGET_TIME - 1, - vec![event_reference(target.event().id_str())], + vec![event_reference(target.event().id_hex().as_str())], "exact", ); let request_id = request.event().id().clone(); @@ -181,7 +181,7 @@ fn nip09_evaluator_author_mismatch_and_unrelated_requests_are_distinct() { let mismatch = admitted_request( FIXTURE_BOB_SECRET_KEY_HEX, TARGET_TIME + 1, - vec![event_reference(target.event().id_str())], + vec![event_reference(target.event().id_hex().as_str())], "wrong author", ); let unrelated = admitted_request( @@ -225,7 +225,7 @@ fn nip09_evaluator_authorized_stale_address_precedes_unauthorized_exact_event() let mismatch = admitted_request( FIXTURE_BOB_SECRET_KEY_HEX, TARGET_TIME + 1, - vec![event_reference(target.event().id_str())], + vec![event_reference(target.event().id_hex().as_str())], "wrong author", ); @@ -251,7 +251,7 @@ fn nip09_evaluator_exact_event_dominates_stale_address_reference() { let exact = admitted_request( FIXTURE_ALICE_SECRET_KEY_HEX, TARGET_TIME - 2, - vec![event_reference(target.event().id_str())], + vec![event_reference(target.event().id_hex().as_str())], "exact", ); let stale = admitted_request( @@ -285,13 +285,13 @@ fn nip09_evaluator_reduction_is_order_and_repeat_invariant() { let exact_a = admitted_request( FIXTURE_ALICE_SECRET_KEY_HEX, TARGET_TIME - 10, - vec![event_reference(target.event().id_str())], + vec![event_reference(target.event().id_hex().as_str())], "exact a", ); let exact_b = admitted_request( FIXTURE_ALICE_SECRET_KEY_HEX, TARGET_TIME + 20, - vec![event_reference(target.event().id_str())], + vec![event_reference(target.event().id_hex().as_str())], "exact b", ); let address_a = admitted_request( @@ -372,7 +372,7 @@ fn nip09_borrowed_request_iterator_matches_slice_evaluation() { admitted_request( FIXTURE_ALICE_SECRET_KEY_HEX, TARGET_TIME - 1, - vec![event_reference(target.event().id_str())], + vec![event_reference(target.event().id_hex().as_str())], "exact", ), admitted_request( @@ -385,7 +385,7 @@ fn nip09_borrowed_request_iterator_matches_slice_evaluation() { FIXTURE_ALICE_SECRET_KEY_HEX, TARGET_TIME + 3, vec![ - event_reference(target.event().id_str()), + event_reference(target.event().id_hex().as_str()), address_reference(coordinate.as_str()), ], "exact and address", @@ -544,7 +544,7 @@ fn signed_event( let author = keys.public_key().to_string(); let id = compute_canonical_nip01_event_id(author.as_str(), created_at, kind, &tags, content) .expect("canonical event id"); - let nostr_id = nostr::EventId::from_hex(id.as_str()).expect("Nostr event id"); + let nostr_id = nostr::EventId::from_hex(&id.to_hex()).expect("Nostr event id"); let message = Message::from_digest(nostr_id.to_bytes()); let signature = SECP256K1.sign_schnorr_no_aux_rand(&message, keys.key_pair(SECP256K1)); diff --git a/crates/event_codec/src/deletion/reconciliation_v1/inbound/tests.rs b/crates/event_codec/src/deletion/reconciliation_v1/inbound/tests.rs @@ -42,9 +42,9 @@ fn projects_raw_mixed_duplicates_trailing_and_unknown_tags() { projection .event_targets() .iter() - .map(|target| (target.event_id().as_str(), target.tag_index())) + .map(|target| (target.event_id().to_hex(), target.tag_index())) .collect::<Vec<_>>(), - vec![(h('a').as_str(), 3), (h('f').as_str(), 1)] + vec![(h('a'), 3), (h('f'), 1)] ); assert_eq!( projection diff --git a/crates/event_codec/src/farm/mod.rs b/crates/event_codec/src/farm/mod.rs @@ -335,7 +335,7 @@ mod tests { EVENT_SIG.to_string(), ) .expect("parsed farm"); - assert_eq!(parsed.event.sig_str(), EVENT_SIG); + assert_eq!(parsed.event.signature_hex(), EVENT_SIG); assert_eq!(parsed.data.data.name, "Test Farm"); for (tag, expected) in [ diff --git a/crates/event_codec/src/farm_crdt/mod.rs b/crates/event_codec/src/farm_crdt/mod.rs @@ -286,7 +286,7 @@ mod tests { EVENT_SIG.to_string(), ) .expect("parsed event"); - assert_eq!(parsed.event.sig_str(), EVENT_SIG); + assert_eq!(parsed.event.signature_hex(), EVENT_SIG); assert_eq!(parsed.data.data, change); let no_author_parts = to_wire_parts(&change).expect("crdt wire parts"); diff --git a/crates/event_codec/src/farm_file/mod.rs b/crates/event_codec/src/farm_file/mod.rs @@ -205,7 +205,7 @@ mod tests { EVENT_SIG.to_string(), ) .expect("parsed event"); - assert_eq!(parsed.event.sig_str(), EVENT_SIG); + assert_eq!(parsed.event.signature_hex(), EVENT_SIG); assert_eq!(parsed.data.data, metadata); } diff --git a/crates/event_codec/src/farm_workspace/mod.rs b/crates/event_codec/src/farm_workspace/mod.rs @@ -204,7 +204,7 @@ mod tests { EVENT_SIG.to_string(), ) .expect("parsed event"); - assert_eq!(parsed.event.sig_str(), EVENT_SIG); + assert_eq!(parsed.event.signature_hex(), EVENT_SIG); assert_same_manifest(&parsed.data.data, &manifest); } diff --git a/crates/event_codec/src/food_availability/revision.rs b/crates/event_codec/src/food_availability/revision.rs @@ -93,7 +93,7 @@ pub fn validate_food_availability_revision( let current_wins = current_event.created_at_u64() > previous_event.created_at_u64() || (current_event.created_at_u64() == previous_event.created_at_u64() - && current_event.id_str() < previous_event.id_str()); + && current_event.id() < previous_event.id()); if !current_wins { return Err(RadrootsFoodAvailabilityRevisionError::NotNewer); } diff --git a/crates/event_codec/src/http_auth/mod.rs b/crates/event_codec/src/http_auth/mod.rs @@ -202,7 +202,7 @@ mod tests { EVENT_SIG.to_string(), ) .expect("parsed event"); - assert_eq!(parsed.event.sig_str(), EVENT_SIG); + assert_eq!(parsed.event.signature_hex(), EVENT_SIG); assert_eq!(parsed.data.data, auth); } diff --git a/crates/event_codec/src/job/traits.rs b/crates/event_codec/src/job/traits.rs @@ -115,27 +115,32 @@ pub trait JobEventLike { } pub trait JobEventBorrow<'a> { - fn raw_id(&'a self) -> &'a str; + fn raw_id(&'a self) -> String; fn raw_author(&'a self) -> String; fn raw_content(&'a self) -> &'a str; fn raw_kind(&'a self) -> u32; } -#[derive(Clone, Copy)] +#[derive(Clone)] pub struct BorrowedEventAdapter<'a, E: JobEventBorrow<'a>> { inner: &'a E, published_at: u64, tags: &'a [Vec<String>], - sig: &'a str, + sig: String, } impl<'a, E: JobEventBorrow<'a>> BorrowedEventAdapter<'a, E> { - pub fn new(inner: &'a E, published_at: u64, tags: &'a [Vec<String>], sig: &'a str) -> Self { + pub fn new( + inner: &'a E, + published_at: u64, + tags: &'a [Vec<String>], + sig: impl Into<String>, + ) -> Self { Self { inner, published_at, tags, - sig, + sig: sig.into(), } } } @@ -143,7 +148,7 @@ impl<'a, E: JobEventBorrow<'a>> BorrowedEventAdapter<'a, E> { impl<'a, E: JobEventBorrow<'a>> JobEventLike for BorrowedEventAdapter<'a, E> { #[inline] fn raw_id(&self) -> String { - self.inner.raw_id().to_owned() + self.inner.raw_id() } #[inline] fn raw_author(&self) -> String { @@ -167,14 +172,14 @@ impl<'a, E: JobEventBorrow<'a>> JobEventLike for BorrowedEventAdapter<'a, E> { } #[inline] fn raw_sig(&self) -> String { - self.sig.to_owned() + self.sig.clone() } } impl<'a> JobEventBorrow<'a> for radroots_event::RadrootsEventEnvelope { #[inline] - fn raw_id(&'a self) -> &'a str { - self.id_str() + fn raw_id(&'a self) -> String { + self.id_hex() } #[inline] fn raw_author(&'a self) -> String { diff --git a/crates/event_codec/src/knowledge/decode.rs b/crates/event_codec/src/knowledge/decode.rs @@ -377,7 +377,7 @@ fn json_content<T: DeserializeOwned>(content: &str) -> Result<T, EventParseError fn parsed<T>(event: RadrootsEventEnvelope, data: T) -> RadrootsParsedEvent<T> { let parsed_data = RadrootsParsedData::new( - event.id_str().to_string(), + event.id_hex(), event.author().to_hex().to_string(), event.created_at_u64(), event.kind_u32(), diff --git a/crates/event_codec/src/operational_listing/decode.rs b/crates/event_codec/src/operational_listing/decode.rs @@ -658,7 +658,7 @@ fn decode_operational_listing_from_event_parts( TAG_RADROOTS_PRIMARY_BIN, ))?; let bins = build_bins(bin_drafts)?; - if !bins.iter().any(|bin| bin.bin_id == primary_bin_id) { + if !bins.iter().any(|bin| bin.bin_id.as_str() == primary_bin_id) { return Err(OperationalListingDecodeError::InvalidTag( TAG_RADROOTS_PRIMARY_BIN, )); @@ -746,7 +746,7 @@ pub fn data_from_nostr_event( event: &RadrootsEventEnvelope, ) -> Result<RadrootsParsedData<RadrootsOperationalListing>, EventParseError> { data_from_event( - event.id_str().to_string(), + event.id_hex(), event.author().to_hex().to_string(), event.created_at_u64(), event.kind_u32(), @@ -759,13 +759,13 @@ pub fn parsed_from_nostr_event( event: &RadrootsEventEnvelope, ) -> Result<RadrootsParsedEvent<RadrootsOperationalListing>, EventParseError> { parsed_from_event( - event.id_str().to_string(), + event.id_hex(), event.author().to_hex().to_string(), event.created_at_u64(), event.kind_u32(), event.content().to_string(), event.tags_as_vec(), - event.sig_str().to_string(), + event.signature_hex(), ) } diff --git a/crates/event_codec/src/order/decode.rs b/crates/event_codec/src/order/decode.rs @@ -156,8 +156,8 @@ pub fn order_request_from_event( validate_order_binding( event, &envelope, - &envelope.payload.order_id, - &envelope.payload.listing_addr, + envelope.payload.order_id.as_str(), + envelope.payload.listing_addr.as_str(), &envelope.payload.buyer_pubkey, &envelope.payload.seller_pubkey, )?; @@ -182,8 +182,8 @@ pub fn order_decision_from_event( validate_order_binding( event, &envelope, - &envelope.payload.order_id, - &envelope.payload.listing_addr, + envelope.payload.order_id.as_str(), + envelope.payload.listing_addr.as_str(), &envelope.payload.seller_pubkey, &envelope.payload.buyer_pubkey, )?; @@ -208,8 +208,8 @@ pub fn order_cancellation_from_event( validate_order_binding( event, &envelope, - &envelope.payload.order_id, - &envelope.payload.listing_addr, + envelope.payload.order_id.as_str(), + envelope.payload.listing_addr.as_str(), &envelope.payload.buyer_pubkey, &envelope.payload.seller_pubkey, )?; @@ -587,7 +587,7 @@ mod tests { built.tags[2], vec![TAG_D.to_string(), "order-1".to_string()] ); - assert_eq!(envelope.payload.economics.quote_id, "quote-1"); + assert_eq!(envelope.payload.economics.quote_id.as_str(), "quote-1"); assert_eq!(envelope.payload.economics.total, usd("15")); assert!( built diff --git a/crates/event_codec/src/order/encode.rs b/crates/event_codec/src/order/encode.rs @@ -111,13 +111,15 @@ fn order_envelope_event_build<T: serde::Serialize>( ); envelope.validate().map_err(map_order_envelope_error)?; let content = serde_json::to_string(&envelope).map_err(|_| EventEncodeError::Json)?; + let root_event_id = parts.root_event_id.map(RadrootsEventId::to_hex); + let prev_event_id = parts.prev_event_id.map(RadrootsEventId::to_hex); let tags = order_envelope_tags( parts.recipient_pubkey.to_hex(), parts.listing_addr, Some(parts.order_id), parts.listing_event, - parts.root_event_id.map(RadrootsEventId::as_str), - parts.prev_event_id.map(RadrootsEventId::as_str), + root_event_id.as_deref(), + prev_event_id.as_deref(), )?; Ok(RadrootsNip01EventWireParts { kind: parts.message_type.kind(), @@ -135,8 +137,8 @@ pub fn order_request_event_build( order_envelope_event_build(OrderEnvelopeEventBuildParts { recipient_pubkey: &payload.seller_pubkey, message_type: RadrootsOrderEventType::OrderRequested, - listing_addr: &payload.listing_addr, - order_id: &payload.order_id, + listing_addr: payload.listing_addr.as_str(), + order_id: payload.order_id.as_str(), listing_event: Some(listing_event), root_event_id: None, prev_event_id: None, @@ -154,8 +156,8 @@ pub fn order_decision_event_build( order_envelope_event_build(OrderEnvelopeEventBuildParts { recipient_pubkey: &payload.buyer_pubkey, message_type: RadrootsOrderEventType::OrderDecision, - listing_addr: &payload.listing_addr, - order_id: &payload.order_id, + listing_addr: payload.listing_addr.as_str(), + order_id: payload.order_id.as_str(), listing_event: None, root_event_id: Some(root_event_id), prev_event_id: Some(prev_event_id), @@ -173,8 +175,8 @@ pub fn order_cancellation_event_build( order_envelope_event_build(OrderEnvelopeEventBuildParts { recipient_pubkey: &payload.seller_pubkey, message_type: RadrootsOrderEventType::OrderCancelled, - listing_addr: &payload.listing_addr, - order_id: &payload.order_id, + listing_addr: payload.listing_addr.as_str(), + order_id: payload.order_id.as_str(), listing_event: None, root_event_id: Some(root_event_id), prev_event_id: Some(prev_event_id), diff --git a/crates/event_codec/src/order/tags.rs b/crates/event_codec/src/order/tags.rs @@ -31,7 +31,7 @@ fn build_event_ptr_tag( .map_err(|_| EventEncodeError::InvalidField(field_prefix))?; let mut tag = Vec::with_capacity(3); tag.push(name.to_owned()); - tag.push(event_id.as_str().to_owned()); + tag.push(event_id.to_hex()); if let Some(relay) = &ptr.relays { if relay.trim().is_empty() { return Err(EventEncodeError::EmptyRequiredField("listing_event.relays")); @@ -69,7 +69,7 @@ fn parse_event_ptr_tag( .map_err(|_| EventParseError::InvalidTag(name))?; } Ok(Some(RadrootsEventPtr { - id: event_id.as_str().to_owned(), + id: event_id.to_hex(), relays: relay, })) } diff --git a/crates/event_codec/src/parsed.rs b/crates/event_codec/src/parsed.rs @@ -161,7 +161,7 @@ mod tests { "payload".to_string(), ) .unwrap(); - assert_eq!(out.event.id_str(), EVENT_ID); + assert_eq!(out.event.id_hex(), EVENT_ID); assert_eq!(out.event.author().to_hex(), AUTHOR); assert_eq!(out.event.created_at_u64(), 77); assert_eq!(out.event.kind_u32(), 1111); @@ -170,7 +170,7 @@ mod tests { out.event.tags_as_vec(), vec![vec!["e".to_string(), "root".to_string()]] ); - assert_eq!(out.event.sig_str(), SIG); + assert_eq!(out.event.signature_hex(), SIG); assert_eq!(out.data.id, EVENT_ID); assert_eq!(out.data.author, AUTHOR); assert_eq!(out.data.published_at, 77); diff --git a/crates/event_codec/src/relay_auth/mod.rs b/crates/event_codec/src/relay_auth/mod.rs @@ -142,7 +142,7 @@ mod tests { EVENT_SIG.to_string(), ) .expect("parsed event"); - assert_eq!(parsed.event.sig_str(), EVENT_SIG); + assert_eq!(parsed.event.signature_hex(), EVENT_SIG); assert_eq!(parsed.data.data, auth); } diff --git a/crates/event_codec/src/reply/authored.rs b/crates/event_codec/src/reply/authored.rs @@ -38,7 +38,7 @@ pub fn authored_nip10_reply_to_wire_parts( fn event_tag(reference: &RadrootsNip10ReplyReference, marker: &str) -> Vec<String> { vec![ "e".to_string(), - reference.event_id().as_str().to_string(), + reference.event_id().to_hex(), reference.relay_or_empty().to_string(), marker.to_string(), ] diff --git a/crates/event_codec/src/reply/inbound/registry_v7/tests.rs b/crates/event_codec/src/reply/inbound/registry_v7/tests.rs @@ -70,13 +70,13 @@ fn tolerant_inbound_retains_raw_optional_metadata_and_orders_diagnostics() { assert!(!projection.is_direct()); assert_eq!(projection.root().tag_index(), 0); assert_eq!(projection.root().raw_tag(), tags[0]); - assert_eq!(projection.root().event_id().as_str(), root_id); + assert_eq!(projection.root().event_id().to_hex(), root_id); assert!(projection.root().relay().is_none()); assert!(projection.root().author_hint().is_none()); let parent = projection.reply_reference().expect("reply reference"); assert_eq!(parent.tag_index(), 1); assert_eq!(parent.raw_tag(), tags[1]); - assert_eq!(parent.event_id().as_str(), parent_id); + assert_eq!(parent.event_id().to_hex(), parent_id); assert_eq!(projection.participants().len(), 1); assert_eq!(projection.participants()[0].tag_index(), 4); assert_eq!(projection.participants()[0].raw_tag(), tags[4]); @@ -281,11 +281,11 @@ fn marked_inbound_retains_citations_and_ignores_malformed_supplements() { let projection = project_nip10_reply_parts(KIND_POST, &tags, "Reply", 10) .expect("supplemental references must not erase a marked Reply"); - assert_eq!(projection.root().event_id().as_str(), root_id); + assert_eq!(projection.root().event_id().to_hex(), root_id); assert_eq!(projection.citations().len(), 1); assert_eq!(projection.citations()[0].tag_index(), 1); assert_eq!(projection.citations()[0].raw_tag(), tags[1]); - assert_eq!(projection.citations()[0].event_id().as_str(), citation_id); + assert_eq!(projection.citations()[0].event_id().to_hex(), citation_id); assert_eq!( projection.citations()[0] .relay() @@ -391,10 +391,10 @@ fn positional_inbound_accepts_empty_markers_and_tolerates_middle_citations() { let nested = project_nip10_reply_parts(KIND_POST, &nested_tags, "Nested", 10) .expect("malformed middle citations must not erase positional anchors"); assert_eq!(nested.style(), RadrootsNip10ReplyStyle::LegacyPositional); - assert_eq!(nested.parent().event_id().as_str(), parent_id); + assert_eq!(nested.parent().event_id().to_hex(), parent_id); assert_eq!(nested.citations().len(), 1); assert_eq!(nested.citations()[0].tag_index(), 2); - assert_eq!(nested.citations()[0].event_id().as_str(), citation_id); + assert_eq!(nested.citations()[0].event_id().to_hex(), citation_id); assert_eq!( nested .diagnostics() diff --git a/crates/event_codec/src/trade/mod.rs b/crates/event_codec/src/trade/mod.rs @@ -117,7 +117,7 @@ fn validate_trade_mutation_tags( return Err(RadrootsTradeMutationParseError::ContractTagMismatch); } let trade_id = required_tag_value(tags, TAG_D)?; - if trade_id != envelope.trade_id.as_str() { + if trade_id != envelope.trade_id.to_hex() { return Err(RadrootsTradeMutationParseError::TradeIdTagMismatch); } let counterparty = required_tag_value(tags, "p")?; diff --git a/crates/event_codec/src/verification/v1.rs b/crates/event_codec/src/verification/v1.rs @@ -1,7 +1,7 @@ //! Frozen NIP-01 verification-v1 semantics. #[cfg(not(feature = "std"))] -use alloc::string::{String, ToString}; +use alloc::string::String; use core::fmt; #[cfg(feature = "nostr")] @@ -12,7 +12,6 @@ use radroots_event::contract::registry_v7::{ validate_event_contract_registry_v7 as validate_radroots_event_contract_registry_v7, }; use radroots_event::envelope::RadrootsEventEnvelope; -use radroots_event::ids::RadrootsEventId; use radroots_event::wire::v1::compute_canonical_nip01_event_id_v1; #[derive(Clone, Debug, PartialEq, Eq)] @@ -139,8 +138,6 @@ pub fn verify_event_id_v1( kind: event.kind_u32(), } })?; - RadrootsEventId::parse(event.id_str()) - .map_err(|_| RadrootsNip01VerificationError::MalformedEnvelope)?; let expected = compute_canonical_nip01_event_id_v1( &event.author().to_hex(), event.created_at_u64(), @@ -148,12 +145,11 @@ pub fn verify_event_id_v1( &event.tags_as_vec(), event.content(), ) - .map_err(|_| RadrootsNip01VerificationError::MalformedEnvelope)? - .into_string(); - if event.id_str() != expected { + .map_err(|_| RadrootsNip01VerificationError::MalformedEnvelope)?; + if event.id() != &expected { return Err(RadrootsNip01VerificationError::IdMismatch { - expected, - actual: event.id_str().to_string(), + expected: expected.to_hex(), + actual: event.id_hex(), }); } Ok(RadrootsIdVerifiedEvent { event }) @@ -230,7 +226,8 @@ pub fn validate_event_contract_registry_v7( fn raw_event_from_radroots( event: &RadrootsEventEnvelope, ) -> Result<nostr::Event, RadrootsNip01VerificationError> { - let id = nostr::EventId::from_hex(event.id_str()) + let event_id = event.id_hex(); + let id = nostr::EventId::from_hex(event_id.as_str()) .map_err(|_| RadrootsNip01VerificationError::MalformedEnvelope)?; let public_key = nostr::secp256k1::XOnlyPublicKey::from_str(&event.author().to_hex()) .map(nostr::PublicKey::from) @@ -248,7 +245,8 @@ fn raw_event_from_radroots( .map_err(|_| RadrootsNip01VerificationError::MalformedEnvelope)?, ); } - let sig = nostr::secp256k1::schnorr::Signature::from_str(event.sig_str()) + let signature = event.signature_hex(); + let sig = nostr::secp256k1::schnorr::Signature::from_str(signature.as_str()) .map_err(|_| RadrootsNip01VerificationError::MalformedEnvelope)?; Ok(nostr::Event::new( id, diff --git a/crates/event_codec/src/verification/v1/tests.rs b/crates/event_codec/src/verification/v1/tests.rs @@ -85,7 +85,7 @@ fn id_verification_rejects_an_out_of_range_kind_before_hashing() { kind, tags: original.tags_as_vec(), content: original.content().to_owned(), - sig: original.sig_str().to_owned(), + sig: original.signature_hex(), }) .expect("base envelope permits the wider internal kind representation"); diff --git a/crates/event_codec/tests/app_data.rs b/crates/event_codec/tests/app_data.rs @@ -131,12 +131,12 @@ fn app_data_metadata_and_index_from_event_roundtrip() { EVENT_SIG.to_string(), ) .unwrap(); - assert_eq!(index.event.id_str(), EVENT_ID); + assert_eq!(index.event.id_hex(), EVENT_ID); assert_eq!(index.event.author().to_hex(), AUTHOR); assert_eq!(index.event.created_at_u64(), 42); assert_eq!(index.event.kind_u32(), KIND_APP_DATA); assert_eq!(index.event.content(), "payload"); - assert_eq!(index.event.sig_str(), EVENT_SIG); + assert_eq!(index.event.signature_hex(), EVENT_SIG); assert_eq!(index.data.data.d_tag, "radroots.app"); } diff --git a/crates/event_codec/tests/article.rs b/crates/event_codec/tests/article.rs @@ -217,8 +217,8 @@ fn article_wrappers_preserve_event_metadata() { ) .unwrap(); - assert_eq!(parsed.event.id_str(), EVENT_ID); + assert_eq!(parsed.event.id_hex(), EVENT_ID); assert_eq!(parsed.event.author().to_hex(), AUTHOR); - assert_eq!(parsed.event.sig_str(), EVENT_SIG); + assert_eq!(parsed.event.signature_hex(), EVENT_SIG); assert_eq!(parsed.data.data.d_tag, VALID_D_TAG); } diff --git a/crates/event_codec/tests/calendar.rs b/crates/event_codec/tests/calendar.rs @@ -605,7 +605,7 @@ fn kind_specific_encoders_and_parsed_wrappers_preserve_envelopes() { EVENT_SIG.to_string(), ) .unwrap(); - assert_eq!(parsed.event.sig_str(), EVENT_SIG); + assert_eq!(parsed.event.signature_hex(), EVENT_SIG); assert_eq!(parsed.data.data.common().d_tag(), DATE_D_TAG); let event_reference = RadrootsCalendarEventReference::parse( @@ -649,7 +649,7 @@ fn kind_specific_encoders_and_parsed_wrappers_preserve_envelopes() { EVENT_SIG.to_string(), ) .unwrap(); - assert_eq!(parsed.event.sig_str(), EVENT_SIG); + assert_eq!(parsed.event.signature_hex(), EVENT_SIG); assert_eq!(parsed.data.data.title(), "Farm calendar"); let rsvp = RadrootsAuthoredCalendarEventRsvp::new( @@ -687,7 +687,7 @@ fn kind_specific_encoders_and_parsed_wrappers_preserve_envelopes() { EVENT_SIG.to_string(), ) .unwrap(); - assert_eq!(parsed.event.sig_str(), EVENT_SIG); + assert_eq!(parsed.event.signature_hex(), EVENT_SIG); assert_eq!(parsed.data.data.d_tag(), "DDDDDDDDDDDDDDDDDDDDDw"); } diff --git a/crates/event_codec/tests/calendar_conformance.rs b/crates/event_codec/tests/calendar_conformance.rs @@ -564,7 +564,7 @@ fn assert_revision_reference( let relay = expected.get("relay").and_then(Value::as_str); assert_eq!(actual.raw_event_id(), event_id, "{}", vector_id(vector)); assert_eq!( - actual.event_id().as_str(), + actual.event_id().to_hex(), event_id.to_ascii_lowercase(), "{} normalized revision id", vector_id(vector) @@ -574,7 +574,7 @@ fn assert_revision_reference( relay.is_none_or(|relay| radroots_event::ids::RadrootsRelayUrl::parse(relay).is_ok()); assert_eq!( actual.is_canonical(), - event_id == actual.event_id().as_str() && canonical_relay, + event_id == actual.event_id().to_hex() && canonical_relay, "{} revision canonicality", vector_id(vector) ); diff --git a/crates/event_codec/tests/file_metadata.rs b/crates/event_codec/tests/file_metadata.rs @@ -384,6 +384,6 @@ fn file_metadata_wrappers_preserve_event_metadata() { .unwrap(); assert_eq!(parsed.event.created_at_u64(), 90); - assert_eq!(parsed.event.sig_str(), EVENT_SIG); + assert_eq!(parsed.event.signature_hex(), EVENT_SIG); assert_eq!(parsed.data.data.sha256, VALID_HASH); } diff --git a/crates/event_codec/tests/follow.rs b/crates/event_codec/tests/follow.rs @@ -190,7 +190,7 @@ fn follow_metadata_and_index_from_event_roundtrip() { ) .unwrap(); assert_eq!(index.event.kind_u32(), KIND_FOLLOW); - assert_eq!(index.event.sig_str(), EVENT_SIG); + assert_eq!(index.event.signature_hex(), EVENT_SIG); assert_eq!(index.data.data.list.len(), 1); } diff --git a/crates/event_codec/tests/food_availability_conformance.rs b/crates/event_codec/tests/food_availability_conformance.rs @@ -457,7 +457,7 @@ fn authored_error_value(error: &RadrootsFoodAvailabilityEncodeError) -> Value { fn projection_valid(vector: &Vector) { let input = event_input(vector); let verified = verified_event(&input.event, &vector.id); - let event_id = verified.event().id_str().to_string(); + let event_id = verified.event().id_hex().to_string(); let outcome = project_verified_food_availability_event(&verified) .unwrap_or_else(|error| panic!("{} projection failed: {error}", vector.id)); let actual = match outcome { @@ -519,7 +519,7 @@ fn verify_and_admit_valid(vector: &Vector) { }; let actual = json!({ "outcome": "admitted", - "event_id": admitted.event().id_str(), + "event_id": admitted.event().id_hex(), "projection": projection_value(admitted.projection()), }); assert_eq!(actual, vector.expected, "{}", vector.id); @@ -626,7 +626,7 @@ fn revision_valid(vector: &Vector) { .unwrap_or_else(|error| panic!("{} revision failed: {error}", vector.id)); let actual = json!({ "result": "accepted", - "current_event_id": current.event().id_str(), + "current_event_id": current.event().id_hex(), }); assert_eq!(actual, vector.expected, "{}", vector.id); } @@ -720,7 +720,7 @@ fn directly_signed_verified_event( &raw.content, ) .unwrap_or_else(|error| panic!("{vector_id} direct event id failed: {error}")); - let nostr_id = nostr::EventId::from_hex(id.as_str()) + let nostr_id = nostr::EventId::from_hex(&id.to_hex()) .unwrap_or_else(|error| panic!("{vector_id} direct event id conversion failed: {error}")); let keys = keys_for_pubkey(&raw.pubkey, vector_id); let message = Message::from_digest(nostr_id.to_bytes()); diff --git a/crates/event_codec/tests/geochat.rs b/crates/event_codec/tests/geochat.rs @@ -247,7 +247,7 @@ fn geochat_metadata_and_index_from_event_roundtrip() { ) .unwrap(); assert_eq!(index.event.kind_u32(), KIND_GEOCHAT); - assert_eq!(index.event.sig_str(), EVENT_SIG); + assert_eq!(index.event.signature_hex(), EVENT_SIG); assert_eq!(index.data.data.geohash, "dr5rsj7"); } diff --git a/crates/event_codec/tests/gift_wrap.rs b/crates/event_codec/tests/gift_wrap.rs @@ -165,7 +165,7 @@ fn gift_wrap_metadata_and_index_from_event_roundtrip() { ) .unwrap(); assert_eq!(index.event.kind_u32(), KIND_GIFT_WRAP); - assert_eq!(index.event.sig_str(), EVENT_SIG); + assert_eq!(index.event.signature_hex(), EVENT_SIG); assert_eq!(index.data.data.recipient.public_key, "pubkey"); } diff --git a/crates/event_codec/tests/job_traits.rs b/crates/event_codec/tests/job_traits.rs @@ -63,10 +63,11 @@ fn borrowed_event_adapter_builds_request_metadata() { let event = event_envelope(parts.kind, parts.tags.clone(), "payload"); let tags = event.tags_as_vec(); - let adapter = BorrowedEventAdapter::new(&event, event.created_at_u64(), &tags, event.sig_str()); + let adapter = + BorrowedEventAdapter::new(&event, event.created_at_u64(), &tags, event.signature_hex()); let metadata = adapter.to_job_request_metadata().unwrap(); - assert_eq!(metadata.id, event.id_str()); + assert_eq!(metadata.id, event.id_hex()); assert_eq!(metadata.author, event.author().to_hex()); assert_eq!(metadata.published_at, event.created_at_u64()); assert_eq!(metadata.kind, event.kind_u32()); @@ -123,7 +124,8 @@ fn borrowed_event_adapter_builds_request_metadata_and_index() { let event = event_envelope(parts.kind, parts.tags, "payload"); let tags = event.tags_as_vec(); - let adapter = BorrowedEventAdapter::new(&event, event.created_at_u64(), &tags, event.sig_str()); + let adapter = + BorrowedEventAdapter::new(&event, event.created_at_u64(), &tags, event.signature_hex()); assert_eq!(adapter.raw_id(), EVENT_ID); assert_eq!(adapter.raw_author(), AUTHOR); assert_eq!(adapter.raw_published_at(), 42); @@ -133,12 +135,12 @@ fn borrowed_event_adapter_builds_request_metadata_and_index() { assert_eq!(adapter.raw_sig(), EVENT_SIG); let index = adapter.to_job_request_event_index().unwrap(); - assert_eq!(index.event.id_str(), event.id_str()); + assert_eq!(index.event.id_hex(), event.id_hex()); assert_eq!(index.event.author().to_hex(), event.author().to_hex()); assert_eq!(index.event.created_at_u64(), event.created_at_u64()); assert_eq!(index.event.kind_u32(), event.kind_u32()); assert_eq!(index.event.content(), event.content()); - assert_eq!(index.event.sig_str(), event.sig_str()); + assert_eq!(index.event.signature_hex(), event.signature_hex()); } #[test] @@ -148,9 +150,10 @@ fn borrowed_event_adapter_builds_result_metadata_and_index() { let event = event_envelope(parts.kind, parts.tags, "payload"); let tags = event.tags_as_vec(); - let adapter = BorrowedEventAdapter::new(&event, event.created_at_u64(), &tags, event.sig_str()); + let adapter = + BorrowedEventAdapter::new(&event, event.created_at_u64(), &tags, event.signature_hex()); let metadata = adapter.to_job_result_metadata().unwrap(); - assert_eq!(metadata.id, event.id_str()); + assert_eq!(metadata.id, event.id_hex()); assert_eq!(metadata.author, event.author().to_hex()); assert_eq!(metadata.published_at, event.created_at_u64()); assert_eq!(metadata.kind, event.kind_u32()); @@ -159,12 +162,12 @@ fn borrowed_event_adapter_builds_result_metadata_and_index() { assert_eq!(metadata.data.content.as_deref(), Some("payload")); let index = adapter.to_job_result_event_index().unwrap(); - assert_eq!(index.event.id_str(), event.id_str()); + assert_eq!(index.event.id_hex(), event.id_hex()); assert_eq!(index.event.author().to_hex(), event.author().to_hex()); assert_eq!(index.event.created_at_u64(), event.created_at_u64()); assert_eq!(index.event.kind_u32(), event.kind_u32()); assert_eq!(index.event.content(), event.content()); - assert_eq!(index.event.sig_str(), event.sig_str()); + assert_eq!(index.event.signature_hex(), event.signature_hex()); } #[test] @@ -174,9 +177,10 @@ fn borrowed_event_adapter_builds_feedback_metadata_and_index() { let event = event_envelope(parts.kind, parts.tags, "payload"); let tags = event.tags_as_vec(); - let adapter = BorrowedEventAdapter::new(&event, event.created_at_u64(), &tags, event.sig_str()); + let adapter = + BorrowedEventAdapter::new(&event, event.created_at_u64(), &tags, event.signature_hex()); let metadata = adapter.to_job_feedback_metadata().unwrap(); - assert_eq!(metadata.id, event.id_str()); + assert_eq!(metadata.id, event.id_hex()); assert_eq!(metadata.author, event.author().to_hex()); assert_eq!(metadata.published_at, event.created_at_u64()); assert_eq!(metadata.kind, event.kind_u32()); @@ -185,10 +189,10 @@ fn borrowed_event_adapter_builds_feedback_metadata_and_index() { assert_eq!(metadata.data.content.as_deref(), Some("payload")); let index = adapter.to_job_feedback_event_index().unwrap(); - assert_eq!(index.event.id_str(), event.id_str()); + assert_eq!(index.event.id_hex(), event.id_hex()); assert_eq!(index.event.author().to_hex(), event.author().to_hex()); assert_eq!(index.event.created_at_u64(), event.created_at_u64()); assert_eq!(index.event.kind_u32(), event.kind_u32()); assert_eq!(index.event.content(), event.content()); - assert_eq!(index.event.sig_str(), event.sig_str()); + assert_eq!(index.event.signature_hex(), event.signature_hex()); } diff --git a/crates/event_codec/tests/knowledge.rs b/crates/event_codec/tests/knowledge.rs @@ -92,13 +92,13 @@ fn event_with_parts( content: String, ) -> RadrootsEventEnvelope { RadrootsEventEnvelope::new(RadrootsEventEnvelopeParts { - id: event.id_str().to_string(), + id: event.id_hex().to_string(), author: event.author().to_hex().to_string(), created_at: event.created_at_u64(), kind: event.kind_u32(), tags, content, - sig: event.sig_str().to_string(), + sig: event.signature_hex().to_string(), }) .unwrap() } diff --git a/crates/event_codec/tests/knowledge_fixtures.rs b/crates/event_codec/tests/knowledge_fixtures.rs @@ -89,7 +89,7 @@ fn event_with_parts( sig: String, ) -> RadrootsEventEnvelope { RadrootsEventEnvelope::new(RadrootsEventEnvelopeParts { - id: event.id_str().to_string(), + id: event.id_hex().to_string(), author: event.author().to_hex().to_string(), created_at: event.created_at_u64(), kind: event.kind_u32(), @@ -107,7 +107,7 @@ fn mutate_tags(event: &mut RadrootsEventEnvelope, update: impl FnOnce(&mut Vec<V event, tags, event.content().to_string(), - event.sig_str().to_string(), + event.signature_hex().to_string(), ); } @@ -116,7 +116,7 @@ fn replace_content(event: &mut RadrootsEventEnvelope, content: String) { event, event.tags_as_vec(), content, - event.sig_str().to_string(), + event.signature_hex().to_string(), ); } diff --git a/crates/event_codec/tests/list.rs b/crates/event_codec/tests/list.rs @@ -185,7 +185,7 @@ fn list_metadata_and_index_from_event_roundtrip() { ) .unwrap(); assert_eq!(index.event.kind_u32(), KIND_LIST_MUTE); - assert_eq!(index.event.sig_str(), EVENT_SIG); + assert_eq!(index.event.signature_hex(), EVENT_SIG); assert_eq!(index.data.data.entries.len(), 2); } diff --git a/crates/event_codec/tests/list_set.rs b/crates/event_codec/tests/list_set.rs @@ -219,7 +219,7 @@ fn list_set_metadata_and_index_from_event_roundtrip() { ) .unwrap(); assert_eq!(index.event.kind_u32(), KIND_LIST_SET_FOLLOW); - assert_eq!(index.event.sig_str(), EVENT_SIG); + assert_eq!(index.event.signature_hex(), EVENT_SIG); assert_eq!(index.data.data.entries.len(), 2); } diff --git a/crates/event_codec/tests/message.rs b/crates/event_codec/tests/message.rs @@ -287,7 +287,7 @@ fn message_metadata_and_index_from_event_roundtrip() { .unwrap(); assert_eq!(index.event.kind_u32(), KIND_MESSAGE); assert_eq!( - index.event.sig_str(), + index.event.signature_hex(), concat!( "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" diff --git a/crates/event_codec/tests/message_file.rs b/crates/event_codec/tests/message_file.rs @@ -416,7 +416,7 @@ fn message_file_metadata_and_index_from_event_roundtrip() { ) .unwrap(); assert_eq!(index.event.kind_u32(), KIND_MESSAGE_FILE); - assert_eq!(index.event.sig_str(), EVENT_SIG); + assert_eq!(index.event.signature_hex(), EVENT_SIG); assert_eq!(index.data.data.file_type, "image/jpeg"); } diff --git a/crates/event_codec/tests/nip09_suppression_conformance.rs b/crates/event_codec/tests/nip09_suppression_conformance.rs @@ -370,14 +370,14 @@ fn actual_decision(decision: &RadrootsNip09SuppressionDecision) -> ExpectedDecis event_reference: decision .event_reference() .map(|evidence| ExpectedEventReference { - request_id: evidence.request_id().as_str().to_owned(), + request_id: evidence.request_id().to_hex(), }), address_reference: decision .address_reference() .map(|evidence| ExpectedAddressReference { coordinate: evidence.coordinate().as_str().to_owned(), inclusive_cutoff: evidence.inclusive_cutoff(), - request_id: evidence.request_id().as_str().to_owned(), + request_id: evidence.request_id().to_hex(), }), } } diff --git a/crates/event_codec/tests/operational_listing.rs b/crates/event_codec/tests/operational_listing.rs @@ -1147,17 +1147,17 @@ fn listing_parsed_wrappers_preserve_event_metadata() { EVENT_SIG.to_string(), ) .unwrap(); - assert_eq!(parsed.event.id_str(), EVENT_ID); + assert_eq!(parsed.event.id_hex(), EVENT_ID); assert_eq!(parsed.event.author().to_hex(), AUTHOR); assert_eq!(parsed.event.created_at_u64(), 7); - assert_eq!(parsed.event.sig_str(), EVENT_SIG); + assert_eq!(parsed.event.signature_hex(), EVENT_SIG); assert_eq!(parsed.data.data.d_tag, listing.d_tag); let event = event_envelope(parts.kind, parts.tags, parts.content); let data = data_from_nostr_event(&event).unwrap(); assert_eq!(data.data.d_tag, listing.d_tag); let parsed = parsed_from_nostr_event(&event).unwrap(); - assert_eq!(parsed.event.sig_str(), EVENT_SIG); + assert_eq!(parsed.event.signature_hex(), EVENT_SIG); assert_eq!(parsed.data.data.d_tag, listing.d_tag); let err = parsed_from_event( diff --git a/crates/event_codec/tests/profile.rs b/crates/event_codec/tests/profile.rs @@ -203,7 +203,7 @@ fn profile_parsed_event_preserves_wire_event_and_decoded_data() { .expect("parsed profile"); assert_eq!( - parsed.event.id_str(), + parsed.event.id_hex(), "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ); assert_eq!(parsed.event.author().to_hex(), AUTHOR); @@ -211,7 +211,7 @@ fn profile_parsed_event_preserves_wire_event_and_decoded_data() { assert_eq!(parsed.event.kind_u32(), KIND_PROFILE); assert_eq!(parsed.event.content(), "{\"name\":\"alice\"}"); assert_eq!( - parsed.event.sig_str(), + parsed.event.signature_hex(), concat!( "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" diff --git a/crates/event_codec/tests/reaction.rs b/crates/event_codec/tests/reaction.rs @@ -436,6 +436,6 @@ fn reaction_metadata_and_index_from_event_roundtrip() { ) .unwrap(); assert_eq!(index.event.kind_u32(), KIND_REACTION); - assert_eq!(index.event.sig_str(), EVENT_SIG); + assert_eq!(index.event.signature_hex(), EVENT_SIG); assert_event_target(&index.data.data.target); } diff --git a/crates/event_codec/tests/report.rs b/crates/event_codec/tests/report.rs @@ -451,6 +451,6 @@ fn report_wrappers_preserve_event_metadata() { EVENT_SIG.to_string(), ) .unwrap(); - assert_eq!(parsed.event.sig_str(), EVENT_SIG); + assert_eq!(parsed.event.signature_hex(), EVENT_SIG); assert_eq!(parsed.data.data.reported_pubkey, REPORTED); } diff --git a/crates/event_codec/tests/repost.rs b/crates/event_codec/tests/repost.rs @@ -432,7 +432,7 @@ fn repost_wrappers_preserve_event_metadata() { EVENT_SIG.to_string(), ) .unwrap(); - assert_eq!(parsed.event.sig_str(), EVENT_SIG); + assert_eq!(parsed.event.signature_hex(), EVENT_SIG); let generic_parts = generic_repost_to_wire_parts(&generic_article_repost()).unwrap(); let generic_data = generic_repost_data_from_event( diff --git a/crates/event_codec/tests/seal.rs b/crates/event_codec/tests/seal.rs @@ -90,7 +90,7 @@ fn seal_metadata_and_index_from_event_roundtrip() { ) .unwrap(); assert_eq!(index.event.kind_u32(), KIND_SEAL); - assert_eq!(index.event.sig_str(), EVENT_SIG); + assert_eq!(index.event.signature_hex(), EVENT_SIG); assert_eq!(index.data.data.content, "payload"); } diff --git a/crates/event_codec/tests/structured_decode.rs b/crates/event_codec/tests/structured_decode.rs @@ -280,7 +280,7 @@ fn farm_metadata_and_index_decode_roundtrip() { EVENT_SIG.to_string(), ) .expect("farm index"); - assert_eq!(index.event.id_str(), EVENT_ID); + assert_eq!(index.event.id_hex(), EVENT_ID); assert_eq!(index.data.data.d_tag, d_tag); } @@ -833,7 +833,7 @@ fn resource_area_metadata_and_index_decode_roundtrip() { EVENT_SIG.to_string(), ) .expect("area index"); - assert_eq!(index.event.id_str(), EVENT_ID); + assert_eq!(index.event.id_hex(), EVENT_ID); assert_eq!(index.data.data.d_tag, d_tag); } @@ -916,6 +916,6 @@ fn resource_cap_metadata_and_index_decode_roundtrip() { EVENT_SIG.to_string(), ) .expect("cap index"); - assert_eq!(index.event.sig_str(), EVENT_SIG); + assert_eq!(index.event.signature_hex(), EVENT_SIG); assert_eq!(index.data.data.d_tag, d_tag); } diff --git a/crates/event_codec/tests/verified_admission_conformance.rs b/crates/event_codec/tests/verified_admission_conformance.rs @@ -72,7 +72,7 @@ fn conformance_vectors() -> Cow<'static, str> { fn execute(vector: &Vector) { let envelope = event_envelope(&vector.input["event"]); - let event_id = envelope.id_str().to_owned(); + let event_id = envelope.id_hex().to_owned(); let verified = verify_nip01_event(envelope) .unwrap_or_else(|error| panic!("{} fixture is not NIP-01 verified: {error}", vector.id)); let result = admit_verified_event(verified); @@ -93,12 +93,12 @@ fn execute(vector: &Vector) { vector.id ); assert_eq!( - admitted.event().id_str(), + admitted.event().id_hex(), expected_str(vector, "event_id"), "{}", vector.id ); - assert_eq!(admitted.into_verified_event().event().id_str(), event_id); + assert_eq!(admitted.into_verified_event().event().id_hex(), event_id); } "event.admit_verified.invalid" => { let error = match result { diff --git a/crates/event_codec/tests/verified_comment_conformance.rs b/crates/event_codec/tests/verified_comment_conformance.rs @@ -444,7 +444,7 @@ fn projection_snapshot(projection: &RadrootsInboundNip22CommentProjection) -> Va RadrootsInboundNip22CommentRoot::Event(root) => json!({ "type": "event", "tag_index": root.tag_index(), - "event_id": root.event_id().as_str(), + "event_id": root.event_id().to_hex(), "kind_tag_index": root.kind_tag_index(), "kind_raw_tag": root.kind_raw_tag(), "kind": root.kind().as_u32(), @@ -470,7 +470,7 @@ fn projection_snapshot(projection: &RadrootsInboundNip22CommentProjection) -> Va "type": "top_event", "reference": { "tag_index": reference.tag_index(), - "event_id": reference.event_id().as_str(), + "event_id": reference.event_id().to_hex(), "kind_tag_index": reference.kind_tag_index(), "kind_raw_tag": reference.kind_raw_tag(), "kind": reference.kind(), @@ -497,7 +497,7 @@ fn projection_snapshot(projection: &RadrootsInboundNip22CommentProjection) -> Va }, "current_revision": { "tag_index": current_revision.tag_index(), - "event_id": current_revision.event_id().as_str(), + "event_id": current_revision.event_id().to_hex(), "relay": current_revision.relay().map(|relay| relay.as_str()), "raw_tag": current_revision.raw_tag(), }, @@ -506,7 +506,7 @@ fn projection_snapshot(projection: &RadrootsInboundNip22CommentProjection) -> Va "type": "nested", "parent": { "tag_index": parent.tag_index(), - "event_id": parent.event_id().as_str(), + "event_id": parent.event_id().to_hex(), "kind_tag_index": parent.kind_tag_index(), "kind_raw_tag": parent.kind_raw_tag(), "kind": parent.kind(), diff --git a/crates/event_codec/tests/verified_deletion_conformance.rs b/crates/event_codec/tests/verified_deletion_conformance.rs @@ -758,7 +758,7 @@ fn projection_snapshot(projection: &RadrootsInboundNip09DeletionProjection) -> V "contract_id": projection.contract_id(), "event_targets": projection.event_targets().iter().map(|target| json!({ "tag_index": target.tag_index(), - "event_id": target.event_id().as_str(), + "event_id": target.event_id().to_hex(), "raw_tag": target.raw_tag(), })).collect::<Vec<_>>(), "address_targets": projection.address_targets().iter().map(|target| json!({ diff --git a/crates/event_codec/tests/verified_post_conformance.rs b/crates/event_codec/tests/verified_post_conformance.rs @@ -578,7 +578,7 @@ fn reply_event_reference_value(reference: &RadrootsInboundNip10EventReference) - json!({ "tag_index": reference.tag_index(), "raw_tag": reference.raw_tag(), - "event_id": reference.event_id().as_str(), + "event_id": reference.event_id().to_hex(), "relay": reference.relay().map(|relay| relay.as_str()), "author_hint": reference.author_hint().map(|author| author.to_hex()), }) diff --git a/crates/event_codec/tests/verified_profile_conformance.rs b/crates/event_codec/tests/verified_profile_conformance.rs @@ -104,7 +104,7 @@ fn verify_valid(vector: &Vector) { let verified = verify_nip01_event(canonical_envelope(input_str(vector, "event_json"))) .unwrap_or_else(|error| panic!("{} failed: {error}", vector.id)); assert_eq!( - verified.event().id_str(), + verified.event().id_hex(), expected_str(vector, "event_id"), "{}", vector.id @@ -160,9 +160,9 @@ fn verify_kind_overflow(vector: &Vector) { fn profile_admit_valid(vector: &Vector) { let admitted = admitted_event(input_str(vector, "event_json"), &vector.id); - assert_eq!(admitted.event().id_str(), expected_str(vector, "event_id")); + assert_eq!(admitted.event().id_hex(), expected_str(vector, "event_id")); assert_eq!( - admitted.verified_event().event().id_str(), + admitted.verified_event().event().id_hex(), expected_str(vector, "event_id") ); assert_eq!( @@ -175,7 +175,7 @@ fn profile_admit_valid(vector: &Vector) { vector.expected["residual_fields"] ); let (verified, metadata) = admitted.into_parts(); - assert_eq!(verified.event().id_str(), expected_str(vector, "event_id")); + assert_eq!(verified.event().id_hex(), expected_str(vector, "event_id")); assert!(metadata.name().is_none()); } diff --git a/crates/event_codec/tests/wire.rs b/crates/event_codec/tests/wire.rs @@ -61,7 +61,7 @@ fn draft_validation_accepts_wire_parts_without_signed_envelope() { assert_eq!(draft.expected_pubkey().to_hex(), "a".repeat(64)); assert_eq!(draft.content(), "hello"); assert_eq!(draft.tags().len(), 1); - assert_eq!(draft.expected_event_id_str().len(), 64); + assert_eq!(draft.expected_event_id_hex().len(), 64); } #[test] diff --git a/crates/event_store/contracts/source_maintenance_v1.manifest.json b/crates/event_store/contracts/source_maintenance_v1.manifest.json @@ -264,15 +264,15 @@ { "role": "event_contract_registry_v7_authority", "path": "crates/event/src/contract/registry_v7.rs", - "byte_length": 155738, - "sha256": "e9133e65b37810478c3e34ec4ac2005d81209a714ec2de5bd0232b9f02740dde", + "byte_length": 155739, + "sha256": "64f5a67f8a54f364287210a3f717d9124bc1cb2b9c5fc67e9ff0e40acd7bd216", "hash_algorithm": "sha256_bytes_v1" }, { "role": "event_envelope_authority", "path": "crates/event/src/envelope.rs", - "byte_length": 31165, - "sha256": "97a3bb38d630666bba497b98e856ee457d6899de230dabf6cab786a5bd55a3ce", + "byte_length": 31127, + "sha256": "df22443b825e9ad3da1640029ca6ba9c2ef18a36e14d713bb167766be8ffb439", "hash_algorithm": "sha256_bytes_v1" }, { @@ -285,22 +285,22 @@ { "role": "event_head_v1_authority", "path": "crates/event/src/event_head/v1.rs", - "byte_length": 7529, - "sha256": "0a4b50c4b7a93e9d88cc995cf69d9e87b341cba66d7feb51c357dfa4e5b2de37", + "byte_length": 7515, + "sha256": "ff3236d2d1628aad5674e0d9a3d607b947190a1cf0020143a139cc28413ad36e", "hash_algorithm": "sha256_bytes_v1" }, { "role": "event_ids_authority", "path": "crates/event/src/ids.rs", - "byte_length": 46282, - "sha256": "f3c34e7dcf09fc225cb9c12f02ae932d5155c859f73f8b8573db8e5ebf298678", + "byte_length": 51018, + "sha256": "c420320528bac5a8381382cf33d5bed87037a2c753c0495bbc1c74a49de2756d", "hash_algorithm": "sha256_bytes_v1" }, { "role": "event_trade_authority", "path": "crates/event/src/trade.rs", - "byte_length": 68376, - "sha256": "1012b44295cb26844206304bc24b355a49c18a023844f6b3905337c63b1417a7", + "byte_length": 68354, + "sha256": "a26ad42c55c82ae6c646ac2678819cff26bd8325e53cd56018819bfd14269e33", "hash_algorithm": "sha256_bytes_v1" }, { @@ -320,15 +320,15 @@ { "role": "event_draft_authority", "path": "crates/event/src/draft.rs", - "byte_length": 58674, - "sha256": "fa4e802f1143eba72ba7fc334104ea0d6613c886725ff9f3e61dab2443c243b6", + "byte_length": 58691, + "sha256": "b3b816bd195eb3269bf696c334d8cd51b406ea305f86cd496fe81fd5e8bcd513", "hash_algorithm": "sha256_bytes_v1" }, { "role": "event_calendar_authority", "path": "crates/event/src/calendar.rs", "byte_length": 103814, - "sha256": "f8e0fcb4802d0dcd2a1a13b17216a0c5278950a60c09a261ab349e9ce1989d72", + "sha256": "f7320e27daa113bff6fcc5da837bcce7d3b67c4df5fb9d9434e96f6ada753d6a", "hash_algorithm": "sha256_bytes_v1" }, { @@ -355,8 +355,8 @@ { "role": "event_comment_authority", "path": "crates/event/src/comment.rs", - "byte_length": 36375, - "sha256": "f4d1a57780eff0d315bc4e2fbad316dfb7c7ced1bcc9e8e85afe0b5ecdaf3aa8", + "byte_length": 36411, + "sha256": "9f3e1b6457945a2defb1a1cf15d2b0230c1a0d2b72861fb5881859cd936299c7", "hash_algorithm": "sha256_bytes_v1" }, { @@ -369,15 +369,15 @@ { "role": "event_deletion_authority", "path": "crates/event/src/deletion.rs", - "byte_length": 31155, - "sha256": "c8b7ab79998ae62e03497f5511dd3950a41d73155edda3d8d34c65fc797e9d09", + "byte_length": 31177, + "sha256": "eaf5eac81cd90039dd2c8f5a1f647d7916f961841d51887f1c5a679947bc816a", "hash_algorithm": "sha256_bytes_v1" }, { "role": "event_relay_hint_authority", "path": "crates/event/src/relay_hint.rs", - "byte_length": 14317, - "sha256": "1a14aea5d2f2620970dc1de9e3d311d9042cab4d5805a56461548168112a0801", + "byte_length": 14019, + "sha256": "f50a8fddd1ec9996a452f944ebc59ca4217fc8b28d90be33c2cca925dc3465d0", "hash_algorithm": "sha256_bytes_v1" }, { @@ -418,8 +418,8 @@ { "role": "event_codec_verification_v1_authority", "path": "crates/event_codec/src/verification/v1.rs", - "byte_length": 8751, - "sha256": "fc4c5d45e475151c56330ba9c4db70de603e4ec48adabd6365f80d5f6a3733f4", + "byte_length": 8649, + "sha256": "1ef3d12f90eb7d35f4cafe36c2cc0bbd33731df278b58c9062fb13934e2a98c8", "hash_algorithm": "sha256_bytes_v1" }, { @@ -516,8 +516,8 @@ { "role": "event_codec_job_traits_authority", "path": "crates/event_codec/src/job/traits.rs", - "byte_length": 5029, - "sha256": "353df3703de4d99fc318474952dc6c95cbce9a19756f3e235ed2d715f36c4364", + "byte_length": 5067, + "sha256": "de0b3f67177a48bd8e3c62534850103d09b7be099e80e88a9583363db705fcbb", "hash_algorithm": "sha256_bytes_v1" }, { @@ -593,8 +593,8 @@ { "role": "source_generation_rebuild_authority", "path": "crates/event_store/src/nip09/reconciliation_v1.rs", - "byte_length": 184402, - "sha256": "7fa01e52f51d3470ba60e6068dc05797c2a6eaf5eb317d23111a961dbe4451f9", + "byte_length": 184499, + "sha256": "883f7695f71e76b28e2dbd428d0ddb821ff62ae319cde61f823c62203869742b", "hash_algorithm": "sha256_bytes_v1" }, { @@ -607,43 +607,50 @@ { "role": "public_store_and_transaction_authority", "path": "crates/event_store/src/store.rs", - "byte_length": 394732, - "sha256": "6710a4b3e366b724f6b3d4904e2403c15456f23111996945931d2ba20e301f52", + "byte_length": 395012, + "sha256": "5538b600fa5e457e10f23fe4e3a3c55496662098abaef2692108dc69c29aa3e6", "hash_algorithm": "sha256_bytes_v1" }, { "role": "addressable_transition_feed_store", "path": "crates/event_store/src/store/addressable_transition_feed_v1.rs", - "byte_length": 40254, - "sha256": "de656face46735b938b7b20780687404eade47885871129cc5a7c009155d6336", + "byte_length": 40260, + "sha256": "46ea9c9786099c85150e4979c9dac6f84c1b85b8f30ec44aae6d25f9eb9bebc5", + "hash_algorithm": "sha256_bytes_v1" + }, + { + "role": "current_visibility_store", + "path": "crates/event_store/src/store/current_visibility_v1.rs", + "byte_length": 15786, + "sha256": "bf03f9fc45561366cc489daa400b39d65e68cc70aea2ef4a9cd7724224ca9514", "hash_algorithm": "sha256_bytes_v1" }, { "role": "food_projection_store", "path": "crates/event_store/src/store/food_availability_projection_v1.rs", - "byte_length": 48971, - "sha256": "189b824af305f39c7f71a285f4746455ff30f1a27b24b95d8d21223b41772152", + "byte_length": 48970, + "sha256": "9e0e63d6ca74e49d8ec77f088927983aa4d89a5dae4c9f2d766159e70ed53534", "hash_algorithm": "sha256_bytes_v1" }, { "role": "predecessor_post_core_v1_extension", "path": "crates/event_store/src/store/post_core_extensions_v1.rs", "byte_length": 6923, - "sha256": "2fbfc6252f9ce249468a99b5230fd6b7b59b9e47ee4f38783c5fd9379c823fd0", + "sha256": "3820dad764a0575c20f3dc80a2f850651a1e41ab767cf46305377bf800558699", "hash_algorithm": "sha256_bytes_v1" }, { "role": "predecessor_post_core_v1_storage", "path": "crates/event_store/src/store/post_core_storage_v1.rs", - "byte_length": 16876, - "sha256": "f27dc7dcd643762226f8d4df0d297027b384bcf1004277222e978965bc2d40cf", + "byte_length": 16897, + "sha256": "3fb583b06dbd2e4fde96346da21e6d4516e79c8a4a3889299a7dd736c882c5df", "hash_algorithm": "sha256_bytes_v1" }, { "role": "raw_ingest_capacity_authority", "path": "crates/event_store/src/store/protocol_reconciliation_v1.rs", - "byte_length": 30145, - "sha256": "a8a26763dc39124ab7537fdcc3f89a1f0aa7e1830f4f9dec9ee4057bbb4fd228", + "byte_length": 30153, + "sha256": "de7c327d940d561f0818fade4dc79cabb0b5141e30e02574c702b6f109aee392", "hash_algorithm": "sha256_bytes_v1" }, { @@ -656,15 +663,15 @@ { "role": "source_maintenance_runtime", "path": "crates/event_store/src/source_maintenance_v1.rs", - "byte_length": 51762, - "sha256": "5db9c9e86fd18a2fcc08dbc3468f373bf39d8948bc6a08936b252a4dda3546e9", + "byte_length": 51849, + "sha256": "db43df5849c811d767a87bfa7884ce499400d0b169734e18242542a4415b3a51", "hash_algorithm": "sha256_bytes_v1" }, { "role": "predecessor_food_result_vector_executor", "path": "crates/event_store/tests/food_availability_projection_v1_result_vector.rs", - "byte_length": 34070, - "sha256": "aa098bcb0f975f690ca9535d3cbb76c6e57e6d70fd3a892c4399fd35fe8ec21c", + "byte_length": 34061, + "sha256": "7cdbdda875a876482a061bcd8886d9ba56c10fab0fa76a07d73d0f368324b545", "hash_algorithm": "sha256_bytes_v1" }, { @@ -677,22 +684,22 @@ { "role": "predecessor_successor_governance", "path": "tools/xtask/src/contract/food_availability_projection.rs", - "byte_length": 197137, - "sha256": "78db6c9c85e2f58c7924f61ab5cef67e8994e703bbbeb222a721e5677b229c56", + "byte_length": 197115, + "sha256": "a9f6553e26c10e255bbfda158989ecead2698e3e791ce577e290ffa88231692b", "hash_algorithm": "sha256_bytes_v1" }, { "role": "transitive_predecessor_membership_governance", "path": "tools/xtask/src/contract/nip09_reconciliation.rs", "byte_length": 836171, - "sha256": "989efbb26615e05efc2898e26d2b9d73cf35b4ab95f7601106fc2458eec7b6f2", + "sha256": "a4f34441a90334f797d3542e4b0e009d0cfe0b23a1835e9984bd788fda4f493a", "hash_algorithm": "sha256_bytes_v1" }, { "role": "source_maintenance_governance", "path": "tools/xtask/src/contract/source_maintenance.rs", - "byte_length": 191236, - "sha256": "caed650cd1e8567941819f821c43ea8f88491b9aa07ef420c0d3b390c496ef2e", + "byte_length": 191437, + "sha256": "bd4682f287b777b2ae1348358511a524a4d2294a16e526553c08f220ca37a001", "hash_algorithm": "sha256_bytes_v1" }, { diff --git a/crates/event_store/contracts/source_maintenance_v1.manifest.sha256 b/crates/event_store/contracts/source_maintenance_v1.manifest.sha256 @@ -1 +1 @@ -12e9a26c99807a3b821b0757f550e34806a719e8dd7304072fe9c161665efc8f +267a332c0cfdc9dbc064c98dab23a41ea32ed7d2c2fe31b50777b1c92dbfba01 diff --git a/crates/event_store/src/generated/source_maintenance_manifest.rs b/crates/event_store/src/generated/source_maintenance_manifest.rs @@ -1,8 +1,8 @@ // @generated by `cargo xtask contract source-maintenance-manifest --write`; do not edit. -pub(crate) const SOURCE_MAINTENANCE_MANIFEST_JSON: &str = "{\n \"schema_version\": 1,\n \"contract_id\": \"radroots_event_store.source_maintenance_v1\",\n \"hook_id\": \"source_maintenance_v1\",\n \"manifest_schema\": {\n \"path\": \"crates/event_store/contracts/source_maintenance_v1.manifest.schema.json\",\n \"byte_length\": 12315,\n \"sha256\": \"96ea98a5abf3348b61565954cd34f2c622411d8dd34205ef04134bbe0e3d3f2b\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n \"predecessor\": {\n \"hook_id\": \"food_availability_projection_v1\",\n \"manifest\": {\n \"path\": \"crates/event_store/contracts/food_availability_projection_v1.manifest.json\",\n \"byte_length\": 17455,\n \"sha256\": \"02dfe1b450fbdac16e718888215b4dd5c85d8975440fa21e8f439fb24c2b2990\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n }\n },\n \"migration\": {\n \"version\": 4,\n \"name\": \"source_maintenance\",\n \"up\": {\n \"path\": \"crates/event_store/migrations/0004_source_maintenance.up.sql\",\n \"byte_length\": 19841,\n \"sha256\": \"ab2724188f8d08c897eebea2533a635e7c74282a25e84e4c0c37e78b08837a43\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n \"down\": {\n \"path\": \"crates/event_store/migrations/0004_source_maintenance.down.sql\",\n \"byte_length\": 5172,\n \"sha256\": \"fe44fd53c51545c08ea479b385e6781079dab70fc63da2a3c205d727a00ce860\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n \"schema_sha256\": \"074f85b663444ac150239ecd8441ea4a96ad83a798a55e22d2e5e2f7ee943a8c\",\n \"catalog\": {\n \"objects\": [\n \"radroots_event_store_source_capacity_delete_guard\",\n \"radroots_event_store_source_capacity_insert_guard\",\n \"radroots_event_store_source_capacity_marker_close_guard\",\n \"radroots_event_store_source_capacity_update_guard\",\n \"radroots_event_store_source_capacity_v1\",\n \"radroots_event_store_source_generation_capacity_advance\",\n \"radroots_event_store_source_generation_capacity_guard\"\n ],\n \"replaced_objects\": [\n \"radroots_event_store_food_availability_image_delete_guard\",\n \"radroots_event_store_food_availability_projection_delete_guard\",\n \"radroots_event_store_source_rebuild_marker_insert_guard\"\n ],\n \"tables\": [\n \"radroots_event_store_source_capacity_v1\"\n ],\n \"fts5_tables\": []\n }\n },\n \"source_maintenance\": {\n \"version\": 1,\n \"event_contract_registry_version\": 7,\n \"capacity_authority_id\": \"radroots_event_store_source_capacity_v1\",\n \"accounting\": {\n \"algorithm\": \"sqlite_cast_blob_octet_sum_v1\",\n \"raw_event_columns\": [\n \"event_id\",\n \"pubkey\",\n \"tags_json\",\n \"content\",\n \"sig\",\n \"raw_json\"\n ],\n \"raw_tag_columns\": [\n \"event_id\",\n \"tag_name\",\n \"tag_value\",\n \"tag_json\"\n ],\n \"nullable_raw_tag_columns\": [\n \"tag_value\"\n ]\n },\n \"limits\": {\n \"raw_events\": 25000,\n \"raw_tags\": 250000,\n \"raw_event_text_bytes\": 67108864,\n \"raw_tag_text_bytes\": 33554432,\n \"retained_source_generations\": 8\n },\n \"reopen_validation\": {\n \"mode\": \"bounded_full_raw_recount_v1\",\n \"raw_event_rejection_scan_bound\": 25001,\n \"raw_tag_rejection_scan_bound\": 250001,\n \"generation_history_validation\": \"bounded_count_plus_active_ordinal_v1\",\n \"retained_generation_rejection_scan_bound\": 9\n },\n \"rebuild_seal\": {\n \"nip09_hook_id\": \"nip09_reconciliation_v1\",\n \"nip09_manifest_sha256\": \"74af832420ffbaa9805e89df3c0b34f126a443e1598f757e3372f407f9003b77\",\n \"food_hook_id\": \"food_availability_projection_v1\",\n \"food_manifest_sha256\": \"02dfe1b450fbdac16e718888215b4dd5c85d8975440fa21e8f439fb24c2b2990\",\n \"food_scope_fingerprint_sha256\": \"8b63c5ddc48a2cc7db69295238b96d5f814dba50427c80b4d0079f061e6d3de0\",\n \"active_generation_authority\": \"radroots_event_store_source_state\",\n \"marker_close_authority\": \"radroots_event_store_source_capacity_marker_close_guard\"\n }\n },\n \"entry_points\": [\n {\n \"role\": \"migration_registry\",\n \"rust_path\": \"radroots_event_store::migrations::EVENT_STORE_MIGRATIONS[3]\"\n },\n {\n \"role\": \"migration_apply_hook\",\n \"rust_path\": \"radroots_event_store::schema::apply_migration_hook\"\n },\n {\n \"role\": \"migration_validation_hook\",\n \"rust_path\": \"radroots_event_store::schema::validate_migration_hook_state\"\n },\n {\n \"role\": \"capacity_query\",\n \"rust_path\": \"radroots_event_store::RadrootsEventStore::source_capacity_v1\"\n },\n {\n \"role\": \"raw_append_preflight\",\n \"rust_path\": \"radroots_event_store::source_maintenance_v1::preflight_unique_raw_source_append_v1\"\n },\n {\n \"role\": \"raw_append_advance\",\n \"rust_path\": \"radroots_event_store::source_maintenance_v1::advance_source_capacity_after_insert_v1\"\n },\n {\n \"role\": \"generation_append_preflight\",\n \"rust_path\": \"radroots_event_store::source_maintenance_v1::preflight_source_generation_append_v1\"\n },\n {\n \"role\": \"generation_rebuild_bind\",\n \"rust_path\": \"radroots_event_store::source_maintenance_v1::bind_source_capacity_to_generation_v1\"\n },\n {\n \"role\": \"sqlite_encoding_preflight\",\n \"rust_path\": \"radroots_event_store::store::validate_main_database_encoding\"\n },\n {\n \"role\": \"source_generation_history_rollback_guard\",\n \"rust_path\": \"radroots_event_store::schema::validate_rollback_preserves_source_generation_history\"\n },\n {\n \"role\": \"result_vector_executor\",\n \"rust_path\": \"source_maintenance_v1_result_vector\"\n }\n ],\n \"source_files\": [\n {\n \"role\": \"workspace_dependency_authority\",\n \"path\": \"Cargo.toml\",\n \"byte_length\": 12411,\n \"sha256\": \"cad96f080b0cc9ac7ffda703c8807540c9cf89f47a2299b141e6e7949714bf9f\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_currency_value_authority\",\n \"path\": \"crates/core/src/currency.rs\",\n \"byte_length\": 4142,\n \"sha256\": \"42e6da2d8d2fdd6955dc2d83e98dd00266e02bc910b69923b117662c05089d14\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_decimal_value_authority\",\n \"path\": \"crates/core/src/decimal.rs\",\n \"byte_length\": 7839,\n \"sha256\": \"4b1d681a92d7a9e074bee7e1f20eb1499bb05bfc6528a6c9ba69fa7d00416550\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_money_value_authority\",\n \"path\": \"crates/core/src/money.rs\",\n \"byte_length\": 8025,\n \"sha256\": \"3f30bc21e21951a62fdc5d4033736ed42a883df590e8403940775bd2edfeebc5\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_percent_value_authority\",\n \"path\": \"crates/core/src/percent.rs\",\n \"byte_length\": 2652,\n \"sha256\": \"42ceab109881329f3539d06a0ee0381ab4359985fe185a18d58a9c9558c5eb7f\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_quantity_value_authority\",\n \"path\": \"crates/core/src/quantity.rs\",\n \"byte_length\": 6785,\n \"sha256\": \"d14e619da3829cdaf3ca7385fb892d330c286c1e21455c135c37518cbb588b5f\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_quantity_price_value_authority\",\n \"path\": \"crates/core/src/quantity_price.rs\",\n \"byte_length\": 7061,\n \"sha256\": \"d60f70377099470ed283f45868a5119d7bb46143cb250b5082a4c038ba7f6cdc\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_unit_value_authority\",\n \"path\": \"crates/core/src/unit.rs\",\n \"byte_length\": 10023,\n \"sha256\": \"550e9582b6a5290aac3f637b83853b21fefcbab92c432d067c83448f4b2fe3e9\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"blossom_public_surface\",\n \"path\": \"crates/blossom/src/lib.rs\",\n \"byte_length\": 510,\n \"sha256\": \"a4dfcbd193457c50c1b0fbfc91bb547981ecd3a6e23cfc6f1030edfb511dc58c\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"blossom_authorization_authority\",\n \"path\": \"crates/blossom/src/authorization.rs\",\n \"byte_length\": 39360,\n \"sha256\": \"461947b30516315a342b3b5697599f701d27050888f29f67f5d7a7ad4afa4c28\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"blossom_descriptor_authority\",\n \"path\": \"crates/blossom/src/descriptor.rs\",\n \"byte_length\": 13702,\n \"sha256\": \"b2a4ffa760256e1316f70e012d200e2b5f4afd8ede771b85a5147f96b247f599\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"blossom_error_authority\",\n \"path\": \"crates/blossom/src/error.rs\",\n \"byte_length\": 17229,\n \"sha256\": \"02af55beacf437040be17d1fc3271d6e2a62915f656ec2dbe06247deef83f95a\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"blossom_hash_authority\",\n \"path\": \"crates/blossom/src/hash.rs\",\n \"byte_length\": 11006,\n \"sha256\": \"45eca0d81ac0f46c305a32f81aafcdd90b14679d0614f72862289a6e5d4cb08f\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"blossom_media_type_authority\",\n \"path\": \"crates/blossom/src/media_type.rs\",\n \"byte_length\": 2368,\n \"sha256\": \"69db5c0f9fcdd7dbe1f22daa499f65603ae4ce198083dab2c73a36813fa18a46\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"blossom_url_authority\",\n \"path\": \"crates/blossom/src/url.rs\",\n \"byte_length\": 14580,\n \"sha256\": \"342c995fcf620e5fb32461a7d8276f5668ba2662890bd32d12780cc9121c6451\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_contract_facade\",\n \"path\": \"crates/event/src/contract.rs\",\n \"byte_length\": 86,\n \"sha256\": \"9994cbca9dcc7450ad133b6b927e7c06bee08ef813652452cc1e56a284c1be10\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_contract_registry_v7_authority\",\n \"path\": \"crates/event/src/contract/registry_v7.rs\",\n \"byte_length\": 155738,\n \"sha256\": \"e9133e65b37810478c3e34ec4ac2005d81209a714ec2de5bd0232b9f02740dde\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_envelope_authority\",\n \"path\": \"crates/event/src/envelope.rs\",\n \"byte_length\": 31165,\n \"sha256\": \"97a3bb38d630666bba497b98e856ee457d6899de230dabf6cab786a5bd55a3ce\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_head_facade\",\n \"path\": \"crates/event/src/event_head.rs\",\n \"byte_length\": 68,\n \"sha256\": \"cb52f6006f7ecd862707d6b048f9fc407e0cd5ebcd3091b3c54e195ffa5cba64\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_head_v1_authority\",\n \"path\": \"crates/event/src/event_head/v1.rs\",\n \"byte_length\": 7529,\n \"sha256\": \"0a4b50c4b7a93e9d88cc995cf69d9e87b341cba66d7feb51c357dfa4e5b2de37\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_ids_authority\",\n \"path\": \"crates/event/src/ids.rs\",\n \"byte_length\": 46282,\n \"sha256\": \"f3c34e7dcf09fc225cb9c12f02ae932d5155c859f73f8b8573db8e5ebf298678\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_trade_authority\",\n \"path\": \"crates/event/src/trade.rs\",\n \"byte_length\": 68376,\n \"sha256\": \"1012b44295cb26844206304bc24b355a49c18a023844f6b3905337c63b1417a7\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_kinds_authority\",\n \"path\": \"crates/event/src/kinds.rs\",\n \"byte_length\": 34961,\n \"sha256\": \"8b3ce6193cab1f7e1587d0c1b2880a81b0aa43c77d89671b602772db37edcebf\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_tags_authority\",\n \"path\": \"crates/event/src/tags.rs\",\n \"byte_length\": 4530,\n \"sha256\": \"cb8f12a639fc72d9238e32495d9e67e928e6627fb8c94ec0a58c5d95e7373cd6\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_draft_authority\",\n \"path\": \"crates/event/src/draft.rs\",\n \"byte_length\": 58674,\n \"sha256\": \"fa4e802f1143eba72ba7fc334104ea0d6613c886725ff9f3e61dab2443c243b6\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_calendar_authority\",\n \"path\": \"crates/event/src/calendar.rs\",\n \"byte_length\": 103814,\n \"sha256\": \"f8e0fcb4802d0dcd2a1a13b17216a0c5278950a60c09a261ab349e9ce1989d72\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_classified_listing_authority\",\n \"path\": \"crates/event/src/classified_listing.rs\",\n \"byte_length\": 8226,\n \"sha256\": \"745aa08953a6243ea1afad22aa63e44f6746f2f243ab0d6b617d6ab64fa58749\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_profile_authority\",\n \"path\": \"crates/event/src/profile.rs\",\n \"byte_length\": 18848,\n \"sha256\": \"7c7ac7f4926938f5cb5530be5450e5e23f18f216bdb222150fbdd451cec20d5c\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_post_authority\",\n \"path\": \"crates/event/src/post.rs\",\n \"byte_length\": 22738,\n \"sha256\": \"7ed4a4c39bed40b134369d16e1fc35ab2c7d27ee300dd36d367025def2283b39\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_comment_authority\",\n \"path\": \"crates/event/src/comment.rs\",\n \"byte_length\": 36375,\n \"sha256\": \"f4d1a57780eff0d315bc4e2fbad316dfb7c7ced1bcc9e8e85afe0b5ecdaf3aa8\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_food_availability_authority\",\n \"path\": \"crates/event/src/food_availability.rs\",\n \"byte_length\": 45429,\n \"sha256\": \"b4357dfb6954631673b6cd58794015da29303cb54ce8405a57ad543870036c9e\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_deletion_authority\",\n \"path\": \"crates/event/src/deletion.rs\",\n \"byte_length\": 31155,\n \"sha256\": \"c8b7ab79998ae62e03497f5511dd3950a41d73155edda3d8d34c65fc797e9d09\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_relay_hint_authority\",\n \"path\": \"crates/event/src/relay_hint.rs\",\n \"byte_length\": 14317,\n \"sha256\": \"1a14aea5d2f2620970dc1de9e3d311d9042cab4d5805a56461548168112a0801\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_media_authority\",\n \"path\": \"crates/event/src/media.rs\",\n \"byte_length\": 3521,\n \"sha256\": \"8f670e634452872a525efdad0cb9480288885c62f22a9b9915a67a7e7965651c\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_social_authority\",\n \"path\": \"crates/event/src/social.rs\",\n \"byte_length\": 5483,\n \"sha256\": \"1b89c6d0954822e7f1e778479ed43694e88929bcd5310ee066f8f4ba6505045a\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_wire_facade\",\n \"path\": \"crates/event/src/wire.rs\",\n \"byte_length\": 68,\n \"sha256\": \"cb52f6006f7ecd862707d6b048f9fc407e0cd5ebcd3091b3c54e195ffa5cba64\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_wire_v1_authority\",\n \"path\": \"crates/event/src/wire/v1.rs\",\n \"byte_length\": 22133,\n \"sha256\": \"cc28c8cbd962b32ed2efe43e84c1e0d1ea3bd89636efff2d5553714072fce1a4\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_verification_facade\",\n \"path\": \"crates/event_codec/src/verification.rs\",\n \"byte_length\": 253,\n \"sha256\": \"b49a32df605035c87f295c0a151140d43d2e588c5e11b05183e5fc92993dae0e\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_verification_v1_authority\",\n \"path\": \"crates/event_codec/src/verification/v1.rs\",\n \"byte_length\": 8751,\n \"sha256\": \"fc4c5d45e475151c56330ba9c4db70de603e4ec48adabd6365f80d5f6a3733f4\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_registry_v7_admission_authority\",\n \"path\": \"crates/event_codec/src/admission/registry_v7.rs\",\n \"byte_length\": 5350,\n \"sha256\": \"755e63dd7ad1115c219e5a3ea540bef67d2770fc9f2a5aa6ba97c925c99bdced\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_profile_inbound_facade\",\n \"path\": \"crates/event_codec/src/profile/inbound.rs\",\n \"byte_length\": 86,\n \"sha256\": \"9994cbca9dcc7450ad133b6b927e7c06bee08ef813652452cc1e56a284c1be10\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_profile_registry_v7_authority\",\n \"path\": \"crates/event_codec/src/profile/inbound/registry_v7.rs\",\n \"byte_length\": 10394,\n \"sha256\": \"c37c225ea8153beb098a39c4a56203aa03382af12646f40cd3f8628663700702\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_post_inbound_facade\",\n \"path\": \"crates/event_codec/src/post/inbound.rs\",\n \"byte_length\": 86,\n \"sha256\": \"9994cbca9dcc7450ad133b6b927e7c06bee08ef813652452cc1e56a284c1be10\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_post_registry_v7_authority\",\n \"path\": \"crates/event_codec/src/post/inbound/registry_v7.rs\",\n \"byte_length\": 16016,\n \"sha256\": \"bc0bb839c28f3588f05544c846c987528ea3934c75305fef70af8e027a97cc58\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_reply_inbound_facade\",\n \"path\": \"crates/event_codec/src/reply/inbound.rs\",\n \"byte_length\": 86,\n \"sha256\": \"9994cbca9dcc7450ad133b6b927e7c06bee08ef813652452cc1e56a284c1be10\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_reply_registry_v7_authority\",\n \"path\": \"crates/event_codec/src/reply/inbound/registry_v7.rs\",\n \"byte_length\": 26812,\n \"sha256\": \"a72e9721ed13addca2a63942ac9e43c1daa8f1d1457eef08ec6a3ee5eb8872c5\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_comment_inbound_facade\",\n \"path\": \"crates/event_codec/src/comment/inbound.rs\",\n \"byte_length\": 86,\n \"sha256\": \"9994cbca9dcc7450ad133b6b927e7c06bee08ef813652452cc1e56a284c1be10\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_comment_registry_v7_authority\",\n \"path\": \"crates/event_codec/src/comment/inbound/registry_v7.rs\",\n \"byte_length\": 53783,\n \"sha256\": \"30d1b0155963b25d64685ddd042f423ef7707b111dc56ead15bd468e0433a432\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_deletion_facade\",\n \"path\": \"crates/event_codec/src/deletion/mod.rs\",\n \"byte_length\": 115,\n \"sha256\": \"17d56f82ddb0a86bc97abbcf3e037fe460ea31fff2548f527be4bf004dac3a95\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_deletion_reconciliation_v1_authority\",\n \"path\": \"crates/event_codec/src/deletion/reconciliation_v1.rs\",\n \"byte_length\": 38469,\n \"sha256\": \"3e06d1fa923ca5faabb1e95338c35650b0e20b078ff5c972e35ab845d8b7476c\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_food_inbound_facade\",\n \"path\": \"crates/event_codec/src/food_availability/inbound.rs\",\n \"byte_length\": 86,\n \"sha256\": \"9994cbca9dcc7450ad133b6b927e7c06bee08ef813652452cc1e56a284c1be10\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_food_registry_v7_authority\",\n \"path\": \"crates/event_codec/src/food_availability/inbound/registry_v7.rs\",\n \"byte_length\": 26764,\n \"sha256\": \"a5786cff942b7b0038f741afb5b9a19230ac58cb57a5ba747b32e1b95d414e15\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_job_traits_authority\",\n \"path\": \"crates/event_codec/src/job/traits.rs\",\n \"byte_length\": 5029,\n \"sha256\": \"353df3703de4d99fc318474952dc6c95cbce9a19756f3e235ed2d715f36c4364\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_store_dependency_authority\",\n \"path\": \"crates/event_store/Cargo.toml\",\n \"byte_length\": 1567,\n \"sha256\": \"46e03d3c758e1116638021a0499dfa588b4266498e0d50cfa758f9bef9bcfeb3\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_store_error_and_limits\",\n \"path\": \"crates/event_store/src/error.rs\",\n \"byte_length\": 19517,\n \"sha256\": \"4bf24ee1aa6117597ab467b1379a05549b79024213dc7622a2d276bc26fffab4\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"generated_descriptor_registration\",\n \"path\": \"crates/event_store/src/generated.rs\",\n \"byte_length\": 144,\n \"sha256\": \"6b0a8d6f249bd4fc3f878d37cb5e418680f0f1be2d9eec2518dedf03efc47121\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"public_surface\",\n \"path\": \"crates/event_store/src/lib.rs\",\n \"byte_length\": 3844,\n \"sha256\": \"3cd9653bcb752fb3c4442d4904b98a0a6208011a9a238125b7b7073d7f4e312b\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"migration_registry\",\n \"path\": \"crates/event_store/src/migrations.rs\",\n \"byte_length\": 73585,\n \"sha256\": \"a47477d04759ec6e71d14d3d05459864eae78fce0e3c2481a1b03147f04637f7\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"predecessor_model_public_surface\",\n \"path\": \"crates/event_store/src/model.rs\",\n \"byte_length\": 33596,\n \"sha256\": \"98b1742ffb517f66f8e9edefa61d1c3cf3e22be5985202c6c340310a98c72c8e\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_store_reconciliation_v1_model\",\n \"path\": \"crates/event_store/src/model/reconciliation_v1.rs\",\n \"byte_length\": 11138,\n \"sha256\": \"8a26bc373035878ef9b41767ceea7b681896e17d88bedce118de1d622125e1d6\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_store_reconciliation_v1_ingest_model\",\n \"path\": \"crates/event_store/src/model/ingest_reconciliation_v1.rs\",\n \"byte_length\": 1626,\n \"sha256\": \"47bf13b3fc0f8a913a660f7d655413de0f6b90568bc4acc510aa6bd741bab47b\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"addressable_transition_feed_model\",\n \"path\": \"crates/event_store/src/model/addressable_transition_feed_v1.rs\",\n \"byte_length\": 22279,\n \"sha256\": \"f8ea454a0e998a3d433bba52d1ff9759a04fcb91db286cf2a2b10ef7d0057694\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"food_projection_model\",\n \"path\": \"crates/event_store/src/model/food_availability_projection_v1.rs\",\n \"byte_length\": 17437,\n \"sha256\": \"6fdfc8c5eb3dd9c451fd47b2394af123b50f7fe6d74113f8777221a8fa31ba30\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"source_generation_rebuild_authority\",\n \"path\": \"crates/event_store/src/nip09/reconciliation_v1.rs\",\n \"byte_length\": 184402,\n \"sha256\": \"7fa01e52f51d3470ba60e6068dc05797c2a6eaf5eb317d23111a961dbe4451f9\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"schema_migration_and_reopen_authority\",\n \"path\": \"crates/event_store/src/schema.rs\",\n \"byte_length\": 146146,\n \"sha256\": \"93b060e80d3edd73f86208e4bf698fa9d53eaf1eeb04526c9261fb8b5726fb0d\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"public_store_and_transaction_authority\",\n \"path\": \"crates/event_store/src/store.rs\",\n \"byte_length\": 394732,\n \"sha256\": \"6710a4b3e366b724f6b3d4904e2403c15456f23111996945931d2ba20e301f52\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"addressable_transition_feed_store\",\n \"path\": \"crates/event_store/src/store/addressable_transition_feed_v1.rs\",\n \"byte_length\": 40254,\n \"sha256\": \"de656face46735b938b7b20780687404eade47885871129cc5a7c009155d6336\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"food_projection_store\",\n \"path\": \"crates/event_store/src/store/food_availability_projection_v1.rs\",\n \"byte_length\": 48971,\n \"sha256\": \"189b824af305f39c7f71a285f4746455ff30f1a27b24b95d8d21223b41772152\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"predecessor_post_core_v1_extension\",\n \"path\": \"crates/event_store/src/store/post_core_extensions_v1.rs\",\n \"byte_length\": 6923,\n \"sha256\": \"2fbfc6252f9ce249468a99b5230fd6b7b59b9e47ee4f38783c5fd9379c823fd0\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"predecessor_post_core_v1_storage\",\n \"path\": \"crates/event_store/src/store/post_core_storage_v1.rs\",\n \"byte_length\": 16876,\n \"sha256\": \"f27dc7dcd643762226f8d4df0d297027b384bcf1004277222e978965bc2d40cf\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"raw_ingest_capacity_authority\",\n \"path\": \"crates/event_store/src/store/protocol_reconciliation_v1.rs\",\n \"byte_length\": 30145,\n \"sha256\": \"a8a26763dc39124ab7537fdcc3f89a1f0aa7e1830f4f9dec9ee4057bbb4fd228\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"predecessor_protocol_storage\",\n \"path\": \"crates/event_store/src/store/protocol_storage_v1.rs\",\n \"byte_length\": 10929,\n \"sha256\": \"20de4436945bac0d8cbeca0ae6cd95232a92da8cd6be6ae6beacba17fe50d658\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"source_maintenance_runtime\",\n \"path\": \"crates/event_store/src/source_maintenance_v1.rs\",\n \"byte_length\": 51762,\n \"sha256\": \"5db9c9e86fd18a2fcc08dbc3468f373bf39d8948bc6a08936b252a4dda3546e9\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"predecessor_food_result_vector_executor\",\n \"path\": \"crates/event_store/tests/food_availability_projection_v1_result_vector.rs\",\n \"byte_length\": 34070,\n \"sha256\": \"aa098bcb0f975f690ca9535d3cbb76c6e57e6d70fd3a892c4399fd35fe8ec21c\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"artifact_transaction_authority\",\n \"path\": \"tools/xtask/src/contract/artifact_bundle.rs\",\n \"byte_length\": 38279,\n \"sha256\": \"f326ea57b56d40135f95b6b1e15961f66eed363337180a6d12a5ea903e1a9a29\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"predecessor_successor_governance\",\n \"path\": \"tools/xtask/src/contract/food_availability_projection.rs\",\n \"byte_length\": 197137,\n \"sha256\": \"78db6c9c85e2f58c7924f61ab5cef67e8994e703bbbeb222a721e5677b229c56\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"transitive_predecessor_membership_governance\",\n \"path\": \"tools/xtask/src/contract/nip09_reconciliation.rs\",\n \"byte_length\": 836171,\n \"sha256\": \"989efbb26615e05efc2898e26d2b9d73cf35b4ab95f7601106fc2458eec7b6f2\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"source_maintenance_governance\",\n \"path\": \"tools/xtask/src/contract/source_maintenance.rs\",\n \"byte_length\": 191236,\n \"sha256\": \"caed650cd1e8567941819f821c43ea8f88491b9aa07ef420c0d3b390c496ef2e\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"contract_command_authority\",\n \"path\": \"tools/xtask/src/contract.rs\",\n \"byte_length\": 506277,\n \"sha256\": \"3a06ed79b5b342dce5b6582fc5c58311378a2dba97e5a8c74361f0186886023d\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"xtask_dispatch_and_release_preflight\",\n \"path\": \"tools/xtask/src/main.rs\",\n \"byte_length\": 16426,\n \"sha256\": \"abc24896c6c740c10811a3e003ec4be8ebdb376a7b6b01445bfa7a5889f094a7\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n }\n ],\n \"public_api\": {\n \"inherited_predecessor_symbols\": [\n \"RADROOTS_ADDRESSABLE_TRANSITION_CURSOR_JSON_MAX_BYTES_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_D_TAG_MAX_BYTES_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_FEED_VERSION_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_PAGE_LIMIT_MAX_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_PAGE_RAW_JSON_MAX_BYTES_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_PAGE_SCAN_MAX_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_SCOPE_KIND_MAX_V1\",\n \"RADROOTS_FOOD_AVAILABILITY_PROJECTION_APPLY_PAGE_LIMIT_V1\",\n \"RADROOTS_FOOD_AVAILABILITY_PROJECTION_VERSION_V1\",\n \"RADROOTS_FOOD_AVAILABILITY_SEARCH_QUERY_MAX_BYTES_V1\",\n \"RADROOTS_FOOD_AVAILABILITY_SEARCH_QUERY_MAX_TERMS_V1\",\n \"RadrootsAddressableTransitionCauseV1\",\n \"RadrootsAddressableTransitionCoordinateV1\",\n \"RadrootsAddressableTransitionCursorV1\",\n \"RadrootsAddressableTransitionEventReferenceV1\",\n \"RadrootsAddressableTransitionOriginV1\",\n \"RadrootsAddressableTransitionPageV1\",\n \"RadrootsAddressableTransitionRawHeadDecisionV1\",\n \"RadrootsAddressableTransitionScopeFingerprintV1\",\n \"RadrootsAddressableTransitionScopeV1\",\n \"RadrootsAddressableTransitionV1\",\n \"RadrootsAddressableTransitionVisibilityV1\",\n \"RadrootsCurrentEventVisibilityV1\",\n \"RadrootsCurrentVisibilityDecisionV1\",\n \"RadrootsFoodAvailabilitySearchQueryV1\",\n \"RadrootsFoodAvailabilityStatusFilterV1\",\n \"RadrootsNip09SuppressionEvidenceV1\",\n \"RadrootsNip09SuppressionOutcome\",\n \"RadrootsNip09SuppressionReason\",\n \"RadrootsStoreProducedCanonicalEventV1\",\n \"RadrootsStoredFoodAvailabilityImageV1\",\n \"RadrootsStoredFoodAvailabilityV1\"\n ],\n \"added_symbols\": [\n \"RADROOTS_EVENT_STORE_RAW_EVENT_COUNT_LIMIT_V1\",\n \"RADROOTS_EVENT_STORE_RAW_EVENT_TEXT_BYTES_LIMIT_V1\",\n \"RADROOTS_EVENT_STORE_RAW_TAG_COUNT_LIMIT_V1\",\n \"RADROOTS_EVENT_STORE_RAW_TAG_TEXT_BYTES_LIMIT_V1\",\n \"RADROOTS_EVENT_STORE_RETAINED_SOURCE_GENERATION_LIMIT_V1\",\n \"RadrootsEventStoreSourceCapacityResourceV1\",\n \"RadrootsEventStoreSourceCapacityV1\"\n ],\n \"methods\": [\n \"RadrootsEventStore::source_capacity_v1\",\n \"RadrootsEventStoreSourceCapacityResourceV1::as_str\",\n \"RadrootsEventStoreSourceCapacityV1::source_generation\",\n \"RadrootsEventStoreSourceCapacityV1::raw_event_count\",\n \"RadrootsEventStoreSourceCapacityV1::raw_tag_count\",\n \"RadrootsEventStoreSourceCapacityV1::raw_event_text_bytes\",\n \"RadrootsEventStoreSourceCapacityV1::raw_tag_text_bytes\",\n \"RadrootsEventStoreSourceCapacityV1::raw_high_water_seq\",\n \"RadrootsEventStoreSourceCapacityV1::retained_generation_count\",\n \"RadrootsEventStoreSourceCapacityV1::retained_generation_limit\"\n ],\n \"error_variants\": [\n \"SourceCapacityExceeded\",\n \"SourceGenerationHistoryLimitReached\",\n \"PersistedEphemeralRawEvent\",\n \"SourceCapacityStateDrift\",\n \"SqliteMainDatabaseEncodingNotUtf8\",\n \"RollbackWouldDiscardSourceGenerationHistory\"\n ],\n \"removed_symbols\": [\n \"RadrootsEventStoreReconciliationResource\",\n \"RadrootsEventStoreError::ReconciliationCapacityExceeded\"\n ],\n \"breaking_replacements\": [\n {\n \"removed\": \"RadrootsEventStoreReconciliationResource\",\n \"replacement\": \"RadrootsEventStoreSourceCapacityResourceV1\"\n },\n {\n \"removed\": \"RadrootsEventStoreError::ReconciliationCapacityExceeded\",\n \"replacement\": \"RadrootsEventStoreError::SourceCapacityExceeded\"\n }\n ]\n },\n \"result_vector\": {\n \"canonical_path\": \"contracts/conformance/vectors/event_store/source_maintenance.v1.json\",\n \"mirror_path\": \"crates/event_store/tests/fixtures/source_maintenance.v1.json\",\n \"byte_length\": 16253,\n \"sha256\": \"997aba2604a2b9d199fb87dc9d07942ca50d91863aeadcf3eeacf16d191dd71f\",\n \"hash_algorithm\": \"sha256_bytes_v1\",\n \"executor_id\": \"radroots_event_store.source_maintenance_v1.result_vector_executor.v1\",\n \"executor_path\": \"crates/event_store/tests/source_maintenance_v1_result_vector.rs\",\n \"executor_test\": \"source_maintenance_v1_result_vector\",\n \"executor_byte_length\": 23510,\n \"executor_sha256\": \"a7487afdfe19fc5fc794811d0f0e6035203e1aabcf0a33a1d398f6b3555d38f3\",\n \"executor_hash_algorithm\": \"sha256_bytes_v1\"\n }\n}\n"; -pub(crate) const SOURCE_MAINTENANCE_MANIFEST_BYTE_LENGTH: usize = 31374; +pub(crate) const SOURCE_MAINTENANCE_MANIFEST_JSON: &str = "{\n \"schema_version\": 1,\n \"contract_id\": \"radroots_event_store.source_maintenance_v1\",\n \"hook_id\": \"source_maintenance_v1\",\n \"manifest_schema\": {\n \"path\": \"crates/event_store/contracts/source_maintenance_v1.manifest.schema.json\",\n \"byte_length\": 12315,\n \"sha256\": \"96ea98a5abf3348b61565954cd34f2c622411d8dd34205ef04134bbe0e3d3f2b\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n \"predecessor\": {\n \"hook_id\": \"food_availability_projection_v1\",\n \"manifest\": {\n \"path\": \"crates/event_store/contracts/food_availability_projection_v1.manifest.json\",\n \"byte_length\": 17455,\n \"sha256\": \"02dfe1b450fbdac16e718888215b4dd5c85d8975440fa21e8f439fb24c2b2990\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n }\n },\n \"migration\": {\n \"version\": 4,\n \"name\": \"source_maintenance\",\n \"up\": {\n \"path\": \"crates/event_store/migrations/0004_source_maintenance.up.sql\",\n \"byte_length\": 19841,\n \"sha256\": \"ab2724188f8d08c897eebea2533a635e7c74282a25e84e4c0c37e78b08837a43\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n \"down\": {\n \"path\": \"crates/event_store/migrations/0004_source_maintenance.down.sql\",\n \"byte_length\": 5172,\n \"sha256\": \"fe44fd53c51545c08ea479b385e6781079dab70fc63da2a3c205d727a00ce860\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n \"schema_sha256\": \"074f85b663444ac150239ecd8441ea4a96ad83a798a55e22d2e5e2f7ee943a8c\",\n \"catalog\": {\n \"objects\": [\n \"radroots_event_store_source_capacity_delete_guard\",\n \"radroots_event_store_source_capacity_insert_guard\",\n \"radroots_event_store_source_capacity_marker_close_guard\",\n \"radroots_event_store_source_capacity_update_guard\",\n \"radroots_event_store_source_capacity_v1\",\n \"radroots_event_store_source_generation_capacity_advance\",\n \"radroots_event_store_source_generation_capacity_guard\"\n ],\n \"replaced_objects\": [\n \"radroots_event_store_food_availability_image_delete_guard\",\n \"radroots_event_store_food_availability_projection_delete_guard\",\n \"radroots_event_store_source_rebuild_marker_insert_guard\"\n ],\n \"tables\": [\n \"radroots_event_store_source_capacity_v1\"\n ],\n \"fts5_tables\": []\n }\n },\n \"source_maintenance\": {\n \"version\": 1,\n \"event_contract_registry_version\": 7,\n \"capacity_authority_id\": \"radroots_event_store_source_capacity_v1\",\n \"accounting\": {\n \"algorithm\": \"sqlite_cast_blob_octet_sum_v1\",\n \"raw_event_columns\": [\n \"event_id\",\n \"pubkey\",\n \"tags_json\",\n \"content\",\n \"sig\",\n \"raw_json\"\n ],\n \"raw_tag_columns\": [\n \"event_id\",\n \"tag_name\",\n \"tag_value\",\n \"tag_json\"\n ],\n \"nullable_raw_tag_columns\": [\n \"tag_value\"\n ]\n },\n \"limits\": {\n \"raw_events\": 25000,\n \"raw_tags\": 250000,\n \"raw_event_text_bytes\": 67108864,\n \"raw_tag_text_bytes\": 33554432,\n \"retained_source_generations\": 8\n },\n \"reopen_validation\": {\n \"mode\": \"bounded_full_raw_recount_v1\",\n \"raw_event_rejection_scan_bound\": 25001,\n \"raw_tag_rejection_scan_bound\": 250001,\n \"generation_history_validation\": \"bounded_count_plus_active_ordinal_v1\",\n \"retained_generation_rejection_scan_bound\": 9\n },\n \"rebuild_seal\": {\n \"nip09_hook_id\": \"nip09_reconciliation_v1\",\n \"nip09_manifest_sha256\": \"74af832420ffbaa9805e89df3c0b34f126a443e1598f757e3372f407f9003b77\",\n \"food_hook_id\": \"food_availability_projection_v1\",\n \"food_manifest_sha256\": \"02dfe1b450fbdac16e718888215b4dd5c85d8975440fa21e8f439fb24c2b2990\",\n \"food_scope_fingerprint_sha256\": \"8b63c5ddc48a2cc7db69295238b96d5f814dba50427c80b4d0079f061e6d3de0\",\n \"active_generation_authority\": \"radroots_event_store_source_state\",\n \"marker_close_authority\": \"radroots_event_store_source_capacity_marker_close_guard\"\n }\n },\n \"entry_points\": [\n {\n \"role\": \"migration_registry\",\n \"rust_path\": \"radroots_event_store::migrations::EVENT_STORE_MIGRATIONS[3]\"\n },\n {\n \"role\": \"migration_apply_hook\",\n \"rust_path\": \"radroots_event_store::schema::apply_migration_hook\"\n },\n {\n \"role\": \"migration_validation_hook\",\n \"rust_path\": \"radroots_event_store::schema::validate_migration_hook_state\"\n },\n {\n \"role\": \"capacity_query\",\n \"rust_path\": \"radroots_event_store::RadrootsEventStore::source_capacity_v1\"\n },\n {\n \"role\": \"raw_append_preflight\",\n \"rust_path\": \"radroots_event_store::source_maintenance_v1::preflight_unique_raw_source_append_v1\"\n },\n {\n \"role\": \"raw_append_advance\",\n \"rust_path\": \"radroots_event_store::source_maintenance_v1::advance_source_capacity_after_insert_v1\"\n },\n {\n \"role\": \"generation_append_preflight\",\n \"rust_path\": \"radroots_event_store::source_maintenance_v1::preflight_source_generation_append_v1\"\n },\n {\n \"role\": \"generation_rebuild_bind\",\n \"rust_path\": \"radroots_event_store::source_maintenance_v1::bind_source_capacity_to_generation_v1\"\n },\n {\n \"role\": \"sqlite_encoding_preflight\",\n \"rust_path\": \"radroots_event_store::store::validate_main_database_encoding\"\n },\n {\n \"role\": \"source_generation_history_rollback_guard\",\n \"rust_path\": \"radroots_event_store::schema::validate_rollback_preserves_source_generation_history\"\n },\n {\n \"role\": \"result_vector_executor\",\n \"rust_path\": \"source_maintenance_v1_result_vector\"\n }\n ],\n \"source_files\": [\n {\n \"role\": \"workspace_dependency_authority\",\n \"path\": \"Cargo.toml\",\n \"byte_length\": 12411,\n \"sha256\": \"cad96f080b0cc9ac7ffda703c8807540c9cf89f47a2299b141e6e7949714bf9f\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_currency_value_authority\",\n \"path\": \"crates/core/src/currency.rs\",\n \"byte_length\": 4142,\n \"sha256\": \"42e6da2d8d2fdd6955dc2d83e98dd00266e02bc910b69923b117662c05089d14\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_decimal_value_authority\",\n \"path\": \"crates/core/src/decimal.rs\",\n \"byte_length\": 7839,\n \"sha256\": \"4b1d681a92d7a9e074bee7e1f20eb1499bb05bfc6528a6c9ba69fa7d00416550\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_money_value_authority\",\n \"path\": \"crates/core/src/money.rs\",\n \"byte_length\": 8025,\n \"sha256\": \"3f30bc21e21951a62fdc5d4033736ed42a883df590e8403940775bd2edfeebc5\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_percent_value_authority\",\n \"path\": \"crates/core/src/percent.rs\",\n \"byte_length\": 2652,\n \"sha256\": \"42ceab109881329f3539d06a0ee0381ab4359985fe185a18d58a9c9558c5eb7f\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_quantity_value_authority\",\n \"path\": \"crates/core/src/quantity.rs\",\n \"byte_length\": 6785,\n \"sha256\": \"d14e619da3829cdaf3ca7385fb892d330c286c1e21455c135c37518cbb588b5f\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_quantity_price_value_authority\",\n \"path\": \"crates/core/src/quantity_price.rs\",\n \"byte_length\": 7061,\n \"sha256\": \"d60f70377099470ed283f45868a5119d7bb46143cb250b5082a4c038ba7f6cdc\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_unit_value_authority\",\n \"path\": \"crates/core/src/unit.rs\",\n \"byte_length\": 10023,\n \"sha256\": \"550e9582b6a5290aac3f637b83853b21fefcbab92c432d067c83448f4b2fe3e9\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"blossom_public_surface\",\n \"path\": \"crates/blossom/src/lib.rs\",\n \"byte_length\": 510,\n \"sha256\": \"a4dfcbd193457c50c1b0fbfc91bb547981ecd3a6e23cfc6f1030edfb511dc58c\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"blossom_authorization_authority\",\n \"path\": \"crates/blossom/src/authorization.rs\",\n \"byte_length\": 39360,\n \"sha256\": \"461947b30516315a342b3b5697599f701d27050888f29f67f5d7a7ad4afa4c28\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"blossom_descriptor_authority\",\n \"path\": \"crates/blossom/src/descriptor.rs\",\n \"byte_length\": 13702,\n \"sha256\": \"b2a4ffa760256e1316f70e012d200e2b5f4afd8ede771b85a5147f96b247f599\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"blossom_error_authority\",\n \"path\": \"crates/blossom/src/error.rs\",\n \"byte_length\": 17229,\n \"sha256\": \"02af55beacf437040be17d1fc3271d6e2a62915f656ec2dbe06247deef83f95a\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"blossom_hash_authority\",\n \"path\": \"crates/blossom/src/hash.rs\",\n \"byte_length\": 11006,\n \"sha256\": \"45eca0d81ac0f46c305a32f81aafcdd90b14679d0614f72862289a6e5d4cb08f\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"blossom_media_type_authority\",\n \"path\": \"crates/blossom/src/media_type.rs\",\n \"byte_length\": 2368,\n \"sha256\": \"69db5c0f9fcdd7dbe1f22daa499f65603ae4ce198083dab2c73a36813fa18a46\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"blossom_url_authority\",\n \"path\": \"crates/blossom/src/url.rs\",\n \"byte_length\": 14580,\n \"sha256\": \"342c995fcf620e5fb32461a7d8276f5668ba2662890bd32d12780cc9121c6451\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_contract_facade\",\n \"path\": \"crates/event/src/contract.rs\",\n \"byte_length\": 86,\n \"sha256\": \"9994cbca9dcc7450ad133b6b927e7c06bee08ef813652452cc1e56a284c1be10\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_contract_registry_v7_authority\",\n \"path\": \"crates/event/src/contract/registry_v7.rs\",\n \"byte_length\": 155739,\n \"sha256\": \"64f5a67f8a54f364287210a3f717d9124bc1cb2b9c5fc67e9ff0e40acd7bd216\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_envelope_authority\",\n \"path\": \"crates/event/src/envelope.rs\",\n \"byte_length\": 31127,\n \"sha256\": \"df22443b825e9ad3da1640029ca6ba9c2ef18a36e14d713bb167766be8ffb439\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_head_facade\",\n \"path\": \"crates/event/src/event_head.rs\",\n \"byte_length\": 68,\n \"sha256\": \"cb52f6006f7ecd862707d6b048f9fc407e0cd5ebcd3091b3c54e195ffa5cba64\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_head_v1_authority\",\n \"path\": \"crates/event/src/event_head/v1.rs\",\n \"byte_length\": 7515,\n \"sha256\": \"ff3236d2d1628aad5674e0d9a3d607b947190a1cf0020143a139cc28413ad36e\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_ids_authority\",\n \"path\": \"crates/event/src/ids.rs\",\n \"byte_length\": 51018,\n \"sha256\": \"c420320528bac5a8381382cf33d5bed87037a2c753c0495bbc1c74a49de2756d\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_trade_authority\",\n \"path\": \"crates/event/src/trade.rs\",\n \"byte_length\": 68354,\n \"sha256\": \"a26ad42c55c82ae6c646ac2678819cff26bd8325e53cd56018819bfd14269e33\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_kinds_authority\",\n \"path\": \"crates/event/src/kinds.rs\",\n \"byte_length\": 34961,\n \"sha256\": \"8b3ce6193cab1f7e1587d0c1b2880a81b0aa43c77d89671b602772db37edcebf\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_tags_authority\",\n \"path\": \"crates/event/src/tags.rs\",\n \"byte_length\": 4530,\n \"sha256\": \"cb8f12a639fc72d9238e32495d9e67e928e6627fb8c94ec0a58c5d95e7373cd6\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_draft_authority\",\n \"path\": \"crates/event/src/draft.rs\",\n \"byte_length\": 58691,\n \"sha256\": \"b3b816bd195eb3269bf696c334d8cd51b406ea305f86cd496fe81fd5e8bcd513\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_calendar_authority\",\n \"path\": \"crates/event/src/calendar.rs\",\n \"byte_length\": 103814,\n \"sha256\": \"f7320e27daa113bff6fcc5da837bcce7d3b67c4df5fb9d9434e96f6ada753d6a\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_classified_listing_authority\",\n \"path\": \"crates/event/src/classified_listing.rs\",\n \"byte_length\": 8226,\n \"sha256\": \"745aa08953a6243ea1afad22aa63e44f6746f2f243ab0d6b617d6ab64fa58749\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_profile_authority\",\n \"path\": \"crates/event/src/profile.rs\",\n \"byte_length\": 18848,\n \"sha256\": \"7c7ac7f4926938f5cb5530be5450e5e23f18f216bdb222150fbdd451cec20d5c\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_post_authority\",\n \"path\": \"crates/event/src/post.rs\",\n \"byte_length\": 22738,\n \"sha256\": \"7ed4a4c39bed40b134369d16e1fc35ab2c7d27ee300dd36d367025def2283b39\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_comment_authority\",\n \"path\": \"crates/event/src/comment.rs\",\n \"byte_length\": 36411,\n \"sha256\": \"9f3e1b6457945a2defb1a1cf15d2b0230c1a0d2b72861fb5881859cd936299c7\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_food_availability_authority\",\n \"path\": \"crates/event/src/food_availability.rs\",\n \"byte_length\": 45429,\n \"sha256\": \"b4357dfb6954631673b6cd58794015da29303cb54ce8405a57ad543870036c9e\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_deletion_authority\",\n \"path\": \"crates/event/src/deletion.rs\",\n \"byte_length\": 31177,\n \"sha256\": \"eaf5eac81cd90039dd2c8f5a1f647d7916f961841d51887f1c5a679947bc816a\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_relay_hint_authority\",\n \"path\": \"crates/event/src/relay_hint.rs\",\n \"byte_length\": 14019,\n \"sha256\": \"f50a8fddd1ec9996a452f944ebc59ca4217fc8b28d90be33c2cca925dc3465d0\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_media_authority\",\n \"path\": \"crates/event/src/media.rs\",\n \"byte_length\": 3521,\n \"sha256\": \"8f670e634452872a525efdad0cb9480288885c62f22a9b9915a67a7e7965651c\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_social_authority\",\n \"path\": \"crates/event/src/social.rs\",\n \"byte_length\": 5483,\n \"sha256\": \"1b89c6d0954822e7f1e778479ed43694e88929bcd5310ee066f8f4ba6505045a\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_wire_facade\",\n \"path\": \"crates/event/src/wire.rs\",\n \"byte_length\": 68,\n \"sha256\": \"cb52f6006f7ecd862707d6b048f9fc407e0cd5ebcd3091b3c54e195ffa5cba64\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_wire_v1_authority\",\n \"path\": \"crates/event/src/wire/v1.rs\",\n \"byte_length\": 22133,\n \"sha256\": \"cc28c8cbd962b32ed2efe43e84c1e0d1ea3bd89636efff2d5553714072fce1a4\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_verification_facade\",\n \"path\": \"crates/event_codec/src/verification.rs\",\n \"byte_length\": 253,\n \"sha256\": \"b49a32df605035c87f295c0a151140d43d2e588c5e11b05183e5fc92993dae0e\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_verification_v1_authority\",\n \"path\": \"crates/event_codec/src/verification/v1.rs\",\n \"byte_length\": 8649,\n \"sha256\": \"1ef3d12f90eb7d35f4cafe36c2cc0bbd33731df278b58c9062fb13934e2a98c8\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_registry_v7_admission_authority\",\n \"path\": \"crates/event_codec/src/admission/registry_v7.rs\",\n \"byte_length\": 5350,\n \"sha256\": \"755e63dd7ad1115c219e5a3ea540bef67d2770fc9f2a5aa6ba97c925c99bdced\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_profile_inbound_facade\",\n \"path\": \"crates/event_codec/src/profile/inbound.rs\",\n \"byte_length\": 86,\n \"sha256\": \"9994cbca9dcc7450ad133b6b927e7c06bee08ef813652452cc1e56a284c1be10\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_profile_registry_v7_authority\",\n \"path\": \"crates/event_codec/src/profile/inbound/registry_v7.rs\",\n \"byte_length\": 10394,\n \"sha256\": \"c37c225ea8153beb098a39c4a56203aa03382af12646f40cd3f8628663700702\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_post_inbound_facade\",\n \"path\": \"crates/event_codec/src/post/inbound.rs\",\n \"byte_length\": 86,\n \"sha256\": \"9994cbca9dcc7450ad133b6b927e7c06bee08ef813652452cc1e56a284c1be10\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_post_registry_v7_authority\",\n \"path\": \"crates/event_codec/src/post/inbound/registry_v7.rs\",\n \"byte_length\": 16016,\n \"sha256\": \"bc0bb839c28f3588f05544c846c987528ea3934c75305fef70af8e027a97cc58\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_reply_inbound_facade\",\n \"path\": \"crates/event_codec/src/reply/inbound.rs\",\n \"byte_length\": 86,\n \"sha256\": \"9994cbca9dcc7450ad133b6b927e7c06bee08ef813652452cc1e56a284c1be10\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_reply_registry_v7_authority\",\n \"path\": \"crates/event_codec/src/reply/inbound/registry_v7.rs\",\n \"byte_length\": 26812,\n \"sha256\": \"a72e9721ed13addca2a63942ac9e43c1daa8f1d1457eef08ec6a3ee5eb8872c5\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_comment_inbound_facade\",\n \"path\": \"crates/event_codec/src/comment/inbound.rs\",\n \"byte_length\": 86,\n \"sha256\": \"9994cbca9dcc7450ad133b6b927e7c06bee08ef813652452cc1e56a284c1be10\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_comment_registry_v7_authority\",\n \"path\": \"crates/event_codec/src/comment/inbound/registry_v7.rs\",\n \"byte_length\": 53783,\n \"sha256\": \"30d1b0155963b25d64685ddd042f423ef7707b111dc56ead15bd468e0433a432\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_deletion_facade\",\n \"path\": \"crates/event_codec/src/deletion/mod.rs\",\n \"byte_length\": 115,\n \"sha256\": \"17d56f82ddb0a86bc97abbcf3e037fe460ea31fff2548f527be4bf004dac3a95\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_deletion_reconciliation_v1_authority\",\n \"path\": \"crates/event_codec/src/deletion/reconciliation_v1.rs\",\n \"byte_length\": 38469,\n \"sha256\": \"3e06d1fa923ca5faabb1e95338c35650b0e20b078ff5c972e35ab845d8b7476c\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_food_inbound_facade\",\n \"path\": \"crates/event_codec/src/food_availability/inbound.rs\",\n \"byte_length\": 86,\n \"sha256\": \"9994cbca9dcc7450ad133b6b927e7c06bee08ef813652452cc1e56a284c1be10\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_food_registry_v7_authority\",\n \"path\": \"crates/event_codec/src/food_availability/inbound/registry_v7.rs\",\n \"byte_length\": 26764,\n \"sha256\": \"a5786cff942b7b0038f741afb5b9a19230ac58cb57a5ba747b32e1b95d414e15\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_codec_job_traits_authority\",\n \"path\": \"crates/event_codec/src/job/traits.rs\",\n \"byte_length\": 5067,\n \"sha256\": \"de0b3f67177a48bd8e3c62534850103d09b7be099e80e88a9583363db705fcbb\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_store_dependency_authority\",\n \"path\": \"crates/event_store/Cargo.toml\",\n \"byte_length\": 1567,\n \"sha256\": \"46e03d3c758e1116638021a0499dfa588b4266498e0d50cfa758f9bef9bcfeb3\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_store_error_and_limits\",\n \"path\": \"crates/event_store/src/error.rs\",\n \"byte_length\": 19517,\n \"sha256\": \"4bf24ee1aa6117597ab467b1379a05549b79024213dc7622a2d276bc26fffab4\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"generated_descriptor_registration\",\n \"path\": \"crates/event_store/src/generated.rs\",\n \"byte_length\": 144,\n \"sha256\": \"6b0a8d6f249bd4fc3f878d37cb5e418680f0f1be2d9eec2518dedf03efc47121\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"public_surface\",\n \"path\": \"crates/event_store/src/lib.rs\",\n \"byte_length\": 3844,\n \"sha256\": \"3cd9653bcb752fb3c4442d4904b98a0a6208011a9a238125b7b7073d7f4e312b\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"migration_registry\",\n \"path\": \"crates/event_store/src/migrations.rs\",\n \"byte_length\": 73585,\n \"sha256\": \"a47477d04759ec6e71d14d3d05459864eae78fce0e3c2481a1b03147f04637f7\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"predecessor_model_public_surface\",\n \"path\": \"crates/event_store/src/model.rs\",\n \"byte_length\": 33596,\n \"sha256\": \"98b1742ffb517f66f8e9edefa61d1c3cf3e22be5985202c6c340310a98c72c8e\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_store_reconciliation_v1_model\",\n \"path\": \"crates/event_store/src/model/reconciliation_v1.rs\",\n \"byte_length\": 11138,\n \"sha256\": \"8a26bc373035878ef9b41767ceea7b681896e17d88bedce118de1d622125e1d6\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_store_reconciliation_v1_ingest_model\",\n \"path\": \"crates/event_store/src/model/ingest_reconciliation_v1.rs\",\n \"byte_length\": 1626,\n \"sha256\": \"47bf13b3fc0f8a913a660f7d655413de0f6b90568bc4acc510aa6bd741bab47b\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"addressable_transition_feed_model\",\n \"path\": \"crates/event_store/src/model/addressable_transition_feed_v1.rs\",\n \"byte_length\": 22279,\n \"sha256\": \"f8ea454a0e998a3d433bba52d1ff9759a04fcb91db286cf2a2b10ef7d0057694\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"food_projection_model\",\n \"path\": \"crates/event_store/src/model/food_availability_projection_v1.rs\",\n \"byte_length\": 17437,\n \"sha256\": \"6fdfc8c5eb3dd9c451fd47b2394af123b50f7fe6d74113f8777221a8fa31ba30\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"source_generation_rebuild_authority\",\n \"path\": \"crates/event_store/src/nip09/reconciliation_v1.rs\",\n \"byte_length\": 184499,\n \"sha256\": \"883f7695f71e76b28e2dbd428d0ddb821ff62ae319cde61f823c62203869742b\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"schema_migration_and_reopen_authority\",\n \"path\": \"crates/event_store/src/schema.rs\",\n \"byte_length\": 146146,\n \"sha256\": \"93b060e80d3edd73f86208e4bf698fa9d53eaf1eeb04526c9261fb8b5726fb0d\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"public_store_and_transaction_authority\",\n \"path\": \"crates/event_store/src/store.rs\",\n \"byte_length\": 395012,\n \"sha256\": \"5538b600fa5e457e10f23fe4e3a3c55496662098abaef2692108dc69c29aa3e6\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"addressable_transition_feed_store\",\n \"path\": \"crates/event_store/src/store/addressable_transition_feed_v1.rs\",\n \"byte_length\": 40260,\n \"sha256\": \"46ea9c9786099c85150e4979c9dac6f84c1b85b8f30ec44aae6d25f9eb9bebc5\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"current_visibility_store\",\n \"path\": \"crates/event_store/src/store/current_visibility_v1.rs\",\n \"byte_length\": 15786,\n \"sha256\": \"bf03f9fc45561366cc489daa400b39d65e68cc70aea2ef4a9cd7724224ca9514\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"food_projection_store\",\n \"path\": \"crates/event_store/src/store/food_availability_projection_v1.rs\",\n \"byte_length\": 48970,\n \"sha256\": \"9e0e63d6ca74e49d8ec77f088927983aa4d89a5dae4c9f2d766159e70ed53534\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"predecessor_post_core_v1_extension\",\n \"path\": \"crates/event_store/src/store/post_core_extensions_v1.rs\",\n \"byte_length\": 6923,\n \"sha256\": \"3820dad764a0575c20f3dc80a2f850651a1e41ab767cf46305377bf800558699\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"predecessor_post_core_v1_storage\",\n \"path\": \"crates/event_store/src/store/post_core_storage_v1.rs\",\n \"byte_length\": 16897,\n \"sha256\": \"3fb583b06dbd2e4fde96346da21e6d4516e79c8a4a3889299a7dd736c882c5df\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"raw_ingest_capacity_authority\",\n \"path\": \"crates/event_store/src/store/protocol_reconciliation_v1.rs\",\n \"byte_length\": 30153,\n \"sha256\": \"de7c327d940d561f0818fade4dc79cabb0b5141e30e02574c702b6f109aee392\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"predecessor_protocol_storage\",\n \"path\": \"crates/event_store/src/store/protocol_storage_v1.rs\",\n \"byte_length\": 10929,\n \"sha256\": \"20de4436945bac0d8cbeca0ae6cd95232a92da8cd6be6ae6beacba17fe50d658\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"source_maintenance_runtime\",\n \"path\": \"crates/event_store/src/source_maintenance_v1.rs\",\n \"byte_length\": 51849,\n \"sha256\": \"db43df5849c811d767a87bfa7884ce499400d0b169734e18242542a4415b3a51\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"predecessor_food_result_vector_executor\",\n \"path\": \"crates/event_store/tests/food_availability_projection_v1_result_vector.rs\",\n \"byte_length\": 34061,\n \"sha256\": \"7cdbdda875a876482a061bcd8886d9ba56c10fab0fa76a07d73d0f368324b545\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"artifact_transaction_authority\",\n \"path\": \"tools/xtask/src/contract/artifact_bundle.rs\",\n \"byte_length\": 38279,\n \"sha256\": \"f326ea57b56d40135f95b6b1e15961f66eed363337180a6d12a5ea903e1a9a29\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"predecessor_successor_governance\",\n \"path\": \"tools/xtask/src/contract/food_availability_projection.rs\",\n \"byte_length\": 197115,\n \"sha256\": \"a9f6553e26c10e255bbfda158989ecead2698e3e791ce577e290ffa88231692b\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"transitive_predecessor_membership_governance\",\n \"path\": \"tools/xtask/src/contract/nip09_reconciliation.rs\",\n \"byte_length\": 836171,\n \"sha256\": \"a4f34441a90334f797d3542e4b0e009d0cfe0b23a1835e9984bd788fda4f493a\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"source_maintenance_governance\",\n \"path\": \"tools/xtask/src/contract/source_maintenance.rs\",\n \"byte_length\": 191437,\n \"sha256\": \"bd4682f287b777b2ae1348358511a524a4d2294a16e526553c08f220ca37a001\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"contract_command_authority\",\n \"path\": \"tools/xtask/src/contract.rs\",\n \"byte_length\": 506277,\n \"sha256\": \"3a06ed79b5b342dce5b6582fc5c58311378a2dba97e5a8c74361f0186886023d\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"xtask_dispatch_and_release_preflight\",\n \"path\": \"tools/xtask/src/main.rs\",\n \"byte_length\": 16426,\n \"sha256\": \"abc24896c6c740c10811a3e003ec4be8ebdb376a7b6b01445bfa7a5889f094a7\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n }\n ],\n \"public_api\": {\n \"inherited_predecessor_symbols\": [\n \"RADROOTS_ADDRESSABLE_TRANSITION_CURSOR_JSON_MAX_BYTES_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_D_TAG_MAX_BYTES_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_FEED_VERSION_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_PAGE_LIMIT_MAX_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_PAGE_RAW_JSON_MAX_BYTES_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_PAGE_SCAN_MAX_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_SCOPE_KIND_MAX_V1\",\n \"RADROOTS_FOOD_AVAILABILITY_PROJECTION_APPLY_PAGE_LIMIT_V1\",\n \"RADROOTS_FOOD_AVAILABILITY_PROJECTION_VERSION_V1\",\n \"RADROOTS_FOOD_AVAILABILITY_SEARCH_QUERY_MAX_BYTES_V1\",\n \"RADROOTS_FOOD_AVAILABILITY_SEARCH_QUERY_MAX_TERMS_V1\",\n \"RadrootsAddressableTransitionCauseV1\",\n \"RadrootsAddressableTransitionCoordinateV1\",\n \"RadrootsAddressableTransitionCursorV1\",\n \"RadrootsAddressableTransitionEventReferenceV1\",\n \"RadrootsAddressableTransitionOriginV1\",\n \"RadrootsAddressableTransitionPageV1\",\n \"RadrootsAddressableTransitionRawHeadDecisionV1\",\n \"RadrootsAddressableTransitionScopeFingerprintV1\",\n \"RadrootsAddressableTransitionScopeV1\",\n \"RadrootsAddressableTransitionV1\",\n \"RadrootsAddressableTransitionVisibilityV1\",\n \"RadrootsCurrentEventVisibilityV1\",\n \"RadrootsCurrentVisibilityDecisionV1\",\n \"RadrootsFoodAvailabilitySearchQueryV1\",\n \"RadrootsFoodAvailabilityStatusFilterV1\",\n \"RadrootsNip09SuppressionEvidenceV1\",\n \"RadrootsNip09SuppressionOutcome\",\n \"RadrootsNip09SuppressionReason\",\n \"RadrootsStoreProducedCanonicalEventV1\",\n \"RadrootsStoredFoodAvailabilityImageV1\",\n \"RadrootsStoredFoodAvailabilityV1\"\n ],\n \"added_symbols\": [\n \"RADROOTS_EVENT_STORE_RAW_EVENT_COUNT_LIMIT_V1\",\n \"RADROOTS_EVENT_STORE_RAW_EVENT_TEXT_BYTES_LIMIT_V1\",\n \"RADROOTS_EVENT_STORE_RAW_TAG_COUNT_LIMIT_V1\",\n \"RADROOTS_EVENT_STORE_RAW_TAG_TEXT_BYTES_LIMIT_V1\",\n \"RADROOTS_EVENT_STORE_RETAINED_SOURCE_GENERATION_LIMIT_V1\",\n \"RadrootsEventStoreSourceCapacityResourceV1\",\n \"RadrootsEventStoreSourceCapacityV1\"\n ],\n \"methods\": [\n \"RadrootsEventStore::source_capacity_v1\",\n \"RadrootsEventStoreSourceCapacityResourceV1::as_str\",\n \"RadrootsEventStoreSourceCapacityV1::source_generation\",\n \"RadrootsEventStoreSourceCapacityV1::raw_event_count\",\n \"RadrootsEventStoreSourceCapacityV1::raw_tag_count\",\n \"RadrootsEventStoreSourceCapacityV1::raw_event_text_bytes\",\n \"RadrootsEventStoreSourceCapacityV1::raw_tag_text_bytes\",\n \"RadrootsEventStoreSourceCapacityV1::raw_high_water_seq\",\n \"RadrootsEventStoreSourceCapacityV1::retained_generation_count\",\n \"RadrootsEventStoreSourceCapacityV1::retained_generation_limit\"\n ],\n \"error_variants\": [\n \"SourceCapacityExceeded\",\n \"SourceGenerationHistoryLimitReached\",\n \"PersistedEphemeralRawEvent\",\n \"SourceCapacityStateDrift\",\n \"SqliteMainDatabaseEncodingNotUtf8\",\n \"RollbackWouldDiscardSourceGenerationHistory\"\n ],\n \"removed_symbols\": [\n \"RadrootsEventStoreReconciliationResource\",\n \"RadrootsEventStoreError::ReconciliationCapacityExceeded\"\n ],\n \"breaking_replacements\": [\n {\n \"removed\": \"RadrootsEventStoreReconciliationResource\",\n \"replacement\": \"RadrootsEventStoreSourceCapacityResourceV1\"\n },\n {\n \"removed\": \"RadrootsEventStoreError::ReconciliationCapacityExceeded\",\n \"replacement\": \"RadrootsEventStoreError::SourceCapacityExceeded\"\n }\n ]\n },\n \"result_vector\": {\n \"canonical_path\": \"contracts/conformance/vectors/event_store/source_maintenance.v1.json\",\n \"mirror_path\": \"crates/event_store/tests/fixtures/source_maintenance.v1.json\",\n \"byte_length\": 16253,\n \"sha256\": \"997aba2604a2b9d199fb87dc9d07942ca50d91863aeadcf3eeacf16d191dd71f\",\n \"hash_algorithm\": \"sha256_bytes_v1\",\n \"executor_id\": \"radroots_event_store.source_maintenance_v1.result_vector_executor.v1\",\n \"executor_path\": \"crates/event_store/tests/source_maintenance_v1_result_vector.rs\",\n \"executor_test\": \"source_maintenance_v1_result_vector\",\n \"executor_byte_length\": 23510,\n \"executor_sha256\": \"a7487afdfe19fc5fc794811d0f0e6035203e1aabcf0a33a1d398f6b3555d38f3\",\n \"executor_hash_algorithm\": \"sha256_bytes_v1\"\n }\n}\n"; +pub(crate) const SOURCE_MAINTENANCE_MANIFEST_BYTE_LENGTH: usize = 31654; pub(crate) const SOURCE_MAINTENANCE_MANIFEST_SHA256: &str = - "12e9a26c99807a3b821b0757f550e34806a719e8dd7304072fe9c161665efc8f"; + "267a332c0cfdc9dbc064c98dab23a41ea32ed7d2c2fe31b50777b1c92dbfba01"; pub(crate) const SOURCE_MAINTENANCE_MANIFEST_SCHEMA_VERSION: u32 = 1; pub(crate) const SOURCE_MAINTENANCE_CONTRACT_ID: &str = "radroots_event_store.source_maintenance_v1"; diff --git a/crates/event_store/src/nip09/reconciliation_v1.rs b/crates/event_store/src/nip09/reconciliation_v1.rs @@ -404,7 +404,7 @@ impl<'a> RequestIndex<'a> { for (index, request) in requests.iter().enumerate() { for target in request.projection().event_targets() { event_targets - .entry(target.event_id().as_str().to_owned()) + .entry(target.event_id().to_hex().to_owned()) .or_default() .push(index); } @@ -432,7 +432,7 @@ impl<'a> RequestIndex<'a> { ) -> impl Iterator<Item = &'index RadrootsAdmittedNip09DeletionRequestEventV1> + 'index { let event_indices = self .event_targets - .get(event.id_str()) + .get(&event.id_hex()) .map(Vec::as_slice) .unwrap_or_default(); let address_indices = nip01_coordinate_key(event) @@ -1475,7 +1475,7 @@ async fn load_reconciliation_snapshot( RadrootsEventIngest::from_raw_json_reconciliation_v1(raw_json, inserted_at_ms) .map_err(|_| raw_mismatch(event_id.as_str(), "raw_json"))?; let event = ingest.event(); - compare_raw_field(event.id_str() == event_id, event_id.as_str(), "event_id")?; + compare_raw_field(event.id_hex() == event_id, event_id.as_str(), "event_id")?; compare_raw_field( event.author().to_hex() == pubkey, event_id.as_str(), @@ -1499,7 +1499,7 @@ async fn load_reconciliation_snapshot( "tags_json", )?; compare_raw_field(event.content() == content, event_id.as_str(), "content")?; - compare_raw_field(event.sig_str() == sig, event_id.as_str(), "sig")?; + compare_raw_field(event.signature_hex() == sig, event_id.as_str(), "sig")?; compare_raw_tags( event_id.as_str(), event.tags_as_vec().as_slice(), @@ -1669,7 +1669,7 @@ async fn update_derived_tags( .find(|candidate| candidate.name == name) }); let tag_index = i64::try_from(index) - .map_err(|_| raw_mismatch(event.verified_event.event().id_str(), "tag_index"))?; + .map_err(|_| raw_mismatch(&event.verified_event.event().id_hex(), "tag_index"))?; sqlx::query( "UPDATE event_envelope_tags SET contract_semantic = ?, contract_value_type = ?, relay_indexed = ? WHERE event_id = ? AND tag_index = ?", ) @@ -1678,7 +1678,7 @@ async fn update_derived_tags( .bind(i64::from( contract_tag.map(|tag| tag.relay_indexed).unwrap_or(false), )) - .bind(event.verified_event.event().id_str()) + .bind(event.verified_event.event().id_hex()) .bind(tag_index) .execute(&mut *connection) .await?; @@ -1734,7 +1734,7 @@ async fn validate_derived_event_storage( { return hook_drift(format!( "derived envelope fields disagree for `{}`", - envelope.id_str() + envelope.id_hex() )); } } @@ -1757,7 +1757,7 @@ async fn validate_derived_event_storage( .find(|candidate| candidate.name == name) }); expected_tags.insert(( - event.verified_event.event().id_str().to_owned(), + event.verified_event.event().id_hex().to_owned(), i64_from_usize("tag_index", index)?, contract_tag.map(|tag| tag_semantic_name(tag.semantic).to_owned()), contract_tag.map(|tag| tag_value_type_name(tag.value_type).to_owned()), @@ -1881,7 +1881,7 @@ async fn rebuild_raw_heads( ) .bind(i64::from(*kind)) .bind(pubkey.to_hex()) - .bind(winner.candidate.event_id.as_str()) + .bind(winner.candidate.event_id.to_hex()) .bind(i64_from_u64( "raw_head_created_at", winner.candidate.created_at, @@ -1901,7 +1901,7 @@ async fn rebuild_raw_heads( .bind(i64::from(*kind)) .bind(pubkey.to_hex()) .bind(d_tag) - .bind(winner.candidate.event_id.as_str()) + .bind(winner.candidate.event_id.to_hex()) .bind(i64_from_u64( "raw_head_created_at", winner.candidate.created_at, @@ -2062,7 +2062,7 @@ fn event_coordinate_fact( return Ok(None); }; Ok(Some(EventCoordinateFact { - event_id: envelope.id_str().to_owned(), + event_id: envelope.id_hex().to_owned(), event_seq: event.seq, coordinate_type: coordinate_type.to_owned(), kind: i64::from(kind), @@ -2118,7 +2118,7 @@ async fn persist_nip09_facts( hook_id: NIP09_HOOK_ID, reason: format!( "centrally admitted deletion request `{}` failed typed admission: {}", - event.verified_event.event().id_str(), + event.verified_event.event().id_hex(), error ), })?; @@ -2150,11 +2150,11 @@ async fn validate_nip09_fact_graph( hook_id: NIP09_HOOK_ID, reason: format!( "centrally admitted deletion request `{}` failed typed admission: {error}", - event.verified_event.event().id_str() + event.verified_event.event().id_hex() ), })?; expected_requests.insert(RequestFact { - request_event_id: request.event().id_str().to_owned(), + request_event_id: request.event().id_hex().to_owned(), request_event_seq: event.seq, request_pubkey: request.event().author().to_hex().to_owned(), request_created_at: i64_from_u64( @@ -2166,8 +2166,8 @@ async fn validate_nip09_fact_graph( let source_tag_value = request_source_tag_value(request.event(), target.tag_index(), "e")?; expected_event_targets.insert(EventTargetFact { - request_event_id: request.event().id_str().to_owned(), - target_event_id: target.event_id().as_str().to_owned(), + request_event_id: request.event().id_hex().to_owned(), + target_event_id: target.event_id().to_hex().to_owned(), source_tag_index: i64_from_usize("source_tag_index", target.tag_index())?, source_tag_value: source_tag_value.to_owned(), }); @@ -2178,7 +2178,7 @@ async fn validate_nip09_fact_graph( let (source_kind_text, source_pubkey_text, source_d_tag) = raw_coordinate_parts(source_tag_value)?; expected_address_targets.insert(AddressTargetFact { - request_event_id: request.event().id_str().to_owned(), + request_event_id: request.event().id_hex().to_owned(), target_kind: i64::from(target.coordinate().kind()), target_pubkey: target.coordinate().pubkey().to_hex(), target_d_tag: target.coordinate().identifier().to_owned(), @@ -2288,7 +2288,7 @@ async fn synchronize_insert_delta( })?; persist_request_fact(connection, generation, inserted_seq, &request).await?; affected_coordinates.extend( - load_request_affected_coordinates(connection, generation, request.event().id_str()) + load_request_affected_coordinates(connection, generation, &request.event().id_hex()) .await?, ); } @@ -2329,7 +2329,7 @@ async fn persist_request_fact( "INSERT INTO radroots_event_store_nip09_request(source_generation, request_event_id, request_event_seq, request_pubkey, request_created_at) VALUES (?, ?, ?, ?, ?)", ) .bind(generation.as_bytes().as_slice()) - .bind(event.id_str()) + .bind(event.id_hex()) .bind(request_seq) .bind(event.author().to_hex()) .bind(i64_from_u64( @@ -2345,8 +2345,8 @@ async fn persist_request_fact( "INSERT INTO radroots_event_store_nip09_event_target(source_generation, request_event_id, target_event_id, source_tag_index, source_tag_value) VALUES (?, ?, ?, ?, ?)", ) .bind(generation.as_bytes().as_slice()) - .bind(event.id_str()) - .bind(target.event_id().as_str()) + .bind(event.id_hex()) + .bind(target.event_id().to_hex()) .bind(i64_from_usize("source_tag_index", target.tag_index())?) .bind(source_tag_value) .execute(&mut *connection) @@ -2361,7 +2361,7 @@ async fn persist_request_fact( "INSERT INTO radroots_event_store_nip09_address_target(source_generation, request_event_id, target_kind, target_pubkey, target_d_tag, inclusive_cutoff, source_tag_index, source_tag_value, source_kind_text, source_pubkey_text, source_d_tag) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", ) .bind(generation.as_bytes().as_slice()) - .bind(event.id_str()) + .bind(event.id_hex()) .bind(i64::from(target.coordinate().kind())) .bind(target.coordinate().pubkey().to_hex()) .bind(target.coordinate().identifier()) @@ -2585,7 +2585,7 @@ fn desired_addressable_states( ) -> Result<BTreeMap<(i64, String, String), AddressableHeadState>, RadrootsEventStoreError> { let event_by_id = events .iter() - .map(|event| (event.verified_event.event().id_str(), event)) + .map(|event| (event.verified_event.event().id_hex(), event)) .collect::<BTreeMap<_, _>>(); let winners = select_raw_head_winners(events); let request_index = RequestIndex::new(requests); @@ -2600,7 +2600,7 @@ fn desired_addressable_states( continue; }; let event = event_by_id - .get(winner.candidate.event_id.as_str()) + .get(&winner.candidate.event_id.to_hex()) .ok_or_else(|| RadrootsEventStoreError::MigrationHookStateDrift { hook_id: NIP09_HOOK_ID, reason: format!( @@ -2806,7 +2806,7 @@ fn expected_transition_history( .filter(|event| event.seq > source.baseline_raw_high_water_seq); let event_by_id = events .iter() - .map(|event| (event.verified_event.event().id_str(), event)) + .map(|event| (event.verified_event.event().id_hex(), event)) .collect::<BTreeMap<_, _>>(); let mut requests = admitted_nip09_requests(&baseline_events)?; let mut winners = select_raw_head_winners(&baseline_events); @@ -2843,7 +2843,7 @@ fn expected_transition_history( continue; }; let target = event_by_id - .get(winner.candidate.event_id.as_str()) + .get(&winner.candidate.event_id.to_hex()) .ok_or_else(|| RadrootsEventStoreError::MigrationHookStateDrift { hook_id: NIP09_HOOK_ID, reason: format!( @@ -2893,7 +2893,7 @@ fn expected_transition_history( } })?; let target = event_by_id - .get(winner.candidate.event_id.as_str()) + .get(&winner.candidate.event_id.to_hex()) .ok_or_else(|| RadrootsEventStoreError::MigrationHookStateDrift { hook_id: NIP09_HOOK_ID, reason: format!( @@ -2924,11 +2924,12 @@ fn expected_transition_history( .map(|prior| (prior.raw_head_event_seq, prior.raw_head_event_id.as_str())); next_transition_seq = checked_authority_add(next_transition_seq, 1, "transition sequence")?; + let inserted_event_id = event.verified_event.event().id_hex(); transitions.push(addressable_transition_fact( next_transition_seq, &desired, TransitionOrigin::Incremental, - Some((event.seq, event.verified_event.event().id_str())), + Some((event.seq, inserted_event_id.as_str())), retracted, raw_head_decision_code(&raw_head_decision), )); @@ -2961,7 +2962,7 @@ fn admitted_nip09_request( hook_id: NIP09_HOOK_ID, reason: format!( "centrally admitted deletion request `{}` failed typed admission: {error}", - event.verified_event.event().id_str() + event.verified_event.event().id_hex() ), } }) @@ -3042,9 +3043,9 @@ fn addressable_state_for_event<'a>( state.nip09_reason = Some(decision.reason().code().to_owned()); state.event_reference_request_id = decision .event_reference() - .map(|evidence| evidence.request_id().as_str().to_owned()); + .map(|evidence| evidence.request_id().to_hex().to_owned()); if let Some(evidence) = decision.address_reference() { - state.address_reference_request_id = Some(evidence.request_id().as_str().to_owned()); + state.address_reference_request_id = Some(evidence.request_id().to_hex().to_owned()); state.address_reference_cutoff = Some(i64_from_u64( "address_reference_cutoff", evidence.inclusive_cutoff(), @@ -3115,7 +3116,7 @@ fn addressable_state_base( kind, pubkey: pubkey.to_owned(), d_tag: d_tag.to_owned(), - raw_head_event_id: envelope.id_str().to_owned(), + raw_head_event_id: envelope.id_hex().to_owned(), raw_head_event_seq: event_seq, raw_head_created_at: i64_from_u64("raw_head_created_at", envelope.created_at_u64())?, admission_status: event.admission.status.as_str().to_owned(), @@ -3463,7 +3464,7 @@ fn request_source_tag_value<'a>( hook_id: NIP09_HOOK_ID, reason: format!( "admitted deletion request `{}` has no `{expected_name}` value at source tag {tag_index}", - event.id_str() + event.id_hex() ), })?; Ok(tag.as_str()) @@ -3654,7 +3655,7 @@ mod tests { vec![vec!["d".to_owned(), "rotation".to_owned()]], "{}", ); - let target_id = target.id_str().to_owned(); + let target_id = target.id_hex().to_owned(); seed_v1_raw_event(&pool, target, 1_000).await; seed_v1_raw_event( &pool, @@ -4027,7 +4028,7 @@ INSERT INTO radroots_event_store_owned_child_probe(id, parent_id) VALUES (1, 999 request.projection().address_targets().len(), RADROOTS_NIP09_DELETION_TAG_MAX_COUNT ); - let request_id = request.event().id_str().to_owned(); + let request_id = request.event().id_hex().to_owned(); let requests = vec![request]; let request_index = RequestIndex::new(&requests); @@ -4105,14 +4106,14 @@ INSERT INTO radroots_event_store_owned_child_probe(id, parent_id) VALUES (1, 999 admitted_request( REQUEST_CREATED_AT, vec![ - vec!["e".to_owned(), target.id_str().to_owned()], + vec!["e".to_owned(), target.id_hex().to_owned()], vec!["a".to_owned(), target_coordinate.clone()], ], "both", ), admitted_request( REQUEST_CREATED_AT + 1, - vec![vec!["e".to_owned(), target.id_str().to_owned()]], + vec![vec!["e".to_owned(), target.id_hex().to_owned()]], "event", ), admitted_request( @@ -4128,7 +4129,7 @@ INSERT INTO radroots_event_store_owned_child_probe(id, parent_id) VALUES (1, 999 assert_eq!( request_index .event_targets - .get(target.id_str()) + .get(&target.id_hex()) .expect("event indices") .len(), 2 @@ -4255,13 +4256,13 @@ INSERT INTO caller_child(id, parent_id) VALUES (1, 999);", let inserted = sqlx::query( "INSERT INTO event_envelopes(event_id, pubkey, created_at, kind, tags_json, content, sig, raw_json, verification_status, contract_status, contract_id, event_class, projection_eligible, inserted_at_ms, updated_at_ms) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'verified', ?, ?, ?, ?, ?, ?)", ) - .bind(event.id_str()) + .bind(event.id_hex()) .bind(event.author().to_hex()) .bind(i64::try_from(event.created_at_u64()).expect("created_at")) .bind(i64::from(event.kind_u32())) .bind(tags_json) .bind(event.content()) - .bind(event.sig_str()) + .bind(event.signature_hex()) .bind(ingest.raw_json()) .bind(admission.status.as_str()) .bind(admission.contract.map(|contract| contract.id)) @@ -4288,7 +4289,7 @@ INSERT INTO caller_child(id, parent_id) VALUES (1, 999);", let inserted = sqlx::query( "INSERT INTO event_envelope_tags(event_id, tag_index, tag_name, tag_value, tag_json, contract_semantic, contract_value_type, relay_indexed) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", ) - .bind(event.id_str()) + .bind(event.id_hex()) .bind(i64::try_from(index).expect("tag index")) .bind(name) .bind(value) @@ -4310,13 +4311,13 @@ INSERT INTO caller_child(id, parent_id) VALUES (1, 999);", observed_at_ms: i64, ) -> RadrootsEventIngest { let wire = RadrootsNip01EventWire { - id: envelope.id_str().to_owned(), + id: envelope.id_hex().to_owned(), pubkey: envelope.author().to_hex().to_owned(), created_at: envelope.created_at_u64(), kind: envelope.kind_u32(), tags: envelope.tags_as_vec(), content: envelope.content().to_owned(), - sig: envelope.sig_str().to_owned(), + sig: envelope.signature_hex().to_owned(), extra: Default::default(), }; let raw_json = serde_json::to_string(&wire).expect("wire JSON"); @@ -4447,12 +4448,12 @@ INSERT INTO caller_child(id, parent_id) VALUES (1, 999);", let inserted = sqlx::query( "INSERT INTO event_envelopes(event_id, pubkey, created_at, kind, tags_json, content, sig, raw_json, verification_status, contract_status, contract_id, event_class, projection_eligible, inserted_at_ms, updated_at_ms) VALUES (?, ?, ?, ?, '[]', ?, ?, ?, 'verified', ?, ?, ?, ?, ?, ?)", ) - .bind(event.id_str()) + .bind(event.id_hex()) .bind(event.author().to_hex()) .bind(i64::try_from(event.created_at_u64()).expect("created_at")) .bind(i64::from(event.kind_u32())) .bind(event.content()) - .bind(event.sig_str()) + .bind(event.signature_hex()) .bind(ingest.raw_json()) .bind(admission.status.as_str()) .bind(admission.contract.map(|contract| contract.id)) @@ -4474,7 +4475,7 @@ INSERT INTO caller_child(id, parent_id) VALUES (1, 999);", &ingest, &admission, inserted_seq, - event.id_str(), + &event.id_hex(), 0, &RadrootsRawHeadDecision::NotPersisted, ) @@ -4546,7 +4547,7 @@ INSERT INTO caller_child(id, parent_id) VALUES (1, 999);", let id = compute_canonical_nip01_event_id(author.as_str(), created_at, kind, &tags, content) .expect("event id"); - let nostr_id = nostr::EventId::from_hex(id.as_str()).expect("Nostr event id"); + let nostr_id = nostr::EventId::from_hex(&id.to_hex()).expect("Nostr event id"); let message = Message::from_digest(nostr_id.to_bytes()); let signature = SECP256K1.sign_schnorr_no_aux_rand(&message, keys.key_pair(SECP256K1)); RadrootsEventEnvelope::new(RadrootsEventEnvelopeParts { diff --git a/crates/event_store/src/source_maintenance_v1.rs b/crates/event_store/src/source_maintenance_v1.rs @@ -79,12 +79,14 @@ pub(crate) fn raw_source_capacity_delta_v1( tags_json: &str, ) -> Result<RawSourceCapacityDeltaV1, RadrootsEventStoreError> { let event = ingest.event(); + let event_id = event.id_hex(); + let signature = event.signature_hex(); let raw_event_bytes = raw_event_row_bytes_v1( - event.id_str(), + event_id.as_str(), &event.author().to_hex(), tags_json, event.content(), - event.sig_str(), + signature.as_str(), ingest.raw_json(), )?; let mut raw_tags = 0_u64; @@ -102,7 +104,7 @@ pub(crate) fn raw_source_capacity_delta_v1( raw_tag_bytes = checked_capacity_add( RadrootsEventStoreSourceCapacityResourceV1::RawTagBytes, raw_tag_bytes, - raw_tag_row_bytes_v1(event.id_str(), tag_name, tag_value, tag_json.as_str())?, + raw_tag_row_bytes_v1(event_id.as_str(), tag_name, tag_value, tag_json.as_str())?, )?; } Ok(RawSourceCapacityDeltaV1 { diff --git a/crates/event_store/src/store.rs b/crates/event_store/src/store.rs @@ -417,7 +417,8 @@ impl RadrootsEventStore { let mut tx = self.pool.begin().await?; let mut evaluated = BTreeMap::new(); for (index, event_id) in unique_event_ids.into_iter().enumerate() { - let visibility = event_visibility_in_transaction(&mut tx, event_id.as_str()).await?; + let event_id_hex = event_id.to_hex(); + let visibility = event_visibility_in_transaction(&mut tx, &event_id_hex).await?; evaluated.insert(event_id, visibility); after_evaluation(index + 1).await?; } @@ -933,7 +934,7 @@ impl RadrootsEventStore { let row = sqlx::query( "SELECT mutation_id, trade_id, root_mutation_id, contract_id, mutation_kind, schema_version, candidate_id, proposal_mutation_id, target_claim_mutation_id, author_pubkey, counterparty_pubkey, buyer_pubkey, seller_pubkey, farm_id, authored_at_unix_s, canonical_payload_bytes, payload_sha256, first_event_seq, first_transport_event_id, inserted_at_ms FROM trade_mutation WHERE mutation_id = ?", ) - .bind(mutation_id.as_str()) + .bind(mutation_id.to_hex()) .fetch_optional(&self.pool) .await?; row.map(trade_mutation_from_row).transpose() @@ -948,7 +949,7 @@ impl RadrootsEventStore { let rows = sqlx::query( "SELECT mutation_id, trade_id, root_mutation_id, contract_id, mutation_kind, schema_version, candidate_id, proposal_mutation_id, target_claim_mutation_id, author_pubkey, counterparty_pubkey, buyer_pubkey, seller_pubkey, farm_id, authored_at_unix_s, canonical_payload_bytes, payload_sha256, first_event_seq, first_transport_event_id, inserted_at_ms FROM trade_mutation WHERE trade_id = ? ORDER BY authored_at_unix_s, mutation_id LIMIT ?", ) - .bind(trade_id.as_str()) + .bind(trade_id.to_hex()) .bind(i64::from(limit)) .fetch_all(&self.pool) .await?; @@ -962,7 +963,7 @@ impl RadrootsEventStore { let rows = sqlx::query( "SELECT mutation_id, parent_mutation_id, parent_index FROM trade_mutation_parent WHERE mutation_id = ? ORDER BY parent_index", ) - .bind(mutation_id.as_str()) + .bind(mutation_id.to_hex()) .fetch_all(&self.pool) .await?; rows.into_iter() @@ -977,7 +978,7 @@ impl RadrootsEventStore { let rows = sqlx::query( "SELECT transport_event_id, mutation_id, trade_id, transport_kind, pubkey, created_at, event_seq, payload_sha256, observed_at_ms FROM trade_transport_envelope WHERE mutation_id = ? ORDER BY observed_at_ms, transport_event_id", ) - .bind(mutation_id.as_str()) + .bind(mutation_id.to_hex()) .fetch_all(&self.pool) .await?; rows.into_iter() @@ -992,7 +993,7 @@ impl RadrootsEventStore { let rows = sqlx::query( "SELECT trade_id, mutation_id, missing_parent_mutation_id, first_transport_event_id, first_seen_at_ms FROM trade_missing_parent WHERE trade_id = ? ORDER BY first_seen_at_ms, mutation_id, missing_parent_mutation_id", ) - .bind(trade_id.as_str()) + .bind(trade_id.to_hex()) .fetch_all(&self.pool) .await?; rows.into_iter() @@ -1035,11 +1036,11 @@ impl RadrootsEventStore { sqlx::query( "INSERT INTO trade_projection_checkpoint(trade_id, reducer_contract_id, reducer_version, projection_digest, root_mutation_id, negotiation_state, agreement_state, evidence_state, conflict_state, private_terms_state, attestation_state, fulfillment_state, payment_state, projection_json, last_mutation_id, last_transport_event_seq, updated_at_ms) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(trade_id) DO UPDATE SET reducer_contract_id = excluded.reducer_contract_id, reducer_version = excluded.reducer_version, projection_digest = excluded.projection_digest, root_mutation_id = excluded.root_mutation_id, negotiation_state = excluded.negotiation_state, agreement_state = excluded.agreement_state, evidence_state = excluded.evidence_state, conflict_state = excluded.conflict_state, private_terms_state = excluded.private_terms_state, attestation_state = excluded.attestation_state, fulfillment_state = excluded.fulfillment_state, payment_state = excluded.payment_state, projection_json = excluded.projection_json, last_mutation_id = excluded.last_mutation_id, last_transport_event_seq = excluded.last_transport_event_seq, updated_at_ms = excluded.updated_at_ms", ) - .bind(checkpoint.trade_id.as_str()) + .bind(checkpoint.trade_id.to_hex()) .bind(checkpoint.reducer_contract_id.as_str()) .bind(i64::from(checkpoint.reducer_version)) .bind(checkpoint.projection_digest.as_str()) - .bind(checkpoint.root_mutation_id.as_ref().map(RadrootsTradeMutationId::as_str)) + .bind(checkpoint.root_mutation_id.as_ref().map(RadrootsTradeMutationId::to_hex)) .bind(checkpoint.negotiation_state.as_str()) .bind(checkpoint.agreement_state.as_str()) .bind(checkpoint.evidence_state.as_str()) @@ -1049,7 +1050,7 @@ impl RadrootsEventStore { .bind(checkpoint.fulfillment_state.as_str()) .bind(checkpoint.payment_state.as_str()) .bind(checkpoint.projection_json.as_str()) - .bind(checkpoint.last_mutation_id.as_ref().map(RadrootsTradeMutationId::as_str)) + .bind(checkpoint.last_mutation_id.as_ref().map(RadrootsTradeMutationId::to_hex)) .bind(checkpoint.last_transport_event_seq) .bind(checkpoint.updated_at_ms) .execute(&self.pool) @@ -1064,7 +1065,7 @@ impl RadrootsEventStore { let row = sqlx::query( "SELECT trade_id, reducer_contract_id, reducer_version, projection_digest, root_mutation_id, negotiation_state, agreement_state, evidence_state, conflict_state, private_terms_state, attestation_state, fulfillment_state, payment_state, projection_json, last_mutation_id, last_transport_event_seq, updated_at_ms FROM trade_projection_checkpoint WHERE trade_id = ?", ) - .bind(trade_id.as_str()) + .bind(trade_id.to_hex()) .fetch_optional(&self.pool) .await?; row.map(trade_projection_checkpoint_from_row).transpose() @@ -1089,8 +1090,7 @@ async fn event_visibility_in_transaction( event_id: event_id.to_owned(), }, )? - .as_str() - .to_owned(), + .to_hex(), }, RadrootsCurrentVisibilityDecisionV1::Suppressed => { let evidence = current.suppression().ok_or_else(|| { @@ -2100,12 +2100,14 @@ mod tests { let tags = event.tags_as_vec(); let tags_json = serde_json::to_string(&tags).expect("tags JSON"); let pubkey = event.pubkey().to_hex(); + let event_id = event.id_hex(); + let signature = event.signature_hex(); let event_bytes = [ - event.id_str(), + event_id.as_str(), pubkey.as_str(), tags_json.as_str(), event.content(), - event.sig_str(), + signature.as_str(), event.raw_json(), ] .into_iter() @@ -2115,7 +2117,7 @@ mod tests { .iter() .map(|tag| { let tag_json = serde_json::to_string(tag).expect("tag JSON"); - event.id_str().len() + event.id_hex().len() + tag.first().map_or(0, String::len) + tag.get(1).map_or(0, String::len) + tag_json.len() @@ -2730,13 +2732,13 @@ mod tests { sqlx::query( "INSERT INTO event_envelopes(event_id, pubkey, created_at, kind, tags_json, content, sig, raw_json, verification_status, contract_status, contract_id, event_class, projection_eligible, inserted_at_ms, updated_at_ms) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'verified', 'admitted', 'radroots.post.v1', 'regular', 1, ?, ?)", ) - .bind(event.id_str()) + .bind(event.id_hex()) .bind(event.author().to_hex()) .bind(i64::try_from(event.created_at_u64()).expect("created_at")) .bind(i64::from(event.kind_u32())) .bind(tags_json) .bind(event.content()) - .bind(event.sig_str()) + .bind(event.signature_hex()) .bind(ingest.raw_json()) .bind(observed_at_ms) .bind(observed_at_ms) @@ -2750,7 +2752,7 @@ mod tests { sqlx::query( "INSERT INTO event_envelope_tags(event_id, tag_index, tag_name, tag_value, tag_json, contract_semantic, contract_value_type, relay_indexed) VALUES (?, ?, ?, ?, ?, NULL, NULL, 0)", ) - .bind(event.id_str()) + .bind(event.id_hex()) .bind(i64::try_from(tag_index).expect("tag index")) .bind(tag_name) .bind(tag_value) @@ -2796,7 +2798,7 @@ mod tests { let deletion = deletion_event( &fixture_keys(), 30, - vec![vec!["e".to_owned(), target.id_str().to_owned()]], + vec![vec!["e".to_owned(), target.id_hex().to_owned()]], ); let target_receipt = store .ingest_event(RadrootsEventIngest::new(target.clone(), 2_000)) @@ -2855,7 +2857,7 @@ mod tests { assert_ne!(second_generation, first_generation); assert_eq!(raw_authority_digest(&store).await, expected_raw_digest); let reconciled = store - .raw_event(target.id_str()) + .raw_event(&target.id_hex()) .await .expect("target read") .expect("target row"); @@ -3007,7 +3009,7 @@ mod tests { .await .expect("projection lookup") .expect("projection after rebuild"); - assert_eq!(projected.event_id().as_str(), food.id_str()); + assert_eq!(projected.event_id().to_hex(), food.id_hex()); validate_nip09_authority(&store).await; store .audit_food_availability_projection_v1() @@ -3137,7 +3139,7 @@ mod tests { .await .expect("projection lookup") .expect("projection"); - assert_eq!(projected.event_id().as_str(), food.id_str()); + assert_eq!(projected.event_id().to_hex(), food.id_hex()); assert_eq!(projected.images().len(), 1); assert!(projected.images()[0].qualifies()); assert_eq!( @@ -3246,7 +3248,7 @@ mod tests { rollback_store_to_v1(&store).await; sqlx::query("UPDATE event_envelopes SET seq = ? WHERE event_id = ?") .bind(invalid_seq) - .bind(event.id_str()) + .bind(event.id_hex()) .execute(store.pool()) .await .expect("install invalid legacy sequence"); @@ -3273,7 +3275,7 @@ mod tests { .expect("seed"); rollback_store_to_v1(&mismatch_store).await; sqlx::query("UPDATE event_envelopes SET content = 'forged' WHERE event_id = ?") - .bind(mismatch.id_str()) + .bind(mismatch.id_hex()) .execute(mismatch_store.pool()) .await .expect("forge immutable content"); @@ -3442,7 +3444,7 @@ mod tests { .expect("prior raw event bytes"); sqlx::query("UPDATE event_envelopes SET pubkey = ? WHERE event_id = ?") .bind("f".repeat(4_096)) - .bind(event.id_str()) + .bind(event.id_hex()) .execute(store.pool()) .await .expect("oversized legacy pubkey"); @@ -3540,8 +3542,8 @@ mod tests { &fixture_keys(), 10, vec![ - vec!["e".to_owned(), exact_target.id_str().to_owned()], - vec!["e".to_owned(), exact_target.id_str().to_owned()], + vec!["e".to_owned(), exact_target.id_hex().to_owned()], + vec!["e".to_owned(), exact_target.id_hex().to_owned()], vec!["a".to_owned(), exact_coordinate.clone()], vec!["a".to_owned(), exact_coordinate], vec!["k".to_owned(), KIND_LIST_SET_RELAY.to_string()], @@ -3589,12 +3591,12 @@ mod tests { let wrong_deletion = deletion_event( &alternate_keys(), 50, - vec![vec!["e".to_owned(), wrong_target.id_str().to_owned()]], + vec![vec!["e".to_owned(), wrong_target.id_hex().to_owned()]], ); let delete_deletion = deletion_event( &fixture_keys(), 60, - vec![vec!["e".to_owned(), mixed_deletion.id_str().to_owned()]], + vec![vec!["e".to_owned(), mixed_deletion.id_hex().to_owned()]], ); let missing_d = addressable_event(&fixture_keys(), 1, Vec::new(), "{}"); let valueless_d = addressable_event(&fixture_keys(), 2, vec![vec!["d".to_owned()]], "{}"); @@ -3707,7 +3709,7 @@ mod tests { assert_eq!(after_duplicate, before_duplicate); assert!( store - .valid_event(delete_deletion.id_str()) + .valid_event(&delete_deletion.id_hex()) .await .expect("kind-5 query") .is_some() @@ -3717,14 +3719,14 @@ mod tests { let mixed_event_targets: i64 = sqlx::query_scalar( "SELECT COUNT(*) FROM radroots_event_store_nip09_event_target WHERE request_event_id = ?", ) - .bind(mixed_deletion.id_str()) + .bind(mixed_deletion.id_hex()) .fetch_one(baseline.pool()) .await .expect("mixed event targets"); let mixed_address_targets: i64 = sqlx::query_scalar( "SELECT COUNT(*) FROM radroots_event_store_nip09_address_target WHERE request_event_id = ?", ) - .bind(mixed_deletion.id_str()) + .bind(mixed_deletion.id_hex()) .fetch_one(baseline.pool()) .await .expect("mixed address targets"); @@ -3739,7 +3741,7 @@ mod tests { let row = sqlx::query( "SELECT raw_d_tag, nip09_matchable, nip09_d_tag FROM radroots_event_store_event_coordinate WHERE event_id = ?", ) - .bind(event.id_str()) + .bind(event.id_hex()) .fetch_one(baseline.pool()) .await .expect("coordinate fact"); @@ -3791,7 +3793,7 @@ mod tests { state["exact"].2.as_deref(), Some("deletion_event_id_reference") ); - assert_eq!(state["cutoff"].0, cutoff_v2.id_str()); + assert_eq!(state["cutoff"].0, cutoff_v2.id_hex()); assert_eq!(state["cutoff"].1, "visible"); assert_eq!( state["cutoff"].2.as_deref(), @@ -4043,7 +4045,7 @@ mod tests { &fixture_keys(), 30, vec![ - vec!["e".to_owned(), target.id_str().to_owned()], + vec!["e".to_owned(), target.id_hex().to_owned()], vec!["a".to_owned(), addressable_coordinate("guard")], ], ); @@ -4205,7 +4207,7 @@ mod tests { .await .expect("snapshot invalidator"); let stale_event = signed_event(KIND_POST, 13, Vec::new(), "stale writer"); - let stale_event_id = stale_event.id_str().to_owned(); + let stale_event_id = stale_event.id_hex().to_owned(); let stale_error = store .ingest_event_in_transaction( &mut stale_tx, @@ -4670,14 +4672,14 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", "UPDATE event_envelopes SET kind = 20001 WHERE event_id = ?", ] { sqlx::query(statement) - .bind(event.id_str()) + .bind(event.id_hex()) .execute(store.pool()) .await .expect_err("envelope mutation must be rejected"); } let raw = store - .raw_event(event.id_str()) + .raw_event(&event.id_hex()) .await .expect("raw read") .expect("stored event"); @@ -4833,7 +4835,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", ], "Café-grown carrots 🥕 in Victoria\0", ); - let event_id = event.id_str().to_owned(); + let event_id = event.id_hex().to_owned(); let expected_tag_count = u64::try_from(event.tags_as_vec().len()).expect("tag count fits u64"); let (expected_event_bytes, expected_tag_bytes) = raw_source_text_bytes(&event); @@ -4904,7 +4906,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .await .expect("capacity after duplicate ingest"); let stored = store - .raw_event(event.id_str()) + .raw_event(&event.id_hex()) .await .expect("get") .expect("stored"); @@ -4932,7 +4934,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", assert!(stored.valid_stream_eligible); assert_eq!( store - .tags_for_event(event.id_str()) + .tags_for_event(&event.id_hex()) .await .expect("tags") .len(), @@ -5054,8 +5056,8 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", assert_eq!(before_race.raw_event_text_bytes(), filler_target); filler_store.pool().close().await; - let contender_a_id = contender_a.id_str().to_owned(); - let contender_b_id = contender_b.id_str().to_owned(); + let contender_a_id = contender_a.id_hex().to_owned(); + let contender_b_id = contender_b.id_hex().to_owned(); let store_a = RadrootsEventStore::open_file(&path) .await .expect("first independent store"); @@ -5213,7 +5215,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", let observation_count: i64 = sqlx::query_scalar( "SELECT COUNT(*) FROM event_transport_observation WHERE event_id = ?", ) - .bind(retained.id_str()) + .bind(retained.id_hex()) .fetch_one(&mut *transaction) .await .expect("duplicate observation count"); @@ -5265,7 +5267,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", let ephemeral_observation_count: i64 = sqlx::query_scalar( "SELECT COUNT(*) FROM event_transport_observation WHERE event_id = ?", ) - .bind(ephemeral.id_str()) + .bind(ephemeral.id_hex()) .fetch_one(&mut *transaction) .await .expect("ephemeral observation count"); @@ -5284,14 +5286,14 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .expect("roll back exact-bound fixture"); assert!( store - .raw_event(unique.id_str()) + .raw_event(&unique.id_hex()) .await .expect("unique raw event after rollback") .is_none() ); assert!( store - .raw_event(ephemeral.id_str()) + .raw_event(&ephemeral.id_hex()) .await .expect("ephemeral raw event after rollback") .is_none() @@ -5313,8 +5315,8 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", vec![vec!["t".to_owned(), "soil".to_owned()]], "same event", ); - assert_eq!(first_event.id_str(), second_event.id_str()); - assert_ne!(first_event.sig_str(), second_event.sig_str()); + assert_eq!(first_event.id_hex(), second_event.id_hex()); + assert_ne!(first_event.signature_hex(), second_event.signature_hex()); assert_ne!(first_event.raw_json(), second_event.raw_json()); store @@ -5324,14 +5326,14 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", sqlx::query( "UPDATE event_envelopes SET contract_status = 'unsupported', contract_id = NULL, projection_eligible = 0 WHERE event_id = ?", ) - .bind(first_event.id_str()) + .bind(first_event.id_hex()) .execute(store.pool()) .await .expect_err("derived classification mutation must be rejected"); let before: (String, String, String, i64) = sqlx::query_as( "SELECT sig, raw_json, tags_json, updated_at_ms FROM event_envelopes WHERE event_id = ?", ) - .bind(first_event.id_str()) + .bind(first_event.id_hex()) .fetch_one(store.pool()) .await .expect("before"); @@ -5347,7 +5349,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", let after: (String, String, String, i64) = sqlx::query_as( "SELECT sig, raw_json, tags_json, updated_at_ms FROM event_envelopes WHERE event_id = ?", ) - .bind(first_event.id_str()) + .bind(first_event.id_hex()) .fetch_one(store.pool()) .await .expect("after"); @@ -5373,11 +5375,11 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", RadrootsRawHeadDecision::NotHeadSelected ); assert_eq!(after, before); - assert_eq!(after.0, first_event.sig_str()); + assert_eq!(after.0, first_event.signature_hex()); assert_eq!(after.1, first_event.raw_json()); assert_eq!( store - .raw_event(first_event.id_str()) + .raw_event(&first_event.id_hex()) .await .expect("raw event") .expect("stored") @@ -5386,7 +5388,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", ); assert!( store - .valid_event(first_event.id_str()) + .valid_event(&first_event.id_hex()) .await .expect("valid event") .is_some() @@ -5398,8 +5400,8 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", let store = RadrootsEventStore::open_memory().await.expect("open"); let first_event = signed_event(KIND_POST, 12, Vec::new(), "legacy"); let second_event = signed_event(KIND_POST, 12, Vec::new(), "legacy"); - assert_eq!(first_event.id_str(), second_event.id_str()); - assert_ne!(first_event.sig_str(), second_event.sig_str()); + assert_eq!(first_event.id_hex(), second_event.id_hex()); + assert_ne!(first_event.signature_hex(), second_event.signature_hex()); store .ingest_event(RadrootsEventIngest::new(first_event.clone(), 1_300)) @@ -5408,14 +5410,14 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", sqlx::query( "UPDATE event_envelopes SET contract_status = 'supported', event_class = NULL WHERE event_id = ?", ) - .bind(first_event.id_str()) + .bind(first_event.id_hex()) .execute(store.pool()) .await .expect_err("legacy classification mutation must be rejected"); let before: (String, String, String, String, Option<String>, i64) = sqlx::query_as( "SELECT sig, raw_json, tags_json, contract_status, event_class, updated_at_ms FROM event_envelopes WHERE event_id = ?", ) - .bind(first_event.id_str()) + .bind(first_event.id_hex()) .fetch_one(store.pool()) .await .expect("before"); @@ -5427,7 +5429,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", let after: (String, String, String, String, Option<String>, i64) = sqlx::query_as( "SELECT sig, raw_json, tags_json, contract_status, event_class, updated_at_ms FROM event_envelopes WHERE event_id = ?", ) - .bind(first_event.id_str()) + .bind(first_event.id_hex()) .fetch_one(store.pool()) .await .expect("after"); @@ -5438,25 +5440,25 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", RadrootsEventAdmissionStatus::Admitted ); assert_eq!(after, before); - assert_eq!(after.0, first_event.sig_str()); + assert_eq!(after.0, first_event.signature_hex()); assert_eq!(after.1, first_event.raw_json()); assert!( store - .raw_event(first_event.id_str()) + .raw_event(&first_event.id_hex()) .await .expect("raw event") .is_some() ); assert!( store - .valid_event(first_event.id_str()) + .valid_event(&first_event.id_hex()) .await .expect("valid event") .is_some() ); assert_eq!( store - .event_visibility(first_event.id_str()) + .event_visibility(&first_event.id_hex()) .await .expect("visibility"), Some(RadrootsEventVisibility::Visible) @@ -5500,8 +5502,8 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", sha256_hex(decision.content.as_bytes()) ); assert_eq!( - stored_decision.first_transport_event_id.as_str(), - decision_event.id_str() + stored_decision.first_transport_event_id.to_hex(), + decision_event.id_hex() ); assert_eq!( stored_decision.mutation_kind, @@ -5577,7 +5579,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", "post-core forged raw authority", ); register_protocol_post_extension_raw_authority_forge( - trigger_event.id_str().to_owned(), + trigger_event.id_hex().to_owned(), RadrootsEventIngest::new(forged_event.clone(), 2_251), ); @@ -5619,21 +5621,21 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", assert!( store - .raw_event(prior_event.id_str()) + .raw_event(&prior_event.id_hex()) .await .expect("prior raw event") .is_some() ); assert!( store - .raw_event(trigger_event.id_str()) + .raw_event(&trigger_event.id_hex()) .await .expect("trigger raw event") .is_none() ); assert!( store - .raw_event(forged_event.id_str()) + .raw_event(&forged_event.id_hex()) .await .expect("forged raw event") .is_none() @@ -5758,7 +5760,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", let proposal = canonical_trade_mutation_content(proposal_envelope).expect("unique proposal"); let trigger_event = signed_trade_mutation(&proposal); - register_protocol_post_extension_schema_forge(trigger_event.id_str().to_owned()); + register_protocol_post_extension_schema_forge(trigger_event.id_hex().to_owned()); let error = store .ingest_event(RadrootsEventIngest::new(trigger_event.clone(), 2_252)) @@ -5771,7 +5773,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", )); assert!( store - .raw_event(trigger_event.id_str()) + .raw_event(&trigger_event.id_hex()) .await .expect("trigger raw event") .is_none() @@ -5854,7 +5856,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", format!("{} ", proposal.content), &fixture_keys(), ); - let malformed_id = malformed.id_str().to_owned(); + let malformed_id = malformed.id_hex().to_owned(); let malformed_receipt = store .ingest_event(RadrootsEventIngest::new(malformed, 2_400)) .await @@ -5886,7 +5888,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", let missing_id_content = canonical_jcs_value(&missing_id_value).expect("canonical json"); let missing_id = signed_trade_content_with_keys(&proposal, missing_id_content, &fixture_keys()); - let missing_id_event_id = missing_id.id_str().to_owned(); + let missing_id_event_id = missing_id.id_hex().to_owned(); let missing_id_receipt = store .ingest_event(RadrootsEventIngest::new(missing_id, 2_500)) .await @@ -5906,7 +5908,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", let mismatched_author = signed_trade_content_with_keys(&proposal, proposal.content.clone(), &alternate_keys()); - let mismatched_author_id = mismatched_author.id_str().to_owned(); + let mismatched_author_id = mismatched_author.id_hex().to_owned(); let mismatched_author_receipt = store .ingest_event(RadrootsEventIngest::new(mismatched_author, 2_600)) .await @@ -6144,7 +6146,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .await .expect("ingest"); let stored = store - .raw_event(event.id_str()) + .raw_event(&event.id_hex()) .await .expect("get") .expect("stored"); @@ -6180,7 +6182,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", ); assert!( store - .valid_event(event.id_str()) + .valid_event(&event.id_hex()) .await .expect("valid event") .is_none() @@ -6211,12 +6213,12 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", fn test_helpers_cover_signature_and_non_head_branches() { let zero_sig = synthetic_signed_event(KIND_POST, 12, Vec::new(), "zero"); let zero_sig = tamper_signature(&zero_sig); - assert!(zero_sig.sig_str().starts_with('0')); + assert!(zero_sig.signature_hex().starts_with('0')); let nonzero_sig = tamper_signature(&signed_event(KIND_POST, 12, Vec::new(), "nonzero")); assert_ne!( - nonzero_sig.sig_str(), - signed_event(KIND_POST, 12, Vec::new(), "nonzero").sig_str() + nonzero_sig.signature_hex(), + signed_event(KIND_POST, 12, Vec::new(), "nonzero").signature_hex() ); } @@ -6260,7 +6262,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", )); assert!( store - .raw_event(event.id_str()) + .raw_event(&event.id_hex()) .await .expect("raw event") .is_none() @@ -6292,7 +6294,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", )); assert!( store - .raw_event(event.id_str()) + .raw_event(&event.id_hex()) .await .expect("raw event") .is_none() @@ -6365,28 +6367,28 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", for event in [&admitted, &unsupported, &invalid] { assert!( store - .raw_event(event.id_str()) + .raw_event(&event.id_hex()) .await .expect("raw event") .is_none() ); assert!( store - .valid_event(event.id_str()) + .valid_event(&event.id_hex()) .await .expect("valid event") .is_none() ); assert_eq!( store - .event_visibility(event.id_str()) + .event_visibility(&event.id_hex()) .await .expect("visibility"), None ); assert!( store - .tags_for_event(event.id_str()) + .tags_for_event(&event.id_hex()) .await .expect("tags") .is_empty() @@ -6394,7 +6396,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", } assert!( store - .observations_for_event(admitted.id_str()) + .observations_for_event(&admitted.id_hex()) .await .expect("observations") .is_empty() @@ -6444,7 +6446,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .await .expect("ingest"); let stored = store - .raw_event(event.id_str()) + .raw_event(&event.id_hex()) .await .expect("get") .expect("stored"); @@ -6468,11 +6470,11 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .expect("raw head") .expect("stored raw head") .event_id, - event.id_str() + event.id_hex() ); assert_eq!( store - .event_visibility(event.id_str()) + .event_visibility(&event.id_hex()) .await .expect("visibility"), Some(RadrootsEventVisibility::NotAdmitted) @@ -6536,14 +6538,14 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", assert!(capacity_after.raw_tag_text_bytes() > capacity_before.raw_tag_text_bytes()); assert!( store - .raw_event(event.id_str()) + .raw_event(&event.id_hex()) .await .expect("raw event") .is_some() ); assert!( store - .valid_event(event.id_str()) + .valid_event(&event.id_hex()) .await .expect("valid event") .is_none() @@ -6555,11 +6557,11 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .expect("raw head") .expect("head") .event_id, - event.id_str() + event.id_hex() ); assert_eq!( store - .event_visibility(event.id_str()) + .event_visibility(&event.id_hex()) .await .expect("visibility"), Some(RadrootsEventVisibility::NotAdmitted) @@ -6632,7 +6634,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .await .expect("food lookup") .expect("projected carrots"); - assert_eq!(projected.event_id().as_str(), carrots.id_str()); + assert_eq!(projected.event_id().to_hex(), carrots.id_hex()); assert_eq!(projected.title().as_str(), "Nantes Carrots"); assert_eq!(projected.summary().as_str(), "Fresh bunches"); assert_eq!(projected.price().amount(), "3"); @@ -6686,7 +6688,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .await .expect("search"); assert_eq!(matches.len(), 1); - assert_eq!(matches[0].event_id().as_str(), carrots.id_str()); + assert_eq!(matches[0].event_id().to_hex(), carrots.id_hex()); let summary_query = crate::RadrootsFoodAvailabilitySearchQueryV1::parse("Fresh") .expect("summary search query"); let summary_matches = store @@ -6698,7 +6700,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .await .expect("summary search"); assert_eq!(summary_matches.len(), 1); - assert_eq!(summary_matches[0].event_id().as_str(), carrots.id_str()); + assert_eq!(summary_matches[0].event_id().to_hex(), carrots.id_hex()); let sold = food_availability_event( 220, @@ -6718,7 +6720,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .await .expect("replacement lookup") .expect("sold projection"); - assert_eq!(replacement.event_id().as_str(), sold.id_str()); + assert_eq!(replacement.event_id().to_hex(), sold.id_hex()); assert_eq!(replacement.status(), RadrootsFoodAvailabilityStatus::Sold); assert_eq!(replacement.published_at().as_u64(), 100); assert!(replacement.images().is_empty()); @@ -6731,7 +6733,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", assert_eq!(replacement_projection_count, 2); assert_eq!( store - .current_event_visibility_v1(carrots.id_str()) + .current_event_visibility_v1(&carrots.id_hex()) .await .expect("old visibility") .expect("stored old revision") @@ -6740,7 +6742,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", ); assert_eq!( store - .current_event_visibility_v1(sold.id_str()) + .current_event_visibility_v1(&sold.id_hex()) .await .expect("sold visibility") .expect("stored sold revision") @@ -6753,13 +6755,13 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .await .expect("active after replacement"); assert_eq!(active.len(), 1); - assert_eq!(active[0].event_id().as_str(), kale.id_str()); + assert_eq!(active[0].event_id().to_hex(), kale.id_hex()); let sold_rows = store .recent_food_availability_v1(crate::RadrootsFoodAvailabilityStatusFilterV1::Sold, 10) .await .expect("sold food"); assert_eq!(sold_rows.len(), 1); - assert_eq!(sold_rows[0].event_id().as_str(), sold.id_str()); + assert_eq!(sold_rows[0].event_id().to_hex(), sold.id_hex()); let stale_query = crate::RadrootsFoodAvailabilitySearchQueryV1::parse("Fresh bunches") .expect("stale query"); @@ -6785,7 +6787,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .await .expect("replacement search"); assert_eq!(replacement_matches.len(), 1); - assert_eq!(replacement_matches[0].event_id().as_str(), sold.id_str()); + assert_eq!(replacement_matches[0].event_id().to_hex(), sold.id_hex()); } #[tokio::test] @@ -6854,7 +6856,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", let event_seq: i64 = sqlx::query_scalar( "SELECT event_seq FROM radroots_event_store_food_availability_projection WHERE event_id = ?", ) - .bind(replacement.id_str()) + .bind(replacement.id_hex()) .fetch_one(store.pool()) .await .expect("replacement sequence"); @@ -7099,7 +7101,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", let mut expected_ids = events .iter() - .map(|event| event.id_str().to_owned()) + .map(|event| event.id_hex().to_owned()) .collect::<Vec<_>>(); expected_ids.sort(); let recent = store @@ -7112,7 +7114,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", assert_eq!( recent .iter() - .map(|projection| projection.event_id().as_str()) + .map(|projection| projection.event_id().to_hex()) .collect::<Vec<_>>(), expected_ids.iter().map(String::as_str).collect::<Vec<_>>(), ); @@ -7122,7 +7124,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .await .expect("minimum-limit recent query")[0] .event_id() - .as_str(), + .to_hex(), expected_ids[0], ); for invalid_limit in [0, RADROOTS_EVENT_STORE_QUERY_LIMIT_MAX + 1] { @@ -7150,7 +7152,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", assert_eq!( search .iter() - .map(|projection| projection.event_id().as_str()) + .map(|projection| projection.event_id().to_hex()) .collect::<Vec<_>>(), expected_ids.iter().map(String::as_str).collect::<Vec<_>>(), ); @@ -7293,7 +7295,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .expect("sealed retracted projection count"); assert_eq!(retracted_projection_count, 0); let suppressed = store - .current_event_visibility_v1(sold.id_str()) + .current_event_visibility_v1(&sold.id_hex()) .await .expect("suppressed visibility") .expect("stored sold revision"); @@ -7310,8 +7312,8 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", evidence .address_reference_request_id() .expect("address deletion id") - .as_str(), - deletion.id_str() + .to_hex(), + deletion.id_hex() ); assert_eq!(evidence.address_reference_cutoff(), Some(230)); @@ -7332,7 +7334,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", ); assert_eq!( store - .current_event_visibility_v1(older.id_str()) + .current_event_visibility_v1(&older.id_hex()) .await .expect("older visibility") .expect("stored older revision") @@ -7349,7 +7351,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .await .expect("recovered lookup") .expect("recovered projection"); - assert_eq!(projection.event_id().as_str(), recovered.id_str()); + assert_eq!(projection.event_id().to_hex(), recovered.id_hex()); assert_eq!(projection.status(), RadrootsFoodAvailabilityStatus::Active); let recovered_projection_count: i64 = sqlx::query_scalar( "SELECT projected_row_count FROM radroots_event_store_food_availability_cursor WHERE singleton = 1", @@ -7372,8 +7374,8 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .cause_event() .expect("deletion cause metadata"); assert_eq!( - deletion_cause.event().event_id().as_str(), - deletion.id_str() + deletion_cause.event().event_id().to_hex(), + deletion.id_hex() ); assert_eq!( &deletion_cause.pubkey().to_hex(), @@ -7392,8 +7394,8 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .retracted_event() .expect("sold retraction") .event_id() - .as_str(), - sold.id_str() + .to_hex(), + sold.id_hex() ); assert!(page.transitions()[2].visible_event().is_none()); assert_eq!( @@ -7408,8 +7410,8 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .visible_event() .expect("recovered canonical event") .event_id() - .as_str(), - recovered.id_str() + .to_hex(), + recovered.id_hex() ); assert!(page.transitions()[3].retracted_event().is_none()); assert_eq!(projection.source_transition_seq(), 4); @@ -7493,8 +7495,8 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .expect("restored lookup") .expect("restored projection") .event_id() - .as_str(), - restored.id_str(), + .to_hex(), + restored.id_hex(), ); let page = store .addressable_transition_page_v1( @@ -7514,20 +7516,20 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .visible_event() .expect("operational transition payload") .event_id() - .as_str(), - operational.id_str(), + .to_hex(), + operational.id_hex(), ); assert_eq!( page.transitions()[1] .retracted_event() .expect("focused projection retraction") .event_id() - .as_str(), + .to_hex(), page.transitions()[0] .visible_event() .expect("initial focused payload") .event_id() - .as_str(), + .to_hex(), ); } @@ -7572,7 +7574,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", assert!( store - .raw_event(event.id_str()) + .raw_event(&event.id_hex()) .await .expect("raw event after rollback") .is_none() @@ -7608,7 +7610,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .await .expect("committed projection") .expect("projected event"); - assert_eq!(committed.event_id().as_str(), event.id_str()); + assert_eq!(committed.event_id().to_hex(), event.id_hex()); let committed_page = store .addressable_transition_page_v1(&scope, Some(&initial_cursor), 64) .await @@ -7636,7 +7638,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", let wrong_author_deletion = deletion_event( &alternate_keys(), 210, - vec![vec!["e".to_owned(), food.id_str().to_owned()]], + vec![vec!["e".to_owned(), food.id_hex().to_owned()]], ); store .ingest_event(RadrootsEventIngest::new( @@ -7653,10 +7655,10 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .await .expect("projection lookup") .expect("projection remains visible"); - assert_eq!(projection.event_id().as_str(), food.id_str()); + assert_eq!(projection.event_id().to_hex(), food.id_hex()); assert_eq!(projection.source_transition_seq(), 1); let visibility = store - .current_event_visibility_v1(food.id_str()) + .current_event_visibility_v1(&food.id_hex()) .await .expect("current visibility") .expect("stored event"); @@ -7684,8 +7686,8 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .visible_event() .expect("same visible event") .event_id() - .as_str(), - food.id_str() + .to_hex(), + food.id_hex() ); assert!(unchanged.retracted_event().is_none()); assert_eq!( @@ -7694,8 +7696,8 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .expect("deletion cause") .event() .event_id() - .as_str(), - wrong_author_deletion.id_str() + .to_hex(), + wrong_author_deletion.id_hex() ); } @@ -7716,9 +7718,9 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", let visibilities = store .event_visibilities_with_probe( [ - event.id_str().to_owned(), + event.id_hex().to_owned(), missing_event_id.clone(), - event.id_str().to_owned(), + event.id_hex().to_owned(), ], move |_| { let probe_count = Arc::clone(&probe_count); @@ -7742,7 +7744,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", let max = RADROOTS_EVENT_STORE_QUERY_LIMIT_MAX as usize; let exact_max = store - .event_visibilities(vec![event.id_str().to_owned(); max]) + .event_visibilities(vec![event.id_hex().to_owned(); max]) .await .expect("maximum visibility batch"); assert_eq!(exact_max.len(), max); @@ -7765,13 +7767,13 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", ); assert!(matches!( closed - .event_visibilities([event.id_str().to_owned(), "not-an-event-id".to_owned(),]) + .event_visibilities([event.id_hex().to_owned(), "not-an-event-id".to_owned(),]) .await, Err(RadrootsEventStoreError::IdParse(_)) )); assert!(matches!( closed - .event_visibilities(vec![event.id_str().to_owned(); max + 1]) + .event_visibilities(vec![event.id_hex().to_owned(); max + 1]) .await, Err(RadrootsEventStoreError::EventVisibilityBatchTooLarge { max: actual_max, @@ -7836,7 +7838,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", let committed_new_bob = new_bob.clone(); let snapshot = store .event_visibilities_with_probe( - [old_alice.id_str(), old_bob.id_str()], + [old_alice.id_hex(), old_bob.id_hex()], move |evaluated| { let concurrent_store = concurrent_store.clone(); let new_alice = committed_new_alice.clone(); @@ -7866,11 +7868,11 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", for (old, new) in [(&old_alice, &new_alice), (&old_bob, &new_bob)] { assert_eq!( store - .event_visibility(old.id_str()) + .event_visibility(&old.id_hex()) .await .expect("post-commit visibility"), Some(RadrootsEventVisibility::NotCurrent { - raw_head_event_id: new.id_str().to_owned(), + raw_head_event_id: new.id_hex().to_owned(), }) ); } @@ -7919,7 +7921,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", } let regular_current = store - .current_event_visibility_v1(regular.id_str()) + .current_event_visibility_v1(&regular.id_hex()) .await .expect("regular current visibility") .expect("regular event"); @@ -7931,14 +7933,14 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", assert!(regular_current.raw_head_event_id().is_none()); assert_eq!( store - .event_visibility(regular.id_str()) + .event_visibility(&regular.id_hex()) .await .expect("regular compatibility visibility"), Some(RadrootsEventVisibility::Visible) ); assert!( store - .visible_event(regular.id_str()) + .visible_event(&regular.id_hex()) .await .expect("regular visible event") .is_some() @@ -7947,27 +7949,27 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", for (event, expected_head, expected_decision) in [ ( &older_profile, - newer_profile.id_str(), + newer_profile.id_hex(), crate::RadrootsCurrentVisibilityDecisionV1::NotCurrent, ), ( &newer_profile, - newer_profile.id_str(), + newer_profile.id_hex(), crate::RadrootsCurrentVisibilityDecisionV1::Visible, ), ( &older_food, - newer_food.id_str(), + newer_food.id_hex(), crate::RadrootsCurrentVisibilityDecisionV1::NotCurrent, ), ( &newer_food, - newer_food.id_str(), + newer_food.id_hex(), crate::RadrootsCurrentVisibilityDecisionV1::Visible, ), ] { let current = store - .current_event_visibility_v1(event.id_str()) + .current_event_visibility_v1(&event.id_hex()) .await .expect("coordinate current visibility") .expect("coordinate event"); @@ -7976,12 +7978,12 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", current .raw_head_event_id() .expect("coordinate raw head") - .as_str(), + .to_hex(), expected_head ); assert_eq!( store - .visible_event(event.id_str()) + .visible_event(&event.id_hex()) .await .expect("coordinate visible event") .is_some(), @@ -7993,20 +7995,20 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .visible_event_head(&profile_coordinate()) .await .expect("profile visible head") - .is_some_and(|head| head.raw_head().event_id == newer_profile.id_str()) + .is_some_and(|head| head.raw_head().event_id == newer_profile.id_hex()) ); assert!( store .visible_event_head(&head_coordinate_for_event(&newer_food)) .await .expect("food visible head") - .is_some_and(|head| head.raw_head().event_id == newer_food.id_str()) + .is_some_and(|head| head.raw_head().event_id == newer_food.id_hex()) ); let regular_deletion = deletion_event( &fixture_keys(), 150, - vec![vec!["e".to_owned(), regular.id_str().to_owned()]], + vec![vec!["e".to_owned(), regular.id_hex().to_owned()]], ); store .ingest_event(RadrootsEventIngest::new(regular_deletion.clone(), 37_005)) @@ -8014,7 +8016,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .expect("regular deletion"); assert_eq!( store - .current_event_visibility_v1(regular.id_str()) + .current_event_visibility_v1(&regular.id_hex()) .await .expect("suppressed regular visibility") .expect("stored regular event") @@ -8023,7 +8025,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", ); assert!(matches!( store - .event_visibility(regular.id_str()) + .event_visibility(&regular.id_hex()) .await .expect("regular compatibility suppression"), Some(RadrootsEventVisibility::Suppressed { @@ -8031,11 +8033,11 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", event_reference_request_id: Some(request_id), address_reference_request_id: None, address_reference_cutoff: None, - }) if request_id.as_str() == regular_deletion.id_str() + }) if request_id.to_hex() == regular_deletion.id_hex() )); assert!( store - .visible_event(regular.id_str()) + .visible_event(&regular.id_hex()) .await .expect("suppressed regular event") .is_none() @@ -8044,14 +8046,14 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", let deletion_of_deletion = deletion_event( &fixture_keys(), 160, - vec![vec!["e".to_owned(), regular_deletion.id_str().to_owned()]], + vec![vec!["e".to_owned(), regular_deletion.id_hex().to_owned()]], ); store .ingest_event(RadrootsEventIngest::new(deletion_of_deletion, 37_006)) .await .expect("deletion-of-deletion ingest"); let immune = store - .current_event_visibility_v1(regular_deletion.id_str()) + .current_event_visibility_v1(&regular_deletion.id_hex()) .await .expect("deletion request visibility") .expect("stored deletion request"); @@ -8069,7 +8071,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", assert!(immune_evidence.address_reference_cutoff().is_none()); assert_eq!( store - .event_visibility(regular_deletion.id_str()) + .event_visibility(&regular_deletion.id_hex()) .await .expect("compatibility deletion-request visibility"), Some(RadrootsEventVisibility::Visible) @@ -8131,8 +8133,8 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .visible_event() .expect("first visible event") .event_id() - .as_str(), - first.id_str() + .to_hex(), + first.id_hex() ); assert_eq!(first_page.source_high_water(), 4); assert_eq!(first_page.next_cursor().last_transition_seq(), 3); @@ -8148,8 +8150,8 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .visible_event() .expect("second visible event") .event_id() - .as_str(), - second.id_str() + .to_hex(), + second.id_hex() ); assert_eq!(second_page.next_cursor().last_transition_seq(), 4); assert!(!second_page.has_more()); @@ -8207,7 +8209,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", vec![vec!["d".to_owned(), format!("page-limit-{index:02}")]], "page-limit fixture", ); - expected_ids.push(event.id_str().to_owned()); + expected_ids.push(event.id_hex().to_owned()); store .ingest_event_in_transaction( &mut transaction, @@ -8237,7 +8239,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", first .transitions() .iter() - .map(|transition| transition.raw_head().event_id().as_str()) + .map(|transition| transition.raw_head().event_id().to_hex()) .collect::<Vec<_>>(), expected_ids[..usize::try_from( crate::RADROOTS_ADDRESSABLE_TRANSITION_PAGE_LIMIT_MAX_V1 @@ -8255,8 +8257,8 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .expect("continued page"); assert_eq!(second.transitions().len(), 1); assert_eq!( - second.transitions()[0].raw_head().event_id().as_str(), - expected_ids.last().expect("last expected event"), + second.transitions()[0].raw_head().event_id().to_hex(), + expected_ids.last().expect("last expected event").as_str(), ); assert!(!second.has_more()); } @@ -8285,7 +8287,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", let transition = &page.transitions()[0]; assert_eq!(transition.coordinate().kind(), 30_340); assert_eq!(transition.coordinate().d_tag(), d_tag); - assert_eq!(transition.raw_head().event_id().as_str(), event.id_str()); + assert_eq!(transition.raw_head().event_id().to_hex(), event.id_hex()); assert_eq!(transition.raw_head_created_at(), 204); assert!(!page.has_more()); } @@ -8352,8 +8354,8 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .visible_event() .expect("FoodAvailability canonical event") .event_id() - .as_str(), - food.id_str() + .to_hex(), + food.id_hex() ); assert_eq!(second.next_cursor().last_transition_seq(), 1_025); assert!(!second.has_more()); @@ -8373,7 +8375,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", format!("payload-cap-{index:02}").as_str(), content.clone(), ); - expected_ids.push(event.id_str().to_owned()); + expected_ids.push(event.id_hex().to_owned()); store .ingest_event_in_transaction( &mut transaction, @@ -8402,7 +8404,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .visible_event() .expect("admitted calendar canonical event") .event_id() - .as_str() + .to_hex() .to_owned(), ); } @@ -8547,7 +8549,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .expect("missing raw head") .expect("missing head") .event_id, - missing_value.id_str() + missing_value.id_hex() ); for (event, expected_d) in [(&opaque, " opaque/value "), (&control, "line\nbreak")] { let coordinate = head_coordinate_for_event(event); @@ -8560,11 +8562,11 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .await .expect("raw head") .expect("head"); - assert_eq!(head.event_id, event.id_str()); + assert_eq!(head.event_id, event.id_hex()); assert_eq!(head.d_tag.as_deref(), Some(expected_d)); } let missing_tags = store - .tags_for_event(missing_value.id_str()) + .tags_for_event(&missing_value.id_hex()) .await .expect("tags"); assert_eq!(missing_tags[0].tag_name, "d"); @@ -8581,7 +8583,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .await .expect("kind ingest"); sqlx::query("UPDATE event_envelope_head SET kind = 10002 WHERE event_id = ?") - .bind(kind_event.id_str()) + .bind(kind_event.id_hex()) .execute(store.pool()) .await .expect_err("kind mutation must be rejected"); @@ -8594,7 +8596,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", let other_pubkey = alternate_keys().public_key().to_hex(); sqlx::query("UPDATE event_envelope_head SET pubkey = ? WHERE event_id = ?") .bind(other_pubkey.as_str()) - .bind(author_event.id_str()) + .bind(author_event.id_hex()) .execute(store.pool()) .await .expect_err("author mutation must be rejected"); @@ -8607,7 +8609,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", sqlx::query( "UPDATE event_envelope_head SET coordinate_type = 'addressable', d_tag = 'wrong-class' WHERE event_id = ?", ) - .bind(class_event.id_str()) + .bind(class_event.id_hex()) .execute(store.pool()) .await .expect_err("coordinate-class mutation must be rejected"); @@ -8623,7 +8625,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .await .expect("d ingest"); sqlx::query("UPDATE event_envelope_head SET d_tag = 'wrong-d' WHERE event_id = ?") - .bind(d_event.id_str()) + .bind(d_event.id_hex()) .execute(store.pool()) .await .expect_err("d-tag mutation must be rejected"); @@ -8637,7 +8639,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", sqlx::query( "UPDATE event_envelope_head SET created_at = created_at + 1 WHERE event_id = ?", ) - .bind(created_event.id_str()) + .bind(created_event.id_hex()) .execute(store.pool()) .await .expect_err("created-at mutation must be rejected"); @@ -8648,7 +8650,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .expect("raw head") .expect("stored head") .event_id, - created_event.id_str() + created_event.id_hex() ); let reference_event = signed_event(10_006, 45, Vec::new(), "reference"); @@ -8663,8 +8665,8 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .await .expect("unrelated ingest"); sqlx::query("UPDATE event_envelope_head SET event_id = ? WHERE event_id = ?") - .bind(unrelated_event.id_str()) - .bind(reference_event.id_str()) + .bind(unrelated_event.id_hex()) + .bind(reference_event.id_hex()) .execute(store.pool()) .await .expect_err("event reference mutation must be rejected"); @@ -8684,7 +8686,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .expect("missing ingest"); sqlx::query("UPDATE event_envelope_head SET event_id = ? WHERE event_id = ?") .bind(event_id('f')) - .bind(missing_event.id_str()) + .bind(missing_event.id_hex()) .execute(store.pool()) .await .expect_err("missing event reference mutation must be rejected"); @@ -8727,7 +8729,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", assert_eq!(first.raw_head_decision, RadrootsRawHeadDecision::Applied); assert!(matches!(error, RadrootsEventStoreError::EventWire(_))); - assert_eq!(head.event_id, original.id_str()); + assert_eq!(head.event_id, original.id_hex()); } #[tokio::test] @@ -8767,12 +8769,12 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", )); assert!( store - .raw_event(invalid.id_str()) + .raw_event(&invalid.id_hex()) .await .expect("raw event") .is_none() ); - assert_eq!(head.event_id, original.id_str()); + assert_eq!(head.event_id, original.id_hex()); } #[tokio::test] @@ -8824,7 +8826,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", second_invalid.raw_head_decision, RadrootsRawHeadDecision::SkippedDuplicate ); - assert_eq!(head.event_id, invalid.id_str()); + assert_eq!(head.event_id, invalid.id_hex()); } #[tokio::test] @@ -8860,7 +8862,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", second.raw_head_decision, RadrootsRawHeadDecision::SkippedDuplicate ); - assert_eq!(head.event_id, event.id_str()); + assert_eq!(head.event_id, event.id_hex()); } #[tokio::test] @@ -8873,7 +8875,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .await .expect("ingest"); let stored = store - .raw_event(event.id_str()) + .raw_event(&event.id_hex()) .await .expect("get") .expect("stored"); @@ -8890,21 +8892,21 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", assert!(stored.valid_stream_eligible); assert!( store - .valid_event(event.id_str()) + .valid_event(&event.id_hex()) .await .expect("valid event") .is_some() ); assert_eq!( store - .event_visibility(event.id_str()) + .event_visibility(&event.id_hex()) .await .expect("visibility"), Some(RadrootsEventVisibility::Visible) ); assert!( store - .visible_event(event.id_str()) + .visible_event(&event.id_hex()) .await .expect("visible event") .is_some() @@ -8970,8 +8972,8 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .await .expect("tag query"); assert_eq!(events.len(), 2); - assert_eq!(events[0].raw_event().event_id, high_created_at.id_str()); - assert_eq!(events[1].raw_event().event_id, low_created_at.id_str()); + assert_eq!(events[0].raw_event().event_id, high_created_at.id_hex()); + assert_eq!(events[1].raw_event().event_id, low_created_at.id_hex()); assert!( events .iter() @@ -8983,14 +8985,14 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .await .expect("raw tag query"); assert_eq!(raw_events.len(), 3); - assert_eq!(raw_events[0].event_id, unsupported.id_str()); + assert_eq!(raw_events[0].event_id, unsupported.id_hex()); let limited = store .valid_stream_by_tag("t", "soil", 1) .await .expect("limited tag query"); assert_eq!(limited.len(), 1); - assert_eq!(limited[0].raw_event().event_id, high_created_at.id_str()); + assert_eq!(limited[0].raw_event().event_id, high_created_at.id_hex()); } #[tokio::test] @@ -9066,7 +9068,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .await .expect("contract tag query"); assert_eq!(events.len(), 1); - assert_eq!(events[0].raw_event().event_id, matching_trade.id_str()); + assert_eq!(events[0].raw_event().event_id, matching_trade.id_hex()); assert_eq!( events[0].raw_event().contract_id.as_deref(), Some(RADROOTS_TRADE_PROPOSAL_CONTRACT_ID) @@ -9091,7 +9093,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .ingest_event(RadrootsEventIngest::new(event.clone(), 3_000)) .await .expect("ingest"); - let tags = store.tags_for_event(event.id_str()).await.expect("tags"); + let tags = store.tags_for_event(&event.id_hex()).await.expect("tags"); assert_eq!(tags[0].tag_index, 0); assert_eq!(tags[0].tag_name, "p"); @@ -9115,16 +9117,16 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .ingest_event(RadrootsEventIngest::new(event.clone(), 3_000)) .await .expect("ingest"); - let before = store.tags_for_event(event.id_str()).await.expect("tags"); + let before = store.tags_for_event(&event.id_hex()).await.expect("tags"); sqlx::query( "UPDATE event_envelope_tags SET relay_indexed = 2 WHERE event_id = ? AND tag_index = 0", ) - .bind(event.id_str()) + .bind(event.id_hex()) .execute(store.pool()) .await .expect_err("non-boolean relay_indexed mutation must be rejected"); - let tags = store.tags_for_event(event.id_str()).await.expect("tags"); + let tags = store.tags_for_event(&event.id_hex()).await.expect("tags"); assert_eq!(tags, before); } @@ -9138,7 +9140,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .ingest_event(RadrootsEventIngest::new(event.clone(), 3_100)) .await .expect("ingest"); - let tags = store.tags_for_event(event.id_str()).await.expect("tags"); + let tags = store.tags_for_event(&event.id_hex()).await.expect("tags"); let contract_tag = tags .iter() .find(|tag| tag.tag_name == "contract") @@ -9160,7 +9162,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", assert!(!contract_tag.relay_indexed); assert_eq!( mutation_tag.tag_value.as_deref(), - Some(proposal.mutation_id.as_str()) + Some(proposal.mutation_id.to_hex()).as_deref() ); assert_eq!( mutation_tag.contract_semantic.as_deref(), @@ -9206,7 +9208,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", store.ingest_event(ingest).await.expect("older duplicate"); let observations = store - .observations_for_event(event.id_str()) + .observations_for_event(&event.id_hex()) .await .expect("stale duplicate observations"); assert_eq!(observations.len(), 1); @@ -9255,7 +9257,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .expect("newer duplicate without message"); let observations = store - .observations_for_event(event.id_str()) + .observations_for_event(&event.id_hex()) .await .expect("observations"); assert_eq!(observations.len(), 1); @@ -9331,11 +9333,11 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", Err(RadrootsEventStoreError::InvalidStoredTransportEndpointFingerprint { event_id, .. - }) if event_id == event.id_str() + }) if event_id == event.id_hex() )); assert!( store - .raw_event(event.id_str()) + .raw_event(&event.id_hex()) .await .expect("raw event") .is_none() @@ -9369,12 +9371,12 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", sqlx::query( "UPDATE event_transport_observation SET observation_count = 0 WHERE event_id = ?", ) - .bind(event.id_str()) + .bind(event.id_hex()) .execute(store.pool()) .await .expect("corrupt observation count"); assert!(matches!( - store.observations_for_event(event.id_str()).await, + store.observations_for_event(&event.id_hex()).await, Err(RadrootsEventStoreError::InvalidStoredTransportObservation { observation_count: 0, .. @@ -9384,7 +9386,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", sqlx::query( "UPDATE event_transport_observation SET observation_count = 1, first_observed_at_ms = 4_100, last_observed_at_ms = 4_000 WHERE event_id = ?", ) - .bind(event.id_str()) + .bind(event.id_hex()) .execute(store.pool()) .await .expect("corrupt observation time order"); @@ -9402,12 +9404,12 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", sqlx::query( "UPDATE event_transport_observation SET first_observed_at_ms = -1, last_observed_at_ms = 4_000 WHERE event_id = ?", ) - .bind(event.id_str()) + .bind(event.id_hex()) .execute(store.pool()) .await .expect("corrupt observation timestamp"); assert!(matches!( - store.observations_for_event(event.id_str()).await, + store.observations_for_event(&event.id_hex()).await, Err(RadrootsEventStoreError::InvalidStoredTransportObservation { first_observed_at_ms: -1, .. @@ -9418,29 +9420,29 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", "UPDATE event_transport_observation SET first_observed_at_ms = 4_000, redacted_message = ? WHERE event_id = ?", ) .bind("line\nbreak") - .bind(event.id_str()) + .bind(event.id_hex()) .execute(store.pool()) .await .expect("corrupt observation message"); assert!(matches!( - store.observations_for_event(event.id_str()).await, + store.observations_for_event(&event.id_hex()).await, Err( RadrootsEventStoreError::InvalidStoredTransportObservationMessage { ref event_id, .. } - ) if event_id == event.id_str() + ) if event_id.as_str() == event.id_hex() )); sqlx::query( "UPDATE event_transport_observation SET observation_count = 1, first_observed_at_ms = 4_000, last_observed_at_ms = 4_000, redacted_message = NULL, transport_kind = 'NOSTR' WHERE event_id = ?", ) - .bind(event.id_str()) + .bind(event.id_hex()) .execute(store.pool()) .await .expect("corrupt transport kind canonical form"); assert!(matches!( - store.observations_for_event(event.id_str()).await, + store.observations_for_event(&event.id_hex()).await, Err(RadrootsEventStoreError::Transport( radroots_transport::RadrootsTransportError::InvalidTransportKind )) @@ -9449,12 +9451,12 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", sqlx::query( "UPDATE event_transport_observation SET transport_kind = 'nostr', endpoint_fingerprint = upper(endpoint_fingerprint) WHERE event_id = ?", ) - .bind(event.id_str()) + .bind(event.id_hex()) .execute(store.pool()) .await .expect("corrupt endpoint fingerprint canonical form"); assert!(matches!( - store.observations_for_event(event.id_str()).await, + store.observations_for_event(&event.id_hex()).await, Err(RadrootsEventStoreError::InvalidStoredTransportEndpointFingerprint { .. }) )); } @@ -9489,48 +9491,48 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .expect("raw head") .expect("head") .event_id, - newer.id_str() + newer.id_hex() ); assert!( store - .valid_event(older.id_str()) + .valid_event(&older.id_hex()) .await .expect("valid") .is_some() ); assert!( store - .valid_event(newer.id_str()) + .valid_event(&newer.id_hex()) .await .expect("invalid") .is_none() ); assert_eq!( store - .event_visibility(older.id_str()) + .event_visibility(&older.id_hex()) .await .expect("older visibility"), Some(RadrootsEventVisibility::NotCurrent { - raw_head_event_id: newer.id_str().to_owned(), + raw_head_event_id: newer.id_hex().to_owned(), }) ); assert_eq!( store - .event_visibility(newer.id_str()) + .event_visibility(&newer.id_hex()) .await .expect("newer visibility"), Some(RadrootsEventVisibility::NotAdmitted) ); assert!( store - .visible_event(older.id_str()) + .visible_event(&older.id_hex()) .await .expect("older visible") .is_none() ); assert!( store - .visible_event(newer.id_str()) + .visible_event(&newer.id_hex()) .await .expect("newer visible") .is_none() @@ -9544,7 +9546,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", ); let valid_stream = store.valid_stream_after(0, 10).await.expect("valid stream"); assert_eq!(valid_stream.len(), 1); - assert_eq!(valid_stream[0].raw_event().event_id, older.id_str()); + assert_eq!(valid_stream[0].raw_event().event_id, older.id_hex()); let older_duplicate = store .ingest_event(RadrootsEventIngest::new(older, 4_700)) @@ -9589,7 +9591,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .expect("raw head") .expect("preserved head") .event_id, - newer.id_str() + newer.id_hex() ); } @@ -9599,7 +9601,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", signed_event(KIND_PROFILE, 20, Vec::new(), "{\"name\":\"a\"}"), signed_event(KIND_PROFILE, 20, Vec::new(), "{\"name\":\"b\"}"), ]; - events.sort_by(|left, right| left.id_str().cmp(right.id_str())); + events.sort_by(|left, right| left.id_hex().cmp(&right.id_hex())); let lower = events[0].clone(); let higher = events[1].clone(); @@ -9620,7 +9622,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", assert_eq!(first.raw_head_decision, RadrootsRawHeadDecision::Applied); assert_eq!(second.raw_head_decision, RadrootsRawHeadDecision::Applied); - assert_eq!(head.event_id, lower.id_str()); + assert_eq!(head.event_id, lower.id_hex()); let store = RadrootsEventStore::open_memory().await.expect("open"); store @@ -9641,7 +9643,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", second.raw_head_decision, RadrootsRawHeadDecision::SkippedSameTimestampHigherEventId ); - assert_eq!(head.event_id, lower.id_str()); + assert_eq!(head.event_id, lower.id_hex()); } #[tokio::test] @@ -9673,8 +9675,8 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .await .expect("initial replay"); assert_eq!(replay.len(), 2); - assert_eq!(replay[0].raw_event().event_id, first.id_str()); - assert_eq!(replay[1].raw_event().event_id, second.id_str()); + assert_eq!(replay[0].raw_event().event_id, first.id_hex()); + assert_eq!(replay[1].raw_event().event_id, second.id_hex()); let first_cursor = RadrootsProjectionCursor { projection_id: "social".to_owned(), projection_version: 1, @@ -9703,7 +9705,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", .await .expect("next replay"); assert_eq!(replay.len(), 1); - assert_eq!(replay[0].raw_event().event_id, second.id_str()); + assert_eq!(replay[0].raw_event().event_id, second.id_hex()); let second_cursor = RadrootsProjectionCursor { projection_id: "social".to_owned(), @@ -9809,7 +9811,7 @@ CREATE TABLE aux.event_transport_observation (event_id TEXT);", let mutation_plan = explain_query_plan( &store, "EXPLAIN QUERY PLAN SELECT mutation_id FROM trade_mutation WHERE trade_id = ? ORDER BY authored_at_unix_s, mutation_id LIMIT 10", - trade_id().as_str(), + trade_id().to_hex().as_str(), ) .await; assert!( diff --git a/crates/event_store/src/store/addressable_transition_feed_v1.rs b/crates/event_store/src/store/addressable_transition_feed_v1.rs @@ -590,10 +590,10 @@ async fn validate_incremental_cause( "SELECT EXISTS(SELECT 1 FROM radroots_event_store_nip09_event_target WHERE source_generation = ? AND request_event_id = ? AND target_event_id = ?) OR EXISTS(SELECT 1 FROM radroots_event_store_nip09_address_target WHERE source_generation = ? AND request_event_id = ? AND target_kind = ? AND target_pubkey = ? AND target_d_tag = ?)", ) .bind(generation.as_bytes().as_slice()) - .bind(cause_reference.event_id().as_str()) - .bind(raw_head.event_id().as_str()) + .bind(cause_reference.event_id().to_hex()) + .bind(raw_head.event_id().to_hex()) .bind(generation.as_bytes().as_slice()) - .bind(cause_reference.event_id().as_str()) + .bind(cause_reference.event_id().to_hex()) .bind(i64::from(coordinate.kind())) .bind(coordinate.pubkey().to_hex()) .bind(coordinate.d_tag()) @@ -863,7 +863,7 @@ async fn load_and_validate_stored_event( "SELECT seq, event_id, pubkey, created_at, kind, tags_json, content, sig, raw_json, verification_status, contract_status, contract_id, event_class, projection_eligible, inserted_at_ms, updated_at_ms FROM event_envelopes WHERE seq = ? AND event_id = ?", ) .bind(reference.event_seq()) - .bind(reference.event_id().as_str()) + .bind(reference.event_id().to_hex()) .fetch_optional(&mut *connection) .await? .ok_or_else(|| { @@ -883,13 +883,13 @@ async fn load_and_validate_stored_event( "stored raw event tags cannot be canonicalized: {error}" )) })?; - if stored.event_id != event.id_str() + if stored.event_id != event.id_hex() || stored.pubkey != event.author().to_hex() || stored.created_at != event.created_at_u64() || stored.kind != event.kind_u32() || stored.tags_json != tags_json || stored.content != event.content() - || stored.sig != event.sig_str() + || stored.sig != event.signature_hex() { return Err(corruption(format!( "stored event `{}` disagrees with its signed raw JSON", @@ -937,7 +937,7 @@ async fn validate_addressable_reference( ) .bind(generation.as_bytes().as_slice()) .bind(reference.event_seq()) - .bind(reference.event_id().as_str()) + .bind(reference.event_id().to_hex()) .bind(i64::from(coordinate.kind())) .bind(coordinate.pubkey().to_hex()) .bind(coordinate.d_tag()) diff --git a/crates/event_store/src/store/current_visibility_v1.rs b/crates/event_store/src/store/current_visibility_v1.rs @@ -185,7 +185,7 @@ fn validate_visibility_shape( && visibility .raw_head_event_id .as_ref() - .is_none_or(|raw_head_event_id| raw_head_event_id.as_str() != event_id) + .is_none_or(|raw_head_event_id| raw_head_event_id.to_hex() != event_id) { return current_visibility_drift(format!( "event `{event_id}` is marked as the raw head without matching head identity" @@ -307,18 +307,14 @@ async fn validate_addressable_head_projection( != evidence.map(|value| value.outcome.code()) || row.try_get::<Option<String>, _>("nip09_reason")?.as_deref() != evidence.map(|value| value.reason.code()) - || row - .try_get::<Option<String>, _>("event_reference_request_id")? - .as_deref() + || row.try_get::<Option<String>, _>("event_reference_request_id")? != evidence .and_then(|value| value.event_reference_request_id.as_ref()) - .map(RadrootsEventId::as_str) - || row - .try_get::<Option<String>, _>("address_reference_request_id")? - .as_deref() + .map(RadrootsEventId::to_hex) + || row.try_get::<Option<String>, _>("address_reference_request_id")? != evidence .and_then(|value| value.address_reference_request_id.as_ref()) - .map(RadrootsEventId::as_str) + .map(RadrootsEventId::to_hex) || stored_cutoff != evidence.and_then(|value| value.address_reference_cutoff) { return current_visibility_drift(format!( diff --git a/crates/event_store/src/store/food_availability_projection_v1.rs b/crates/event_store/src/store/food_availability_projection_v1.rs @@ -342,17 +342,17 @@ async fn apply_transition( .await?; let visible_event_id = transition .visible_event() - .map(|event| event.event_id().as_str()); + .map(|event| event.event_id().to_hex()); let mut projected_row_delta = 0_i64; match (existing_event_id.as_deref(), transition.retracted_event()) { - (Some(existing), Some(retracted)) if existing == retracted.event_id().as_str() => { + (Some(existing), Some(retracted)) if existing == retracted.event_id().to_hex() => { let deleted = sqlx::query( "DELETE FROM radroots_event_store_food_availability_projection WHERE source_generation = ? AND pubkey = ? AND d_tag = ? AND event_id = ?", ) .bind(transition.source_generation().as_bytes().as_slice()) .bind(coordinate.pubkey().to_hex()) .bind(coordinate.d_tag()) - .bind(retracted.event_id().as_str()) + .bind(retracted.event_id().to_hex()) .execute(&mut *connection) .await?; if deleted.rows_affected() != 1 { @@ -362,7 +362,7 @@ async fn apply_transition( } projected_row_delta = -1; } - (Some(existing), None) if visible_event_id == Some(existing) => { + (Some(existing), None) if visible_event_id.as_deref() == Some(existing) => { if transition.contract_id() != Some(FOOD_AVAILABILITY_CONTRACT_ID) { return Err(projection_drift( "unchanged visible FoodAvailability event lost its contract admission", @@ -404,7 +404,7 @@ async fn apply_transition( } }; let event = ingest.event(); - if canonical.event_id().as_str() != event.id_str() + if canonical.event_id().to_hex() != event.id_hex() || canonical.pubkey() != event.author() || canonical.created_at() != event.created_at_u64() || canonical.kind() != event.kind_u32() @@ -443,7 +443,7 @@ async fn persist_projection( .bind(projection.source_generation().as_bytes().as_slice()) .bind(projection.pubkey().to_hex()) .bind(projection.identifier().as_str()) - .bind(projection.event_id().as_str()) + .bind(projection.event_id().to_hex()) .bind(projection.event_seq()) .bind(i64_from_u64("food.created_at", projection.created_at())?) .bind(FOOD_AVAILABILITY_CONTRACT_ID) @@ -528,7 +528,7 @@ pub(crate) async fn validate_food_availability_projection_hook_v1( actual_coordinates.push(( projection.pubkey().to_hex(), projection.identifier().as_str().to_owned(), - projection.event_id().as_str().to_owned(), + projection.event_id().to_hex().to_owned(), projection.event_seq(), i64_from_u64("food.created_at", projection.created_at())?, )); @@ -597,10 +597,10 @@ async fn validate_projection_source_transition( .bind(projection.source_generation().as_bytes().as_slice()) .bind(projection.pubkey().to_hex()) .bind(projection.identifier().as_str()) - .bind(projection.event_id().as_str()) + .bind(projection.event_id().to_hex()) .bind(projection.event_seq()) .bind(i64_from_u64("food.created_at", projection.created_at())?) - .bind(projection.event_id().as_str()) + .bind(projection.event_id().to_hex()) .bind(projection.event_seq()) .bind(FOOD_AVAILABILITY_CONTRACT_ID) .fetch_one(&mut *connection) @@ -714,7 +714,7 @@ fn load_and_validate_projection_row( let raw_json: String = row.try_get("immutable_raw_json")?; let ingest = RadrootsEventIngest::from_raw_json(raw_json, 0) .map_err(|error| projection_drift(format!("projected event reverify failed: {error}")))?; - if ingest.event().id_str() != event_id.as_str() + if ingest.event().id() != &event_id || ingest.event().author() != &pubkey || ingest.event().created_at_u64() != created_at || ingest.event().kind_u32() != 30_402 @@ -870,7 +870,7 @@ async fn validate_fts_row( .fetch_optional(&mut *connection) .await? .ok_or_else(|| projection_drift("FoodAvailability FTS row is missing"))?; - if row.try_get::<String, _>("event_id")? != projection.event_id().as_str() + if row.try_get::<String, _>("event_id")? != projection.event_id().to_hex() || row.try_get::<String, _>("pubkey")? != projection.pubkey().to_hex() || row.try_get::<String, _>("d_tag")? != projection.identifier().as_str() || row.try_get::<String, _>("title")? != projection.title().as_str() diff --git a/crates/event_store/src/store/post_core_extensions_v1.rs b/crates/event_store/src/store/post_core_extensions_v1.rs @@ -55,7 +55,7 @@ async fn store_trade_mutation_event( .quarantine_trade( None, None, - Some(event.id_str()), + Some(event.id_hex()), reason.as_str(), ingest.observed_at_ms(), ) @@ -68,9 +68,9 @@ async fn store_trade_mutation_event( None => { storage .quarantine_trade( - Some(parsed.trade_id.as_str()), + Some(parsed.trade_id.to_hex()), None, - Some(event.id_str()), + Some(event.id_hex()), "canonical trade mutation content is missing mutation_id", ingest.observed_at_ms(), ) @@ -81,9 +81,9 @@ async fn store_trade_mutation_event( if &parsed.author_pubkey != event.author() { storage .quarantine_trade( - Some(parsed.trade_id.as_str()), - Some(mutation_id.as_str()), - Some(event.id_str()), + Some(parsed.trade_id.to_hex()), + Some(mutation_id.to_hex()), + Some(event.id_hex()), "trade mutation author_pubkey does not match transport event pubkey", ingest.observed_at_ms(), ) diff --git a/crates/event_store/src/store/post_core_storage_v1.rs b/crates/event_store/src/store/post_core_storage_v1.rs @@ -66,9 +66,9 @@ impl<'borrow, 'db> PostCoreStorageV1<'borrow, 'db> { pub(super) async fn quarantine_trade( &mut self, - trade_id: Option<&str>, - mutation_id: Option<&str>, - transport_event_id: Option<&str>, + trade_id: Option<String>, + mutation_id: Option<String>, + transport_event_id: Option<String>, reason: &str, observed_at_ms: i64, ) -> Result<(), RadrootsEventStoreError> { @@ -93,19 +93,19 @@ impl<'borrow, 'db> PostCoreStorageV1<'borrow, 'db> { .mutation .root_mutation_id .as_ref() - .map(|mutation_id| mutation_id.as_str()); - let candidate_id = write.candidate_id.map(|candidate_id| candidate_id.as_str()); + .map(|mutation_id| mutation_id.to_hex()); + let candidate_id = write.candidate_id.map(|candidate_id| candidate_id.to_hex()); let proposal_mutation_id = write .proposal_mutation_id - .map(|mutation_id| mutation_id.as_str()); + .map(|mutation_id| mutation_id.to_hex()); let target_claim_mutation_id = write .target_claim_mutation_id - .map(|mutation_id| mutation_id.as_str()); + .map(|mutation_id| mutation_id.to_hex()); sqlx::query( "INSERT OR IGNORE INTO trade_mutation(mutation_id, trade_id, root_mutation_id, contract_id, mutation_kind, schema_version, candidate_id, proposal_mutation_id, target_claim_mutation_id, author_pubkey, counterparty_pubkey, buyer_pubkey, seller_pubkey, farm_id, authored_at_unix_s, canonical_payload_bytes, payload_sha256, first_event_seq, first_transport_event_id, inserted_at_ms) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", ) - .bind(write.mutation_id.as_str()) - .bind(write.mutation.trade_id.as_str()) + .bind(write.mutation_id.to_hex()) + .bind(write.mutation.trade_id.to_hex()) .bind(root_mutation_id) .bind(write.mutation.contract_id.as_str()) .bind(trade_mutation_kind_storage_value( @@ -127,7 +127,7 @@ impl<'borrow, 'db> PostCoreStorageV1<'borrow, 'db> { .bind(write.event.content().as_bytes()) .bind(write.payload_sha256) .bind(write.stored_event_seq) - .bind(write.event.id_str()) + .bind(write.event.id_hex()) .bind(write.observed_at_ms) .execute(&mut **self.tx) .await?; @@ -149,9 +149,10 @@ impl<'borrow, 'db> PostCoreStorageV1<'borrow, 'db> { } #[cfg(test)] - self.apply_raw_authority_forge(write.event.id_str()).await?; + self.apply_raw_authority_forge(&write.event.id_hex()) + .await?; #[cfg(test)] - self.apply_schema_forge(write.event.id_str()).await?; + self.apply_schema_forge(&write.event.id_hex()).await?; Ok(()) } @@ -186,8 +187,8 @@ impl<'borrow, 'db> PostCoreStorageV1<'borrow, 'db> { sqlx::query( "INSERT OR IGNORE INTO trade_mutation_parent(mutation_id, parent_mutation_id, parent_index) VALUES (?, ?, ?)", ) - .bind(mutation_id.as_str()) - .bind(parent.as_str()) + .bind(mutation_id.to_hex()) + .bind(parent.to_hex()) .bind(i64_from_usize("parent_index", index)?) .execute(&mut **self.tx) .await?; @@ -202,9 +203,9 @@ impl<'borrow, 'db> PostCoreStorageV1<'borrow, 'db> { sqlx::query( "INSERT OR IGNORE INTO trade_transport_envelope(transport_event_id, mutation_id, trade_id, transport_kind, pubkey, created_at, event_seq, payload_sha256, observed_at_ms) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", ) - .bind(write.event.id_str()) - .bind(write.mutation_id.as_str()) - .bind(write.mutation.trade_id.as_str()) + .bind(write.event.id_hex()) + .bind(write.mutation_id.to_hex()) + .bind(write.mutation.trade_id.to_hex()) .bind(RadrootsTransportKind::Nostr.canonical_label()) .bind(write.event.author().to_hex()) .bind(i64_from_u64("created_at", write.event.created_at_u64())?) @@ -223,17 +224,17 @@ impl<'borrow, 'db> PostCoreStorageV1<'borrow, 'db> { for parent in &write.mutation.parent_mutation_ids { let exists: Option<i64> = sqlx::query_scalar("SELECT 1 FROM trade_mutation WHERE mutation_id = ? LIMIT 1") - .bind(parent.as_str()) + .bind(parent.to_hex()) .fetch_optional(&mut **self.tx) .await?; if exists.is_none() { sqlx::query( "INSERT OR IGNORE INTO trade_missing_parent(trade_id, mutation_id, missing_parent_mutation_id, first_transport_event_id, first_seen_at_ms) VALUES (?, ?, ?, ?, ?)", ) - .bind(write.mutation.trade_id.as_str()) - .bind(write.mutation_id.as_str()) - .bind(parent.as_str()) - .bind(write.event.id_str()) + .bind(write.mutation.trade_id.to_hex()) + .bind(write.mutation_id.to_hex()) + .bind(parent.to_hex()) + .bind(write.event.id_hex()) .bind(write.observed_at_ms) .execute(&mut **self.tx) .await?; @@ -247,7 +248,7 @@ impl<'borrow, 'db> PostCoreStorageV1<'borrow, 'db> { mutation_id: &RadrootsTradeMutationId, ) -> Result<(), RadrootsEventStoreError> { sqlx::query("DELETE FROM trade_missing_parent WHERE missing_parent_mutation_id = ?") - .bind(mutation_id.as_str()) + .bind(mutation_id.to_hex()) .execute(&mut **self.tx) .await?; Ok(()) @@ -265,9 +266,9 @@ impl<'borrow, 'db> PostCoreStorageV1<'borrow, 'db> { "INSERT OR IGNORE INTO seller_inventory_reservation(reservation_id, trade_id, candidate_id, claim_mutation_id, inventory_authority_pubkey, inventory_epoch, assertion_commitment, reservation_expires_at_unix_s, reservation_json, inserted_at_ms) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", ) .bind(reservation.reservation_id.as_str()) - .bind(mutation.trade_id.as_str()) - .bind(reservation.candidate_id.as_str()) - .bind(claim_mutation_id.as_str()) + .bind(mutation.trade_id.to_hex()) + .bind(reservation.candidate_id.to_hex()) + .bind(claim_mutation_id.to_hex()) .bind(reservation.inventory_authority_id.to_hex()) .bind(i64_from_u64( "inventory_epoch", diff --git a/crates/event_store/src/store/protocol_reconciliation_v1.rs b/crates/event_store/src/store/protocol_reconciliation_v1.rs @@ -89,7 +89,7 @@ pub(super) async fn ingest_event_protocol_reconciliation_v1( return Ok(ProtocolReconciliationV1IngestResult { receipt: RadrootsEventIngestReceipt { persistence: RadrootsEventPersistence::NotPersisted, - event_id: event.id_str().to_owned(), + event_id: event.id_hex().to_owned(), admission_status: admission.status, admission_code: admission.code, contract_id: admission.contract.map(|contract| contract.id.to_owned()), @@ -103,7 +103,7 @@ pub(super) async fn ingest_event_protocol_reconciliation_v1( } let tags = event.tags_as_vec(); let tags_json = serde_json::to_string(&tags)?; - let event_id = event.id_str().to_owned(); + let event_id = event.id_hex().to_owned(); let existing_raw_event: i64 = sqlx::query_scalar("SELECT EXISTS (SELECT 1 FROM event_envelopes WHERE event_id = ?)") .bind(event_id.as_str()) @@ -457,13 +457,13 @@ async fn insert_raw_event( let result = sqlx::query( "INSERT OR IGNORE INTO event_envelopes(event_id, pubkey, created_at, kind, tags_json, content, sig, raw_json, verification_status, contract_status, contract_id, event_class, projection_eligible, inserted_at_ms, updated_at_ms) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", ) - .bind(event.id_str()) + .bind(event.id_hex()) .bind(event.author().to_hex()) .bind(i64_from_u64("created_at", event.created_at_u64())?) .bind(i64::from(event.kind_u32())) .bind(tags_json) .bind(event.content()) - .bind(event.sig_str()) + .bind(event.signature_hex()) .bind(raw_json) .bind("verified") .bind(admission.status.as_str()) @@ -475,7 +475,7 @@ async fn insert_raw_event( .execute(&mut **tx) .await?; let inserted = result.rows_affected() > 0; - let seq = event_seq(tx, event.id_str()).await?; + let seq = event_seq(tx, &event.id_hex()).await?; if inserted { return Ok(InsertRawEventResult { inserted: true, @@ -486,7 +486,7 @@ async fn insert_raw_event( }); } - let existing = stored_raw_event_row_in_transaction(tx, event.id_str()).await?; + let existing = stored_raw_event_row_in_transaction(tx, &event.id_hex()).await?; let stored = stored_raw_event_from_row(existing)?; Ok(InsertRawEventResult { inserted: false, @@ -545,7 +545,7 @@ async fn insert_tags( sqlx::query( "INSERT INTO event_envelope_tags(event_id, tag_index, tag_name, tag_value, tag_json, contract_semantic, contract_value_type, relay_indexed) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", ) - .bind(event.id_str()) + .bind(event.id_hex()) .bind(i64::try_from(index).map_err(|_| RadrootsEventStoreError::IntegerRange { field: "tag_index", value: i64::MAX, @@ -640,7 +640,7 @@ async fn upsert_head( ) .bind(i64::from(*kind)) .bind(pubkey.to_hex()) - .bind(candidate.event_id.as_str()) + .bind(candidate.event_id.to_hex()) .bind(i64_from_u64("created_at", candidate.created_at)?) .bind(updated_at_ms) .execute(&mut **tx) @@ -665,7 +665,7 @@ async fn upsert_head( .bind(i64::from(*kind)) .bind(pubkey.to_hex()) .bind(d_tag.as_str()) - .bind(candidate.event_id.as_str()) + .bind(candidate.event_id.to_hex()) .bind(i64_from_u64("created_at", candidate.created_at)?) .bind(updated_at_ms) .execute(&mut **tx) diff --git a/crates/event_store/tests/food_availability_projection_v1_result_vector.rs b/crates/event_store/tests/food_availability_projection_v1_result_vector.rs @@ -442,7 +442,7 @@ async fn execute_case(case: ProjectionCase) { .unwrap_or_else(|error| panic!("{}: search projection: {error}", case.id)); let event_ids = actual .iter() - .map(|projection| projection.event_id().as_str()) + .map(|projection| projection.event_id().to_hex()) .collect::<Vec<_>>(); assert_eq!(event_ids, expected.event_ids, "{}: search", case.id); } @@ -666,8 +666,8 @@ async fn execute_case(case: ProjectionCase) { ); assert_eq!(actual.is_raw_head(), expected.is_raw_head, "{}", case.id); assert_eq!( - actual.raw_head_event_id().map(|event_id| event_id.as_str()), - expected.raw_head_event_id.0.as_deref(), + actual.raw_head_event_id().map(|event_id| event_id.to_hex()), + expected.raw_head_event_id.0.clone(), "{}: current raw head", case.id ); @@ -688,7 +688,7 @@ async fn execute_case(case: ProjectionCase) { .visible_event() .unwrap_or_else(|| panic!("{}: historical visible payload is absent", case.id)); assert_eq!( - historical_payload.event_id().as_str(), + historical_payload.event_id().to_hex(), witness.event_id, "{}: historical visible payload identity", case.id @@ -749,7 +749,7 @@ fn assert_event_reference( actual: &RadrootsAddressableTransitionEventReferenceV1, ) { assert_eq!( - actual.event_id().as_str(), + actual.event_id().to_hex(), expected.event_id, "{case_id}: {label}" ); @@ -768,15 +768,15 @@ fn assert_optional_suppression( assert_eq!( actual .event_reference_request_id() - .map(|event_id| event_id.as_str()), - expected.event_reference_request_id.0.as_deref(), + .map(|event_id| event_id.to_hex()), + expected.event_reference_request_id.0.clone(), "{case_id}" ); assert_eq!( actual .address_reference_request_id() - .map(|event_id| event_id.as_str()), - expected.address_reference_request_id.0.as_deref(), + .map(|event_id| event_id.to_hex()), + expected.address_reference_request_id.0.clone(), "{case_id}" ); assert_eq!( @@ -804,7 +804,7 @@ fn assert_canonical_visible_event( .iter() .find(|observed| observed.event.id == expected.event.event_id) .unwrap_or_else(|| panic!("{}: expected event is absent from input", case.id)); - assert_eq!(actual.event_id().as_str(), observed.event.id, "{}", case.id); + assert_eq!(actual.event_id().to_hex(), observed.event.id, "{}", case.id); assert_eq!( actual.pubkey().to_hex(), observed.event.pubkey, @@ -913,7 +913,7 @@ fn assert_projection( expected: &ExpectedProjection, actual: &RadrootsStoredFoodAvailabilityV1, ) { - assert_eq!(actual.event_id().as_str(), expected.event_id, "{case_id}"); + assert_eq!(actual.event_id().to_hex(), expected.event_id, "{case_id}"); assert_eq!(actual.content().as_str(), expected.content, "{case_id}"); assert_eq!(actual.title().as_str(), expected.title, "{case_id}"); assert_eq!(actual.summary().as_str(), expected.summary, "{case_id}"); diff --git a/crates/nostr/src/draft_signing.rs b/crates/nostr/src/draft_signing.rs @@ -28,9 +28,10 @@ pub fn radroots_nostr_sign_frozen_draft( .custom_created_at(RadrootsNostrTimestamp::from_secs(draft.created_at_u64())) .sign_with_keys(keys)?; let actual_event_id = event.id.to_hex(); - if actual_event_id != draft.expected_event_id_str() { + let expected_event_id = draft.expected_event_id_hex(); + if actual_event_id != expected_event_id { return Err(RadrootsNostrError::FrozenDraftEventIdMismatch { - expected_event_id: draft.expected_event_id_str().to_owned(), + expected_event_id, actual_event_id, }); } @@ -73,7 +74,7 @@ mod tests { let draft = generic_draft(FIXTURE_ALICE.public_key_hex); let signed = radroots_nostr_sign_frozen_draft(&keys, &draft).expect("signed event"); - assert_eq!(signed.id_str(), draft.expected_event_id_str()); + assert_eq!(signed.id_str(), draft.expected_event_id_hex()); assert_eq!(signed.pubkey().to_hex(), draft.expected_pubkey().to_hex()); assert_eq!(signed.created_at(), draft.created_at_u64()); assert_eq!(signed.kind(), draft.kind_u32()); diff --git a/crates/nostr/src/event_verify.rs b/crates/nostr/src/event_verify.rs @@ -88,7 +88,7 @@ mod tests { sig: String, ) -> RadrootsEventEnvelope { RadrootsEventEnvelope::new(RadrootsEventEnvelopeParts { - id: event.id_str().to_owned(), + id: event.id_hex(), author: event.author().to_hex().to_owned(), created_at: event.created_at_u64(), kind, @@ -120,7 +120,7 @@ mod tests { &original, "tampered".to_owned(), original.kind_u32(), - original.sig_str().to_owned(), + original.signature_hex(), ); assert_eq!( @@ -132,7 +132,7 @@ mod tests { #[test] fn reports_signature_invalid_for_valid_id_with_wrong_signature() { let original = signed_event(); - let mut sig = original.sig_str().to_owned(); + let mut sig = original.signature_hex(); let replacement = if sig.starts_with('0') { "1" } else { "0" }; sig.replace_range(0..1, replacement); let event = envelope_with( @@ -155,7 +155,7 @@ mod tests { &original, original.content().to_owned(), u32::from(u16::MAX) + 1, - original.sig_str().to_owned(), + original.signature_hex(), ); assert_eq!( @@ -188,7 +188,7 @@ mod tests { kind, tags: original.tags_as_vec(), content: original.content().to_owned(), - sig: original.sig_str().to_owned(), + sig: original.signature_hex(), }) .expect("envelope"); diff --git a/crates/nostr/src/job_adapter.rs b/crates/nostr/src/job_adapter.rs @@ -33,8 +33,8 @@ impl<'a> RadrootsNostrEventAdapter<'a> { impl<'a> JobEventBorrow<'a> for RadrootsNostrEventAdapter<'a> { #[inline] - fn raw_id(&'a self) -> &'a str { - &self.id_hex + fn raw_id(&'a self) -> String { + self.id_hex.clone() } #[inline] fn raw_author(&'a self) -> String { diff --git a/crates/nostr/tests/nip10_reply_profile.rs b/crates/nostr/tests/nip10_reply_profile.rs @@ -86,7 +86,7 @@ fn typed_nip10_reply_builders_sign_exact_marked_direct_and_nested_profiles() { .reply_reference() .expect("nested parent") .event_id() - .as_str(), + .to_hex(), PARENT_EVENT_ID ); } @@ -124,7 +124,7 @@ fn signed_nip10_reply_is_thread_excluded_before_semantic_reply_admission() { ); assert!(admitted.projection().is_direct()); assert_eq!( - admitted.projection().root().event_id().as_str(), + admitted.projection().root().event_id().to_hex(), ROOT_EVENT_ID ); } @@ -152,7 +152,7 @@ fn verified_legacy_positional_nip10_reply_remains_tolerated_inbound() { ); assert!(admitted.projection().is_direct()); assert_eq!( - admitted.projection().root().event_id().as_str(), + admitted.projection().root().event_id().to_hex(), ROOT_EVENT_ID ); } diff --git a/crates/outbox/src/store.rs b/crates/outbox/src/store.rs @@ -158,7 +158,7 @@ impl RadrootsOutbox { ensure_generic_outbox_draft_allowed(&input.draft)?; validate_signed_nostr_event_matches_draft(&input.signed_event, &input.draft)?; let prepared = - prepare_delivery_plan(input.draft.expected_event_id_str(), &input.delivery_plan)?; + prepare_delivery_plan(&input.draft.expected_event_id_hex(), &input.delivery_plan)?; let operation_digest = operation_idempotency_digest( input.operation_kind.as_str(), &input.draft.expected_pubkey().to_hex(), @@ -196,13 +196,13 @@ impl RadrootsOutbox { ) -> Result<RadrootsOutboxIdempotencyPreflight, RadrootsOutboxError> { validate_signed_nostr_event_matches_draft(&input.signed_event, &input.draft)?; let semantic = validate_trade_mutation_input( - input.trade_id.as_str(), - input.mutation_id.as_str(), + &input.trade_id.to_hex(), + &input.mutation_id.to_hex(), input.canonical_payload_sha256.as_str(), &input.draft, )?; let prepared = - prepare_delivery_plan(input.draft.expected_event_id_str(), &input.delivery_plan)?; + prepare_delivery_plan(&input.draft.expected_event_id_hex(), &input.delivery_plan)?; let operation_digest = trade_mutation_operation_idempotency_digest( input.operation_kind.as_str(), &input.draft.expected_pubkey().to_hex(), @@ -213,7 +213,7 @@ impl RadrootsOutbox { &self.pool, input.operation_kind.as_str(), &input.draft.expected_pubkey().to_hex(), - input.mutation_id.as_str(), + &input.mutation_id.to_hex(), ) .await? && existing.operation_idempotency_digest != operation_digest @@ -258,7 +258,7 @@ impl RadrootsOutbox { ) -> Result<RadrootsOutboxEnqueueReceipt, RadrootsOutboxError> { ensure_generic_outbox_draft_allowed(&input.draft)?; let prepared = - prepare_delivery_plan(input.draft.expected_event_id_str(), &input.delivery_plan)?; + prepare_delivery_plan(&input.draft.expected_event_id_hex(), &input.delivery_plan)?; let operation_digest = operation_idempotency_digest( input.operation_kind.as_str(), &input.draft.expected_pubkey().to_hex(), @@ -325,7 +325,7 @@ impl RadrootsOutbox { "INSERT INTO outbox_event(operation_id, event_id, expected_pubkey, draft_json, state, attempt_count, next_attempt_after_ms, event_store_ingested, event_store_inserted, created_at_ms, updated_at_ms) VALUES (?, ?, ?, ?, ?, 0, ?, 0, 0, ?, ?)", ) .bind(operation_id) - .bind(input.draft.expected_event_id_str()) + .bind(input.draft.expected_event_id_hex()) .bind(input.draft.expected_pubkey().to_hex()) .bind(draft_json.as_str()) .bind(RadrootsOutboxEventState::DraftQueued.as_str()) @@ -344,7 +344,7 @@ impl RadrootsOutbox { operation_id, outbox_event_id, delivery_plan_id: plan.delivery_plan_id, - expected_event_id: input.draft.expected_event_id_str().to_owned(), + expected_event_id: input.draft.expected_event_id_hex().to_owned(), operation_idempotency_digest: operation_digest, delivery_plan_idempotency_digest: prepared.delivery_plan_idempotency_digest, }) @@ -357,7 +357,7 @@ impl RadrootsOutbox { ensure_generic_outbox_draft_allowed(&input.draft)?; validate_signed_nostr_event_matches_draft(&input.signed_event, &input.draft)?; let prepared = - prepare_delivery_plan(input.draft.expected_event_id_str(), &input.delivery_plan)?; + prepare_delivery_plan(&input.draft.expected_event_id_hex(), &input.delivery_plan)?; let operation_digest = operation_idempotency_digest( input.operation_kind.as_str(), &input.draft.expected_pubkey().to_hex(), @@ -431,7 +431,7 @@ impl RadrootsOutbox { "INSERT INTO outbox_event(operation_id, event_id, expected_pubkey, draft_json, signed_event_json, raw_event_json, state, attempt_count, next_attempt_after_ms, event_store_ingested, event_store_inserted, event_store_ingested_at_ms, created_at_ms, updated_at_ms) VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?, 1, ?, ?, ?, ?)", ) .bind(operation_id) - .bind(input.draft.expected_event_id_str()) + .bind(input.draft.expected_event_id_hex()) .bind(input.draft.expected_pubkey().to_hex()) .bind(draft_json.as_str()) .bind(signed_event_json.as_str()) @@ -455,7 +455,7 @@ impl RadrootsOutbox { operation_id, outbox_event_id, delivery_plan_id: plan.delivery_plan_id, - expected_event_id: input.draft.expected_event_id_str().to_owned(), + expected_event_id: input.draft.expected_event_id_hex().to_owned(), operation_idempotency_digest: operation_digest, delivery_plan_idempotency_digest: prepared.delivery_plan_idempotency_digest, }) @@ -466,13 +466,13 @@ impl RadrootsOutbox { input: RadrootsOutboxTradeMutationInput, ) -> Result<RadrootsOutboxEnqueueReceipt, RadrootsOutboxError> { let semantic = validate_trade_mutation_input( - input.trade_id.as_str(), - input.mutation_id.as_str(), + &input.trade_id.to_hex(), + &input.mutation_id.to_hex(), input.canonical_payload_sha256.as_str(), &input.draft, )?; let prepared = - prepare_delivery_plan(input.draft.expected_event_id_str(), &input.delivery_plan)?; + prepare_delivery_plan(&input.draft.expected_event_id_hex(), &input.delivery_plan)?; let operation_digest = trade_mutation_operation_idempotency_digest( input.operation_kind.as_str(), &input.draft.expected_pubkey().to_hex(), @@ -484,7 +484,7 @@ impl RadrootsOutbox { &mut tx, input.operation_kind.as_str(), &input.draft.expected_pubkey().to_hex(), - input.mutation_id.as_str(), + &input.mutation_id.to_hex(), ) .await? { @@ -566,8 +566,8 @@ impl RadrootsOutbox { ) .bind(input.operation_kind.as_str()) .bind(input.draft.expected_pubkey().to_hex()) - .bind(input.trade_id.as_str()) - .bind(input.mutation_id.as_str()) + .bind(input.trade_id.to_hex()) + .bind(input.mutation_id.to_hex()) .bind(input.canonical_payload_sha256.as_str()) .bind(input.idempotency_key.as_deref()) .bind(operation_digest.as_str()) @@ -582,7 +582,7 @@ impl RadrootsOutbox { "INSERT INTO outbox_event(operation_id, event_id, expected_pubkey, draft_json, state, attempt_count, next_attempt_after_ms, event_store_ingested, event_store_inserted, created_at_ms, updated_at_ms) VALUES (?, ?, ?, ?, ?, 0, ?, 0, 0, ?, ?)", ) .bind(operation_id) - .bind(input.draft.expected_event_id_str()) + .bind(input.draft.expected_event_id_hex()) .bind(input.draft.expected_pubkey().to_hex()) .bind(draft_json.as_str()) .bind(RadrootsOutboxEventState::DraftQueued.as_str()) @@ -601,7 +601,7 @@ impl RadrootsOutbox { operation_id, outbox_event_id, delivery_plan_id: plan.delivery_plan_id, - expected_event_id: input.draft.expected_event_id_str().to_owned(), + expected_event_id: input.draft.expected_event_id_hex().to_owned(), operation_idempotency_digest: operation_digest, delivery_plan_idempotency_digest: prepared.delivery_plan_idempotency_digest, }) @@ -613,13 +613,13 @@ impl RadrootsOutbox { ) -> Result<RadrootsOutboxEnqueueReceipt, RadrootsOutboxError> { validate_signed_nostr_event_matches_draft(&input.signed_event, &input.draft)?; let semantic = validate_trade_mutation_input( - input.trade_id.as_str(), - input.mutation_id.as_str(), + &input.trade_id.to_hex(), + &input.mutation_id.to_hex(), input.canonical_payload_sha256.as_str(), &input.draft, )?; let prepared = - prepare_delivery_plan(input.draft.expected_event_id_str(), &input.delivery_plan)?; + prepare_delivery_plan(&input.draft.expected_event_id_hex(), &input.delivery_plan)?; let operation_digest = trade_mutation_operation_idempotency_digest( input.operation_kind.as_str(), &input.draft.expected_pubkey().to_hex(), @@ -631,7 +631,7 @@ impl RadrootsOutbox { &mut tx, input.operation_kind.as_str(), &input.draft.expected_pubkey().to_hex(), - input.mutation_id.as_str(), + &input.mutation_id.to_hex(), ) .await? { @@ -725,8 +725,8 @@ impl RadrootsOutbox { ) .bind(input.operation_kind.as_str()) .bind(input.draft.expected_pubkey().to_hex()) - .bind(input.trade_id.as_str()) - .bind(input.mutation_id.as_str()) + .bind(input.trade_id.to_hex()) + .bind(input.mutation_id.to_hex()) .bind(input.canonical_payload_sha256.as_str()) .bind(input.idempotency_key.as_deref()) .bind(operation_digest.as_str()) @@ -742,7 +742,7 @@ impl RadrootsOutbox { "INSERT INTO outbox_event(operation_id, event_id, expected_pubkey, draft_json, signed_event_json, raw_event_json, state, attempt_count, next_attempt_after_ms, event_store_ingested, event_store_inserted, event_store_ingested_at_ms, created_at_ms, updated_at_ms) VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?, 1, ?, ?, ?, ?)", ) .bind(operation_id) - .bind(input.draft.expected_event_id_str()) + .bind(input.draft.expected_event_id_hex()) .bind(input.draft.expected_pubkey().to_hex()) .bind(draft_json.as_str()) .bind(signed_event_json.as_str()) @@ -766,7 +766,7 @@ impl RadrootsOutbox { operation_id, outbox_event_id, delivery_plan_id: plan.delivery_plan_id, - expected_event_id: input.draft.expected_event_id_str().to_owned(), + expected_event_id: input.draft.expected_event_id_hex().to_owned(), operation_idempotency_digest: operation_digest, delivery_plan_idempotency_digest: prepared.delivery_plan_idempotency_digest, }) @@ -780,7 +780,7 @@ impl RadrootsOutbox { ensure_generic_outbox_draft_allowed(&input.draft)?; validate_signed_nostr_event_matches_draft(&input.signed_event, &input.draft)?; let prepared = - prepare_delivery_plan(input.draft.expected_event_id_str(), &input.delivery_plan)?; + prepare_delivery_plan(&input.draft.expected_event_id_hex(), &input.delivery_plan)?; let operation_digest = operation_idempotency_digest( input.operation_kind.as_str(), &input.draft.expected_pubkey().to_hex(), @@ -851,7 +851,7 @@ impl RadrootsOutbox { "INSERT INTO outbox_event(operation_id, event_id, expected_pubkey, draft_json, signed_event_json, raw_event_json, state, attempt_count, next_attempt_after_ms, event_store_ingested, event_store_inserted, event_store_ingested_at_ms, created_at_ms, updated_at_ms) VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?, 1, ?, ?, ?, ?)", ) .bind(operation_id) - .bind(input.draft.expected_event_id_str()) + .bind(input.draft.expected_event_id_hex()) .bind(input.draft.expected_pubkey().to_hex()) .bind(draft_json.as_str()) .bind(signed_event_json.as_str()) @@ -873,7 +873,7 @@ impl RadrootsOutbox { operation_id, outbox_event_id, delivery_plan_id: plan.delivery_plan_id, - expected_event_id: input.draft.expected_event_id_str().to_owned(), + expected_event_id: input.draft.expected_event_id_hex().to_owned(), operation_idempotency_digest: operation_digest, delivery_plan_idempotency_digest: prepared.delivery_plan_idempotency_digest, }) @@ -3179,7 +3179,7 @@ fn validate_trade_mutation_input( field: "author_pubkey", }); } - if parsed.trade_id.as_str() != trade_id { + if parsed.trade_id.to_hex() != trade_id { return Err(RadrootsOutboxError::TradeMutationMetadataMismatch { field: "trade_id" }); } let Some(parsed_mutation_id) = parsed.mutation_id.as_ref() else { @@ -3187,7 +3187,7 @@ fn validate_trade_mutation_input( field: "mutation_id", }); }; - if parsed_mutation_id.as_str() != mutation_id { + if parsed_mutation_id.to_hex() != mutation_id { return Err(RadrootsOutboxError::TradeMutationMetadataMismatch { field: "mutation_id", }); @@ -3886,8 +3886,8 @@ mod tests { let valid_hash = sha256_hex(canonical.content.as_bytes()); assert!(matches!( validate_trade_mutation_input( - canonical.envelope.trade_id.as_str(), - canonical.mutation_id.as_str(), + &canonical.envelope.trade_id.to_hex(), + &canonical.mutation_id.to_hex(), valid_hash.as_str(), &generic_draft(FIXTURE_ALICE_PUBLIC_KEY_HEX, "not a trade mutation"), ), @@ -3896,8 +3896,8 @@ mod tests { for invalid_hash in ["short".to_owned(), "g".repeat(64)] { assert!(matches!( validate_trade_mutation_input( - canonical.envelope.trade_id.as_str(), - canonical.mutation_id.as_str(), + &canonical.envelope.trade_id.to_hex(), + &canonical.mutation_id.to_hex(), invalid_hash.as_str(), &valid_draft, ), @@ -3912,8 +3912,8 @@ mod tests { ); assert!(matches!( validate_trade_mutation_input( - canonical.envelope.trade_id.as_str(), - canonical.mutation_id.as_str(), + &canonical.envelope.trade_id.to_hex(), + &canonical.mutation_id.to_hex(), valid_hash.as_str(), &invalid_content, ), @@ -3924,8 +3924,8 @@ mod tests { proposal_draft_with_content(canonical.content.clone(), FIXTURE_BOB_PUBLIC_KEY_HEX); assert!(matches!( validate_trade_mutation_input( - canonical.envelope.trade_id.as_str(), - canonical.mutation_id.as_str(), + &canonical.envelope.trade_id.to_hex(), + &canonical.mutation_id.to_hex(), valid_hash.as_str(), &author_mismatch, ), @@ -3936,7 +3936,7 @@ mod tests { assert!(matches!( validate_trade_mutation_input( hex_32('2').as_str(), - canonical.mutation_id.as_str(), + &canonical.mutation_id.to_hex(), valid_hash.as_str(), &valid_draft, ), @@ -3944,7 +3944,7 @@ mod tests { )); assert!(matches!( validate_trade_mutation_input( - canonical.envelope.trade_id.as_str(), + &canonical.envelope.trade_id.to_hex(), hex_64('3').as_str(), valid_hash.as_str(), &valid_draft, @@ -3955,8 +3955,8 @@ mod tests { )); assert!(matches!( validate_trade_mutation_input( - canonical.envelope.trade_id.as_str(), - canonical.mutation_id.as_str(), + &canonical.envelope.trade_id.to_hex(), + &canonical.mutation_id.to_hex(), "0".repeat(64).as_str(), &valid_draft, ), @@ -3976,8 +3976,8 @@ mod tests { ); assert!(matches!( validate_trade_mutation_input( - envelope_without_mutation_id.trade_id.as_str(), - canonical.mutation_id.as_str(), + &envelope_without_mutation_id.trade_id.to_hex(), + &canonical.mutation_id.to_hex(), sha256_hex(content_without_mutation_id.as_bytes()).as_str(), &draft_without_mutation_id, ), @@ -4668,7 +4668,7 @@ mod tests { .is_err() ); sqlx::query("UPDATE outbox_operations SET trade_id = ?, mutation_id = 'invalid' WHERE operation_id = ?") - .bind(canonical.envelope.trade_id.as_str()) + .bind(&canonical.envelope.trade_id.to_hex()) .bind(trade_operation.operation_id) .execute(outbox.pool()) .await @@ -4680,7 +4680,7 @@ mod tests { .is_err() ); sqlx::query("UPDATE outbox_operations SET mutation_id = ? WHERE operation_id = ?") - .bind(canonical.mutation_id.as_str()) + .bind(&canonical.mutation_id.to_hex()) .bind(trade_operation.operation_id) .execute(outbox.pool()) .await @@ -5785,7 +5785,7 @@ mod tests { sqlx::query( "UPDATE outbox_operations SET mutation_id = ?, operation_idempotency_digest = 'corrupt' WHERE operation_id = ?", ) - .bind(canonical.mutation_id.as_str()) + .bind(&canonical.mutation_id.to_hex()) .bind(first.operation_id) .execute(outbox.pool()) .await @@ -5969,7 +5969,7 @@ mod tests { assert_ne!(scoped.fingerprint(), rescaled.fingerprint()); let first_prepared = prepare_delivery_plan( - draft.expected_event_id_str(), + &draft.expected_event_id_hex(), &RadrootsOutboxDeliveryPlanInput::new( "transport.nostr.local", 1, @@ -5979,7 +5979,7 @@ mod tests { ) .expect("first plan"); let relabeled_prepared = prepare_delivery_plan( - draft.expected_event_id_str(), + &draft.expected_event_id_hex(), &RadrootsOutboxDeliveryPlanInput::new( "transport.nostr.local", 1, @@ -5989,7 +5989,7 @@ mod tests { ) .expect("relabeled plan"); let rescaled_prepared = prepare_delivery_plan( - draft.expected_event_id_str(), + &draft.expected_event_id_hex(), &RadrootsOutboxDeliveryPlanInput::new( "transport.nostr.local", 1, diff --git a/crates/replica_sync/src/ingest.rs b/crates/replica_sync/src/ingest.rs @@ -252,7 +252,7 @@ fn ingest_profile_event( event: &RadrootsEventEnvelope, ) -> Result<RadrootsReplicaIngestOutcome, RadrootsReplicaEventsError> { let data_result = profile_decode::data_from_event( - event.id_str().to_owned(), + event.id_hex(), event.author().to_hex().to_owned(), event.created_at_u64(), event.kind_u32(), @@ -1022,7 +1022,7 @@ fn event_head_decision( kind: event.kind_u32(), pubkey: event.author().to_hex().to_owned(), d_tag: String::new(), - last_event_id: event.id_str().to_owned(), + last_event_id: event.id_hex(), last_created_at: event.created_at_u64(), content_hash: String::new(), }); @@ -1069,7 +1069,7 @@ fn event_head_decision( kind, pubkey, d_tag, - last_event_id: event.id_str().to_owned(), + last_event_id: event.id_hex(), last_created_at: event.created_at_u64(), content_hash, }) @@ -1683,13 +1683,13 @@ mod tests { content: String, ) -> RadrootsEventEnvelope { RadrootsEventEnvelope::new(RadrootsEventEnvelopeParts { - id: event.id_str().to_owned(), + id: event.id_hex(), author: event.author().to_hex().to_owned(), created_at: event.created_at_u64(), kind, tags, content, - sig: event.sig_str().to_owned(), + sig: event.signature_hex(), }) .expect("test event envelope parts") } @@ -2918,7 +2918,7 @@ mod tests { .expect("event state") .result .expect("state row"); - assert_eq!(state.last_event_id, archived.id_str()); + assert_eq!(state.last_event_id, archived.id_hex()); let stale_active = listing_event(&seller_pubkey, 11, listing_d_tag, "active", "Stale Eggs"); assert_eq!( @@ -3151,7 +3151,7 @@ mod tests { .expect("event state") .result .expect("state row"); - assert_eq!(state_before_replacement.last_event_id, active.id_str()); + assert_eq!(state_before_replacement.last_event_id, active.id_hex()); assert_eq!( radroots_replica_ingest_event(&exec, &signed_replacement) @@ -3178,7 +3178,7 @@ mod tests { &format!("Equal-time focused replacement {nonce}"), ) }) - .find(|candidate| candidate.id_str() < tied_operational.id_str()) + .find(|candidate| candidate.id_hex() < tied_operational.id_hex()) .expect("deterministic lower-id focused candidate"); assert_eq!( radroots_replica_ingest_event(&exec, &tied_focused) @@ -3201,7 +3201,7 @@ mod tests { .expect("final event state") .result .expect("final state row"); - assert_eq!(final_state.last_event_id, tied_focused.id_str()); + assert_eq!(final_state.last_event_id, tied_focused.id_hex()); } #[test] diff --git a/crates/trade/src/operational_listing/mutation.rs b/crates/trade/src/operational_listing/mutation.rs @@ -459,10 +459,10 @@ mod tests { build_operational_listing_mutation_draft(&publish, 1_700_000_000).expect("draft"); assert_eq!( - first.expected_event_id_str(), - second.expected_event_id_str() + first.expected_event_id_hex(), + second.expected_event_id_hex() ); - assert_eq!(first.expected_event_id_str().len(), 64); + assert_eq!(first.expected_event_id_hex().len(), 64); assert_eq!(first.tags_as_vec(), second.tags_as_vec()); assert_eq!(first.content(), second.content()); } @@ -484,6 +484,11 @@ mod tests { let validated = validate_operational_listing_event(&verified).expect("validated listing"); assert_eq!(validated.seller_pubkey, SELLER); - assert!(validated.listing_addr.contains(&format!(":{SELLER}:"))); + assert!( + validated + .listing_addr + .as_str() + .contains(&format!(":{SELLER}:")) + ); } } diff --git a/crates/trade/src/operational_listing/validation.rs b/crates/trade/src/operational_listing/validation.rs @@ -89,7 +89,7 @@ pub fn validate_operational_listing_model( listing: RadrootsOperationalListing, seller_pubkey: &PublicKey, ) -> Result<RadrootsOperationalListingTradeProjection, OperationalListingValidationError> { - let listing_id = listing.d_tag.trim().to_string(); + let listing_id = listing.d_tag.as_str().trim().to_string(); if listing.farm.pubkey != seller_pubkey.to_hex() { return Err(OperationalListingValidationError::InvalidSeller); @@ -125,11 +125,11 @@ pub fn validate_operational_listing_model( if listing.bins.is_empty() { return Err(OperationalListingValidationError::MissingBins); } - let primary_bin_id = listing.primary_bin_id.trim().to_string(); + let primary_bin_id = listing.primary_bin_id.as_str().trim().to_string(); let primary_bin_index = listing .bins .iter() - .position(|bin| bin.bin_id == primary_bin_id) + .position(|bin| bin.bin_id.as_str() == primary_bin_id) .ok_or(OperationalListingValidationError::MissingPrimaryBin)?; for (index, bin) in listing.bins.iter().enumerate() { if listing.bins[..index] @@ -736,13 +736,13 @@ mod tests { let verified = base_event(&base_listing()); let event = verified.into_event(); let tampered = RadrootsEventEnvelope::new(RadrootsEventEnvelopeParts { - id: event.id_str().to_owned(), + id: event.id_hex(), author: event.author().to_hex().to_owned(), created_at: event.created_at_u64(), kind: event.kind_u32(), tags: event.tags_as_vec(), content: "tampered".to_owned(), - sig: event.sig_str().to_owned(), + sig: event.signature_hex(), }) .expect("well-shaped tampered envelope"); diff --git a/crates/trade/src/validation_receipt.rs b/crates/trade/src/validation_receipt.rs @@ -511,7 +511,7 @@ pub fn verify_validator_set_event( let address = validator_set_address(event.author(), &validator_set.set_id)?; Ok(RadrootsVerifiedValidatorSetV1 { set: validator_set, - event_id: event.id_str().to_owned(), + event_id: event.id_hex(), address, authority_pubkey: *event.author(), }) diff --git a/tools/xtask/src/contract/food_availability_projection.rs b/tools/xtask/src/contract/food_availability_projection.rs @@ -1813,7 +1813,7 @@ fn validate_food_projection_audit_authority(source: &str) -> Result<(), String> actual_coordinates.push(( projection.pubkey().to_hex(), projection.identifier().as_str().to_owned(), - projection.event_id().as_str().to_owned(), + projection.event_id().to_hex(), projection.event_seq(), i64_from_u64("food.created_at", projection.created_at())?, )); @@ -1907,7 +1907,7 @@ fn validate_food_projection_audit_authority(source: &str) -> Result<(), String> actual_coordinates.push(( projection.pubkey().to_hex(), projection.identifier().as_str().to_owned(), - projection.event_id().as_str().to_owned(), + projection.event_id().to_hex(), projection.event_seq(), i64_from_u64("food.created_at", projection.created_at())?, )); @@ -2014,10 +2014,10 @@ fn validate_food_projection_audit_authority(source: &str) -> Result<(), String> .bind(projection.source_generation().as_bytes().as_slice()) .bind(projection.pubkey().to_hex()) .bind(projection.identifier().as_str()) - .bind(projection.event_id().as_str()) + .bind(projection.event_id().to_hex()) .bind(projection.event_seq()) .bind(i64_from_u64("food.created_at", projection.created_at())?) - .bind(projection.event_id().as_str()) + .bind(projection.event_id().to_hex()) .bind(projection.event_seq()) .bind(FOOD_AVAILABILITY_CONTRACT_ID) .fetch_one(&mut *connection) diff --git a/tools/xtask/src/contract/nip09_reconciliation.rs b/tools/xtask/src/contract/nip09_reconciliation.rs @@ -12758,12 +12758,12 @@ fn validate_source_maintenance_runtime_token_authority( workspace_root: &Path, ) -> Result<(), String> { const SOURCE_RUNTIME_AST_SHA256: &str = - "c52b1acee9261d45590d8b443f10ad4fdd539fa8d6227e4ca8bc09c593c4c2b6"; + "78b9d310aeed0a2d8bcbced1af900fc1e8e6841d9d10398daa4f82a0ca957f23"; const FUNCTION_SPECS: [(&str, &str, &str); 4] = [ ( EVENT_STORE_PROTOCOL_RECONCILIATION_SOURCE_RELATIVE, "ingest_event_protocol_reconciliation_v1", - "f8d26e1d4e1a362c7335f1ba58ad6f1bac2f119162b15ca1067391756149d1e3", + "91bec3d7d7aa061297babc1a85aae1f8be187d8378e6d54a410f0c9af9a39337", ), ( EVENT_STORE_PROTOCOL_RECONCILIATION_SOURCE_RELATIVE, diff --git a/tools/xtask/src/contract/source_maintenance.rs b/tools/xtask/src/contract/source_maintenance.rs @@ -510,6 +510,10 @@ const SOURCE_SPECS: &[SourceSpec] = &[ path: "crates/event_store/src/store/addressable_transition_feed_v1.rs", }, SourceSpec { + role: "current_visibility_store", + path: "crates/event_store/src/store/current_visibility_v1.rs", + }, + SourceSpec { role: "food_projection_store", path: "crates/event_store/src/store/food_availability_projection_v1.rs", }, @@ -635,6 +639,7 @@ const PREDECESSOR_SUPERSEDED_SOURCE_PATHS: &[&str] = &[ "crates/event_store/src/schema.rs", "crates/event_store/src/store.rs", "crates/event_store/src/store/addressable_transition_feed_v1.rs", + "crates/event_store/src/store/current_visibility_v1.rs", "crates/event_store/src/store/food_availability_projection_v1.rs", "crates/event_store/src/store/post_core_extensions_v1.rs", "crates/event_store/src/store/post_core_storage_v1.rs", @@ -3516,9 +3521,9 @@ struct DelegatedAuthoritySpec { } const EXECUTABLE_AUTHORITY_AST_SHA256: &str = - "88a60544e38b546dbb2c555b0347308eac0c4a3eb66f403ba44d45fb4a5818e6"; + "da4ba88c3cabe0e5ed6df4ca0115645c8a65d43cdea7d2dbf5e78d99256e8e15"; const BOUND_AUTHORITY_SOURCE_AST_SHA256: &str = - "211622a960515491cd59e1179a86efe8163c16b108e9220d2fb32ecfad8138b4"; + "14d31381f73b684c3480531acb5321c66ef04b7cb8e25aa6a06269fb4ee6601f"; #[derive(Clone, Debug, Serialize)] struct ExecutableAuthorityIdentity { @@ -3557,9 +3562,9 @@ const DELEGATED_AUTHORITIES: &[DelegatedAuthoritySpec] = &[ "MigrationHookStateDrift", "capacity_after_rollback,capacity_after_prior", "callermaycommitpriorworkafterfailedingest", - "raw_event(prior_event.id_str())", - "raw_event(trigger_event.id_str())", - "raw_event(forged_event.id_str())", + "raw_event(&prior_event.id_hex())", + "raw_event(&trigger_event.id_hex())", + "raw_event(&forged_event.id_hex())", "trade_mutation_count,0", "transition_count,0", "capacity_after_prior",