mirror of
https://github.com/nostr-protocol/nips.git
synced 2024-12-22 08:25:53 -05:00
fix some smallities.
This commit is contained in:
parent
bd6d325196
commit
44ea6d8458
40
93.md
40
93.md
|
@ -8,9 +8,9 @@ NSON
|
||||||
|
|
||||||
### Preamble
|
### Preamble
|
||||||
|
|
||||||
Some [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).
|
Some [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).
|
||||||
|
|
||||||
Meanwhile, 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).
|
Meanwhile, 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).
|
||||||
|
|
||||||
### The actual NIP
|
### The actual NIP
|
||||||
|
|
||||||
|
@ -20,31 +20,27 @@ Here's an example of a NSON-encoded Nostr event:
|
||||||
|
|
||||||
`{"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"]]}`
|
`{"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"]]}`
|
||||||
|
|
||||||
The 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).
|
The 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).
|
||||||
|
|
||||||
### Anatomy of the `"nson"` field
|
### Anatomy of the `"nson"` field
|
||||||
|
|
||||||
It is hex-encoded. Some fields are a single byte, others are two bytes (4 characters).
|
It is hex-encoded. Some fields are a single byte, others are two bytes (4 characters), big-endian.
|
||||||
|
|
||||||
Each explanation starts at the same line as the field it is referring to.
|
tt: number of tags (let's say it's two)
|
||||||
|
nn: number of items on the first tag (let's say it's 3)
|
||||||
number of tags (let's say it's two)
|
1111: number of chars on the first item
|
||||||
number of items on the first tag (let's say it's three)
|
2222: number of chars on the second item
|
||||||
number of chars on the first item
|
3333: number of chars on the third item
|
||||||
number of chars on the second item
|
nn: number of items on the second tag (let's say it's 2)
|
||||||
number of chars on the third item
|
1111: number of chars on the first item
|
||||||
number of items on the second tag (let's say it's two)
|
2222: number of chars on the second item
|
||||||
number of chars on the first item
|
|
||||||
number of chars on the second item
|
|
||||||
"nson":"xxkkccccttnn111122223333nn11112222"
|
"nson":"xxkkccccttnn111122223333nn11112222"
|
||||||
nson size
|
xx: nson size
|
||||||
kind chars
|
kk: kind chars
|
||||||
content chars
|
cccc: content chars
|
||||||
|
|
||||||
### Reference implementation
|
### Reference implementation
|
||||||
|
|
||||||
Beware, all Rust maniacs, the following reference implementation is written in Go:
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func decodeNson(data string) *Event {
|
func decodeNson(data string) *Event {
|
||||||
evt := &Event{}
|
evt := &Event{}
|
||||||
|
@ -167,13 +163,13 @@ func encodeNson(evt *Event) string {
|
||||||
Besides the field ordering and the presence of the `"nson"` field, other restrictions must be applied:
|
Besides the field ordering and the presence of the `"nson"` field, other restrictions must be applied:
|
||||||
|
|
||||||
- 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.
|
- 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.
|
||||||
- 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.
|
- 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.
|
||||||
|
|
||||||
### Backwards-compatibility
|
### Backwards-compatibility
|
||||||
|
|
||||||
Any 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.
|
Any 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.
|
||||||
|
|
||||||
Also, 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.
|
Also, 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.
|
||||||
|
|
||||||
### Other points worth mentioning
|
### Other points worth mentioning
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user