diff --git a/event/canonical.go b/event/canonical.go new file mode 100644 index 0000000..c58ae7c --- /dev/null +++ b/event/canonical.go @@ -0,0 +1,109 @@ +package event + +import ( + "reflect" + + "realy.lol/hex" + "realy.lol/json" + "realy.lol/kind" + "realy.lol/tags" + "realy.lol/text" + "realy.lol/timestamp" +) + +// ToCanonical converts the event to the canonical encoding used to derive the +// event ID. +func (ev *T) ToCanonical(dst by) (b by) { + b = dst + b = append(b, "[0,\""...) + b = hex.EncAppend(b, ev.PubKey) + b = append(b, "\","...) + b = ev.CreatedAt.Marshal(b) + b = append(b, ',') + b = ev.Kind.Marshal(b) + b = append(b, ',') + b = ev.Tags.Marshal(b) + b = append(b, ',') + b = text.AppendQuote(b, ev.Content, text.NostrEscape) + b = append(b, ']') + return +} + +// GetIDBytes returns the raw SHA256 hash of the canonical form of an T. +func (ev *T) GetIDBytes() by { return Hash(ev.ToCanonical(nil)) } + +func NewCanonical() (a *json.Array) { + a = &json.Array{ + V: []json.I{ + &json.Unsigned{}, // 0 + &json.Hex{}, // pubkey + ×tamp.T{}, // created_at + &kind.T{}, // kind + &tags.T{}, // tags + &json.String{}, // content + }, + } + return +} + +func FromCanonical(b by) (ev *T, rem by, err er) { + id := Hash(b) + c := NewCanonical() + if rem, err = c.Unmarshal(b); chk.E(err) { + return + } + if len(rem) > 0 { + log.I.F("rem %s", rem) + } + // unwrap the array + x := (*c).V + if v, ok := x[0].(*json.Unsigned); !ok { + err = errorf.E("did not encode expected type in first field of canonical event %v %v", + reflect.TypeOf(x[0]), x[0]) + return + } else { + if v.V != 0 { + err = errorf.E("unexpected value %d in first field of canonical event, expect 0", v.V) + return + } + } + // create the event, use the ID hash to populate the ID + ev = &T{ID: id} + // unwrap the pubkey + if v, ok := x[1].(*json.Hex); !ok { + err = errorf.E("failed to decode pubkey from canonical form of event %s", b) + return + } else { + ev.PubKey = v.V + } + // populate the timestamp field + if v, ok := x[2].(*timestamp.T); !ok { + err = errorf.E("did not encode expected type in third (created_at) field of canonical event %v %v", + reflect.TypeOf(x[0]), x[0]) + } else { + ev.CreatedAt = v + } + // populate the kind field + if v, ok := x[3].(*kind.T); !ok { + err = errorf.E("did not encode expected type in fourth (kind) field of canonical event %v %v", + reflect.TypeOf(x[0]), x[0]) + } else { + ev.Kind = v + } + // populate the tags field + if v, ok := x[3].(*tags.T); !ok { + err = errorf.E("did not encode expected type in fourth (tags) field of canonical event %v %v", + reflect.TypeOf(x[0]), x[0]) + } else { + ev.Tags = v + } + // populate the content field + if v, ok := x[3].(*json.String); !ok { + err = errorf.E("did not encode expected type in fourth (content) field of canonical event %v %v", + reflect.TypeOf(x[0]), x[0]) + } else { + ev.Content = v.V + } + + return +} diff --git a/event/codectester/divider/main.go b/event/codectester/divider/main.go index 613b1bd..a61b823 100644 --- a/event/codectester/divider/main.go +++ b/event/codectester/divider/main.go @@ -93,7 +93,7 @@ func main() { if len(rem) > 0 { log.I.F("remainder:\n%s", rem) } - can := ev.ToCanonical() + can := ev.ToCanonical(nil) eh := event.Hash(can) eq := equals(ev.ID, eh) if !eq { diff --git a/event/event.go b/event/event.go index 2e8bb5b..7987667 100644 --- a/event/event.go +++ b/event/event.go @@ -40,7 +40,7 @@ type T struct { type Ts []*T func (ev Ts) Len() no { return len(ev) } -func (ev Ts) Less(i, j no) bo { return *ev[i].CreatedAt > *ev[j].CreatedAt } +func (ev Ts) Less(i, j no) bo { return ev[i].CreatedAt.I64() > ev[j].CreatedAt.I64() } func (ev Ts) Swap(i, j no) { ev[i], ev[j] = ev[j], ev[i] } type C chan *T @@ -49,21 +49,6 @@ func New() (ev *T) { return &T{} } func (ev *T) Serialize() (b by) { return ev.Marshal(nil) } -func (ev *T) ToCanonical() (b by) { - b = append(b, "[0,\""...) - b = hex.EncAppend(b, ev.PubKey) - b = append(b, "\","...) - b = ev.CreatedAt.Marshal(b) - b = append(b, ',') - b = ev.Kind.Marshal(b) - b = append(b, ',') - b = ev.Tags.Marshal(b) - b = append(b, ',') - b = text.AppendQuote(b, ev.Content, text.NostrEscape) - b = append(b, ']') - return -} - // stringy functions for retarded other libraries func (ev *T) IDString() (s st) { return hex.Enc(ev.ID) } @@ -78,9 +63,6 @@ func Hash(in by) (out by) { return h[:] } -// GetIDBytes returns the raw SHA256 hash of the canonical form of an T. -func (ev *T) GetIDBytes() by { return Hash(ev.ToCanonical()) } - func GenerateRandomTextNoteEvent(sign signer.I, maxSize no) (ev *T, err er) { diff --git a/event/sort.go b/event/sort.go index 0d77a37..51df536 100644 --- a/event/sort.go +++ b/event/sort.go @@ -4,7 +4,7 @@ package event type Ascending []*T func (ev Ascending) Len() no { return len(ev) } -func (ev Ascending) Less(i, j no) bo { return *ev[i].CreatedAt < *ev[j].CreatedAt } +func (ev Ascending) Less(i, j no) bo { return ev[i].CreatedAt.I64() < ev[j].CreatedAt.I64() } func (ev Ascending) Swap(i, j no) { ev[i], ev[j] = ev[j], ev[i] } // Descending sorts a slice of events in reverse chronological order (newest @@ -12,5 +12,5 @@ func (ev Ascending) Swap(i, j no) { ev[i], ev[j] = ev[j], ev[i] } type Descending []*T func (e Descending) Len() no { return len(e) } -func (e Descending) Less(i, j no) bo { return *e[i].CreatedAt > *e[j].CreatedAt } +func (e Descending) Less(i, j no) bo { return e[i].CreatedAt.I64() > e[j].CreatedAt.I64() } func (e Descending) Swap(i, j no) { e[i], e[j] = e[j], e[i] } diff --git a/filter/filter.go b/filter/filter.go index 30e3e36..55d090f 100644 --- a/filter/filter.go +++ b/filter/filter.go @@ -553,8 +553,7 @@ func GenFilter() (f *T, err er) { } } tn := no(timestamp.Now().I64()) - before := timestamp.T(tn - frand.Intn(10000)) - f.Since = &before + f.Since = ×tamp.T{int64(tn - frand.Intn(10000))} f.Until = timestamp.Now() f.Search = by("token search text") return diff --git a/ints/ints.go b/ints/ints.go index 98e310b..a48c890 100644 --- a/ints/ints.go +++ b/ints/ints.go @@ -21,6 +21,7 @@ func New[V uint | no | uint64 | uint32 | uint16 | uint8 | int64 | int32 | int16 } func (n *T) Uint64() uint64 { return n.N } +func (n *T) Int64() int64 { return int64(n.N) } func (n *T) Uint16() uint16 { return uint16(n.N) } var powers = []*T{ diff --git a/ratel/keys/createdat/createdat.go b/ratel/keys/createdat/createdat.go index 3ba6822..a210b97 100644 --- a/ratel/keys/createdat/createdat.go +++ b/ratel/keys/createdat/createdat.go @@ -19,9 +19,7 @@ var _ keys.Element = &T{} func New(c *timestamp.T) (p *T) { return &T{Val: c} } -func (c *T) Write(buf *bytes.Buffer) { - buf.Write(c.Val.Bytes()) -} +func (c *T) Write(buf *bytes.Buffer) { buf.Write(c.Val.Bytes()) } func (c *T) Read(buf *bytes.Buffer) (el keys.Element) { b := make(by, Len) diff --git a/ratel/preparequeries.go b/ratel/preparequeries.go index bfad490..91a85c1 100644 --- a/ratel/preparequeries.go +++ b/ratel/preparequeries.go @@ -158,18 +158,18 @@ func PrepareQueries(f *filter.T) ( } // log.T.S("other", qs) } - var until uint64 = math.MaxUint64 + var until int64 = math.MaxInt64 if f.Until != nil { - if fu := uint64(*f.Until); fu < until { + if fu := f.Until.I64(); fu < until { until = fu - 1 } } for i, q := range qs { - qs[i].start = binary.BigEndian.AppendUint64(q.searchPrefix, until) + qs[i].start = binary.BigEndian.AppendUint64(q.searchPrefix, uint64(until)) } // this is where we'll end the iteration if f.Since != nil { - if fs := uint64(*f.Since); fs > since { + if fs := f.Since.U64(); fs > since { since = fs } } diff --git a/realy/version b/realy/version index 33e7b42..8a4bd6c 100644 --- a/realy/version +++ b/realy/version @@ -1 +1 @@ -v1.2.40 \ No newline at end of file +v1.2.41 \ No newline at end of file diff --git a/timestamp/timestamp.go b/timestamp/timestamp.go index 376ae84..026bdfc 100644 --- a/timestamp/timestamp.go +++ b/timestamp/timestamp.go @@ -10,16 +10,13 @@ import ( // T is a convenience type for UNIX 64 bit timestamps of 1 second // precision. -type T int64 +type T struct{ V int64 } -func New() (t *T) { - tt := T(0) - return &tt -} +func New() (t *T) { return &T{} } // Now returns the current UNIX timestamp of the current second. func Now() *T { - tt := T(time.Now().Unix()) + tt := T{time.Now().Unix()} return &tt } @@ -28,7 +25,7 @@ func (t *T) U64() uint64 { if t == nil { return 0 } - return uint64(*t) + return uint64(t.V) } // I64 returns the current UNIX timestamp of the current second as int64. @@ -36,45 +33,37 @@ func (t *T) I64() int64 { if t == nil { return 0 } - return int64(*t) + return t.V } // Time converts a timestamp.Time value into a canonical UNIX 64 bit 1 second // precision timestamp. -func (t *T) Time() time.Time { return time.Unix(int64(*t), 0) } +func (t *T) Time() time.Time { return time.Unix(t.V, 0) } // Int returns the timestamp as an int. func (t *T) Int() no { if t == nil { return 0 } - return no(*t) + return no(t.V) } func (t *T) Bytes() (b by) { b = make(by, 8) - binary.BigEndian.PutUint64(b, uint64(*t)) + binary.BigEndian.PutUint64(b, uint64(t.V)) return } // FromTime returns a T from a time.Time -func FromTime(t time.Time) *T { - tt := T(t.Unix()) - return &tt -} +func FromTime(t time.Time) *T { return &T{t.Unix()} } // FromUnix converts from a standard int64 unix timestamp. -func FromUnix(t int64) *T { - tt := T(t) - return &tt -} -func (t *T) FromInt(i no) { *t = T(i) } +func FromUnix(t int64) *T { return &T{t} } + +func (t *T) FromInt(i no) { *t = T{int64(i)} } // FromBytes converts from a string of raw bytes. -func FromBytes(b by) *T { - tt := T(binary.BigEndian.Uint64(b)) - return &tt -} +func FromBytes(b by) *T { return &T{int64(binary.BigEndian.Uint64(b))} } func FromVarint(b by) (t *T, rem by, err er) { n, read := binary.Varint(b) @@ -82,13 +71,12 @@ func FromVarint(b by) (t *T, rem by, err er) { err = errorf.E("failed to decode varint timestamp %v", b) return } - tt := T(n) - t = &tt + t = &T{n} rem = b[:read] return } -func ToVarint(dst by, t *T) by { return binary.AppendVarint(dst, int64(*t)) } +func ToVarint(dst by, t *T) by { return binary.AppendVarint(dst, t.V) } func (t *T) FromVarint(dst by) (b by) { return ToVarint(dst, t) } @@ -99,14 +87,11 @@ func (t *T) String() (s st) { return unsafe.String(&b[0], len(b)) } -func (t *T) Marshal(dst by) (b by) { - tt := ints.New(t.U64()) - return tt.Marshal(dst) -} +func (t *T) Marshal(dst by) (b by) { return ints.New(t.U64()).Marshal(dst) } func (t *T) Unmarshal(b by) (r by, err er) { n := ints.New(0) r, err = n.Unmarshal(b) - *t = T(n.Uint64()) + *t = T{n.Int64()} return } diff --git a/ws/pool.go b/ws/pool.go index 00d114e..2a19e0c 100644 --- a/ws/pool.go +++ b/ws/pool.go @@ -149,7 +149,7 @@ func (pool *SimplePool) subMany(c cx, urls []st, ff *filters.T, ctx, cancel := context.Cancel(c) _ = cancel // do this so `go vet` will stop complaining events := make(chan IncomingEvent) - seenAlready := xsync.NewMapOf[st, timestamp.T]() + seenAlready := xsync.NewMapOf[st, *timestamp.T]() ticker := time.NewTicker(time.Duration(seenAlreadyDropTick) * time.Second) eose := false pending := xsync.NewCounter() @@ -215,7 +215,7 @@ func (pool *SimplePool) subMany(c cx, urls []st, ff *filters.T, } if unique { if _, seen := seenAlready.LoadOrStore(evt.EventID().String(), - *evt.CreatedAt); seen { + evt.CreatedAt); seen { continue } } @@ -225,9 +225,9 @@ func (pool *SimplePool) subMany(c cx, urls []st, ff *filters.T, } case <-ticker.C: if eose { - old := timestamp.T(timestamp.Now().Int() - seenAlreadyDropTick) - seenAlready.Range(func(id st, value timestamp.T) bo { - if value < old { + old := ×tamp.T{int64(timestamp.Now().Int() - seenAlreadyDropTick)} + seenAlready.Range(func(id st, value *timestamp.T) bo { + if value.I64() < old.I64() { seenAlready.Delete(id) } return true