tests run (but not pass) and fine-tuning (specially tag filters) on filter_easyjson.go

This commit is contained in:
fiatjaf 2023-04-16 16:12:42 -03:00
parent 0a3e898c2f
commit c42059f4b4
No known key found for this signature in database
GPG Key ID: BAD43C4BE5C1A3A1
12 changed files with 116 additions and 129 deletions

View File

@ -4,7 +4,6 @@ import (
"crypto/sha256" "crypto/sha256"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"time"
"github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcec/v2/schnorr" "github.com/btcsuite/btcd/btcec/v2/schnorr"
@ -24,12 +23,6 @@ type Event struct {
extra map[string]any extra map[string]any
} }
type Timestamp int64
func (t Timestamp) Time() time.Time {
return time.Unix(int64(t), 0)
}
const ( const (
KindSetMetadata int = 0 KindSetMetadata int = 0
KindTextNote int = 1 KindTextNote int = 1

View File

@ -27,6 +27,7 @@ func easyjsonF642ad3eDecodeGithubComNbdWtfGoNostr(in *jlexer.Lexer, out *Event)
in.Skip() in.Skip()
return return
} }
out.extra = make(map[string]any)
in.Delim('{') in.Delim('{')
for !in.IsDelim('}') { for !in.IsDelim('}') {
key := in.UnsafeFieldName(true) key := in.UnsafeFieldName(true)

View File

@ -3,7 +3,6 @@ package nostr
import ( import (
"encoding/json" "encoding/json"
"testing" "testing"
"time"
) )
func TestEventParsingAndVerifying(t *testing.T) { func TestEventParsingAndVerifying(t *testing.T) {
@ -47,7 +46,7 @@ func TestEventSerialization(t *testing.T) {
ID: "92570b321da503eac8014b23447301eb3d0bbdfbace0d11a4e4072e72bb7205d", ID: "92570b321da503eac8014b23447301eb3d0bbdfbace0d11a4e4072e72bb7205d",
PubKey: "e9142f724955c5854de36324dab0434f97b15ec6b33464d56ebe491e3f559d1b", PubKey: "e9142f724955c5854de36324dab0434f97b15ec6b33464d56ebe491e3f559d1b",
Kind: 4, Kind: 4,
CreatedAt: time.Unix(1671028682, 0), CreatedAt: Timestamp(1671028682),
Tags: Tags{Tag{"p", "f8340b2bde651576b75af61aa26c80e13c65029f00f7f64004eece679bf7059f"}}, Tags: Tags{Tag{"p", "f8340b2bde651576b75af61aa26c80e13c65029f00f7f64004eece679bf7059f"}},
Content: "you say yes, I say no", Content: "you say yes, I say no",
Sig: "ed08d2dd5b0f7b6a3cdc74643d4adee3158ddede9cc848e8cd97630c097001acc2d052d2d3ec2b7ac4708b2314b797106d1b3c107322e61b5e5cc2116e099b79", Sig: "ed08d2dd5b0f7b6a3cdc74643d4adee3158ddede9cc848e8cd97630c097001acc2d052d2d3ec2b7ac4708b2314b797106d1b3c107322e61b5e5cc2116e099b79",
@ -68,7 +67,7 @@ func TestEventSerialization(t *testing.T) {
} }
if evt.ID != re.ID || evt.PubKey != re.PubKey || evt.Content != re.Content || if evt.ID != re.ID || evt.PubKey != re.PubKey || evt.Content != re.Content ||
!evt.CreatedAt.Equal(re.CreatedAt) || evt.Sig != re.Sig || evt.CreatedAt != re.CreatedAt || evt.Sig != re.Sig ||
len(evt.Tags) != len(evt.Tags) { len(evt.Tags) != len(evt.Tags) {
t.Error("reparsed event differs from original") t.Error("reparsed event differs from original")
} }
@ -93,7 +92,7 @@ func TestEventSerializationWithExtraFields(t *testing.T) {
ID: "92570b321da503eac8014b23447301eb3d0bbdfbace0d11a4e4072e72bb7205d", ID: "92570b321da503eac8014b23447301eb3d0bbdfbace0d11a4e4072e72bb7205d",
PubKey: "e9142f724955c5854de36324dab0434f97b15ec6b33464d56ebe491e3f559d1b", PubKey: "e9142f724955c5854de36324dab0434f97b15ec6b33464d56ebe491e3f559d1b",
Kind: 7, Kind: 7,
CreatedAt: time.Unix(1671028682, 0), CreatedAt: Timestamp(1671028682),
Content: "there is an extra field here", Content: "there is an extra field here",
Sig: "ed08d2dd5b0f7b6a3cdc74643d4adee3158ddede9cc848e8cd97630c097001acc2d052d2d3ec2b7ac4708b2314b797106d1b3c107322e61b5e5cc2116e099b79", Sig: "ed08d2dd5b0f7b6a3cdc74643d4adee3158ddede9cc848e8cd97630c097001acc2d052d2d3ec2b7ac4708b2314b797106d1b3c107322e61b5e5cc2116e099b79",
} }
@ -115,7 +114,7 @@ func TestEventSerializationWithExtraFields(t *testing.T) {
} }
if evt.ID != re.ID || evt.PubKey != re.PubKey || evt.Content != re.Content || if evt.ID != re.ID || evt.PubKey != re.PubKey || evt.Content != re.Content ||
!evt.CreatedAt.Equal(re.CreatedAt) || evt.Sig != re.Sig || evt.CreatedAt != re.CreatedAt || evt.Sig != re.Sig ||
len(evt.Tags) != len(evt.Tags) { len(evt.Tags) != len(evt.Tags) {
t.Error("reparsed event differs from original") t.Error("reparsed event differs from original")
} }

View File

@ -9,14 +9,14 @@ import (
type Filters []Filter type Filters []Filter
type Filter struct { type Filter struct {
IDs []string IDs []string `json:"ids"`
Kinds []int Kinds []int `json:"kinds"`
Authors []string Authors []string `json:"authors"`
Tags TagMap Tags TagMap `json:"-"`
Since Timestamp Since *Timestamp `json:"since"`
Until Timestamp Until *Timestamp `json:"until"`
Limit int Limit int `json:"limit"`
Search string Search string `json:"search"`
} }
type TagMap map[string][]string type TagMap map[string][]string
@ -63,11 +63,11 @@ func (ef Filter) Matches(event *Event) bool {
} }
} }
if event.CreatedAt < ef.Since { if ef.Since != nil && event.CreatedAt < *ef.Since {
return false return false
} }
if ef.Until != 0 && event.CreatedAt > ef.Until { if ef.Until != nil && event.CreatedAt > *ef.Until {
return false return false
} }

