github.com/badrootd/nibiru-cometbft@v0.37.5-0.20240307173500-2a75559eee9b/docs/app-dev/indexing-transactions.md (about)

     1  ---
     2  order: 6
     3  ---
     4  
     5  # Indexing Transactions
     6  
     7  CometBFT allows you to index transactions and blocks and later query or
     8  subscribe to their results. Transactions are indexed by `TxResult.Events` and
     9  blocks are indexed by `Response(Begin|End)Block.Events`. However, transactions
    10  are also indexed by a primary key which includes the transaction hash and maps
    11  to and stores the corresponding `TxResult`. Blocks are indexed by a primary key
    12  which includes the block height and maps to and stores the block height, i.e.
    13  the block itself is never stored.
    14  
    15  Each event contains a type and a list of attributes, which are key-value pairs
    16  denoting something about what happened during the method's execution. For more
    17  details on `Events`, see the [ABCI][abci-events] documentation.
    18  
    19  An `Event` has a composite key associated with it. A `compositeKey` is
    20  constructed by its type and key separated by a dot.
    21  
    22  For example:
    23  
    24  ```json
    25  "jack": [
    26    "account.number": 100
    27  ]
    28  ```
    29  
    30  would be equal to the composite key of `jack.account.number`.
    31  
    32  By default, CometBFT will index all transactions by their respective hashes
    33  and height and blocks by their height.
    34  
    35  CometBFT allows for different events within the same height to have
    36  equal attributes.
    37  
    38  ## Configuration
    39  
    40  Operators can configure indexing via the `[tx_index]` section. The `indexer`
    41  field takes a series of supported indexers. If `null` is included, indexing will
    42  be turned off regardless of other values provided.
    43  
    44  ```toml
    45  [tx-index]
    46  
    47  # The backend database to back the indexer.
    48  # If indexer is "null", no indexer service will be used.
    49  #
    50  # The application will set which txs to index. In some cases a node operator will be able
    51  # to decide which txs to index based on configuration set in the application.
    52  #
    53  # Options:
    54  #   1) "null"
    55  #   2) "kv" (default) - the simplest possible indexer, backed by key-value storage (defaults to levelDB; see DBBackend).
    56  #     - When "kv" is chosen "tx.height" and "tx.hash" will always be indexed.
    57  #   3) "psql" - the indexer services backed by PostgreSQL.
    58  # indexer = "kv"
    59  ```
    60  
    61  ### Supported Indexers
    62  
    63  #### KV
    64  
    65  The `kv` indexer type is an embedded key-value store supported by the main
    66  underlying CometBFT database. Using the `kv` indexer type allows you to query
    67  for block and transaction events directly against CometBFT's RPC. However, the
    68  query syntax is limited and so this indexer type might be deprecated or removed
    69  entirely in the future.
    70  
    71  **Implementation and data layout**
    72  
    73  The kv indexer stores each attribute of an event individually, by creating a composite key
    74  with
    75  
    76  - event type,
    77  - attribute key,
    78  - attribute value,
    79  - event generator (e.g. `EndBlock` and `BeginBlock`)
    80  - the height, and
    81  - event counter.
    82   For example the following events:
    83  
    84  ```
    85  Type: "transfer",
    86    Attributes: []abci.EventAttribute{
    87     {Key: "sender", Value: "Bob", Index: true},
    88     {Key: "recipient", Value: "Alice", Index: true},
    89     {Key: "balance", Value: "100", Index: true},
    90     {Key: "note", Value: "nothing", Index: true},
    91     },
    92   
    93  ```
    94  
    95  ```
    96  Type: "transfer",
    97    Attributes: []abci.EventAttribute{
    98     {Key: "sender", Value: "Tom", Index: true},
    99     {Key: "recipient", Value: "Alice", Index: true},
   100     {Key: "balance", Value: "200", Index: true},
   101     {Key: "note", Value: "nothing", Index: true},
   102     },
   103  ```
   104  
   105  will be represented as follows in the store, assuming these events result from the EndBlock call for height 1:
   106  
   107  ```
   108  Key                                 value
   109  ---- event1 ------
   110  transferSenderBobEndBlock11           1
   111  transferRecipientAliceEndBlock11     1
   112  transferBalance100EndBlock11         1
   113  transferNodeNothingEndblock11        1
   114  ---- event2 ------
   115  transferSenderTomEndBlock12          1
   116  transferRecepientAliceEndBlock12     1
   117  transferBalance200EndBlock12         1
   118  transferNodeNothingEndblock12        1
   119   
   120  ```
   121  
   122  The event number is a local variable kept by the indexer and incremented when a new event is processed.
   123  It is an `int64` variable and has no other semantics besides being used to associate attributes belonging to the same events within a height.
   124  This variable is not atomically incremented as event indexing is deterministic. **Should this ever change**, the event id generation
   125  will be broken.
   126  
   127  #### PostgreSQL
   128  
   129  The `psql` indexer type allows an operator to enable block and transaction event
   130  indexing by proxying it to an external PostgreSQL instance allowing for the events
   131  to be stored in relational models. Since the events are stored in a RDBMS, operators
   132  can leverage SQL to perform a series of rich and complex queries that are not
   133  supported by the `kv` indexer type. Since operators can leverage SQL directly,
   134  searching is not enabled for the `psql` indexer type via CometBFT's RPC -- any
   135  such query will fail.
   136  
   137  Note, the SQL schema is stored in `state/indexer/sink/psql/schema.sql` and operators
   138  must explicitly create the relations prior to starting CometBFT and enabling
   139  the `psql` indexer type.
   140  
   141  Example:
   142  
   143  ```shell
   144  psql ... -f state/indexer/sink/psql/schema.sql
   145  ```
   146  
   147  ## Default Indexes
   148  
   149  The CometBFT tx and block event indexer indexes a few select reserved events
   150  by default.
   151  
   152  ### Transactions
   153  
   154  The following indexes are indexed by default:
   155  
   156  - `tx.height`
   157  - `tx.hash`
   158  
   159  ### Blocks
   160  
   161  The following indexes are indexed by default:
   162  
   163  - `block.height`
   164  
   165  ## Adding Events
   166  
   167  Applications are free to define which events to index. CometBFT does not
   168  expose functionality to define which events to index and which to ignore. In
   169  your application's `DeliverTx` method, add the `Events` field with pairs of
   170  UTF-8 encoded strings (e.g. "transfer.sender": "Bob", "transfer.recipient":
   171  "Alice", "transfer.balance": "100").
   172  
   173  Example:
   174  
   175  ```go
   176  func (app *KVStoreApplication) DeliverTx(req types.RequestDeliverTx) types.Result {
   177      //...
   178      events := []abci.Event{
   179          {
   180              Type: "transfer",
   181              Attributes: []abci.EventAttribute{
   182                  {Key: "sender ", Value: "Bob ", Index: true},
   183                  {Key: "recipient ", Value: "Alice ", Index: true},
   184                  {Key: "balance ", Value: "100 ", Index: true},
   185                  {Key: "note ", Value: "nothing ", Index: true},
   186              },
   187          },
   188      }
   189      return types.ResponseDeliverTx{Code: code.CodeTypeOK, Events: events}
   190  }
   191  ```
   192  
   193  If the indexer is not `null`, the transaction will be indexed. Each event is
   194  indexed using a composite key in the form of `{eventType}.{eventAttribute}={eventValue}`,
   195  e.g. `transfer.sender=bob`.
   196  
   197  ## Querying Transactions Events
   198  
   199  You can query for a paginated set of transaction by their events by calling the
   200  `/tx_search` RPC endpoint:
   201  
   202  ```bash
   203  curl "localhost:26657/tx_search?query=\"message.sender='cosmos1...'\"&prove=true"
   204  ```
   205  
   206  Check out [API docs](https://docs.cometbft.com/v0.37/rpc/#/Info/tx_search)
   207  for more information on query syntax and other options.
   208  
   209  ## Subscribing to Transactions
   210  
   211  Clients can subscribe to transactions with the given tags via WebSocket by providing
   212  a query to `/subscribe` RPC endpoint.
   213  
   214  ```json
   215  {
   216    "jsonrpc": "2.0",
   217    "method": "subscribe",
   218    "id": "0",
   219    "params": {
   220      "query": "message.sender='cosmos1...'"
   221    }
   222  }
   223  ```
   224  
   225  Check out [API docs](https://docs.cometbft.com/v0.37/rpc/#subscribe) for more information
   226  on query syntax and other options.
   227  
   228  ## Querying Block Events
   229  
   230  You can query for a paginated set of blocks by their events by calling the
   231  `/block_search` RPC endpoint:
   232  
   233  ```bash
   234  curl "localhost:26657/block_search?query=\"block.height > 10 AND val_set.num_changed > 0\""
   235  ```
   236  
   237  
   238  Storing the event sequence was introduced in CometBFT 0.34.26. Before that, up until Tendermint Core 0.34.26,
   239  the event sequence was not stored in the kvstore and events were stored only by height. That means that queries
   240  returned blocks and transactions whose event attributes match within the height but can match across different
   241  events on that height.
   242  This behavior was fixed with CometBFT 0.34.26+. However, if the data was indexed with earlier versions of
   243  Tendermint Core and not re-indexed, that data will be queried as if all the attributes within a height
   244  occurred within the same event.
   245  
   246  # Event attribute value types
   247  
   248  Users can use anything as an event value. However, if the even attrbute value is a number, the following restrictions apply:
   249  
   250  - Negative numbers will not be properly retrieved when querying the indexer
   251  - When querying the events using `tx_search` and `block_search`, the value given as part of the condition cannot be a float.
   252  - Any event value retrieved from the database will be represented as a `BigInt` (from `math/big`)
   253  - Floating point values are not read from the database even with the introduction of `BigInt`. This was intentionally done
   254  to keep the same beheaviour as was historically present and not introduce breaking  changes. This will be fixed in the 0.38 series.
   255  
   256  [abci-events]: https://github.com/cometbft/cometbft/blob/v0.37.x/spec/abci/abci++_basic_concepts.md#events