Skip to content

Commit

Permalink
Verify events as late as possible
Browse files Browse the repository at this point in the history
Signature verification is expensive and we get disconnected from relays
a lot.
  • Loading branch information
boreq committed Nov 28, 2023
1 parent c4efea2 commit 75151de
Show file tree
Hide file tree
Showing 9 changed files with 148 additions and 118 deletions.
2 changes: 1 addition & 1 deletion service/adapters/memorypubsub/received_event_pubsub.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func NewReceivedEventPubSub() *ReceivedEventPubSub {
}
}

func (m *ReceivedEventPubSub) Publish(relay domain.RelayAddress, event domain.Event) {
func (m *ReceivedEventPubSub) Publish(relay domain.RelayAddress, event domain.UnverifiedEvent) {
m.pubsub.Publish(
app.NewReceivedEvent(relay, event),
)
Expand Down
6 changes: 3 additions & 3 deletions service/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,18 +77,18 @@ type Application struct {

type ReceivedEvent struct {
relay domain.RelayAddress
event domain.Event
event domain.UnverifiedEvent
}

func NewReceivedEvent(relay domain.RelayAddress, event domain.Event) ReceivedEvent {
func NewReceivedEvent(relay domain.RelayAddress, event domain.UnverifiedEvent) ReceivedEvent {
return ReceivedEvent{relay: relay, event: event}
}

func (r ReceivedEvent) Relay() domain.RelayAddress {
return r.relay
}

func (r ReceivedEvent) Event() domain.Event {
func (r ReceivedEvent) Event() domain.UnverifiedEvent {
return r.event
}

Expand Down
2 changes: 1 addition & 1 deletion service/app/downloader.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ var (
)

type ReceivedEventPublisher interface {
Publish(relay domain.RelayAddress, event domain.Event)
Publish(relay domain.RelayAddress, event domain.UnverifiedEvent)
}

type BootstrapRelaySource interface {
Expand Down
11 changes: 10 additions & 1 deletion service/app/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func NewEventFilter(
}
}

func (f EventFilter) IsOk(event domain.Event) bool {
func (f EventFilter) IsOk(event Event) bool {
if f.filterOlderThan != nil {
maxPastAllowed := time.Now().Add(-*f.filterOlderThan)
if event.CreatedAt().Before(maxPastAllowed) {
Expand All @@ -52,3 +52,12 @@ func (f EventFilter) IsOk(event domain.Event) bool {

return true
}

type Event interface {
Id() domain.EventId
PubKey() domain.PublicKey
CreatedAt() time.Time
Kind() domain.EventKind
Tags() []domain.EventTag
Raw() []byte
}
17 changes: 11 additions & 6 deletions service/app/handler_save_received_event.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ var (

type SaveReceivedEvent struct {
relay domain.RelayAddress
event domain.Event
event domain.UnverifiedEvent
}

func NewSaveReceivedEvent(relay domain.RelayAddress, event domain.Event) SaveReceivedEvent {
func NewSaveReceivedEvent(relay domain.RelayAddress, event domain.UnverifiedEvent) SaveReceivedEvent {
return SaveReceivedEvent{relay: relay, event: event}
}

Expand Down Expand Up @@ -85,11 +85,16 @@ func (h *SaveReceivedEventHandler) Handle(ctx context.Context, cmd SaveReceivedE
return nil
}

if err := adapters.Events.Save(ctx, cmd.event); err != nil {
event, err := domain.NewEventFromUnverifiedEvent(cmd.event)
if err != nil {
return errors.Wrap(err, "error checking if event should be downloaded")
}

if err := adapters.Events.Save(ctx, event); err != nil {
return errors.Wrap(err, "error saving the event")
}

if err := adapters.Publisher.PublishEventSaved(ctx, cmd.event.Id()); err != nil {
if err := adapters.Publisher.PublishEventSaved(ctx, event.Id()); err != nil {
return errors.Wrap(err, "error publishing")
}

Expand All @@ -101,7 +106,7 @@ func (h *SaveReceivedEventHandler) Handle(ctx context.Context, cmd SaveReceivedE
return nil
}

func (h *SaveReceivedEventHandler) shouldBeDownloaded(ctx context.Context, adapters Adapters, event domain.Event) (bool, error) {
func (h *SaveReceivedEventHandler) shouldBeDownloaded(ctx context.Context, adapters Adapters, event domain.UnverifiedEvent) (bool, error) {
if h.shouldBeGloballyDownloaded(event.Kind()) {
return true, nil
}
Expand All @@ -127,7 +132,7 @@ func (h *SaveReceivedEventHandler) shouldBeDownloaded(ctx context.Context, adapt
return false, nil
}

func (h *SaveReceivedEventHandler) shouldBeDirectlyMonitored(ctx context.Context, adapters Adapters, event domain.Event) (bool, error) {
func (h *SaveReceivedEventHandler) shouldBeDirectlyMonitored(ctx context.Context, adapters Adapters, event domain.UnverifiedEvent) (bool, error) {
if _, err := adapters.PublicKeysToMonitor.Get(ctx, event.PubKey()); err != nil {
if errors.Is(err, ErrPublicKeyToMonitorNotFound) {
return false, nil
Expand Down
183 changes: 118 additions & 65 deletions service/domain/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,55 @@ import (
"github.com/planetary-social/nos-event-service/internal"
)

type Event struct {
id EventId
pubKey PublicKey
createdAt time.Time
kind EventKind
tags []EventTag
content string
sig EventSignature
type UnverifiedEvent struct {
event event
}

libevent nostr.Event
func NewUnverifiedEvent(libevent nostr.Event) (UnverifiedEvent, error) {
event, err := newEvent(libevent)
if err != nil {
return UnverifiedEvent{}, errors.Wrap(err, "error creating an event")
}

return UnverifiedEvent{
event: event,
}, nil
}

func (u UnverifiedEvent) Id() EventId {
return u.event.id
}

func (u UnverifiedEvent) PubKey() PublicKey {
return u.event.pubKey
}

func (u UnverifiedEvent) CreatedAt() time.Time {
return u.event.createdAt
}

func (u UnverifiedEvent) Kind() EventKind {
return u.event.kind
}

func (u UnverifiedEvent) Tags() []EventTag {
return internal.CopySlice(u.event.tags)
}

func (u UnverifiedEvent) Raw() []byte {
j, err := u.event.libevent.MarshalJSON()
if err != nil {
panic(err)
}
return j
}

func (e UnverifiedEvent) String() string {
return string(e.Raw())
}

type Event struct {
event event
}

func NewEventFromRaw(raw []byte) (Event, error) {
Expand All @@ -31,81 +70,49 @@ func NewEventFromRaw(raw []byte) (Event, error) {
}

func NewEvent(libevent nostr.Event) (Event, error) {
ok, err := libevent.CheckSignature()
unverifiedEvent, err := NewUnverifiedEvent(libevent)
if err != nil {
return Event{}, errors.Wrap(err, "error checking signature")
return Event{}, errors.Wrap(err, "error creating an unverified event")
}

if !ok {
return Event{}, errors.New("invalid signature")
}

id, err := NewEventIdFromHex(libevent.ID)
if err != nil {
return Event{}, errors.Wrap(err, "error creating an event id")
}

pubKey, err := NewPublicKeyFromHex(libevent.PubKey)
if err != nil {
return Event{}, errors.Wrap(err, "error creating a pub key")
}

createdAt := time.Unix(int64(libevent.CreatedAt), 0).UTC()
return NewEventFromUnverifiedEvent(unverifiedEvent)
}

kind, err := NewEventKind(libevent.Kind)
func NewEventFromUnverifiedEvent(event UnverifiedEvent) (Event, error) {
ok, err := event.event.libevent.CheckSignature()
if err != nil {
return Event{}, errors.Wrap(err, "error creating event kind")
}

var tags []EventTag
for _, libtag := range libevent.Tags {
eventTag, err := NewEventTag(libtag)
if err != nil {
return Event{}, errors.Wrap(err, "error creating a tag")
}
tags = append(tags, eventTag)
return Event{}, errors.Wrap(err, "error checking signature")
}

sig, err := NewEventSignature(libevent.Sig)
if err != nil {
return Event{}, errors.Wrap(err, "error creating a signature")
if !ok {
return Event{}, errors.New("invalid signature")
}

return Event{
id: id,
pubKey: pubKey,
createdAt: createdAt,
kind: kind,
tags: tags,
content: libevent.Content,
sig: sig,

libevent: libevent,
}, nil
return Event(event), nil
}

func (e Event) Id() EventId {
return e.id
return e.event.id
}

func (e Event) PubKey() PublicKey {
return e.pubKey
return e.event.pubKey
}

func (e Event) CreatedAt() time.Time {
return e.createdAt
return e.event.createdAt
}

func (e Event) Kind() EventKind {
return e.kind
return e.event.kind
}

func (e Event) Tags() []EventTag {
return internal.CopySlice(e.tags)
return internal.CopySlice(e.event.tags)
}

func (e Event) HasInvalidProfileTags() bool {
for _, tag := range e.tags {
for _, tag := range e.event.tags {
if !tag.IsProfile() {
continue
}
Expand All @@ -118,23 +125,19 @@ func (e Event) HasInvalidProfileTags() bool {
}

func (e Event) Content() string {
return e.content
}

func (e Event) Sig() EventSignature {
return e.sig
return e.event.content
}

func (e Event) Libevent() nostr.Event {
return e.libevent
return e.event.libevent
}

func (e Event) MarshalJSON() ([]byte, error) {
return e.libevent.MarshalJSON()
return e.event.libevent.MarshalJSON()
}

func (e Event) Raw() []byte {
j, err := e.libevent.MarshalJSON()
j, err := e.event.libevent.MarshalJSON()
if err != nil {
panic(err)
}
Expand All @@ -144,3 +147,53 @@ func (e Event) Raw() []byte {
func (e Event) String() string {
return string(e.Raw())
}

type event struct {
id EventId
pubKey PublicKey
createdAt time.Time
kind EventKind
tags []EventTag
content string

libevent nostr.Event
}

func newEvent(libevent nostr.Event) (event, error) {
id, err := NewEventIdFromHex(libevent.ID)
if err != nil {
return event{}, errors.Wrap(err, "error creating an event id")
}

pubKey, err := NewPublicKeyFromHex(libevent.PubKey)
if err != nil {
return event{}, errors.Wrap(err, "error creating a pub key")
}

createdAt := time.Unix(int64(libevent.CreatedAt), 0).UTC()

kind, err := NewEventKind(libevent.Kind)
if err != nil {
return event{}, errors.Wrap(err, "error creating event kind")
}

var tags []EventTag
for _, libtag := range libevent.Tags {
eventTag, err := NewEventTag(libtag)
if err != nil {
return event{}, errors.Wrap(err, "error creating a tag")
}
tags = append(tags, eventTag)
}

return event{
id: id,
pubKey: pubKey,
createdAt: createdAt,
kind: kind,
tags: tags,
content: libevent.Content,

libevent: libevent,
}, nil
}
37 changes: 0 additions & 37 deletions service/domain/event_signature.go

This file was deleted.

Loading

0 comments on commit 75151de

Please sign in to comment.