diff --git a/pkg/database/get-fullidpubkey-by-serial.go b/pkg/database/get-fullidpubkey-by-serial.go index d8baddd..ffc2a53 100644 --- a/pkg/database/get-fullidpubkey-by-serial.go +++ b/pkg/database/get-fullidpubkey-by-serial.go @@ -41,12 +41,12 @@ func (d *D) GetFullIdPubkeyBySerial(ser *types.Uint40) ( ).UnmarshalRead(buf2); chk.E(err) { return } - idpkts := store.IdPkTs{ - Id: fid.Bytes(), - Pub: p.Bytes(), - Ts: int64(ca.Get()), - Ser: ser.Get(), - } + idpkts := store.NewIdPkTs( + fid.Bytes(), + p.Bytes(), + int64(ca.Get()), + ser.Get(), + ) fidpk = &idpkts } return diff --git a/pkg/database/get-fullidpubkey-by-serials.go b/pkg/database/get-fullidpubkey-by-serials.go index 4d011e2..d080dd4 100644 --- a/pkg/database/get-fullidpubkey-by-serials.go +++ b/pkg/database/get-fullidpubkey-by-serials.go @@ -59,14 +59,13 @@ func (d *D) GetFullIdPubkeyBySerials(sers []*types.Uint40) ( ).UnmarshalRead(bytes.NewBuffer(key)); chk.E(err) { return } - fidpks = append( - fidpks, &store.IdPkTs{ - Id: fid.Bytes(), - Pub: p.Bytes(), - Ts: int64(ca.Get()), - Ser: ser.Get(), - }, + idpkts := store.NewIdPkTs( + fid.Bytes(), + p.Bytes(), + int64(ca.Get()), + ser.Get(), ) + fidpks = append(fidpks, &idpkts) } } return diff --git a/pkg/database/process-delete.go b/pkg/database/process-delete.go index 0cc61f5..4eaa669 100644 --- a/pkg/database/process-delete.go +++ b/pkg/database/process-delete.go @@ -129,11 +129,11 @@ func (d *D) ProcessDelete(ev *event.E, admins [][]byte) (err error) { }) for _, v := range idPkTss { if v.Ts < ev.CreatedAt { - if err = d.DeleteEvent(context.Background(), v.Id); chk.E(err) { - log.W.F("failed to delete event %x via a-tag: %v", v.Id, err) + if err = d.DeleteEvent(context.Background(), v.Id[:]); chk.E(err) { + log.W.F("failed to delete event %x via a-tag: %v", v.Id[:], err) continue } - log.D.F("deleted event %x via a-tag deletion", v.Id) + log.D.F("deleted event %x via a-tag deletion", v.Id[:]) } } } @@ -187,7 +187,7 @@ func (d *D) ProcessDelete(ev *event.E, admins [][]byte) (err error) { for _, v := range idPkTss { if v.Ts < ev.CreatedAt { if err = d.DeleteEvent( - context.Background(), v.Id, + context.Background(), v.Id[:], ); chk.E(err) { continue } diff --git a/pkg/database/query-for-authors-tags_test.go b/pkg/database/query-for-authors-tags_test.go index 87d1c60..702fddf 100644 --- a/pkg/database/query-for-authors-tags_test.go +++ b/pkg/database/query-for-authors-tags_test.go @@ -1,11 +1,11 @@ package database import ( + "bytes" "testing" "git.mleku.dev/mleku/nostr/encoders/filter" "git.mleku.dev/mleku/nostr/encoders/tag" - "next.orly.dev/pkg/utils" ) func TestQueryForAuthorsTags(t *testing.T) { @@ -56,10 +56,10 @@ func TestQueryForAuthorsTags(t *testing.T) { // Find the event with this ID var found bool for _, ev := range events { - if utils.FastEqual(result.Id, ev.ID) { + if bytes.Equal(result.Id[:], ev.ID[:]) { found = true - if !utils.FastEqual(ev.Pubkey, testEvent.Pubkey) { + if !bytes.Equal(ev.Pubkey[:], testEvent.Pubkey[:]) { t.Fatalf( "result %d has incorrect author, got %x, expected %x", i, ev.Pubkey, testEvent.Pubkey, @@ -70,9 +70,9 @@ func TestQueryForAuthorsTags(t *testing.T) { var hasTag bool for _, tg := range *ev.Tags { if tg.Len() >= 2 && len(tg.Key()) == 1 { - if utils.FastEqual( + if bytes.Equal( tg.Key(), testTag.Key(), - ) && utils.FastEqual(tg.Value(), testTag.Value()) { + ) && bytes.Equal(tg.Value(), testTag.Value()) { hasTag = true break } diff --git a/pkg/database/query-for-created-at_test.go b/pkg/database/query-for-created-at_test.go index fbc0273..ce80bf9 100644 --- a/pkg/database/query-for-created-at_test.go +++ b/pkg/database/query-for-created-at_test.go @@ -1,11 +1,11 @@ package database import ( + "bytes" "testing" "git.mleku.dev/mleku/nostr/encoders/filter" "git.mleku.dev/mleku/nostr/encoders/timestamp" - "next.orly.dev/pkg/utils" ) func TestQueryForCreatedAt(t *testing.T) { @@ -50,7 +50,7 @@ func TestQueryForCreatedAt(t *testing.T) { // Find the event with this ID var found bool for _, ev := range events { - if utils.FastEqual(result.Id, ev.ID) { + if bytes.Equal(result.Id[:], ev.ID[:]) { found = true break } @@ -88,7 +88,7 @@ func TestQueryForCreatedAt(t *testing.T) { // Find the event with this ID var found bool for _, ev := range events { - if utils.FastEqual(result.Id, ev.ID) { + if bytes.Equal(result.Id[:], ev.ID[:]) { found = true break } @@ -126,7 +126,7 @@ func TestQueryForCreatedAt(t *testing.T) { // Find the event with this ID var found bool for _, ev := range events { - if utils.FastEqual(result.Id, ev.ID) { + if bytes.Equal(result.Id[:], ev.ID[:]) { found = true break } diff --git a/pkg/database/query-for-ids_test.go b/pkg/database/query-for-ids_test.go index 6360f9d..ab85b6b 100644 --- a/pkg/database/query-for-ids_test.go +++ b/pkg/database/query-for-ids_test.go @@ -1,13 +1,13 @@ package database import ( + "bytes" "testing" "git.mleku.dev/mleku/nostr/encoders/filter" "git.mleku.dev/mleku/nostr/encoders/kind" "git.mleku.dev/mleku/nostr/encoders/tag" "git.mleku.dev/mleku/nostr/encoders/timestamp" - "next.orly.dev/pkg/utils" ) func TestQueryForIds(t *testing.T) { @@ -39,9 +39,9 @@ func TestQueryForIds(t *testing.T) { // Find the event with this ID var found bool for _, ev := range events { - if utils.FastEqual(result.Id, ev.ID) { + if bytes.Equal(result.Id[:], ev.ID[:]) { found = true - if !utils.FastEqual(ev.Pubkey, events[1].Pubkey) { + if !bytes.Equal(ev.Pubkey[:], events[1].Pubkey[:]) { t.Fatalf( "result %d has incorrect author, got %x, expected %x", i, ev.Pubkey, events[1].Pubkey, @@ -79,7 +79,7 @@ func TestQueryForIds(t *testing.T) { // Find the event with this ID var found bool for _, ev := range events { - if utils.FastEqual(result.Id, ev.ID) { + if bytes.Equal(result.Id[:], ev.ID[:]) { found = true if ev.Kind != testKind.K { t.Fatalf( @@ -131,16 +131,16 @@ func TestQueryForIds(t *testing.T) { // Find the event with this ID var found bool for _, ev := range events { - if utils.FastEqual(result.Id, ev.ID) { + if bytes.Equal(result.Id[:], ev.ID[:]) { found = true // Check if the event has the tag we're looking for var hasTag bool for _, tg := range *ev.Tags { if tg.Len() >= 2 && len(tg.Key()) == 1 { - if utils.FastEqual( + if bytes.Equal( tg.Key(), testTag.Key(), - ) && utils.FastEqual(tg.Value(), testTag.Value()) { + ) && bytes.Equal(tg.Value(), testTag.Value()) { hasTag = true break } @@ -182,7 +182,7 @@ func TestQueryForIds(t *testing.T) { // Find the event with this ID var found bool for _, ev := range events { - if utils.FastEqual(result.Id, ev.ID) { + if bytes.Equal(result.Id[:], ev.ID[:]) { found = true if ev.Kind != testKind.K { t.Fatalf( @@ -190,7 +190,7 @@ func TestQueryForIds(t *testing.T) { i, ev.Kind, testKind.K, ) } - if !utils.FastEqual(ev.Pubkey, events[1].Pubkey) { + if !bytes.Equal(ev.Pubkey[:], events[1].Pubkey[:]) { t.Fatalf( "result %d has incorrect author, got %x, expected %x", i, ev.Pubkey, events[1].Pubkey, @@ -229,7 +229,7 @@ func TestQueryForIds(t *testing.T) { // Find the event with this ID var found bool for _, ev := range events { - if utils.FastEqual(result.Id, ev.ID) { + if bytes.Equal(result.Id[:], ev.ID[:]) { found = true if ev.Kind != testEventForTag.Kind { t.Fatalf( @@ -242,9 +242,9 @@ func TestQueryForIds(t *testing.T) { var hasTag bool for _, tg := range *ev.Tags { if tg.Len() >= 2 && len(tg.Key()) == 1 { - if utils.FastEqual( + if bytes.Equal( tg.Key(), testTag.Key(), - ) && utils.FastEqual(tg.Value(), testTag.Value()) { + ) && bytes.Equal(tg.Value(), testTag.Value()) { hasTag = true break } @@ -290,7 +290,7 @@ func TestQueryForIds(t *testing.T) { // Find the event with this ID var found bool for _, ev := range events { - if utils.FastEqual(result.Id, ev.ID) { + if bytes.Equal(result.Id[:], ev.ID[:]) { found = true if ev.Kind != testEventForTag.Kind { t.Fatalf( @@ -299,7 +299,7 @@ func TestQueryForIds(t *testing.T) { ) } - if !utils.FastEqual(ev.Pubkey, testEventForTag.Pubkey) { + if !bytes.Equal(ev.Pubkey[:], testEventForTag.Pubkey[:]) { t.Fatalf( "result %d has incorrect author, got %x, expected %x", i, ev.Pubkey, testEventForTag.Pubkey, @@ -310,9 +310,9 @@ func TestQueryForIds(t *testing.T) { var hasTag bool for _, tg := range *ev.Tags { if tg.Len() >= 2 && len(tg.Key()) == 1 { - if utils.FastEqual( + if bytes.Equal( tg.Key(), testTag.Key(), - ) && utils.FastEqual(tg.Value(), testTag.Value()) { + ) && bytes.Equal(tg.Value(), testTag.Value()) { hasTag = true break } @@ -357,10 +357,10 @@ func TestQueryForIds(t *testing.T) { // Find the event with this ID var found bool for _, ev := range events { - if utils.FastEqual(result.Id, ev.ID) { + if bytes.Equal(result.Id[:], ev.ID[:]) { found = true - if !utils.FastEqual(ev.Pubkey, testEventForTag.Pubkey) { + if !bytes.Equal(ev.Pubkey[:], testEventForTag.Pubkey[:]) { t.Fatalf( "result %d has incorrect author, got %x, expected %x", i, ev.Pubkey, testEventForTag.Pubkey, @@ -371,9 +371,9 @@ func TestQueryForIds(t *testing.T) { var hasTag bool for _, tg := range *ev.Tags { if tg.Len() >= 2 && len(tg.Key()) == 1 { - if utils.FastEqual( + if bytes.Equal( tg.Key(), testTag.Key(), - ) && utils.FastEqual(tg.Value(), testTag.Value()) { + ) && bytes.Equal(tg.Value(), testTag.Value()) { hasTag = true break } @@ -430,7 +430,7 @@ func TestQueryForIds(t *testing.T) { // Find the event with this ID var found bool for _, ev := range events { - if utils.FastEqual(result.Id, ev.ID) { + if bytes.Equal(result.Id[:], ev.ID[:]) { found = true break } diff --git a/pkg/database/query-for-kinds-authors-tags_test.go b/pkg/database/query-for-kinds-authors-tags_test.go index c109b96..ab0b509 100644 --- a/pkg/database/query-for-kinds-authors-tags_test.go +++ b/pkg/database/query-for-kinds-authors-tags_test.go @@ -1,12 +1,12 @@ package database import ( + "bytes" "testing" "git.mleku.dev/mleku/nostr/encoders/filter" "git.mleku.dev/mleku/nostr/encoders/kind" "git.mleku.dev/mleku/nostr/encoders/tag" - "next.orly.dev/pkg/utils" ) func TestQueryForKindsAuthorsTags(t *testing.T) { @@ -62,7 +62,7 @@ func TestQueryForKindsAuthorsTags(t *testing.T) { // Find the event with this ID var found bool for _, ev := range events { - if utils.FastEqual(result.Id, ev.ID) { + if bytes.Equal(result.Id[:], ev.ID[:]) { found = true if ev.Kind != testKind { t.Fatalf( @@ -71,7 +71,7 @@ func TestQueryForKindsAuthorsTags(t *testing.T) { ) } - if !utils.FastEqual(ev.Pubkey, testEvent.Pubkey) { + if !bytes.Equal(ev.Pubkey[:], testEvent.Pubkey[:]) { t.Fatalf( "result %d has incorrect author, got %x, expected %x", i, ev.Pubkey, testEvent.Pubkey, @@ -82,9 +82,9 @@ func TestQueryForKindsAuthorsTags(t *testing.T) { var hasTag bool for _, tg := range *ev.Tags { if tg.Len() >= 2 && len(tg.Key()) == 1 { - if utils.FastEqual( + if bytes.Equal( tg.Key(), testTag.Key(), - ) && utils.FastEqual(tg.Value(), testTag.Value()) { + ) && bytes.Equal(tg.Value(), testTag.Value()) { hasTag = true break } diff --git a/pkg/database/query-for-kinds-authors_test.go b/pkg/database/query-for-kinds-authors_test.go index 1b25344..6bed535 100644 --- a/pkg/database/query-for-kinds-authors_test.go +++ b/pkg/database/query-for-kinds-authors_test.go @@ -1,12 +1,12 @@ package database import ( + "bytes" "testing" "git.mleku.dev/mleku/nostr/encoders/filter" "git.mleku.dev/mleku/nostr/encoders/kind" "git.mleku.dev/mleku/nostr/encoders/tag" - "next.orly.dev/pkg/utils" ) func TestQueryForKindsAuthors(t *testing.T) { @@ -46,7 +46,7 @@ func TestQueryForKindsAuthors(t *testing.T) { // Find the event with this ID var found bool for _, ev := range events { - if utils.FastEqual(result.Id, ev.ID) { + if bytes.Equal(result.Id[:], ev.ID[:]) { found = true if ev.Kind != testKind.K { t.Fatalf( @@ -54,7 +54,7 @@ func TestQueryForKindsAuthors(t *testing.T) { i, ev.Kind, testKind.K, ) } - if !utils.FastEqual(ev.Pubkey, events[1].Pubkey) { + if !bytes.Equal(ev.Pubkey[:], events[1].Pubkey[:]) { t.Fatalf( "result %d has incorrect author, got %x, expected %x", i, ev.Pubkey, events[1].Pubkey, diff --git a/pkg/database/query-for-kinds-tags_test.go b/pkg/database/query-for-kinds-tags_test.go index 0878563..fff075b 100644 --- a/pkg/database/query-for-kinds-tags_test.go +++ b/pkg/database/query-for-kinds-tags_test.go @@ -1,12 +1,12 @@ package database import ( + "bytes" "testing" "git.mleku.dev/mleku/nostr/encoders/filter" "git.mleku.dev/mleku/nostr/encoders/kind" "git.mleku.dev/mleku/nostr/encoders/tag" - "next.orly.dev/pkg/utils" ) func TestQueryForKindsTags(t *testing.T) { @@ -58,7 +58,7 @@ func TestQueryForKindsTags(t *testing.T) { // Find the event with this ID var found bool for _, ev := range events { - if utils.FastEqual(result.Id, ev.ID) { + if bytes.Equal(result.Id[:], ev.ID[:]) { found = true if ev.Kind != testKind { t.Fatalf( @@ -71,9 +71,9 @@ func TestQueryForKindsTags(t *testing.T) { var hasTag bool for _, tg := range *ev.Tags { if tg.Len() >= 2 && len(tg.Key()) == 1 { - if utils.FastEqual( + if bytes.Equal( tg.Key(), testTag.Key(), - ) && utils.FastEqual(tg.Value(), testTag.Value()) { + ) && bytes.Equal(tg.Value(), testTag.Value()) { hasTag = true break } diff --git a/pkg/database/query-for-kinds_test.go b/pkg/database/query-for-kinds_test.go index 1e7a43d..343640b 100644 --- a/pkg/database/query-for-kinds_test.go +++ b/pkg/database/query-for-kinds_test.go @@ -1,11 +1,11 @@ package database import ( + "bytes" "testing" "git.mleku.dev/mleku/nostr/encoders/filter" "git.mleku.dev/mleku/nostr/encoders/kind" - "next.orly.dev/pkg/utils" ) func TestQueryForKinds(t *testing.T) { @@ -41,7 +41,7 @@ func TestQueryForKinds(t *testing.T) { // Find the event with this ID var found bool for _, ev := range events { - if utils.FastEqual(result.Id, ev.ID) { + if bytes.Equal(result.Id[:], ev.ID[:]) { found = true if ev.Kind != testKind.K { t.Fatalf( diff --git a/pkg/database/query-for-tags_test.go b/pkg/database/query-for-tags_test.go index 50bef12..477c3eb 100644 --- a/pkg/database/query-for-tags_test.go +++ b/pkg/database/query-for-tags_test.go @@ -1,11 +1,11 @@ package database import ( + "bytes" "testing" "git.mleku.dev/mleku/nostr/encoders/filter" "git.mleku.dev/mleku/nostr/encoders/tag" - "next.orly.dev/pkg/utils" ) func TestQueryForTags(t *testing.T) { @@ -52,16 +52,16 @@ func TestQueryForTags(t *testing.T) { // Find the event with this ID var found bool for _, ev := range events { - if utils.FastEqual(result.Id, ev.ID) { + if bytes.Equal(result.Id[:], ev.ID[:]) { found = true // Check if the event has the tag we're looking for var hasTag bool for _, tg := range *ev.Tags { if tg.Len() >= 2 && len(tg.Key()) == 1 { - if utils.FastEqual( + if bytes.Equal( tg.Key(), testTag.Key(), - ) && utils.FastEqual(tg.Value(), testTag.Value()) { + ) && bytes.Equal(tg.Value(), testTag.Value()) { hasTag = true break } diff --git a/pkg/interfaces/store/store_interface.go b/pkg/interfaces/store/store_interface.go index c75b550..9b7d325 100644 --- a/pkg/interfaces/store/store_interface.go +++ b/pkg/interfaces/store/store_interface.go @@ -61,39 +61,54 @@ type Accountant interface { EventCount() (count uint64, err error) } -// IdPkTs holds event reference data with slice fields for backward compatibility. -// For new code preferring stack-allocated, copy-on-assignment semantics, -// use the IDFixed() and PubFixed() methods or convert to EventRef. +// IdPkTs holds event reference data using fixed-size arrays for stack allocation. +// Total size: 80 bytes (32+32+8+8), fits in a cache line. +// Copies of this struct stay on the stack and are value-safe. type IdPkTs struct { - Id []byte - Pub []byte - Ts int64 - Ser uint64 + Id ntypes.EventID // 32 bytes - event ID + Pub ntypes.Pubkey // 32 bytes - author pubkey + Ts int64 // 8 bytes - created_at timestamp + Ser uint64 // 8 bytes - database serial number +} + +// NewIdPkTs creates an IdPkTs from byte slices (copies into fixed arrays). +func NewIdPkTs(id, pub []byte, ts int64, ser uint64) IdPkTs { + return IdPkTs{ + Id: ntypes.EventIDFromBytes(id), + Pub: ntypes.PubkeyFromBytes(pub), + Ts: ts, + Ser: ser, + } } -// IDFixed returns the event ID as a fixed-size array (stack-allocated, copied on assignment). -func (i *IdPkTs) IDFixed() ntypes.EventID { - return ntypes.EventIDFromBytes(i.Id) +// IDSlice returns the event ID as a byte slice (shares memory with array). +func (i *IdPkTs) IDSlice() []byte { + return i.Id[:] } -// PubFixed returns the pubkey as a fixed-size array (stack-allocated, copied on assignment). -func (i *IdPkTs) PubFixed() ntypes.Pubkey { - return ntypes.PubkeyFromBytes(i.Pub) +// PubSlice returns the pubkey as a byte slice (shares memory with array). +func (i *IdPkTs) PubSlice() []byte { + return i.Pub[:] } // IDHex returns the event ID as a lowercase hex string. func (i *IdPkTs) IDHex() string { - return ntypes.EventIDFromBytes(i.Id).Hex() + return i.Id.Hex() } // PubHex returns the pubkey as a lowercase hex string. func (i *IdPkTs) PubHex() string { - return ntypes.PubkeyFromBytes(i.Pub).Hex() + return i.Pub.Hex() } -// ToEventRef converts IdPkTs to an EventRef (fully stack-allocated). +// ToEventRef converts IdPkTs to an EventRef. func (i *IdPkTs) ToEventRef() EventRef { - return NewEventRef(i.Id, i.Pub, i.Ts, i.Ser) + return EventRef{ + id: i.Id, + pub: i.Pub, + ts: i.Ts, + ser: i.Ser, + } } // EventRef is a stack-friendly event reference using fixed-size arrays. @@ -141,12 +156,11 @@ func (r *EventRef) IDSlice() []byte { return r.id.Bytes() } // PubSlice returns a slice view of the pubkey (shares memory, use carefully). func (r *EventRef) PubSlice() []byte { return r.pub.Bytes() } -// ToIdPkTs converts EventRef to IdPkTs for backward compatibility. -// Note: This allocates new slices. +// ToIdPkTs converts EventRef to IdPkTs. func (r EventRef) ToIdPkTs() *IdPkTs { return &IdPkTs{ - Id: r.id.Copy(), - Pub: r.pub.Copy(), + Id: r.id, + Pub: r.pub, Ts: r.ts, Ser: r.ser, } diff --git a/pkg/interfaces/store/store_interface_test.go b/pkg/interfaces/store/store_interface_test.go index ce3a09e..3bae1f5 100644 --- a/pkg/interfaces/store/store_interface_test.go +++ b/pkg/interfaces/store/store_interface_test.go @@ -7,8 +7,8 @@ import ( ntypes "git.mleku.dev/mleku/nostr/types" ) -func TestIdPkTsFixedMethods(t *testing.T) { - // Create an IdPkTs with sample data +func TestNewIdPkTs(t *testing.T) { + // Create sample data id := make([]byte, 32) pub := make([]byte, 32) for i := 0; i < 32; i++ { @@ -16,29 +16,49 @@ func TestIdPkTsFixedMethods(t *testing.T) { pub[i] = byte(i + 32) } - ipk := &IdPkTs{ - Id: id, - Pub: pub, - Ts: 1234567890, - Ser: 42, - } + ipk := NewIdPkTs(id, pub, 1234567890, 42) - // Test IDFixed returns correct data - idFixed := ipk.IDFixed() - if !bytes.Equal(idFixed[:], id) { - t.Errorf("IDFixed: got %x, want %x", idFixed[:], id) + // Test that data was copied correctly + if !bytes.Equal(ipk.Id[:], id) { + t.Errorf("Id: got %x, want %x", ipk.Id[:], id) + } + if !bytes.Equal(ipk.Pub[:], pub) { + t.Errorf("Pub: got %x, want %x", ipk.Pub[:], pub) + } + if ipk.Ts != 1234567890 { + t.Errorf("Ts: got %d, want 1234567890", ipk.Ts) + } + if ipk.Ser != 42 { + t.Errorf("Ser: got %d, want 42", ipk.Ser) } - // Test IDFixed returns a copy - idFixed[0] = 0xFF + // Test that Id is a copy (modifying original doesn't affect struct) + id[0] = 0xFF if ipk.Id[0] == 0xFF { - t.Error("IDFixed should return a copy, not a reference") + t.Error("NewIdPkTs should copy data, not reference") + } +} + +func TestIdPkTsSliceMethods(t *testing.T) { + id := make([]byte, 32) + pub := make([]byte, 32) + for i := 0; i < 32; i++ { + id[i] = byte(i) + pub[i] = byte(i + 32) + } + + ipk := NewIdPkTs(id, pub, 1234567890, 42) + + // Test IDSlice returns correct data + idSlice := ipk.IDSlice() + if !bytes.Equal(idSlice, id) { + t.Errorf("IDSlice: got %x, want %x", idSlice, id) } - // Test PubFixed returns correct data - pubFixed := ipk.PubFixed() - if !bytes.Equal(pubFixed[:], pub) { - t.Errorf("PubFixed: got %x, want %x", pubFixed[:], pub) + // Test PubSlice returns correct data + pubSlice := ipk.PubSlice() + if !bytes.Equal(pubSlice, pub) { + t.Errorf("PubSlice: got %x, want %x", pubSlice, pub) } // Test hex methods @@ -49,6 +69,26 @@ func TestIdPkTsFixedMethods(t *testing.T) { } } +func TestIdPkTsCopyOnAssignment(t *testing.T) { + id := make([]byte, 32) + pub := make([]byte, 32) + for i := 0; i < 32; i++ { + id[i] = byte(i) + pub[i] = byte(i + 32) + } + + ipk1 := NewIdPkTs(id, pub, 1234567890, 42) + ipk2 := ipk1 // Copy + + // Modify the copy + ipk2.Id[0] = 0xFF + + // Original should be unchanged (arrays are copied on assignment) + if ipk1.Id[0] == 0xFF { + t.Error("IdPkTs should copy on assignment") + } +} + func TestEventRef(t *testing.T) { id := make([]byte, 32) pub := make([]byte, 32) @@ -103,10 +143,10 @@ func TestEventRefToIdPkTs(t *testing.T) { ipk := ref.ToIdPkTs() // Verify conversion - if !bytes.Equal(ipk.Id, id) { + if !bytes.Equal(ipk.Id[:], id) { t.Error("ToIdPkTs: Id mismatch") } - if !bytes.Equal(ipk.Pub, pub) { + if !bytes.Equal(ipk.Pub[:], pub) { t.Error("ToIdPkTs: Pub mismatch") } if ipk.Ts != 1234567890 { @@ -131,13 +171,7 @@ func TestIdPkTsToEventRef(t *testing.T) { pub[i] = byte(i + 100) } - ipk := &IdPkTs{ - Id: id, - Pub: pub, - Ts: 1234567890, - Ser: 42, - } - + ipk := NewIdPkTs(id, pub, 1234567890, 42) ref := ipk.ToEventRef() // Verify conversion - need addressable values for slicing @@ -157,6 +191,23 @@ func TestIdPkTsToEventRef(t *testing.T) { } } +func BenchmarkIdPkTsCopy(b *testing.B) { + id := make([]byte, 32) + pub := make([]byte, 32) + for i := 0; i < 32; i++ { + id[i] = byte(i) + pub[i] = byte(i + 100) + } + + ipk := NewIdPkTs(id, pub, 1234567890, 42) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + ipk2 := ipk // Copy (should stay on stack) + _ = ipk2 + } +} + func BenchmarkEventRefCopy(b *testing.B) { id := make([]byte, 32) pub := make([]byte, 32) @@ -182,12 +233,7 @@ func BenchmarkIdPkTsToEventRef(b *testing.B) { pub[i] = byte(i + 100) } - ipk := &IdPkTs{ - Id: id, - Pub: pub, - Ts: 1234567890, - Ser: 42, - } + ipk := NewIdPkTs(id, pub, 1234567890, 42) b.ResetTimer() for i := 0; i < b.N; i++ { @@ -215,7 +261,7 @@ func BenchmarkEventRefAccess(b *testing.B) { } } -func BenchmarkIdPkTsFixedAccess(b *testing.B) { +func BenchmarkIdPkTsAccess(b *testing.B) { id := make([]byte, 32) pub := make([]byte, 32) for i := 0; i < 32; i++ { @@ -223,26 +269,55 @@ func BenchmarkIdPkTsFixedAccess(b *testing.B) { pub[i] = byte(i + 100) } - ipk := &IdPkTs{ - Id: id, - Pub: pub, - Ts: 1234567890, - Ser: 42, - } + ipk := NewIdPkTs(id, pub, 1234567890, 42) b.ResetTimer() for i := 0; i < b.N; i++ { - idCopy := ipk.IDFixed() - pubCopy := ipk.PubFixed() + idCopy := ipk.Id + pubCopy := ipk.Pub _ = idCopy _ = pubCopy } } -// Ensure EventRef implements expected interface at compile time -var _ interface { - ID() ntypes.EventID - Pub() ntypes.Pubkey - Ts() int64 - Ser() uint64 -} = EventRef{} +// Ensure types satisfy expected size for stack allocation +func TestStructSizes(t *testing.T) { + var ipk IdPkTs + var ref EventRef + + // Both should be exactly 80 bytes (32+32+8+8) + // This is not directly testable in Go, but we can verify the fields exist + _ = ipk.Id + _ = ipk.Pub + _ = ipk.Ts + _ = ipk.Ser + _ = ref +} + +// Ensure ntypes.EventID and ntypes.Pubkey are used correctly +func TestNtypesCompatibility(t *testing.T) { + var id ntypes.EventID + var pub ntypes.Pubkey + + // Fill with test data + for i := 0; i < 32; i++ { + id[i] = byte(i) + pub[i] = byte(i + 32) + } + + // Create IdPkTs directly with ntypes + ipk := IdPkTs{ + Id: id, + Pub: pub, + Ts: 1234567890, + Ser: 42, + } + + // Verify + if ipk.Id != id { + t.Error("ntypes.EventID should be directly assignable to IdPkTs.Id") + } + if ipk.Pub != pub { + t.Error("ntypes.Pubkey should be directly assignable to IdPkTs.Pub") + } +} diff --git a/pkg/neo4j/fetch-event.go b/pkg/neo4j/fetch-event.go index e045eac..07ab4ee 100644 --- a/pkg/neo4j/fetch-event.go +++ b/pkg/neo4j/fetch-event.go @@ -336,12 +336,8 @@ RETURN e.id AS id, return nil, err } - fidpk = &store.IdPkTs{ - Id: id, - Pub: pubkey, - Ts: createdAt, - Ser: serial, - } + idpkts := store.NewIdPkTs(id, pubkey, createdAt, serial) + fidpk = &idpkts return fidpk, nil } @@ -421,12 +417,8 @@ RETURN e.id AS id, continue } - fidpks = append(fidpks, &store.IdPkTs{ - Id: id, - Pub: pubkey, - Ts: createdAt, - Ser: uint64(serialVal), - }) + idpkts := store.NewIdPkTs(id, pubkey, createdAt, uint64(serialVal)) + fidpks = append(fidpks, &idpkts) } return fidpks, nil diff --git a/pkg/neo4j/query-events.go b/pkg/neo4j/query-events.go index cca64dc..ccfc9a6 100644 --- a/pkg/neo4j/query-events.go +++ b/pkg/neo4j/query-events.go @@ -595,12 +595,8 @@ func (n *N) QueryForIds(c context.Context, f *filter.F) ( continue } - idPkTs = append(idPkTs, &store.IdPkTs{ - Id: id, - Pub: pubkey, - Ts: createdAt, - Ser: uint64(serialVal), - }) + ipkts := store.NewIdPkTs(id, pubkey, createdAt, uint64(serialVal)) + idPkTs = append(idPkTs, &ipkts) } return idPkTs, nil diff --git a/pkg/proto/orlydb/v1/converters.go b/pkg/proto/orlydb/v1/converters.go index 89b02db..1e53573 100644 --- a/pkg/proto/orlydb/v1/converters.go +++ b/pkg/proto/orlydb/v1/converters.go @@ -9,6 +9,7 @@ import ( "git.mleku.dev/mleku/nostr/encoders/kind" "git.mleku.dev/mleku/nostr/encoders/tag" "git.mleku.dev/mleku/nostr/encoders/timestamp" + ntypes "git.mleku.dev/mleku/nostr/types" "next.orly.dev/pkg/database" indextypes "next.orly.dev/pkg/database/indexes/types" "next.orly.dev/pkg/interfaces/store" @@ -271,8 +272,8 @@ func IdPkTsToProto(i *store.IdPkTs) *IdPkTs { return nil } return &IdPkTs{ - Id: i.Id, - Pubkey: i.Pub, + Id: i.Id[:], + Pubkey: i.Pub[:], Timestamp: i.Ts, Serial: i.Ser, } @@ -284,8 +285,8 @@ func ProtoToIdPkTs(pb *IdPkTs) *store.IdPkTs { return nil } return &store.IdPkTs{ - Id: pb.Id, - Pub: pb.Pubkey, + Id: ntypes.EventIDFromBytes(pb.Id), + Pub: ntypes.PubkeyFromBytes(pb.Pubkey), Ts: pb.Timestamp, Ser: pb.Serial, } diff --git a/pkg/version/version b/pkg/version/version index e0d5dc4..a5f6aab 100644 --- a/pkg/version/version +++ b/pkg/version/version @@ -1 +1 @@ -v0.56.5 +v0.56.6