Refactor database methods: simplify SaveEvent signature, enhance logging, and introduce deletion check logic with CheckForDeleted.
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
225
pkg/database/query-for-deleted.go
Normal file
225
pkg/database/query-for-deleted.go
Normal file
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user