Deskripsi alur protokol dasar

draft mandatory

NIP ini mendefinisikan protokol dasar yang harus diterapkan oleh semua orang. NIP baru dapat menambahkan bidang dan pesan serta fitur opsional (atau wajib) baru ke struktur dan alur yang dijelaskan di sini.

Setiap pengguna memiliki pasangan kunci. Tanda tangan, kunci publik, dan pengkodean dilakukan sesuai dengan Standar tanda tangan Schnorr untuk kurva secp256k1.

Satu-satunya tipe objek yang ada adalah eventyang memiliki format berikut pada kabelnya:

{
  "id": <32-bytes lowercase hex-encoded sha256 of the serialized event data>,
  "pubkey": <32-bytes lowercase hex-encoded public key of the event creator>,
  "created_at": <unix timestamp in seconds>,
  "kind": <integer between 0 and 65535>,
  "tags": (
    (<arbitrary string>...),
    // ...
  ),
  "content": <arbitrary string>,
  "sig": <64-bytes lowercase hex of the signature of the sha256 hash of the serialized event data, which is the same as the "id" field>
}

Untuk mendapatkan event.idKami sha256 acara berseri. Serialisasi dilakukan melalui string serial JSON UTF-8 (yang dijelaskan di bawah) dengan struktur berikut:

Untuk mencegah perbedaan implementasi dari pembuatan ID peristiwa yang berbeda untuk peristiwa yang sama, aturan berikut HARUS diikuti saat membuat serial:

  • UTF-8 harus digunakan untuk pengkodean.
  • Spasi, jeda baris, atau pemformatan lain yang tidak perlu tidak boleh disertakan dalam output JSON.
  • Karakter berikut dalam bidang konten harus di-escape seperti yang ditunjukkan, dan semua karakter lainnya harus disertakan kata demi kata:
    • Jeda baris (0x0A), menggunakan n
    • Kutipan ganda (0x22), menggunakan "
    • Garis miring terbalik (0x5C), menggunakan \
    • Kereta kembali (0x0D), menggunakan r
    • Karakter tab (0x09), menggunakan t
    • Spasi mundur, (0x08), menggunakan b
    • Umpan formulir, (0x0C), menggunakan f

Setiap tag adalah larik yang terdiri dari satu atau lebih string, dengan beberapa konvensi di sekelilingnya. Lihatlah contoh di bawah ini:

{
  "tags": (
    ("e", "5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36", "wss://nostr.example.com"),
    ("p", "f7234bd4c1394dda46d09f35bd384dd30cc552ad5541990f98844fb06676e9ca"),
    ("a", "30023:f7234bd4c1394dda46d09f35bd384dd30cc552ad5541990f98844fb06676e9ca:abcd", "wss://nostr.example.com"),
    ("alt", "reply"),
    // ...
  ),
  // ...
}

Elemen pertama dari array tag disebut sebagai tag nama atau kunci dan yang kedua sebagai tag nilai. Jadi kita dapat dengan aman mengatakan bahwa peristiwa di atas memiliki e tag disetel ke "5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36"sebuah alt tag disetel ke "reply" dan sebagainya. Semua elemen setelah elemen kedua tidak memiliki nama konvensional.

NIP ini mendefinisikan 3 tag standar yang dapat digunakan di semua jenis acara dengan arti yang sama. Mereka adalah sebagai berikut:

  • Itu e tag, digunakan untuk merujuk pada suatu peristiwa: ("e", <32-bytes lowercase hex of the id of another event>, )
  • Itu p tag, digunakan untuk merujuk ke pengguna lain: ("p", <32-bytes lowercase hex of a pubkey>, )
  • Itu a tag, digunakan untuk merujuk pada peristiwa yang dapat dialamatkan atau diganti
    • untuk acara yang dapat dialamatkan: ("a", :<32-bytes lowercase hex of a pubkey>:, )
    • untuk kejadian normal yang dapat diganti: ("a", :<32-bytes lowercase hex of a pubkey>:, )

Sebagai konvensi, semua tag kunci satu huruf (hanya huruf alfabet Inggris: az, AZ) diharapkan diindeks oleh relai, sehingga memungkinkan, misalnya, untuk menanyakan atau berlangganan peristiwa yang mereferensikan peristiwa tersebut "5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36" dengan menggunakan {"#e": ("5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36")} menyaring. Hanya nilai pertama dalam tag tertentu yang diindeks.

Jenis menentukan bagaimana klien harus menafsirkan arti dari setiap peristiwa dan bidang lain dari setiap peristiwa (misalnya an "r" tag mungkin memiliki arti dalam peristiwa jenis 1 dan arti yang sama sekali berbeda dalam peristiwa jenis 10002). Setiap NIP dapat mendefinisikan arti dari serangkaian jenis yang tidak didefinisikan di tempat lain. NIP ini mendefinisikan dua jenis dasar:

  • 0: metadata pengguna: itu content diatur ke objek JSON yang dirangkai {name: , about: , picture: } menggambarkan pengguna yang membuat acara. Bidang metadata tambahan mungkin disetel. Relai dapat menghapus peristiwa lama setelah mendapatkan peristiwa baru untuk kunci pub yang sama.
  • 1: catatan teks: itu content diatur ke teks biasa isi catatan (apa pun yang ingin dikatakan pengguna). Konten yang harus diurai, seperti Markdown dan HTML, tidak boleh digunakan. Klien juga tidak boleh mengurai konten seperti itu.

