From 02e05e293545901f8c28bcbc38644f6e61bfa92e Mon Sep 17 00:00:00 2001 From: fiatjaf Date: Mon, 6 Nov 2023 12:19:02 -0300 Subject: [PATCH] prevent saving duplicates in badger and lmdb. --- badger/delete.go | 1 - badger/save.go | 17 +++++++++++++++++ lmdb/save.go | 11 +++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/badger/delete.go b/badger/delete.go index 8c8b83d..e2d99b6 100644 --- a/badger/delete.go +++ b/badger/delete.go @@ -25,7 +25,6 @@ func (b *BadgerBackend) DeleteEvent(ctx context.Context, evt *nostr.Event) error it := txn.NewIterator(opts) it.Seek(prefix) if it.ValidForPrefix(prefix) { - // the key is the last 32 bytes idx = append(idx, it.Item().Key()[1+32:]...) } it.Close() diff --git a/badger/save.go b/badger/save.go index a2737c5..d937b6f 100644 --- a/badger/save.go +++ b/badger/save.go @@ -2,14 +2,31 @@ package badger import ( "context" + "encoding/hex" "github.com/dgraph-io/badger/v4" + "github.com/fiatjaf/eventstore" "github.com/nbd-wtf/go-nostr" nostr_binary "github.com/nbd-wtf/go-nostr/binary" ) func (b *BadgerBackend) SaveEvent(ctx context.Context, evt *nostr.Event) error { return b.Update(func(txn *badger.Txn) error { + // query event by id to ensure we don't save duplicates + id, _ := hex.DecodeString(evt.ID) + prefix := make([]byte, 1+32) + copy(prefix[1:], id) + opts := badger.DefaultIteratorOptions + opts.PrefetchValues = false + it := txn.NewIterator(opts) + defer it.Close() + it.Seek(prefix) + if it.ValidForPrefix(prefix) { + // event exists + return eventstore.ErrDupEvent + } + + // encode to binary bin, err := nostr_binary.Marshal(evt) if err != nil { return err diff --git a/lmdb/save.go b/lmdb/save.go index 9eb9f4b..96e01eb 100644 --- a/lmdb/save.go +++ b/lmdb/save.go @@ -2,9 +2,11 @@ package lmdb import ( "context" + "encoding/hex" "fmt" "github.com/bmatsuo/lmdb-go/lmdb" + "github.com/fiatjaf/eventstore" "github.com/nbd-wtf/go-nostr" nostr_binary "github.com/nbd-wtf/go-nostr/binary" ) @@ -16,6 +18,15 @@ func (b *LMDBBackend) SaveEvent(ctx context.Context, evt *nostr.Event) error { } return b.lmdbEnv.Update(func(txn *lmdb.Txn) error { + // check if we already have this id + id, _ := hex.DecodeString(evt.ID) + _, err := txn.Get(b.indexId, id) + if operr, ok := err.(*lmdb.OpError); ok && operr.Errno != lmdb.NotFound { + // we will only proceed if we get a NotFound + return eventstore.ErrDupEvent + } + + // encode to binary form so we'll save it bin, err := nostr_binary.Marshal(evt) if err != nil { return err