diff --git a/app/handle-event.go b/app/handle-event.go index 4b09079..d2fdc4a 100644 --- a/app/handle-event.go +++ b/app/handle-event.go @@ -3,6 +3,7 @@ package app import ( "context" "fmt" + "strings" "encoders.orly/envelopes/eventenvelope" "lol.mleku.dev/chk" @@ -53,8 +54,22 @@ func (l *Listener) HandleEvent(c context.Context, msg []byte) ( } return } + // check if the event was deleted + // + // todo: the list of admin pubkeys should go in the second parameter when it + // is implemented to enable admins to delete events of other users. + if err = l.CheckForDeleted(env.E, nil); err != nil { + if strings.HasPrefix(err.Error(), "blocked:") { + errStr := err.Error()[len("blocked: "):len(err.Error())] + if err = Ok.Error( + l, env, errStr, + ); chk.E(err) { + return + } + } + } // store the event - if _, _, err = l.SaveEvent(c, env.E, false, nil); chk.E(err) { + if _, _, err = l.SaveEvent(c, env.E); chk.E(err) { return } l.publishers.Deliver(env.E) diff --git a/go.mod b/go.mod index 3a03628..6a93528 100644 --- a/go.mod +++ b/go.mod @@ -7,8 +7,10 @@ require ( encoders.orly v0.0.0-00010101000000-000000000000 github.com/adrg/xdg v0.5.3 github.com/coder/websocket v1.8.13 + github.com/dgraph-io/badger/v4 v4.8.0 github.com/pkg/profile v1.7.0 go-simpler.org/env v0.12.0 + interfaces.orly v0.0.0-00010101000000-000000000000 lol.mleku.dev v1.0.2 protocol.orly v0.0.0-00010101000000-000000000000 utils.orly v0.0.0-00010101000000-000000000000 @@ -18,7 +20,6 @@ require ( crypto.orly v0.0.0-00010101000000-000000000000 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dgraph-io/badger/v4 v4.8.0 // indirect github.com/dgraph-io/ristretto/v2 v2.2.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/fatih/color v1.18.0 // indirect @@ -43,7 +44,7 @@ require ( golang.org/x/net v0.41.0 // indirect golang.org/x/sys v0.35.0 // indirect google.golang.org/protobuf v1.36.6 // indirect - interfaces.orly v0.0.0-00010101000000-000000000000 // indirect + lukechampine.com/frand v1.5.1 // indirect ) replace ( diff --git a/main.go b/main.go index 421a498..fc6bef8 100644 --- a/main.go +++ b/main.go @@ -36,8 +36,11 @@ func main() { case <-sigs: fmt.Printf("\r") cancel() + chk.E(db.Close()) + return case <-quit: cancel() + chk.E(db.Close()) return } } diff --git a/pkg/database/database.go b/pkg/database/database.go index 22ee3a5..75da2ee 100644 --- a/pkg/database/database.go +++ b/pkg/database/database.go @@ -79,8 +79,8 @@ func New( case <-d.ctx.Done(): } d.cancel() - d.seq.Release() - d.DB.Close() + // d.seq.Release() + // d.DB.Close() }() return } @@ -131,5 +131,6 @@ func (d *D) Close() (err error) { return } } + log.I.F("%s: database closed", d.dataDir) return } diff --git a/pkg/database/export_test.go b/pkg/database/export_test.go index 5e279a3..364924c 100644 --- a/pkg/database/export_test.go +++ b/pkg/database/export_test.go @@ -55,7 +55,7 @@ func TestExport(t *testing.T) { } // Save the event to the database - if _, _, err = db.SaveEvent(ctx, ev, false, nil); err != nil { + if _, _, err = db.SaveEvent(ctx, ev); err != nil { t.Fatalf("Failed to save event: %v", err) } diff --git a/pkg/database/fetch-event-by-serial_test.go b/pkg/database/fetch-event-by-serial_test.go index fa4a265..aa17326 100644 --- a/pkg/database/fetch-event-by-serial_test.go +++ b/pkg/database/fetch-event-by-serial_test.go @@ -58,7 +58,7 @@ func TestFetchEventBySerial(t *testing.T) { events = append(events, ev) // Save the event to the database - if _, _, err = db.SaveEvent(ctx, ev, false, nil); err != nil { + if _, _, err = db.SaveEvent(ctx, ev); err != nil { t.Fatalf("Failed to save event #%d: %v", eventCount+1, err) } diff --git a/pkg/database/get-serial-by-id_test.go b/pkg/database/get-serial-by-id_test.go index cc764b4..7822f19 100644 --- a/pkg/database/get-serial-by-id_test.go +++ b/pkg/database/get-serial-by-id_test.go @@ -54,7 +54,7 @@ func TestGetSerialById(t *testing.T) { events = append(events, ev) // Save the event to the database - if _, _, err = db.SaveEvent(ctx, ev, false, nil); err != nil { + if _, _, err = db.SaveEvent(ctx, ev); err != nil { t.Fatalf("Failed to save event #%d: %v", eventCount+1, err) } diff --git a/pkg/database/get-serials-by-range_test.go b/pkg/database/get-serials-by-range_test.go index 92049f0..9664377 100644 --- a/pkg/database/get-serials-by-range_test.go +++ b/pkg/database/get-serials-by-range_test.go @@ -61,7 +61,7 @@ func TestGetSerialsByRange(t *testing.T) { events = append(events, ev) // Save the event to the database - if _, _, err = db.SaveEvent(ctx, ev, false, nil); err != nil { + if _, _, err = db.SaveEvent(ctx, ev); err != nil { t.Fatalf("Failed to save event #%d: %v", eventCount+1, err) } diff --git a/pkg/database/import.go b/pkg/database/import.go index 0220706..3008733 100644 --- a/pkg/database/import.go +++ b/pkg/database/import.go @@ -57,7 +57,7 @@ func (d *D) Import(rr io.Reader) { continue } - if _, _, err = d.SaveEvent(d.ctx, ev, false, nil); err != nil { + if _, _, err = d.SaveEvent(d.ctx, ev); err != nil { continue } diff --git a/pkg/database/migrations.go b/pkg/database/migrations.go index 837b220..e94888c 100644 --- a/pkg/database/migrations.go +++ b/pkg/database/migrations.go @@ -14,11 +14,10 @@ import ( ) const ( - currentVersion uint32 = 0 + currentVersion uint32 = 1 ) func (d *D) RunMigrations() { - log.I.F("running migrations...") var err error var dbVersion uint32 // first find the current version tag if any @@ -48,6 +47,7 @@ func (d *D) RunMigrations() { ); chk.E(err) { return } + log.I.F("found version tag: %d", ver.Get()) dbVersion = ver.Get() } return @@ -62,9 +62,13 @@ func (d *D) RunMigrations() { buf := new(bytes.Buffer) vv := new(types.Uint32) vv.Set(currentVersion) + log.I.S(vv) if err = indexes.VersionEnc(vv).MarshalWrite(buf); chk.E(err) { return } + if err = txn.Set(buf.Bytes(), nil); chk.E(err) { + return + } return }, ); chk.E(err) { @@ -72,10 +76,10 @@ func (d *D) RunMigrations() { } } if dbVersion < 1 { + log.I.F("migrating to version 1...") // the first migration is expiration tags d.UpdateExpirationTags() } - log.I.F("migrations complete") } func (d *D) UpdateExpirationTags() { diff --git a/pkg/database/query-events-multiple-param-replaceable_test.go b/pkg/database/query-events-multiple-param-replaceable_test.go index e41efac..4dd98c1 100644 --- a/pkg/database/query-events-multiple-param-replaceable_test.go +++ b/pkg/database/query-events-multiple-param-replaceable_test.go @@ -43,7 +43,7 @@ func TestMultipleParameterizedReplaceableEvents(t *testing.T) { baseEvent.Sign(sign) // Save the base parameterized replaceable event - if _, _, err := db.SaveEvent(ctx, baseEvent, false, nil); err != nil { + if _, _, err := db.SaveEvent(ctx, baseEvent); err != nil { t.Fatalf("Failed to save base parameterized replaceable event: %v", err) } @@ -61,7 +61,7 @@ func TestMultipleParameterizedReplaceableEvents(t *testing.T) { newerEvent.Sign(sign) // Save the newer parameterized replaceable event - if _, _, err := db.SaveEvent(ctx, newerEvent, false, nil); err != nil { + if _, _, err := db.SaveEvent(ctx, newerEvent); err != nil { t.Fatalf( "Failed to save newer parameterized replaceable event: %v", err, ) @@ -81,7 +81,7 @@ func TestMultipleParameterizedReplaceableEvents(t *testing.T) { newestEvent.Sign(sign) // Save the newest parameterized replaceable event - if _, _, err := db.SaveEvent(ctx, newestEvent, false, nil); err != nil { + if _, _, err := db.SaveEvent(ctx, newestEvent); err != nil { t.Fatalf( "Failed to save newest parameterized replaceable event: %v", err, ) diff --git a/pkg/database/query-events_test.go b/pkg/database/query-events_test.go index 116b53d..8b5707b 100644 --- a/pkg/database/query-events_test.go +++ b/pkg/database/query-events_test.go @@ -62,7 +62,7 @@ func setupTestDB(t *testing.T) ( events = append(events, ev) // Save the event to the database - if _, _, err = db.SaveEvent(ctx, ev, false, nil); err != nil { + if _, _, err = db.SaveEvent(ctx, ev); err != nil { t.Fatalf("Failed to save event #%d: %v", eventCount+1, err) } @@ -202,9 +202,7 @@ func TestReplaceableEventsAndDeletion(t *testing.T) { replaceableEvent.Tags = tag.NewS() replaceableEvent.Sign(sign) // Save the replaceable event - if _, _, err := db.SaveEvent( - ctx, replaceableEvent, false, nil, - ); err != nil { + if _, _, err := db.SaveEvent(ctx, replaceableEvent); err != nil { t.Fatalf("Failed to save replaceable event: %v", err) } @@ -217,7 +215,7 @@ func TestReplaceableEventsAndDeletion(t *testing.T) { newerEvent.Tags = tag.NewS() newerEvent.Sign(sign) // Save the newer event - if _, _, err := db.SaveEvent(ctx, newerEvent, false, nil); err != nil { + if _, _, err := db.SaveEvent(ctx, newerEvent); err != nil { t.Fatalf("Failed to save newer event: %v", err) } @@ -294,7 +292,7 @@ func TestReplaceableEventsAndDeletion(t *testing.T) { ) // Save the deletion event - if _, _, err = db.SaveEvent(ctx, deletionEvent, false, nil); err != nil { + if _, _, err = db.SaveEvent(ctx, deletionEvent); err != nil { t.Fatalf("Failed to save deletion event: %v", err) } @@ -379,7 +377,7 @@ func TestParameterizedReplaceableEventsAndDeletion(t *testing.T) { paramEvent.Sign(sign) // Save the parameterized replaceable event - if _, _, err := db.SaveEvent(ctx, paramEvent, false, nil); err != nil { + if _, _, err := db.SaveEvent(ctx, paramEvent); err != nil { t.Fatalf("Failed to save parameterized replaceable event: %v", err) } @@ -405,9 +403,7 @@ func TestParameterizedReplaceableEventsAndDeletion(t *testing.T) { paramDeletionEvent.Sign(sign) // Save the parameterized deletion event - if _, _, err := db.SaveEvent( - ctx, paramDeletionEvent, false, nil, - ); err != nil { + if _, _, err := db.SaveEvent(ctx, paramDeletionEvent); err != nil { t.Fatalf("Failed to save parameterized deletion event: %v", err) } @@ -440,9 +436,7 @@ func TestParameterizedReplaceableEventsAndDeletion(t *testing.T) { paramDeletionEvent2.Sign(sign) // Save the parameterized deletion event with e-tag - if _, _, err := db.SaveEvent( - ctx, paramDeletionEvent2, false, nil, - ); err != nil { + if _, _, err := db.SaveEvent(ctx, paramDeletionEvent2); err != nil { t.Fatalf( "Failed to save parameterized deletion event with e-tag: %v", err, ) diff --git a/pkg/database/query-for-created-at_test.go b/pkg/database/query-for-created-at_test.go index 780286f..419570b 100644 --- a/pkg/database/query-for-created-at_test.go +++ b/pkg/database/query-for-created-at_test.go @@ -58,7 +58,7 @@ func TestQueryForCreatedAt(t *testing.T) { events = append(events, ev) // Save the event to the database - if _, _, err = db.SaveEvent(ctx, ev, false, nil); err != nil { + if _, _, err = db.SaveEvent(ctx, ev); err != nil { t.Fatalf("Failed to save event #%d: %v", eventCount+1, err) } diff --git a/pkg/database/query-for-deleted.go b/pkg/database/query-for-deleted.go new file mode 100644 index 0000000..dfadd95 --- /dev/null +++ b/pkg/database/query-for-deleted.go @@ -0,0 +1,225 @@ +package database + +import ( + "fmt" + "sort" + + "database.orly/indexes/types" + "encoders.orly/event" + "encoders.orly/filter" + "encoders.orly/hex" + "encoders.orly/kind" + "encoders.orly/tag" + "encoders.orly/tag/atag" + "interfaces.orly/store" + "lol.mleku.dev/chk" + "lol.mleku.dev/errorf" +) + +// CheckForDeleted checks if the event is deleted, and returns an error with +// prefix "blocked:" if it is. This function also allows designating admin +// pubkeys that also may delete the event, normally only the author is allowed +// to delete an event. +func (d *D) CheckForDeleted(ev *event.E, admins [][]byte) (err error) { + keys := append([][]byte{ev.Pubkey}, admins...) + authors := tag.NewFromBytesSlice(keys...) + // if the event is addressable, check for a deletion event with the same + // kind/pubkey/dtag + if kind.IsParameterizedReplaceable(ev.Kind) { + var idxs []Range + // construct a tag + t := ev.Tags.GetFirst([]byte("d")) + a := atag.T{ + Kind: kind.New(ev.Kind), + PubKey: ev.Pubkey, + DTag: t.Value(), + } + at := a.Marshal(nil) + if idxs, err = GetIndexesFromFilter( + &filter.F{ + Authors: authors, + Kinds: kind.NewS(kind.Deletion), + Tags: tag.NewS(tag.NewFromAny("#a", at)), + }, + ); chk.E(err) { + return + } + var sers types.Uint40s + for _, idx := range idxs { + var s types.Uint40s + if s, err = d.GetSerialsByRange(idx); chk.E(err) { + return + } + sers = append(sers, s...) + } + if len(sers) > 0 { + // there can be multiple of these because the author/kind/tag is a + // stable value but refers to any event from the author, of the + // kind, with the identifier. so we need to fetch the full ID index + // to get the timestamp and ensure that the event post-dates it. + // otherwise, it should be rejected. + var idPkTss []*store.IdPkTs + var tmp []*store.IdPkTs + if tmp, err = d.GetFullIdPubkeyBySerials(sers); chk.E(err) { + return + } + idPkTss = append(idPkTss, tmp...) + // sort by timestamp, so the first is the newest, which the event + // must be newer to not be deleted. + sort.Slice( + idPkTss, func(i, j int) bool { + return idPkTss[i].Ts > idPkTss[j].Ts + }, + ) + if ev.CreatedAt < idPkTss[0].Ts { + err = errorf.E( + "blocked: %0x was deleted by address %s because it is older than the delete: event: %d delete: %d", + ev.ID, at, ev.CreatedAt, idPkTss[0].Ts, + ) + return + } + return + } + return + } + // if the event is replaceable, check if there is a deletion event newer + // than the event, it must specify the same kind/pubkey. this type of delete + // only has the k tag to specify the kind, it can be what an author would + // use, as the author is part of the replaceable event specification. + if kind.IsReplaceable(ev.Kind) { + var idxs []Range + if idxs, err = GetIndexesFromFilter( + &filter.F{ + Authors: tag.NewFromBytesSlice(ev.Pubkey), + Kinds: kind.NewS(kind.Deletion), + Tags: tag.NewS( + tag.NewFromAny("#k", fmt.Sprint(ev.Kind)), + ), + }, + ); chk.E(err) { + return + } + var sers types.Uint40s + for _, idx := range idxs { + var s types.Uint40s + if s, err = d.GetSerialsByRange(idx); chk.E(err) { + return + } + sers = append(sers, s...) + } + if len(sers) > 0 { + var idPkTss []*store.IdPkTs + var tmp []*store.IdPkTs + if tmp, err = d.GetFullIdPubkeyBySerials(sers); chk.E(err) { + return + } + idPkTss = append(idPkTss, tmp...) + // sort by timestamp, so the first is the newest, which the event + // must be newer to not be deleted. + sort.Slice( + idPkTss, func(i, j int) bool { + return idPkTss[i].Ts > idPkTss[j].Ts + }, + ) + if ev.CreatedAt < idPkTss[0].Ts { + err = errorf.E( + "blocked: %0x was deleted: the event is older than the delete event %0x: event: %d delete: %d", + ev.ID, idPkTss[0].Id, ev.CreatedAt, idPkTss[0].Ts, + ) + return + } + } + // this type of delete can also use an a tag to specify kind and + // author, which would be required for admin deletes + idxs = nil + // construct a tag + a := atag.T{ + Kind: kind.New(ev.Kind), + PubKey: ev.Pubkey, + } + at := a.Marshal(nil) + if idxs, err = GetIndexesFromFilter( + &filter.F{ + Authors: authors, + Kinds: kind.NewS(kind.Deletion), + Tags: tag.NewS(tag.NewFromAny("#a", at)), + }, + ); chk.E(err) { + return + } + sers = nil + for _, idx := range idxs { + var s types.Uint40s + if s, err = d.GetSerialsByRange(idx); chk.E(err) { + return + } + sers = append(sers, s...) + } + if len(sers) > 0 { + var idPkTss []*store.IdPkTs + var tmp []*store.IdPkTs + if tmp, err = d.GetFullIdPubkeyBySerials(sers); chk.E(err) { + return + } + idPkTss = append(idPkTss, tmp...) + // sort by timestamp, so the first is the newest + sort.Slice( + idPkTss, func(i, j int) bool { + return idPkTss[i].Ts > idPkTss[j].Ts + }, + ) + if ev.CreatedAt < idPkTss[0].Ts { + err = errorf.E( + "blocked: %0x was deleted by address %s: event is older than the delete: event: %d delete: %d", + ev.ID, at, idPkTss[0].Id, ev.CreatedAt, idPkTss[0].Ts, + ) + return + } + } + } + // otherwise we check for a delete by event id + var idxs []Range + if idxs, err = GetIndexesFromFilter( + &filter.F{ + Authors: authors, + Kinds: kind.NewS(kind.Deletion), + Tags: tag.NewS( + tag.NewFromAny("#e", hex.Enc(ev.ID)), + ), + }, + ); chk.E(err) { + return + } + var sers types.Uint40s + for _, idx := range idxs { + var s types.Uint40s + if s, err = d.GetSerialsByRange(idx); chk.E(err) { + return + } + sers = append(sers, s...) + } + if len(sers) > 0 { + var idPkTss []*store.IdPkTs + var tmp []*store.IdPkTs + if tmp, err = d.GetFullIdPubkeyBySerials(sers); chk.E(err) { + return + } + idPkTss = append(idPkTss, tmp...) + // sort by timestamp, so the first is the newest + sort.Slice( + idPkTss, func(i, j int) bool { + return idPkTss[i].Ts > idPkTss[j].Ts + }, + ) + if ev.CreatedAt < idPkTss[0].Ts { + err = errorf.E( + "blocked: %0x was deleted because it is older than the delete: event: %d delete: %d", + ev.ID, ev.CreatedAt, idPkTss[0].Ts, + ) + return + } + return + } + + return +} diff --git a/pkg/database/query-for-ids_test.go b/pkg/database/query-for-ids_test.go index d6242f3..c4b25d3 100644 --- a/pkg/database/query-for-ids_test.go +++ b/pkg/database/query-for-ids_test.go @@ -60,7 +60,7 @@ func TestQueryForIds(t *testing.T) { events = append(events, ev) // Save the event to the database - if _, _, err = db.SaveEvent(ctx, ev, false, nil); err != nil { + if _, _, err = db.SaveEvent(ctx, ev); err != nil { t.Fatalf("Failed to save event #%d: %v", eventCount+1, err) } diff --git a/pkg/database/query-for-kinds-authors-tags_test.go b/pkg/database/query-for-kinds-authors-tags_test.go index e6a799e..8e9e86c 100644 --- a/pkg/database/query-for-kinds-authors-tags_test.go +++ b/pkg/database/query-for-kinds-authors-tags_test.go @@ -59,7 +59,7 @@ func TestQueryForKindsAuthorsTags(t *testing.T) { events = append(events, ev) // Save the event to the database - if _, _, err = db.SaveEvent(ctx, ev, false, nil); err != nil { + if _, _, err = db.SaveEvent(ctx, ev); err != nil { t.Fatalf("Failed to save event #%d: %v", eventCount+1, err) } diff --git a/pkg/database/query-for-kinds-authors_test.go b/pkg/database/query-for-kinds-authors_test.go index c2de4f3..9a2f1b1 100644 --- a/pkg/database/query-for-kinds-authors_test.go +++ b/pkg/database/query-for-kinds-authors_test.go @@ -59,7 +59,7 @@ func TestQueryForKindsAuthors(t *testing.T) { events = append(events, ev) // Save the event to the database - if _, _, err = db.SaveEvent(ctx, ev, false, nil); err != nil { + if _, _, err = db.SaveEvent(ctx, ev); err != nil { t.Fatalf("Failed to save event #%d: %v", eventCount+1, err) } diff --git a/pkg/database/query-for-kinds-tags_test.go b/pkg/database/query-for-kinds-tags_test.go index f28189b..966ab61 100644 --- a/pkg/database/query-for-kinds-tags_test.go +++ b/pkg/database/query-for-kinds-tags_test.go @@ -59,7 +59,7 @@ func TestQueryForKindsTags(t *testing.T) { events = append(events, ev) // Save the event to the database - if _, _, err = db.SaveEvent(ctx, ev, false, nil); err != nil { + if _, _, err = db.SaveEvent(ctx, ev); err != nil { t.Fatalf("Failed to save event #%d: %v", eventCount+1, err) } diff --git a/pkg/database/query-for-kinds_test.go b/pkg/database/query-for-kinds_test.go index 27696e1..26ebe5e 100644 --- a/pkg/database/query-for-kinds_test.go +++ b/pkg/database/query-for-kinds_test.go @@ -58,7 +58,7 @@ func TestQueryForKinds(t *testing.T) { events = append(events, ev) // Save the event to the database - if _, _, err = db.SaveEvent(ctx, ev, false, nil); err != nil { + if _, _, err = db.SaveEvent(ctx, ev); err != nil { t.Fatalf("Failed to save event #%d: %v", eventCount+1, err) } diff --git a/pkg/database/query-for-serials_test.go b/pkg/database/query-for-serials_test.go index c4b27b0..e8c474f 100644 --- a/pkg/database/query-for-serials_test.go +++ b/pkg/database/query-for-serials_test.go @@ -61,7 +61,7 @@ func TestQueryForSerials(t *testing.T) { events = append(events, ev) // Save the event to the database - if _, _, err = db.SaveEvent(ctx, ev, false, nil); err != nil { + if _, _, err = db.SaveEvent(ctx, ev); err != nil { t.Fatalf("Failed to save event #%d: %v", eventCount+1, err) } diff --git a/pkg/database/query-for-tags_test.go b/pkg/database/query-for-tags_test.go index c34c305..5b4bd6a 100644 --- a/pkg/database/query-for-tags_test.go +++ b/pkg/database/query-for-tags_test.go @@ -58,7 +58,7 @@ func TestQueryForTags(t *testing.T) { events = append(events, ev) // Save the event to the database - if _, _, err = db.SaveEvent(ctx, ev, false, nil); err != nil { + if _, _, err = db.SaveEvent(ctx, ev); err != nil { t.Fatalf("Failed to save event #%d: %v", eventCount+1, err) } diff --git a/pkg/database/save-event.go b/pkg/database/save-event.go index 68b7d83..1e033cd 100644 --- a/pkg/database/save-event.go +++ b/pkg/database/save-event.go @@ -3,120 +3,23 @@ package database import ( "bytes" "context" - "sort" "database.orly/indexes" "database.orly/indexes/types" "encoders.orly/event" - "encoders.orly/filter" - "encoders.orly/kind" - "encoders.orly/tag" - "encoders.orly/tag/atag" "github.com/dgraph-io/badger/v4" - "interfaces.orly/store" "lol.mleku.dev/chk" "lol.mleku.dev/errorf" "lol.mleku.dev/log" ) // SaveEvent saves an event to the database, generating all the necessary indexes. -func (d *D) SaveEvent( - c context.Context, ev *event.E, noVerify bool, owners [][]byte, -) (kc, vc int, err error) { - if !noVerify { - // check if the event already exists - var ser *types.Uint40 - if ser, err = d.GetSerialById(ev.ID); err == nil && ser != nil { - err = errorf.E("event already exists: %0x", ev.ID) - return - } - } - - // check if an existing delete event references this event submission - if kind.IsParameterizedReplaceable(ev.Kind) { - var idxs []Range - // construct a tag - t := ev.Tags.GetFirst([]byte("d")) - a := atag.T{ - Kind: kind.New(ev.Kind), - PubKey: ev.Pubkey, - DTag: t.Value(), - } - at := a.Marshal(nil) - if idxs, err = GetIndexesFromFilter( - &filter.F{ - Authors: tag.NewFromBytesSlice(ev.Pubkey), - Kinds: kind.NewS(kind.Deletion), - Tags: tag.NewS(tag.NewFromAny("#a", at)), - }, - ); chk.E(err) { - return - } - var sers types.Uint40s - for _, idx := range idxs { - var s types.Uint40s - if s, err = d.GetSerialsByRange(idx); chk.E(err) { - return - } - sers = append(sers, s...) - } - if len(sers) > 0 { - // there can be multiple of these because the author/kind/tag is a - // stable value but refers to any event from the author, of the - // kind, with the identifier. so we need to fetch the full ID index - // to get the timestamp and ensure that the event post-dates it. - // otherwise, it should be rejected. - var idPkTss []*store.IdPkTs - var tmp []*store.IdPkTs - if tmp, err = d.GetFullIdPubkeyBySerials(sers); chk.E(err) { - return - } - idPkTss = append(idPkTss, tmp...) - // sort by timestamp, so the first is the newest - sort.Slice( - idPkTss, func(i, j int) bool { - return idPkTss[i].Ts > idPkTss[j].Ts - }, - ) - if ev.CreatedAt < idPkTss[0].Ts { - err = errorf.E( - "blocked: %0x was deleted by address %s because it is older than the delete: event: %d delete: %d", - ev.ID, at, ev.CreatedAt, idPkTss[0].Ts, - ) - return - } - return - } - } else { - var idxs []Range - keys := [][]byte{ev.Pubkey} - for _, owner := range owners { - keys = append(keys, owner) - } - if idxs, err = GetIndexesFromFilter( - &filter.F{ - Authors: tag.NewFromBytesSlice(keys...), - Kinds: kind.NewS(kind.Deletion), - Tags: tag.NewS(tag.NewFromAny("#e", ev.ID)), - }, - ); chk.E(err) { - return - } - var sers types.Uint40s - for _, idx := range idxs { - var s types.Uint40s - if s, err = d.GetSerialsByRange(idx); chk.E(err) { - return - } - sers = append(sers, s...) - } - if len(sers) > 0 { - // really there can only be one of these; the chances of an idhash - // collision are basically zero in practice, at least, one in a - // billion or more anyway, more than a human is going to create. - err = errorf.E("blocked: event %0x deleted by event ID", ev.ID) - return - } +func (d *D) SaveEvent(c context.Context, ev *event.E) (kc, vc int, err error) { + // check if the event already exists + var ser *types.Uint40 + if ser, err = d.GetSerialById(ev.ID); err == nil && ser != nil { + err = errorf.E("event already exists: %0x", ev.ID) + return } // Get the next sequence number for the event var serial uint64 diff --git a/pkg/database/save-event_test.go b/pkg/database/save-event_test.go index a84013b..8873e18 100644 --- a/pkg/database/save-event_test.go +++ b/pkg/database/save-event_test.go @@ -65,7 +65,7 @@ func TestSaveEvents(t *testing.T) { // Save the event to the database var k, v int - if k, v, err = db.SaveEvent(ctx, ev, false, nil); err != nil { + if k, v, err = db.SaveEvent(ctx, ev); err != nil { t.Fatalf("Failed to save event #%d: %v", eventCount+1, err) } kc += k @@ -125,7 +125,7 @@ func TestDeletionEventWithETagRejection(t *testing.T) { regularEvent.Sign(sign) // Save the regular event - if _, _, err := db.SaveEvent(ctx, regularEvent, false, nil); err != nil { + if _, _, err := db.SaveEvent(ctx, regularEvent); err != nil { t.Fatalf("Failed to save regular event: %v", err) } @@ -151,7 +151,7 @@ func TestDeletionEventWithETagRejection(t *testing.T) { err = errorf.E("deletion events referencing other events with 'e' tag are not allowed") } else { // Try to save the deletion event - _, _, err = db.SaveEvent(ctx, deletionEvent, false, nil) + _, _, err = db.SaveEvent(ctx, deletionEvent) } if err == nil { @@ -204,12 +204,12 @@ func TestSaveExistingEvent(t *testing.T) { ev.Sign(sign) // Save the event for the first time - if _, _, err := db.SaveEvent(ctx, ev, false, nil); err != nil { + if _, _, err := db.SaveEvent(ctx, ev); err != nil { t.Fatalf("Failed to save event: %v", err) } // Try to save the same event again, it should be rejected - _, _, err = db.SaveEvent(ctx, ev, false, nil) + _, _, err = db.SaveEvent(ctx, ev) if err == nil { t.Fatal("Expected error when saving an existing event, but got nil") } diff --git a/pkg/encoders/go.mod b/pkg/encoders/go.mod index d0990d5..d9a5a25 100644 --- a/pkg/encoders/go.mod +++ b/pkg/encoders/go.mod @@ -26,6 +26,7 @@ require ( replace ( acl.orly => ../acl crypto.orly => ../crypto + database.orly => ../database encoders.orly => ../encoders interfaces.orly => ../interfaces next.orly.dev => ../../ diff --git a/pkg/encoders/reason/reason.go b/pkg/encoders/reason/reason.go index efe6e52..ef253bb 100644 --- a/pkg/encoders/reason/reason.go +++ b/pkg/encoders/reason/reason.go @@ -3,8 +3,6 @@ package reason import ( "bytes" "fmt" - - "lol.mleku.dev/log" ) // R is the machine-readable prefix before the colon in an OK or CLOSED envelope message. @@ -38,7 +36,6 @@ func (r R) IsPrefix(reason []byte) bool { // F allows creation of a full R text with a printf style format. func (r R) F(format string, params ...any) (o []byte) { - log.D.F(format, params...) return Msg(r, format, params...) } diff --git a/pkg/interfaces/store/store_interface.go b/pkg/interfaces/store/store_interface.go index afcf988..30406d5 100644 --- a/pkg/interfaces/store/store_interface.go +++ b/pkg/interfaces/store/store_interface.go @@ -84,9 +84,7 @@ type Saver interface { // SaveEvent is called once relay.AcceptEvent reports true. The owners // parameter is for designating admins whose delete by e tag events apply // the same as author's own. - SaveEvent( - c context.Context, ev *event.E, noVerify bool, owners [][]byte, - ) (kc, vc int, err error) + SaveEvent(c context.Context, ev *event.E) (kc, vc int, err error) } type Importer interface {