Dan juga konvensi untuk rentang jenis yang memungkinkan eksperimen lebih mudah dan fleksibilitas implementasi relai:

  • untuk jenis n seperti yang 1000 <= n < 10000 || 4 <= n < 45 || n == 1 || n == 2acara adalah biasayang berarti semuanya diharapkan disimpan oleh relay.
  • untuk jenis n seperti yang 10000 <= n < 20000 || n == 0 || n == 3acara adalah tergantikanyang artinya, untuk setiap kombinasi pubkey Dan kindhanya event terbaru yang HARUS disimpan oleh relay, versi lama MUNGKIN dibuang.
  • untuk jenis n seperti yang 20000 <= n < 30000acara adalah tdk kekalyang berarti mereka tidak diharapkan untuk disimpan oleh relay.
  • untuk jenis n seperti yang 30000 <= n < 40000acara adalah dapat dialamatkan oleh mereka kind, pubkey Dan d nilai tag — yang berarti, untuk setiap kombinasi kind, pubkey dan itu d nilai tag, hanya event terbaru yang HARUS disimpan oleh relay, versi lama MUNGKIN dibuang.

Jika ada peristiwa yang dapat diganti dengan stempel waktu yang sama, peristiwa dengan id terendah (yang pertama dalam urutan leksikal) harus dipertahankan, dan yang lainnya dibuang.

Saat menjawab REQ pesan untuk acara yang dapat diganti seperti {"kinds":(0),"authors":()}bahkan jika relai menyimpan lebih dari satu versi, relai HARUS mengembalikan versi terbaru saja.

Ini hanyalah konvensi dan implementasi relai mungkin berbeda.

Komunikasi antara klien dan relay

Relai mengekspos titik akhir soket web tempat klien dapat terhubung. Klien HARUS membuka satu koneksi websocket ke setiap relay dan menggunakannya untuk semua langganan mereka. Relai MUNGKIN membatasi jumlah koneksi dari IP/klien/dll tertentu.

Dari klien ke relay: mengirim acara dan membuat langganan

Klien dapat mengirim 3 jenis pesan, yang harus berupa array JSON, sesuai dengan pola berikut:

  • ("EVENT", )digunakan untuk mempublikasikan acara.
  • ("REQ", , , , ...)digunakan untuk meminta acara dan berlangganan pembaruan baru.
  • ("CLOSE", )digunakan untuk menghentikan langganan sebelumnya.

adalah string sembarang dan tidak kosong dengan panjang maksimal 64 karakter. Ini mewakili langganan per koneksi. Relai HARUS dikelola s secara independen untuk setiap koneksi WebSocket. s tidak dijamin unik secara global.

adalah objek JSON yang menentukan peristiwa apa yang akan dikirim dalam langganan itu, ia dapat memiliki atribut berikut:

{
  "ids": ,
  "authors": ,
  "kinds": ,
  "#": ,
  "since": = to this to pass>,
  "until": ,
  "limit": 
}

Setelah menerima a REQ pesan, relai HARUS mengembalikan peristiwa yang cocok dengan filter. Setiap peristiwa baru yang diterimanya HARUS dikirim ke soket web yang sama hingga koneksi ditutup, a CLOSE acara diterima dengan hal yang sama atau yang baru REQ dikirim menggunakan yang sama (dalam hal ini langganan baru dibuat, menggantikan langganan lama).

