Skip to main content

vector_core/
event_ext.rs

1//! Event-builder helpers.
2
3use nostr_sdk::prelude::*;
4
5/// Finalize into an `UnsignedEvent` with the event id already computed.
6///
7/// nostr 0.44's `EventBuilder::build` populated `id`; 0.45's `finalize_unsigned`
8/// deliberately leaves it `None` so a caller can mine NIP-13 PoW before the id is
9/// fixed. Vector never mines rumors and reads `.id` throughout the send pipeline
10/// (pending-message keys, retry payloads, edit ids), where a `None` is a
11/// runtime failure the compiler can't see. This restores the old semantics at
12/// every call site that wants an addressable rumor.
13pub trait FinalizeUnsignedWithId {
14    /// Finalize and compute the id.
15    fn finalize_unsigned_with_id(self, public_key: PublicKey) -> UnsignedEvent;
16}
17
18impl FinalizeUnsignedWithId for EventBuilder {
19    #[inline]
20    fn finalize_unsigned_with_id(self, public_key: PublicKey) -> UnsignedEvent {
21        let mut unsigned = self.finalize_unsigned(public_key);
22        unsigned.ensure_id();
23        unsigned
24    }
25}
26
27#[cfg(test)]
28mod tests {
29    use super::*;
30
31    #[test]
32    fn id_is_populated_and_matches_the_signed_event() {
33        let keys = Keys::generate();
34        let unsigned = EventBuilder::text_note("hi").finalize_unsigned_with_id(keys.public_key());
35        let id = unsigned.id.expect("id computed eagerly");
36        let signed = unsigned.finalize(&keys).expect("sign");
37        assert_eq!(id, signed.id, "eager id must equal the signed event id");
38    }
39
40    #[test]
41    fn plain_finalize_unsigned_still_leaves_it_none() {
42        // Guards the reason this trait exists: if upstream ever populates the id
43        // again, this fails and the wrapper can go.
44        let keys = Keys::generate();
45        let unsigned = EventBuilder::text_note("hi").finalize_unsigned(keys.public_key());
46        assert!(unsigned.id.is_none());
47    }
48}