diff --git a/docs/tendermint-core/subscription.md b/docs/tendermint-core/subscription.md index 0f452c563..84979f61a 100644 --- a/docs/tendermint-core/subscription.md +++ b/docs/tendermint-core/subscription.md @@ -2,74 +2,228 @@ order: 7 --- -# Subscribing to events via Websocket +# Subscribing to Events -Tendermint emits different events, which you can subscribe to via -[Websocket](https://en.wikipedia.org/wiki/WebSocket). This can be useful -for third-party applications (for analysis) or for inspecting state. +A Tendermint node emits events about important state transitions during +consensus. These events can be queried by clients via the [RPC interface][rpc] +on nodes that enable it. The [list of supported event types][event-types] can +be found in the tendermint/types Go package. -[List of events](https://godoc.org/github.com/tendermint/tendermint/types#pkg-constants) +In Tendermint v0.36 there are two APIs to query events: -To connect to a node via websocket from the CLI, you can use a tool such as -[wscat](https://github.com/websockets/wscat) and run: +- The [**legacy streaming API**](#legacy-streaming-api), comprising the + `subscribe`, `unsubscribe`, and `unsubscribe_all` RPC methods over websocket. + +- The [**event log API**](#event-log-api), comprising the `events` RPC method. + +The legacy streaming API is deprecated in Tendermint v0.36, and will be removed +in Tendermint v0.37. Clients are strongly encouraged to migrate to the new +event log API as soon as is practical. + +[rpc]: https://docs.tendermint.com/master/rpc +[event-types]: https://godoc.org/github.com/tendermint/tendermint/types#EventNewBlockValue + +## Filter Queries + +Event requests take a [filter query][query] parameter. A filter query is a +string that describes a subset of available event items to return. An empty +query matches all events; otherwise a query comprises one or more *terms* +comparing event metadata to target values. + +For example, to select new block events, use the term: + +``` +tm.event = 'NewBlock' +``` + +Multiple terms can be combined with `AND` (case matters), for example to match +the transaction event with a given hash, use the query: + +``` +tm.event = 'Tx' AND tx.hash = 'EA7B33F' +``` + +Operands may be strings in single quotes (`'Tx'`), numbers (`45`), dates, or +timestamps. + +The comparison operators include `=`, `<`, `<=`, `>`, `>=`, and `CONTAINS` (for +substring match). In addition, the `EXISTS` operator checks for the presence +of an attribute regardless of its value. + +### Attributes + +Tendermint implicitly defines a string-valued `tm.event` attribute for all +event types. Transaction items (type `Tx`) are also assigned `tx.hash` +(string), giving the hash of the transaction, and and `tx.height` (number) +giving the height of the block containing the transaction. For `NewBlock` and +`NewBlockHeader` events, Tendermint defines a `block.height` attribute giving +the height of the block. + +Additional attributes can be provided by the application as [ABCI `Event` +records][abci-event] in response to the `FinalizeBlock` request. The full name +of the attribute in the query is formed by combining the `type` and attribute +`key` with a period. + +For example, given the events + +```go +[]abci.Event{{ + Type: "reward", + Attributes: []abci.EventAttribute{ + {Key: "address", Value: "cosmos1xyz012pdq"}, + {Key: "amount", Value: "45.62"}, + {Key: "balance", Value: "100.390001"}, + }, +}} +``` + +a query may refer to the names `reward.address`, `reward.amount`, and `reward.balance`, as in: + +``` +reward.address EXISTS AND reward.balance > 45 +``` + +Certain application-specific metadata are also indexed for offline queries. +See [Indexing transactions](../app-dev/indexing-transactions.md) for more details. + +[query]: https://godoc.org/github.com/tendermint/tendermint/internal/pubsub/query/syntax +[abci-event]: https://github.com/tendermint/tendermint/blob/master/proto/tendermint/abci/types.proto#L397 + +## Event Log API + +Starting in Tendermint v0.36, when the `rpc.event-log-window-size` +configuration is enabled, the node maintains maintains a log of all events +within this operator-defined time window. This API supersedes the websocket +subscription API described below. + +Clients can query these events can by long-polling the `/events` RPC method, +which returns the most recent items from the log that match the [request +parameters][reqevents]. Each item returned includes a cursor that marks its +location in the log. Cursors can be passed via the `before` and `after` +parameters to fetch events earlier in the log. + +For example, this request: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "events", + "params": { + "filter": { + "query": "tm.event = 'Tx' AND app.key = 'applesauce'" + }, + "maxItems": 1, + "after": "" + } +} +``` + +will return a result similar to the following: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "result": { + "items": [ + { + "cursor": "16ee3d5e65be53d8-03d5", + "event": "Tx", + "data": { + "type": "tendermint/event/Tx", + "value": { + "height": 70, + "tx": "YXBwbGVzYXVjZT1zeXJ1cA==", + "result": { + "events": [ + { + "type": "app", + "attributes": [ + { + "key": "creator", + "value": "Cosmoshi Netowoko", + "index": true + }, + { + "key": "key", + "value": "applesauce", + "index": true + }, + { + "key": "index_key", + "value": "index is working", + "index": true + }, + { + "key": "noindex_key", + "value": "index is working", + "index": false + } + ] + } + ] + } + } + } + } + ], + "more": false, + "oldest": "16ee3d4c471c3b00-0001", + "newest": "16ee3d5f2e05a4e0-0400" + } +} +``` + +The `"items"` array gives the matching items (up to the requested +`"maxResults"`) in decreasing time order (i.e., newest to oldest). In this +case, there is only one result, but if there are additional results that were +not returned, the `"more"` flag will be true. Calling `/events` again with the +same query and `"after"` set to the cursor of the newest result (in this +example, `"16ee3d5e65be53d8-03d5"`) will fetch newer results. + +Go clients can use the [`eventstream`][eventstream] package to simplify the use +of this method. The `eventstream.Stream` automatically handles polling for new +events, updating the cursor, and reporting any missed events. + +[reqevents]: https://pkg.go.dev/github.com/tendermint/tendermint@master/rpc/coretypes#RequestEvents +[eventstream]: https://godoc.org/github.com/tendermint/tendermint/rpc/client/eventstream + +## Legacy Streaming API + +- **Note:** This API is deprecated in Tendermint v0.36, and will be removed in + Tendermint v0.37. New clients and existing use should use the [event log + API](#event-log-api) instead. See [ADR 075][adr075] for more details. + +To subscribe to events in the streaming API, you must connect to the node RPC +service using a [websocket][ws]. From the command line you can use a tool such +as [wscat][wscat], for example: ```sh wscat ws://127.0.0.1:26657/websocket ``` -You can subscribe to any of the events above by calling the `subscribe` RPC -method via Websocket along with a valid query. +[ws]: https://en.wikipedia.org/wiki/WebSocket +[wscat]: https://github.com/websockets/wscat + +To subscribe to events, call the `subscribe` JSON-RPC method method passing in +a [filter query][query] for the events you wish to receive: ```json { "jsonrpc": "2.0", "method": "subscribe", - "id": 0, + "id": 1, "params": { "query": "tm.event='NewBlock'" } } ``` -Check out [API docs](https://docs.tendermint.com/master/rpc/) for -more information on query syntax and other options. +The subscribe method returns an initial response confirming the subscription, +then sends additional JSON-RPC response messages containing the matching events +as they are published. The subscription continues until either the client +explicitly cancels the subscription (by calling `unsubscribe` or +`unsubscribe_all`) or until the websocket connection is terminated. -You can also use tags, given you had included them into DeliverTx -response, to query transaction results. See [Indexing -transactions](../app-dev/indexing-transactions.md) for details. - -## ValidatorSetUpdates - -When validator set changes, ValidatorSetUpdates event is published. The -event carries a list of pubkey/power pairs. The list is the same -Tendermint receives from ABCI application (see [EndBlock -section](https://github.com/tendermint/tendermint/blob/master/spec/abci/abci.md#endblock) in -the ABCI spec). - -Response: - -```json -{ - "jsonrpc": "2.0", - "id": 0, - "result": { - "query": "tm.event='ValidatorSetUpdates'", - "data": { - "type": "tendermint/event/ValidatorSetUpdates", - "value": { - "validator_updates": [ - { - "address": "09EAD022FD25DE3A02E64B0FE9610B1417183EE4", - "pub_key": { - "type": "tendermint/PubKeyEd25519", - "value": "ww0z4WaZ0Xg+YI10w43wTWbBmM3dpVza4mmSQYsd0ck=" - }, - "voting_power": "10", - "proposer_priority": "0" - } - ] - } - } - } -} -``` +[adr075]: https://tinyurl.com/adr075 diff --git a/rpc/openapi/openapi.yaml b/rpc/openapi/openapi.yaml index 74ac3a0ae..d44463da7 100644 --- a/rpc/openapi/openapi.yaml +++ b/rpc/openapi/openapi.yaml @@ -260,10 +260,9 @@ paths: operationId: events description: | Fetch a batch of events posted by the consensus node and matching a - specified query. + specified query string. - The query grammar is defined in - https://godoc.org/github.com/tendermint/tendermint/internal/pubsub/query/syntax. + The query grammar is defined in [pubsub/query/syntax](https://godoc.org/github.com/tendermint/tendermint/internal/pubsub/query/syntax). An empty query matches all events; otherwise a query comprises one or more terms comparing event metadata to target values. For example, to select new block events: @@ -275,13 +274,13 @@ paths: tm.event = 'Tx' AND tx.hash = 'EA7B33F' - The comparison operators include "=", "<", "<=", ">", ">=", and - "CONTAINS". Operands may be strings (in single quotes), numbers, dates, - or timestamps. In addition, the "EXISTS" operator allows you to check + The comparison operators include `=`, `<`, `<=`, `>`, `>=`, and + `CONTAINS`. Operands may be strings (in single quotes), numbers, dates, + or timestamps. In addition, the `EXISTS` operator allows you to check for the presence of an attribute regardless of its value. - Tendermint defines a tm.event attribute for all events. Transactions - are also assigned tx.hash and tx.height attributes. Other attributes + Tendermint defines a `tm.event` attribute for all events. Transactions + are also assigned `tx.hash` and `tx.height` attributes. Other attributes are provided by the application as ABCI Event records. The name of the event in the query is formed by combining the type and attribute key with a period. For example, given: @@ -295,16 +294,16 @@ paths: }, }} - the query may refer to the names "reward.address", "reward.amount", and - "reward.balance", as in: + the query may refer to the names`"reward.address`,`"reward.amount`, and + `reward.balance`, as in: reward.address EXISTS AND reward.balance > 45 The node maintains a log of all events within an operator-defined time window. The /events method returns the most recent items from the log that match the query. Each item returned includes a cursor that marks - its location in the log. Cursors can be passed via the "before" and - "after" parameters to fetch events earlier in the log. + its location in the log. Cursors can be passed via the `before` and + `after` parameters to fetch events earlier in the log. parameters: - in: query name: filter