View File

@ -4,6 +4,7 @@ package nostr
import ( import (
json "encoding/json" json "encoding/json"
easyjson "github.com/mailru/easyjson" easyjson "github.com/mailru/easyjson"
jlexer "github.com/mailru/easyjson/jlexer" jlexer "github.com/mailru/easyjson/jlexer"
jwriter "github.com/mailru/easyjson/jwriter" jwriter "github.com/mailru/easyjson/jwriter"
@ -26,6 +27,7 @@ func easyjson4d398eaaDecodeGithubComNbdWtfGoNostr(in *jlexer.Lexer, out *Filter)
in.Skip() in.Skip()
return return
} }
out.Tags = make(TagMap)
in.Delim('{') in.Delim('{')
for !in.IsDelim('}') { for !in.IsDelim('}') {
key := in.UnsafeFieldName(false) key := in.UnsafeFieldName(false)
@ -36,7 +38,7 @@ func easyjson4d398eaaDecodeGithubComNbdWtfGoNostr(in *jlexer.Lexer, out *Filter)
continue continue
} }
switch key { switch key {
case "IDs": case "ids":
if in.IsNull() { if in.IsNull() {
in.Skip() in.Skip()
out.IDs = nil out.IDs = nil
@ -44,7 +46,7 @@ func easyjson4d398eaaDecodeGithubComNbdWtfGoNostr(in *jlexer.Lexer, out *Filter)
in.Delim('[') in.Delim('[')
if out.IDs == nil { if out.IDs == nil {
if !in.IsDelim(']') { if !in.IsDelim(']') {
out.IDs = make([]string, 0, 4) out.IDs = make([]string, 0, 20)
} else { } else {
out.IDs = []string{} out.IDs = []string{}
} }
@ -59,7 +61,7 @@ func easyjson4d398eaaDecodeGithubComNbdWtfGoNostr(in *jlexer.Lexer, out *Filter)
} }
in.Delim(']') in.Delim(']')
} }
case "Kinds": case "kinds":
if in.IsNull() { if in.IsNull() {
in.Skip() in.Skip()
out.Kinds = nil out.Kinds = nil
@ -82,7 +84,7 @@ func easyjson4d398eaaDecodeGithubComNbdWtfGoNostr(in *jlexer.Lexer, out *Filter)
} }
in.Delim(']') in.Delim(']')
} }
case "Authors": case "authors":
if in.IsNull() { if in.IsNull() {
in.Skip() in.Skip()
out.Authors = nil out.Authors = nil
@ -90,7 +92,7 @@ func easyjson4d398eaaDecodeGithubComNbdWtfGoNostr(in *jlexer.Lexer, out *Filter)
in.Delim('[') in.Delim('[')
if out.Authors == nil { if out.Authors == nil {
if !in.IsDelim(']') { if !in.IsDelim(']') {
out.Authors = make([]string, 0, 4) out.Authors = make([]string, 0, 40)
} else { } else {
out.Authors = []string{} out.Authors = []string{}
} }
@ -105,53 +107,56 @@ func easyjson4d398eaaDecodeGithubComNbdWtfGoNostr(in *jlexer.Lexer, out *Filter)
} }
in.Delim(']') in.Delim(']')
} }
case "Tags": case "since":
if in.IsNull() { if in.IsNull() {
in.Skip() in.Skip()
out.Since = nil
} else { } else {
in.Delim('{') if out.Since == nil {
out.Tags = make(TagMap) out.Since = new(Timestamp)
for !in.IsDelim('}') {
key := string(in.String())
in.WantColon()
var v4 []string
if in.IsNull() {
in.Skip()
v4 = nil
} else {
in.Delim('[')
if v4 == nil {
if !in.IsDelim(']') {
v4 = make([]string, 0, 4)
} else {
v4 = []string{}
}
} else {
v4 = (v4)[:0]
}
for !in.IsDelim(']') {
var v5 string
v5 = string(in.String())
v4 = append(v4, v5)
in.WantComma()
}
in.Delim(']')
}
(out.Tags)[key] = v4
in.WantComma()
} }
in.Delim('}') *out.Since = Timestamp(in.Int64())
} }
case "Since": case "until":
out.Since = Timestamp(in.Int64()) if in.IsNull() {
case "Until": in.Skip()
out.Until = Timestamp(in.Int64()) out.Until = nil
case "Limit": } else {
if out.Until == nil {
out.Until = new(Timestamp)
}
*out.Until = Timestamp(in.Int64())
}
case "limit":
out.Limit = int(in.Int()) out.Limit = int(in.Int())
case "Search": case "search":
out.Search = string(in.String()) out.Search = string(in.String())
default: default:
in.SkipRecursive() if len(key) > 1 && key[0] == '#' {
tagValues := make([]string, 0, 40)
if !in.IsNull() {
in.Delim('[')
if out.Authors == nil {
if !in.IsDelim(']') {
tagValues = make([]string, 0, 4)
} else {
tagValues = []string{}
}
} else {
tagValues = (tagValues)[:0]
}
for !in.IsDelim(']') {
var v3 string
v3 = string(in.String())
tagValues = append(tagValues, v3)
in.WantComma()
}
in.Delim(']')
}
out.Tags[key[1:]] = tagValues
} else {
in.SkipRecursive()
}
} }
in.WantComma() in.WantComma()
} }
@ -160,107 +165,84 @@ func easyjson4d398eaaDecodeGithubComNbdWtfGoNostr(in *jlexer.Lexer, out *Filter)
in.Consumed() in.Consumed()
} }
} }
func easyjson4d398eaaEncodeGithubComNbdWtfGoNostr(out *jwriter.Writer, in Filter) { func easyjson4d398eaaEncodeGithubComNbdWtfGoNostr(out *jwriter.Writer, in Filter) {
out.RawByte('{') out.RawByte('{')
first := true first := true
_ = first _ = first
{ {
const prefix string = ",\"IDs\":" const prefix string = ",\"ids\":"
out.RawString(prefix[1:]) out.RawString(prefix[1:])
if in.IDs == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 { if in.IDs == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
out.RawString("null") out.RawString("null")
} else { } else {
out.RawByte('[') out.RawByte('[')
for v6, v7 := range in.IDs { for v4, v5 := range in.IDs {
if v6 > 0 { if v4 > 0 {
out.RawByte(',') out.RawByte(',')
} }
out.String(string(v7)) out.String(string(v5))
} }
out.RawByte(']') out.RawByte(']')
} }
} }
{ {
const prefix string = ",\"Kinds\":" const prefix string = ",\"kinds\":"
out.RawString(prefix) out.RawString(prefix)
if in.Kinds == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 { if in.Kinds == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
out.RawString("null") out.RawString("null")
} else { } else {
out.RawByte('[') out.RawByte('[')
for v8, v9 := range in.Kinds { for v6, v7 := range in.Kinds {
if v8 > 0 { if v6 > 0 {
out.RawByte(',') out.RawByte(',')
} }
out.Int(int(v9)) out.Int(int(v7))
} }
out.RawByte(']') out.RawByte(']')
} }
} }
{ {
const prefix string = ",\"Authors\":" const prefix string = ",\"authors\":"
out.RawString(prefix) out.RawString(prefix)
if in.Authors == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 { if in.Authors == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
out.RawString("null") out.RawString("null")
} else { } else {
out.RawByte('[') out.RawByte('[')
for v10, v11 := range in.Authors { for v8, v9 := range in.Authors {
if v10 > 0 { if v8 > 0 {
out.RawByte(',') out.RawByte(',')
} }
out.String(string(v11)) out.String(string(v9))
} }
out.RawByte(']') out.RawByte(']')
} }
} }
{ {
const prefix string = ",\"Tags\":" const prefix string = ",\"since\":"
out.RawString(prefix) out.RawString(prefix)
if in.Tags == nil && (out.Flags&jwriter.NilMapAsEmpty) == 0 { if in.Since == nil {
out.RawString(`null`) out.RawString("null")
} else { } else {
out.RawByte('{') out.Int64(int64(*in.Since))
v12First := true
for v12Name, v12Value := range in.Tags {
if v12First {
v12First = false
} else {
out.RawByte(',')
}
out.String(string(v12Name))
out.RawByte(':')
if v12Value == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
out.RawString("null")
} else {
out.RawByte('[')
for v13, v14 := range v12Value {
if v13 > 0 {
out.RawByte(',')
}
out.String(string(v14))
}
out.RawByte(']')
}
}
out.RawByte('}')
} }
} }
{ {
const prefix string = ",\"Since\":" const prefix string = ",\"until\":"
out.RawString(prefix) out.RawString(prefix)
out.Int64(int64(in.Since)) if in.Until == nil {
out.RawString("null")
} else {
out.Int64(int64(*in.Until))
}
} }
{ {
const prefix string = ",\"Until\":" const prefix string = ",\"limit\":"
out.RawString(prefix)
out.Int64(int64(in.Until))
}
{
const prefix string = ",\"Limit\":"
out.RawString(prefix) out.RawString(prefix)
out.Int(int(in.Limit)) out.Int(int(in.Limit))
} }
{ {
const prefix string = ",\"Search\":" const prefix string = ",\"search\":"
out.RawString(prefix) out.RawString(prefix)
out.String(string(in.Search)) out.String(string(in.Search))
} }

