@@ -175,7 +175,11 @@ fn gift_wrap_from_seal_with_pow(
175175 pow : u8 ,
176176) -> Result < Event > {
177177 if seal. kind != nostr_sdk:: Kind :: Seal {
178- return Err ( anyhow:: anyhow!( "Invalid kind" ) ) ;
178+ return Err ( anyhow:: anyhow!(
179+ "Expected Seal (kind {}), got kind {}" ,
180+ nostr_sdk:: Kind :: Seal . as_u16( ) ,
181+ seal. kind. as_u16( ) ,
182+ ) ) ;
179183 }
180184
181185 let ephem = Keys :: generate ( ) ;
@@ -326,3 +330,69 @@ pub async fn print_dm_events(
326330 }
327331 Ok ( ( ) )
328332}
333+
334+ #[ cfg( test) ]
335+ mod tests {
336+ use super :: * ;
337+
338+ fn leading_zero_bits_in_hex ( hex : & str ) -> u32 {
339+ let mut bits = 0_u32 ;
340+ for ch in hex. chars ( ) {
341+ let nibble = ch. to_digit ( 16 ) . expect ( "event id must be hex" ) ;
342+ if nibble == 0 {
343+ bits += 4 ;
344+ } else {
345+ bits += nibble. leading_zeros ( ) - 28 ;
346+ break ;
347+ }
348+ }
349+ bits
350+ }
351+
352+ fn event_meets_pow ( event : & Event , difficulty : u8 ) -> bool {
353+ let id_hex = event. id . to_string ( ) ;
354+ leading_zero_bits_in_hex ( & id_hex) >= difficulty. into ( )
355+ }
356+
357+ #[ test]
358+ fn gift_wrap_from_seal_with_pow_builds_gift_wrap_kind ( ) -> Result < ( ) > {
359+ let receiver = Keys :: generate ( ) . public_key ( ) ;
360+ let seal = EventBuilder :: new ( nostr_sdk:: Kind :: Seal , "sealed payload" )
361+ . sign_with_keys ( & Keys :: generate ( ) ) ?;
362+
363+ let event = gift_wrap_from_seal_with_pow ( & receiver, & seal, Tags :: new ( ) , 0 ) ?;
364+
365+ assert_eq ! ( event. kind, nostr_sdk:: Kind :: GiftWrap ) ;
366+ Ok ( ( ) )
367+ }
368+
369+ #[ test]
370+ fn gift_wrap_from_seal_with_pow_meets_requested_difficulty ( ) -> Result < ( ) > {
371+ let receiver = Keys :: generate ( ) . public_key ( ) ;
372+ let seal = EventBuilder :: new ( nostr_sdk:: Kind :: Seal , "sealed payload" )
373+ . sign_with_keys ( & Keys :: generate ( ) ) ?;
374+ let pow = 8 ;
375+
376+ let event = gift_wrap_from_seal_with_pow ( & receiver, & seal, Tags :: new ( ) , pow) ?;
377+
378+ assert ! (
379+ event_meets_pow( & event, pow) ,
380+ "gift wrap id does not satisfy PoW"
381+ ) ;
382+ Ok ( ( ) )
383+ }
384+
385+ #[ test]
386+ fn gift_wrap_from_seal_with_pow_rejects_non_seal ( ) {
387+ let receiver = Keys :: generate ( ) . public_key ( ) ;
388+ let non_seal = EventBuilder :: new ( nostr_sdk:: Kind :: TextNote , "not a seal" )
389+ . sign_with_keys ( & Keys :: generate ( ) )
390+ . unwrap ( ) ;
391+
392+ let err = gift_wrap_from_seal_with_pow ( & receiver, & non_seal, Tags :: new ( ) , 0 ) . unwrap_err ( ) ;
393+ assert ! (
394+ err. to_string( ) . to_lowercase( ) . contains( "kind" ) ,
395+ "unexpected error: {err}"
396+ ) ;
397+ }
398+ }
0 commit comments