Summary
Create a WebSocket server for ar.io gateways to enable users/developers to subscribe to events on Arweave.
Motivation
There's no service that would enable event subscription in the Arweave ecosystem via websockets.
Use cases for devs
- Wallets can subscribe to an event when a certain transaction gets mined
- Other indexers or backends can subscribe to transactions with specific tags
- Other use-cases coming from a fact that you can particularly sub to any event, e.g. new block mined, new tx mined that meets specific ANS, ...
Other motivations
- The big advantage of WebSockets is that after the handshake procedure, the overhead of individual messages is low, making it good for sending a high number of requests.
- Currently, there is no real-world use for indexed data in the database; this feature would finally give indexing some meaning
- As mentioned above, there's no solution for
ws in the space right now, so it would be a good selling point for ar.io
- Note: This feature will be totally optional by enabling the
WS_ENABLED variable in .env
Specification
Because WebSockets doesn't follow any strict rules/protocols there's a need to create its own communication protocol.
This is a type specification of each message in this new protocol:
{
"method": "<specify the type of action; e.g. subscribe, unsubscribe, error states, etc.>",
"event": "<specify type of event you want to sub; only used in 'ar_subscribe method'>",
"params": "<specify parameters of the event; for every event/method it's different>",
"result": "<specify the result data; used only by server for returning data>"
}
Example of communication
It works by subscribing to particular events. The gateway will return a subscription ID. For each event that matches the subscription, a notification with relevant data is sent together with the subscription ID.
- Create subscription (this example:
subscribe to all new txs):
{
"method": "ar_subscribe",
"event": "new_tx",
"params": null,
}
- Response from
ar.io gateway (returns a subscription id - uuid v4):
{
"method": "ar_subscribe_accepted",
// Subscription ID
"result": "bd52673d-832f-4b34-a79d-79058e7f6989",
}
- After the creation of the subscription, the client will receive a notification in this format:
{
"method": "ar_subscribe_msg",
"params": {
"subscription": "bd52673d-832f-4b34-a79d-79058e7f6989"
},
"result": [
{ "id": "FPDHr4gKD...yG2I", "owner": "sb7fS07r5...AVm0", "tags": [...], ... },
{ "id": "4d0G6Nk4z...hm44", "owner": "pnqyui51Q...jLvQ", "tags": [...], ... },
...
],
}
- If the client wants to cancel the subscription:
{
"method": "ar_unsubscribe",
"params": {
"subscription": "bd52673d-832f-4b34-a79d-79058e7f6989",
},
}
Event methods
ar_subscribe
ar_subscribe_accepted
ar_subscribe_denied
ar_subscribe_msg
ar_unsubscribe
Event types
new_tx
- params:
owner: string
target: string
tags: { name: string, value: string }[]
- result:
Transaction[]
new_block
- params: none
- result:
Block
Rate-limiting
- Gateway operator could be able to somehow rate-limit the
ws server by:
This would probably need some discussion if it's needed or not.
ENVs
WS_ENABLED | type: boolean | default: false | desc: Start the WebSocket server
WS_PORT | type: number | default: 3333 | desc: Port of the WebSocket server
WS_CORS | type: string | default: * | desc: Allow access from specific origin
Implementation details
- Use of the
ws module in Node.js should be sufficient
- Use of
redis (or dragonflydb) in-memory db for storing subscription IDs and params or use just own implementation of some structure?
Considerations
- Notifications are sent for current events and not for past events
- Subscriptions are coupled to a connection. If the connection is closed all subscriptions that are created over this connection are removed
It's the first blueprint, so there will likely be some blind spots that I've missed. Feedback is highly appreciated. :)
Summary
Create a WebSocket server for
ar.iogateways to enable users/developers to subscribe to events on Arweave.Motivation
There's no service that would enable event subscription in the Arweave ecosystem via
websockets.Use cases for devs
Other motivations
wsin the space right now, so it would be a good selling point forar.ioWS_ENABLEDvariable in.envSpecification
Because WebSockets doesn't follow any strict rules/protocols there's a need to create its own communication protocol.
This is a type specification of each message in this new protocol:
{ "method": "<specify the type of action; e.g. subscribe, unsubscribe, error states, etc.>", "event": "<specify type of event you want to sub; only used in 'ar_subscribe method'>", "params": "<specify parameters of the event; for every event/method it's different>", "result": "<specify the result data; used only by server for returning data>" }Example of communication
It works by subscribing to particular events. The gateway will return a subscription ID. For each event that matches the subscription, a notification with relevant data is sent together with the subscription ID.
subscribe to all new txs):{ "method": "ar_subscribe", "event": "new_tx", "params": null, }ar.iogateway (returns a subscription id -uuid v4):{ "method": "ar_subscribe_accepted", // Subscription ID "result": "bd52673d-832f-4b34-a79d-79058e7f6989", }{ "method": "ar_subscribe_msg", "params": { "subscription": "bd52673d-832f-4b34-a79d-79058e7f6989" }, "result": [ { "id": "FPDHr4gKD...yG2I", "owner": "sb7fS07r5...AVm0", "tags": [...], ... }, { "id": "4d0G6Nk4z...hm44", "owner": "pnqyui51Q...jLvQ", "tags": [...], ... }, ... ], }{ "method": "ar_unsubscribe", "params": { "subscription": "bd52673d-832f-4b34-a79d-79058e7f6989", }, }Event methods
ar_subscribear_subscribe_acceptedar_subscribe_deniedar_subscribe_msgar_unsubscribeEvent types
new_txowner: stringtarget: stringtags: { name: string, value: string }[]Transaction[]new_blockBlockRate-limiting
wsserver by:This would probably need some discussion if it's needed or not.
ENVs
WS_ENABLED| type:boolean| default:false| desc:Start the WebSocket serverWS_PORT| type:number| default:3333| desc:Port of the WebSocket serverWS_CORS| type:string| default:*| desc:Allow access from specific originImplementation details
wsmodule inNode.jsshould be sufficientredis(or dragonflydb) in-memory db for storing subscription IDs and params or use just own implementation of some structure?Considerations
It's the first blueprint, so there will likely be some blind spots that I've missed. Feedback is highly appreciated. :)