upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/93.md
diff options
context:
space:
mode:
authorfiatjaf <fiatjaf@gmail.com>2023-05-11 06:00:04 -0300
committerfiatjaf <fiatjaf@gmail.com>2023-05-11 06:00:04 -0300
commit44ea6d84583b64f6d7d994bfb480a4d786ba1699 (patch)
tree7a150ada60c177c1e37c55d8a360ca3157498755 /93.md
parentbd6d3251960f67bc30d1674115cd847c0799e67e (diff)
fix some smallities.nip93-nson
Diffstat (limited to '93.md')
-rw-r--r--93.md40
1 files changed, 18 insertions, 22 deletions
diff --git a/93.md b/93.md
index 121ed5e..e111c5f 100644
--- a/93.md
+++ b/93.md
@@ -8,9 +8,9 @@ NSON
8 8
9### Preamble 9### Preamble
10 10
11Some [benchmarks](https://github.com/fiatjaf/nostr-json-benchmarks/tree/2f254fff91b3ad063ef9726bb4a3d25316cf12d8) made using all libraries available on Golang show that JSON decoding is very slow. And even when people do assembly-level optimizations things only improve up to a point (e.g. for decoding a Nostr event, the decoding time is 50% smaller). 11Some [benchmarks](https://github.com/fiatjaf/nostr-json-benchmarks/tree/2f254fff91b3ad063ef9726bb4a3d25316cf12d8) made using all libraries available on Golang show that JSON decoding is very slow. And even when people do assembly-level optimizations things only improve up to a point (e.g. for decoding a Nostr event, the "Sonic" library uses about 50% of that of the standard library).
12 12
13Meanwhile, doing a simple TLV encoding reduces the decoding time to 35% and a simpler static binary format for Nostr events reduces makes that number drop to 4%. However, it would be bad for Nostr if a binary encoding was introduced, as it would be likely to cause compatibility issues, centralize the protocol and/or increase the work for everybody, more about this at [this comment](https://github.com/nostr-protocol/nips/pull/512#issuecomment-1542368664). 13Meanwhile, doing a simple TLV encoding reduces the decoding time to 35% and a simpler static binary format for Nostr events makes that number drop to 4%. However, it would be bad for Nostr if a binary encoding was introduced, as it would be likely to cause compatibility issues, centralize the protocol and/or increase the work for everybody, more about this in [this comment](https://github.com/nostr-protocol/nips/pull/512#issuecomment-1542368664).
14 14
15### The actual NIP 15### The actual NIP
16 16
@@ -20,31 +20,27 @@ Here's an example of a NSON-encoded Nostr event:
20 20
21`{"id":"57ff66490a6a2af3992accc26ae95f3f60c6e5f84ed0ddf6f59c534d3920d3d2","pubkey":"79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798","sig":"504d142aed7fa7e0f6dab5bcd7eed63963b0277a8e11bbcb03b94531beb4b95a12f1438668b02746bd5362161bc782068e6b71494060975414e793f9e19f57ea","created_at":1683762317,"nson":"2801000b0203000100400005040001004000000014","kind":1,"content":"hello world","tags":[["e","b6de44a9dd47d1c000f795ea0453046914f44ba7d5e369608b04867a575ea83e","reply"],["p","c26f7b252cea77a5b94f42b1a4771021be07d4df766407e47738605f7e3ab774","","wss://relay.damus.io"]]}` 21`{"id":"57ff66490a6a2af3992accc26ae95f3f60c6e5f84ed0ddf6f59c534d3920d3d2","pubkey":"79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798","sig":"504d142aed7fa7e0f6dab5bcd7eed63963b0277a8e11bbcb03b94531beb4b95a12f1438668b02746bd5362161bc782068e6b71494060975414e793f9e19f57ea","created_at":1683762317,"nson":"2801000b0203000100400005040001004000000014","kind":1,"content":"hello world","tags":[["e","b6de44a9dd47d1c000f795ea0453046914f44ba7d5e369608b04867a575ea83e","reply"],["p","c26f7b252cea77a5b94f42b1a4771021be07d4df766407e47738605f7e3ab774","","wss://relay.damus.io"]]}`
22 22
23The idea is that `"id"` comes first, so it can be accessed by reading a slice of the string from character `7` to character `71`, `pubkey` from character `83` to `147` and so on. `"content"`, `"kind"` and `"tags"` have dynamic sizes, so these are given by the values inside the `"nson"` field (which is also dynamic, its size by its first byte). 23The idea is that `"id"` comes first, so it can be accessed by reading a slice of the string from character `7` to character `71`, `pubkey` from character `83` to `147` and so on. `"content"`, `"kind"` and `"tags"` have dynamic sizes, so their sizes are given by the values inside the `"nson"` field (which is also dynamic, its size given by its first byte).
24 24
25### Anatomy of the `"nson"` field 25### Anatomy of the `"nson"` field
26 26
27It is hex-encoded. Some fields are a single byte, others are two bytes (4 characters). 27It is hex-encoded. Some fields are a single byte, others are two bytes (4 characters), big-endian.
28 28
29Each explanation starts at the same line as the field it is referring to. 29 tt: number of tags (let's say it's two)
30 30 nn: number of items on the first tag (let's say it's 3)
31 number of tags (let's say it's two) 31 1111: number of chars on the first item
32 number of items on the first tag (let's say it's three) 32 2222: number of chars on the second item
33 number of chars on the first item 33 3333: number of chars on the third item
34 number of chars on the second item 34 nn: number of items on the second tag (let's say it's 2)
35 number of chars on the third item 35 1111: number of chars on the first item
36 number of items on the second tag (let's say it's two) 36 2222: number of chars on the second item
37 number of chars on the first item
38 number of chars on the second item
39 "nson":"xxkkccccttnn111122223333nn11112222" 37 "nson":"xxkkccccttnn111122223333nn11112222"
40 nson size 38 xx: nson size
41 kind chars 39 kk: kind chars
42 content chars 40 cccc: content chars
43 41
44### Reference implementation 42### Reference implementation
45 43
46Beware, all Rust maniacs, the following reference implementation is written in Go:
47
48```go 44```go
49func decodeNson(data string) *Event { 45func decodeNson(data string) *Event {
50 evt := &Event{} 46 evt := &Event{}
@@ -167,13 +163,13 @@ func encodeNson(evt *Event) string {
167Besides the field ordering and the presence of the `"nson"` field, other restrictions must be applied: 163Besides the field ordering and the presence of the `"nson"` field, other restrictions must be applied:
168 164
169- the `"created_at"` field must have 10, characters, which gives us a range of dates from about 20 years ago up to 250 years in the future. 165- the `"created_at"` field must have 10, characters, which gives us a range of dates from about 20 years ago up to 250 years in the future.
170- to simplify decoding of `"content"` and `"tags"` strings, escape codes like `\uXXXX` are forbidden in NSON, UTF-8 must be used instead. Only `\n`, `\\` and `\"` are the only valid escaped sequences. 166- to simplify decoding of `"content"` and `"tags"` strings, escape codes like `\uXXXX` are forbidden in NSON, UTF-8 must be used instead. `\n`, `\\` and `\"` are the only valid escaped sequences.
171 167
172### Backwards-compatibility 168### Backwards-compatibility
173 169
174Any reader who is not aware of the NSON-encoding can receive these events and decode them using whatever other JSON decoder they happen to have in hand. The `"nson"` field will just be ignored and life will continue as normal. 170Any reader who is not aware of the NSON-encoding can receive these events and decode them using whatever means they want. The `"nson"` field will just be ignored and life will continue as normal.
175 171
176Also, other event fields that may be present (for example, the NIP-03 `"ots"` field) can be added at the end, after `"tags"`, with no loss. 172Also, other event fields that may be present (for example, the NIP-03 `"ots"` field) can be added at the end, after `"tags"`, with no loss to anyone.
177 173
178### Other points worth mentioning 174### Other points worth mentioning
179 175