mirror of
https://github.com/nbd-wtf/go-nostr.git
synced 2025-11-18 10:06:27 +01:00
implement envelope, event and filter parsing with simdjson-go.
This commit is contained in:
@@ -3,7 +3,9 @@ package nostr
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/minio/simdjson-go"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestEventEnvelopeEncodingAndDecoding(t *testing.T) {
|
||||
@@ -174,4 +176,155 @@ func TestParseMessage(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseMessageSIMD(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Name string
|
||||
Message []byte
|
||||
ExpectedEnvelope Envelope
|
||||
ExpectedErrorSubstring string
|
||||
}{
|
||||
{
|
||||
Name: "nil",
|
||||
Message: nil,
|
||||
ExpectedEnvelope: nil,
|
||||
ExpectedErrorSubstring: "parse failed",
|
||||
},
|
||||
{
|
||||
Name: "empty string",
|
||||
Message: []byte(""),
|
||||
ExpectedEnvelope: nil,
|
||||
ExpectedErrorSubstring: "parse failed",
|
||||
},
|
||||
{
|
||||
Name: "invalid input",
|
||||
Message: []byte("invalid input"),
|
||||
ExpectedEnvelope: nil,
|
||||
ExpectedErrorSubstring: "parse failed",
|
||||
},
|
||||
{
|
||||
Name: "invalid JSON",
|
||||
Message: []byte("{not valid json}"),
|
||||
ExpectedEnvelope: nil,
|
||||
ExpectedErrorSubstring: "parse failed",
|
||||
},
|
||||
{
|
||||
Name: "invalid REQ",
|
||||
Message: []byte(`["REQ","zzz", {"authors": [23]}]`),
|
||||
ExpectedEnvelope: nil,
|
||||
ExpectedErrorSubstring: "not string, but int",
|
||||
},
|
||||
{
|
||||
Name: "same invalid REQ from before, but now valid",
|
||||
Message: []byte(`["REQ","zzz", {"kinds": [23]}]`),
|
||||
ExpectedEnvelope: &ReqEnvelope{SubscriptionID: "zzz", Filters: Filters{{Kinds: []int{23}}}},
|
||||
},
|
||||
{
|
||||
Name: "different invalid REQ",
|
||||
Message: []byte(`["REQ","zzz", {"authors": "string"}]`),
|
||||
ExpectedEnvelope: nil,
|
||||
ExpectedErrorSubstring: "next item is not",
|
||||
},
|
||||
{
|
||||
Name: "yet another",
|
||||
Message: []byte(`["REQ","zzz", {"unknownfield": "_"}]`),
|
||||
ExpectedEnvelope: nil,
|
||||
ExpectedErrorSubstring: "unexpected filter field 'unknownfield'",
|
||||
},
|
||||
{
|
||||
Name: "EVENT envelope with subscription id",
|
||||
Message: []byte(
|
||||
`["EVENT","_",{"kind":1,"id":"dc90c95f09947507c1044e8f48bcf6350aa6bff1507dd4acfc755b9239b5c962","pubkey":"3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d","created_at":1644271588,"tags":[],"content":"now that https://blueskyweb.org/blog/2-7-2022-overview was announced we can stop working on nostr?","sig":"230e9d8f0ddaf7eb70b5f7741ccfa37e87a455c9a469282e3464e2052d3192cd63a167e196e381ef9d7e69e9ea43af2443b839974dc85d8aaab9efe1d9296524"}]`,
|
||||
),
|
||||
ExpectedEnvelope: &EventEnvelope{SubscriptionID: ptr("_"), Event: Event{Kind: 1, ID: "dc90c95f09947507c1044e8f48bcf6350aa6bff1507dd4acfc755b9239b5c962", PubKey: "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d", CreatedAt: 1644271588, Tags: Tags{}, Content: "now that https://blueskyweb.org/blog/2-7-2022-overview was announced we can stop working on nostr?", Sig: "230e9d8f0ddaf7eb70b5f7741ccfa37e87a455c9a469282e3464e2052d3192cd63a167e196e381ef9d7e69e9ea43af2443b839974dc85d8aaab9efe1d9296524"}},
|
||||
},
|
||||
{
|
||||
Name: "EVENT envelope without subscription id",
|
||||
Message: []byte(
|
||||
`["EVENT",{"kind":1,"id":"dc90c95f09947507c1044e8f48bcf6350aa6bff1507dd4acfc755b9239b5c962","pubkey":"3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d","created_at":1644271588,"tags":[],"content":"now that https://blueskyweb.org/blog/2-7-2022-overview was announced we can stop working on nostr?","sig":"230e9d8f0ddaf7eb70b5f7741ccfa37e87a455c9a469282e3464e2052d3192cd63a167e196e381ef9d7e69e9ea43af2443b839974dc85d8aaab9efe1d9296524"}]`,
|
||||
),
|
||||
ExpectedEnvelope: &EventEnvelope{Event: Event{Kind: 1, ID: "dc90c95f09947507c1044e8f48bcf6350aa6bff1507dd4acfc755b9239b5c962", PubKey: "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d", CreatedAt: 1644271588, Tags: Tags{}, Content: "now that https://blueskyweb.org/blog/2-7-2022-overview was announced we can stop working on nostr?", Sig: "230e9d8f0ddaf7eb70b5f7741ccfa37e87a455c9a469282e3464e2052d3192cd63a167e196e381ef9d7e69e9ea43af2443b839974dc85d8aaab9efe1d9296524"}},
|
||||
},
|
||||
{
|
||||
Name: "AUTH envelope with challenge",
|
||||
Message: []byte(`["AUTH","challenge-string"]`),
|
||||
ExpectedEnvelope: &AuthEnvelope{Challenge: ptr("challenge-string")},
|
||||
},
|
||||
{
|
||||
Name: "AUTH envelope with event",
|
||||
Message: []byte(
|
||||
`["AUTH", {"kind":22242,"id":"9b86ca5d2a9b4aa09870e710438c2fd2fcdeca12a18b6f17ab9ebcdbc43f1d4a","pubkey":"79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798","created_at":1740505646,"tags":[["relay","ws://localhost:7777","2"],["challenge","3027526784722639360"]],"content":"","sig":"eceb827c4bba1de0ab8ee43f3e98df71194f5bdde0af27b5cda38e5c4338b5f63d31961acb5e3c119fd00ecef8b469867d060b697dbaa6ecee1906b483bc307d"}]`,
|
||||
),
|
||||
ExpectedEnvelope: &AuthEnvelope{Event: Event{Kind: 22242, ID: "9b86ca5d2a9b4aa09870e710438c2fd2fcdeca12a18b6f17ab9ebcdbc43f1d4a", PubKey: "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", CreatedAt: 1740505646, Tags: Tags{Tag{"relay", "ws://localhost:7777", "2"}, Tag{"challenge", "3027526784722639360"}}, Content: "", Sig: "eceb827c4bba1de0ab8ee43f3e98df71194f5bdde0af27b5cda38e5c4338b5f63d31961acb5e3c119fd00ecef8b469867d060b697dbaa6ecee1906b483bc307d"}},
|
||||
},
|
||||
{
|
||||
Name: "NOTICE envelope",
|
||||
Message: []byte(`["NOTICE","test notice message"]`),
|
||||
ExpectedEnvelope: ptr(NoticeEnvelope("test notice message")),
|
||||
},
|
||||
{
|
||||
Name: "EOSE envelope",
|
||||
Message: []byte(`["EOSE","subscription123"]`),
|
||||
ExpectedEnvelope: ptr(EOSEEnvelope("subscription123")),
|
||||
},
|
||||
{
|
||||
Name: "CLOSE envelope",
|
||||
Message: []byte(`["CLOSE","subscription123"]`),
|
||||
ExpectedEnvelope: ptr(CloseEnvelope("subscription123")),
|
||||
},
|
||||
{
|
||||
Name: "CLOSED envelope",
|
||||
Message: []byte(`["CLOSED","subscription123","reason: test closed"]`),
|
||||
ExpectedEnvelope: &ClosedEnvelope{SubscriptionID: "subscription123", Reason: "reason: test closed"},
|
||||
},
|
||||
{
|
||||
Name: "OK envelope",
|
||||
Message: []byte(`["OK","3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefaaaaa",true,""]`),
|
||||
ExpectedEnvelope: &OKEnvelope{EventID: "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefaaaaa", OK: true, Reason: ""},
|
||||
},
|
||||
{
|
||||
Name: "COUNT envelope with just count",
|
||||
Message: []byte(`["COUNT","sub1",{"count":42}]`),
|
||||
ExpectedEnvelope: &CountEnvelope{SubscriptionID: "sub1", Count: ptr(int64(42))},
|
||||
},
|
||||
{
|
||||
Name: "COUNT envelope with count and hll",
|
||||
Message: []byte(`["COUNT","sub1",{"count":42, "hll": "0100000101000000000000040000000001020000000002000000000200000003000002040000000101020001010000000000000007000004010000000200040000020400000000000102000002000004010000010000000301000102030002000301000300010000070000000001000004000102010000000400010002000000000103000100010001000001040100020001000000000000010000020000000000030100000001000400010000000000000901010100000000040000000b030000010100010000010000010000000003000000000000010003000100020000000000010000010100000100000104000200030001000300000001000101000102"}]`),
|
||||
ExpectedEnvelope: &CountEnvelope{SubscriptionID: "sub1", Count: ptr(int64(42)), HyperLogLog: []byte{1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 2, 4, 0, 0, 0, 1, 1, 2, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 4, 1, 0, 0, 0, 2, 0, 4, 0, 0, 2, 4, 0, 0, 0, 0, 0, 1, 2, 0, 0, 2, 0, 0, 4, 1, 0, 0, 1, 0, 0, 0, 3, 1, 0, 1, 2, 3, 0, 2, 0, 3, 1, 0, 3, 0, 1, 0, 0, 7, 0, 0, 0, 0, 1, 0, 0, 4, 0, 1, 2, 1, 0, 0, 0, 4, 0, 1, 0, 2, 0, 0, 0, 0, 1, 3, 0, 1, 0, 1, 0, 1, 0, 0, 1, 4, 1, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 1, 0, 4, 0, 1, 0, 0, 0, 0, 0, 0, 9, 1, 1, 1, 0, 0, 0, 0, 4, 0, 0, 0, 11, 3, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 1, 0, 3, 0, 1, 0, 2, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 4, 0, 2, 0, 3, 0, 1, 0, 3, 0, 0, 0, 1, 0, 1, 1, 0, 1, 2}},
|
||||
},
|
||||
{
|
||||
Name: "REQ envelope",
|
||||
Message: []byte(`["REQ","sub1", {"until": 999999, "kinds":[1]}]`),
|
||||
ExpectedEnvelope: &ReqEnvelope{SubscriptionID: "sub1", Filters: Filters{{Kinds: []int{1}, Until: ptr(Timestamp(999999))}}},
|
||||
},
|
||||
{
|
||||
Name: "bigger REQ envelope",
|
||||
Message: []byte(`["REQ","sub1z\\\"zzz", {"authors":["9b86ca5d2a9b4aa09870e710438c2fd2fcdeca12a18b6f17ab9ebcdbc43f1d4a","8eee10b2ce1162b040fdcfdadb4f888c64aaf87531dab28cc0c09fbdea1b663e","0deadebefb3c1a760f036952abf675076343dd8424efdeaa0f1d9803a359ed46"],"since":1740425099,"limit":2,"#x":["<","as"]}, {"kinds": [2345, 112], "#plic": ["a"], "#ploc": ["blblb", "wuwuw"]}]`),
|
||||
ExpectedEnvelope: &ReqEnvelope{SubscriptionID: "sub1z\\\"zzz", Filters: Filters{{Authors: []string{"9b86ca5d2a9b4aa09870e710438c2fd2fcdeca12a18b6f17ab9ebcdbc43f1d4a", "8eee10b2ce1162b040fdcfdadb4f888c64aaf87531dab28cc0c09fbdea1b663e", "0deadebefb3c1a760f036952abf675076343dd8424efdeaa0f1d9803a359ed46"}, Since: ptr(Timestamp(1740425099)), Limit: 2, Tags: TagMap{"x": []string{"<", "as"}}}, {Kinds: []int{2345, 112}, Tags: TagMap{"plic": []string{"a"}, "ploc": []string{"blblb", "wuwuw"}}}}},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.Name, func(t *testing.T) {
|
||||
var pj *simdjson.ParsedJson
|
||||
envelope, err := ParseMessageSIMD(testCase.Message, pj)
|
||||
|
||||
if testCase.ExpectedErrorSubstring == "" {
|
||||
require.NoError(t, err)
|
||||
} else {
|
||||
require.Contains(t, err.Error(), testCase.ExpectedErrorSubstring)
|
||||
return
|
||||
}
|
||||
|
||||
if testCase.ExpectedEnvelope == nil {
|
||||
require.Nil(t, envelope, "expected nil but got %v", envelope)
|
||||
return
|
||||
}
|
||||
|
||||
require.NotNil(t, envelope, "expected non-nil envelope but got nil")
|
||||
require.Equal(t, testCase.ExpectedEnvelope.Label(), envelope.Label())
|
||||
require.Equal(t, testCase.ExpectedEnvelope.String(), envelope.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func ptr[S any](s S) *S { return &s }
|
||||
|
||||
Reference in New Issue
Block a user