1- #include < openssl/sha.h>
21#include < negentropy.h>
32
43#include " events.h"
@@ -23,7 +22,7 @@ std::string nostrJsonToPackedEvent(const tao::json::value &v) {
2322 uint64_t expiration = 0 ;
2423
2524 if (isReplaceableKind (kind)) {
26- // Prepend virtual d-tag
25+ // Prepend virtual d-tag. Any later d-tags will be ignored during indexing
2726 tagBuilder.add (' d' , " " );
2827 }
2928
@@ -58,7 +57,7 @@ std::string nostrJsonToPackedEvent(const tao::json::value &v) {
5857 }
5958
6059 if (isParamReplaceableKind (kind)) {
61- // Append virtual d-tag
60+ // Append virtual d-tag. Will be overidden by any previous d-tags.
6261 tagBuilder.add (' d' , " " );
6362 }
6463
@@ -84,10 +83,7 @@ Bytes32 nostrHash(const tao::json::value &origJson) {
8483
8584 std::string encoded = tao::json::to_string (arr);
8685
87- unsigned char hash[SHA256_DIGEST_LENGTH];
88- SHA256 (reinterpret_cast <unsigned char *>(encoded.data ()), encoded.size (), hash);
89-
90- return Bytes32 (std::string_view (reinterpret_cast <char *>(hash), SHA256_DIGEST_LENGTH));
86+ return sha256 (encoded);
9187}
9288
9389bool verifySig (secp256k1_context* ctx, std::string_view sig, std::string_view hash, std::string_view pubkey) {
@@ -280,50 +276,52 @@ void writeEvents(lmdb::txn &txn, NegentropyFilterCache &neFilterCache, std::vect
280276 continue ;
281277 }
282278
283- {
279+ if ( isReplaceableKind (packed. kind ()) || isParamReplaceableKind (packed. kind ())) {
284280 std::optional<std::string> replace;
285281
286- if (isReplaceableKind (packed.kind ()) || isParamReplaceableKind (packed.kind ())) {
287- packed.foreachTag ([&](char tagName, std::string_view tagVal){
288- if (tagName != ' d' ) return true ;
289- replace = std::string (tagVal);
290- return false ;
291- });
292- }
282+ packed.foreachTag ([&](char tagName, std::string_view tagVal){
283+ if (tagName != ' d' ) return true ;
284+ replace = std::string (tagVal);
285+ return false ;
286+ });
293287
294288 if (replace) {
295289 auto searchStr = std::string (packed.pubkey ()) + *replace;
296290 auto searchKey = makeKey_StringUint64 (searchStr, packed.kind ());
297291
292+ // Check if there is a newer event in the DB, or an older event to replace
293+
298294 env.generic_foreachFull (txn, env.dbi_Event__replace , searchKey, lmdb::to_sv<uint64_t >(MAX_U64), [&](auto k, auto v) {
299295 if (k != searchKey) return false ;
300296
301297 auto otherEv = lookupEventByLevId (txn, lmdb::from_sv<uint64_t >(v));
302298 auto otherPacked = PackedEventView (otherEv.buf );
303299
304300 if (isEventABeforeEventB (packed, otherPacked)) {
305- ev.status = otherPacked.kind () == 5 ? EventWriteStatus::Deleted : EventWriteStatus::Replaced;
306- return false ; // found more recent replacement event, no need to scan more
301+ ev.status = EventWriteStatus::Replaced;
302+ } else {
303+ if (logLevel >= 1 ) LI << " Deleting event (d-tag). id=" << to_hex (otherPacked.id ());
304+ levIdsToDelete.push_back (otherEv.primaryKeyId );
307305 }
308306
309- return true ;
307+ return false ;
310308 }, true );
311309
312- // If event is accepted (pending write), then do a second pass to remove/unindex outdated events
310+ // If param-replaceable event is still accepted (pending write), check if there is a more recent deletion
313311
314- if (ev.status == EventWriteStatus::Pending) {
315- env. generic_foreachFull (txn, env. dbi_Event__replace , searchKey, lmdb::to_sv< uint64_t >(MAX_U64), [&]( auto k, auto v) {
316- if (k != searchKey) return false ;
312+ if (isParamReplaceableKind (packed. kind ()) && ev.status == EventWriteStatus::Pending) {
313+ auto searchStr = sha256 ( std::to_string (packed. kind ()) + " : " + to_hex (packed. pubkey ()) + " : " + *replace). str ();
314+ auto searchKey = makeKey_StringUint64 (searchStr, MAX_U64) ;
317315
318- auto otherEv = lookupEventByLevId (txn, lmdb::from_sv<uint64_t >(v));
319- auto otherPacked = PackedEventView (otherEv.buf );
316+ env.generic_foreachFull (txn, env.dbi_Event__replaceDeletion , searchKey, lmdb::to_sv<uint64_t >(MAX_U64), [&](auto k, auto v) {
317+ ParsedKey_StringUint64 parsedKey (k);
318+ if (parsedKey.s != searchStr) return false ;
320319
321- if (otherPacked.kind () != 5 ) {
322- if (logLevel >= 1 ) LI << " Deleting event (d-tag). id=" << to_hex (otherPacked.id ());
323- levIdsToDelete.push_back (otherEv.primaryKeyId );
320+ if (parsedKey.n >= packed.created_at ()) {
321+ ev.status = EventWriteStatus::Deleted;
324322 }
325323
326- return true ;
324+ return false ;
327325 }, true );
328326 }
329327 }
@@ -351,14 +349,12 @@ void writeEvents(lmdb::txn &txn, NegentropyFilterCache &neFilterCache, std::vect
351349 auto otherEv = lookupEventByLevId (txn, lmdb::from_sv<uint64_t >(v));
352350 auto otherPacked = PackedEventView (otherEv.buf );
353351
354- if (isEventABeforeEventB (otherPacked, packed)) {
355- if (otherPacked.kind () != 5 ) {
356- if (logLevel >= 1 ) LI << " Deleting replaceable event (kind 5). id=" << to_hex (otherPacked.id ());
357- levIdsToDelete.push_back (otherEv.primaryKeyId );
358- }
352+ if (otherPacked.created_at () <= packed.created_at ()) {
353+ if (logLevel >= 1 ) LI << " Deleting replaceable event (kind 5). id=" << to_hex (otherPacked.id ());
354+ levIdsToDelete.push_back (otherEv.primaryKeyId );
359355 }
360356
361- return true ;
357+ return false ;
362358 }, true );
363359 }
364360 } catch (...) {
0 commit comments