Filter atribut yang berisi daftar (ids, authors, kinds dan tag filter seperti #e) adalah array JSON dengan satu atau lebih nilai. Setidaknya salah satu nilai array harus cocok dengan bidang yang relevan dalam suatu peristiwa agar kondisi tersebut dianggap cocok. Untuk atribut peristiwa skalar seperti authors Dan kindatribut dari acara tersebut harus terdapat dalam daftar filter. Dalam hal atribut tag seperti #edimana suatu peristiwa mungkin memiliki beberapa nilai, nilai kondisi peristiwa dan filter harus memiliki setidaknya satu item yang sama.

Itu ids, authors, #e Dan #p daftar filter HARUS berisi nilai hex huruf kecil 64 karakter yang tepat.

Itu since Dan until properti dapat digunakan untuk menentukan rentang waktu peristiwa yang dikembalikan dalam langganan. Jika filter menyertakan since properti, acara dengan created_at lebih besar atau sama dengan since dianggap cocok dengan filter. Itu until properti serupa kecuali itu created_at harus kurang dari atau sama dengan until. Singkatnya, suatu peristiwa cocok dengan filter jika since <= created_at <= until memegang.

Semua kondisi filter yang ditentukan harus cocok dengan suatu peristiwa agar dapat lolos filter, yaitu, beberapa kondisi diinterpretasikan sebagai && kondisi.

A REQ pesan mungkin berisi beberapa filter. Dalam hal ini, peristiwa yang cocok dengan salah satu filter akan dikembalikan, yaitu, beberapa filter harus diinterpretasikan sebagai || kondisi.

Itu limit properti filter hanya valid untuk kueri awal dan HARUS diabaikan setelahnya. Kapan limit: n hadir, diasumsikan bahwa peristiwa yang dikembalikan dalam kueri awal akan menjadi yang terakhir n acara yang dipesan oleh created_at. Peristiwa yang lebih baru harus muncul terlebih dahulu, dan dalam kasus ikatan, peristiwa dengan id terendah (pertama dalam urutan leksikal) harus menjadi yang pertama. Aman untuk mengembalikan lebih sedikit acara daripada limit ditentukan, tetapi relai diharapkan tidak mengembalikan (lebih) lebih banyak peristiwa daripada yang diminta sehingga klien tidak kewalahan oleh data yang tidak perlu.

Dari relay ke klien: mengirimkan acara dan pemberitahuan

Relai dapat mengirim 5 jenis pesan, yang juga harus berupa array JSON, sesuai dengan pola berikut:

  • ("EVENT", , )digunakan untuk mengirim acara yang diminta oleh klien.
  • ("OK", , , )digunakan untuk menunjukkan penerimaan atau penolakan suatu EVENT pesan.
  • ("EOSE", )digunakan untuk menunjukkan akhir acara yang disimpan dan awal acara yang baru diterima secara real-time.
  • ("CLOSED", , )digunakan untuk menunjukkan bahwa langganan telah diakhiri di sisi server.
  • ("NOTICE", )digunakan untuk mengirim pesan kesalahan yang dapat dibaca manusia atau hal lain ke klien.

NIP ini tidak menjelaskan aturan bagaimana caranya NOTICE pesan harus dikirim atau diperlakukan.

  • EVENT pesan HARUS dikirim hanya dengan ID langganan yang terkait dengan langganan yang sebelumnya dimulai oleh klien (menggunakan REQ pesan di atas).
  • OK pesan HARUS dikirim sebagai tanggapan EVENT pesan yang diterima dari klien, mereka harus menyetel parameter ke-3 true ketika suatu kejadian telah diterima oleh relay, false jika tidak. Parameter ke-4 HARUS selalu ada, tetapi MUNGKIN berupa string kosong jika parameter ke-3 ada truejika tidak maka HARUS berupa string yang dibentuk oleh awalan satu kata yang dapat dibaca mesin diikuti dengan a : dan kemudian pesan yang dapat dibaca manusia. Beberapa contoh:
    • ("OK", "b1a649ebe8...", true, "")
    • ("OK", "b1a649ebe8...", true, "pow: difficulty 25>=24")
    • ("OK", "b1a649ebe8...", true, "duplicate: already have this event")
    • ("OK", "b1a649ebe8...", false, "blocked: you are banned from posting here")
    • ("OK", "b1a649ebe8...", false, "blocked: please register your pubkey at
    • ("OK", "b1a649ebe8...", false, "rate-limited: slow down there chief")
    • ("OK", "b1a649ebe8...", false, "invalid: event creation date is too far off from the current time")
    • ("OK", "b1a649ebe8...", false, "pow: difficulty 26 is less than 30")
    • ("OK", "b1a649ebe8...", false, "error: could not connect to the database")
  • CLOSED pesan HARUS dikirim sebagai tanggapan terhadap a REQ ketika relay menolak untuk memenuhinya. Itu juga dapat dikirim ketika relai memutuskan untuk mematikan langganan di sisinya sebelum klien memutus atau mengirim a CLOSE. Pesan ini menggunakan pola yang sama OK pesan dengan awalan yang dapat dibaca mesin dan pesan yang dapat dibaca manusia. Beberapa contoh:
    • ("CLOSED", "sub1", "unsupported: filter contains unknown elements")
    • ("CLOSED", "sub1", "error: could not connect to the database")
    • ("CLOSED", "sub1", "error: shutting down idle subscription")
  • Awalan standar yang dapat dibaca mesin untuk OK Dan CLOSED adalah: duplicate, pow, blocked, rate-limited, invalidDan error karena ketika tidak ada yang cocok.

Sumber

Krystian Wiśniewski
Krystian Wiśniewski is a dedicated Sports Reporter and Editor with a degree in Sports Journalism from He graduated with a degree in Journalism from the University of Warsaw. Bringing over 14 years of international reporting experience, Krystian has covered major sports events across Europe, Asia, and the United States of America. Known for his dynamic storytelling and in-depth analysis, he is passionate about capturing the excitement of sports for global audiences and currently leads sports coverage and editorial projects at Agen BRILink dan BRI.