View File

@ -3,7 +3,6 @@ package nostr
import ( import (
"encoding/json" "encoding/json"
"testing" "testing"
"time"
"golang.org/x/exp/slices" "golang.org/x/exp/slices"
) )
@ -16,7 +15,7 @@ func TestFilterUnmarshal(t *testing.T) {
t.Errorf("failed to parse filter json: %v", err) t.Errorf("failed to parse filter json: %v", err)
} }
if f.Since == nil || f.Since.UTC().Format("2006-01-02") != "2022-02-07" || if f.Since == nil || f.Since.Time().UTC().Format("2006-01-02") != "2022-02-07" ||
f.Until != nil || f.Until != nil ||
f.Tags == nil || len(f.Tags) != 2 || !slices.Contains(f.Tags["something"], "bab") || f.Tags == nil || len(f.Tags) != 2 || !slices.Contains(f.Tags["something"], "bab") ||
f.Search != "test" { f.Search != "test" {
@ -25,12 +24,11 @@ func TestFilterUnmarshal(t *testing.T) {
} }
func TestFilterMarshal(t *testing.T) { func TestFilterMarshal(t *testing.T) {
tm := time.Unix(12345678, 0) until := Timestamp(12345678)
filterj, err := json.Marshal(Filter{ filterj, err := json.Marshal(Filter{
Kinds: []int{1, 2, 4}, Kinds: []int{1, 2, 4},
Tags: TagMap{"fruit": {"banana", "mango"}}, Tags: TagMap{"fruit": {"banana", "mango"}},
Until: &tm, Until: &until,
}) })
if err != nil { if err != nil {
t.Errorf("failed to marshal filter json: %v", err) t.Errorf("failed to marshal filter json: %v", err)
@ -93,7 +91,7 @@ func TestFilterEquality(t *testing.T) {
t.Error("kind+tags filters should be equal") t.Error("kind+tags filters should be equal")
} }
tm := time.Now() tm := Now()
if !FilterEqual( if !FilterEqual(
Filter{ Filter{
Kinds: []int{4, 5}, Kinds: []int{4, 5},

View File

@ -64,7 +64,7 @@ func Generate(event *nostr.Event, targetDifficulty int, timeout time.Duration) (
for { for {
nonce++ nonce++
tag[1] = strconv.FormatUint(nonce, 10) tag[1] = strconv.FormatUint(nonce, 10)
event.CreatedAt = time.Now() event.CreatedAt = nostr.Now()
if Difficulty(event.GetID()) >= targetDifficulty { if Difficulty(event.GetID()) >= targetDifficulty {
return event, nil return event, nil
} }

View File

@ -135,10 +135,10 @@ jump1:
} }
jump2: jump2:
if d.since != nil && ev.CreatedAt.Before(*d.since) { if d.since != nil && ev.CreatedAt.Time().Before(*d.since) {
return false, fmt.Errorf("Event is created before delegation conditions allow.") return false, fmt.Errorf("Event is created before delegation conditions allow.")
} }
if d.until != nil && ev.CreatedAt.After(*d.until) { if d.until != nil && ev.CreatedAt.Time().After(*d.until) {
return false, fmt.Errorf("Event is created after delegation conditions allow.") return false, fmt.Errorf("Event is created after delegation conditions allow.")
} }
@ -166,7 +166,7 @@ func DelegatedSign(ev *nostr.Event, d *DelegationToken, delegatee_sk string) err
return fmt.Errorf("event already has delegation token") return fmt.Errorf("event already has delegation token")
} }
} }
if d.since != nil && ev.CreatedAt.Before(*d.since) || d.until != nil && ev.CreatedAt.After(*d.until) { if d.since != nil && ev.CreatedAt.Time().Before(*d.since) || d.until != nil && ev.CreatedAt.Time().After(*d.until) {
return fmt.Errorf("event created_at field is not compatible with delegation token time conditions.") return fmt.Errorf("event created_at field is not compatible with delegation token time conditions.")
} }
if len(d.kinds) > 0 { if len(d.kinds) > 0 {

View File

@ -1,9 +1,10 @@
package nip26 package nip26
import ( import (
"github.com/nbd-wtf/go-nostr"
"testing" "testing"
"time" "time"
"github.com/nbd-wtf/go-nostr"
) )
func TestDelegateSign(t *testing.T) { func TestDelegateSign(t *testing.T) {
@ -16,7 +17,7 @@ func TestDelegateSign(t *testing.T) {
t.Error(err) t.Error(err)
} }
ev := &nostr.Event{} ev := &nostr.Event{}
ev.CreatedAt = time.Unix(1600000050, 0) ev.CreatedAt = nostr.Timestamp(1600000050)
ev.Content = "hello world" ev.Content = "hello world"
ev.Kind = 1 ev.Kind = 1
if err != nil { if err != nil {

View File

@ -13,7 +13,7 @@ import (
func CreateUnsignedAuthEvent(challenge, pubkey, relayURL string) nostr.Event { func CreateUnsignedAuthEvent(challenge, pubkey, relayURL string) nostr.Event {
return nostr.Event{ return nostr.Event{
PubKey: pubkey, PubKey: pubkey,
CreatedAt: time.Now(), CreatedAt: nostr.Now(),
Kind: 22242, Kind: 22242,
Tags: nostr.Tags{ Tags: nostr.Tags{
nostr.Tag{"relay", relayURL}, nostr.Tag{"relay", relayURL},
@ -60,7 +60,7 @@ func ValidateAuthEvent(event *nostr.Event, challenge string, relayURL string) (p
} }
now := time.Now() now := time.Now()
if event.CreatedAt.After(now.Add(10*time.Minute)) || event.CreatedAt.Before(now.Add(-10*time.Minute)) { if event.CreatedAt.Time().After(now.Add(10*time.Minute)) || event.CreatedAt.Time().Before(now.Add(-10*time.Minute)) {
return "", false return "", false
} }

View File

@ -21,7 +21,7 @@ func TestPublish(t *testing.T) {
textNote := Event{ textNote := Event{
Kind: 1, Kind: 1,
Content: "hello", Content: "hello",
CreatedAt: time.Unix(1672068534, 0), // random fixed timestamp CreatedAt: Timestamp(1672068534), // random fixed timestamp
Tags: Tags{[]string{"foo", "bar"}}, Tags: Tags{[]string{"foo", "bar"}},
PubKey: pub, PubKey: pub,
} }

13
timestamp.go Normal file
View File

@ -0,0 +1,13 @@
package nostr
import "time"
type Timestamp int64
func Now() Timestamp {
return Timestamp(time.Now().Unix())
}
func (t Timestamp) Time() time.Time {
return time.Unix(int64(t), 0)
}