github.com/KYVENetwork/cometbft/v38@v38.0.3/docs/app-dev/indexing-transactions.md (about)

     1  ---
     2  order: 5
     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 `ResponseFinalizeBlock.tx_results.events` and
     9  blocks are indexed by `ResponseFinalizeBlock.events`. However, transactions
    10  are also indexed by a primary key which includes the transaction hash and maps
    11  to and stores the corresponding transaction results. 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. `FinalizeBlock`)
    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 `FinalizeBlock` call for height 1:
   106  
   107  ```
   108  Key                                 value
   109  ---- event1 ------
   110  transferSenderBobFinalizeBlock11           1
   111  transferRecipientAliceFinalizeBlock11      1
   112  transferBalance100FinalizeBlock11          1
   113  transferNodeNothingFinalizeBlock11         1
   114  ---- event2 ------
   115  transferSenderTomFinalizeBlock12           1
   116  transferRecepientAliceFinalizeBlock12      1
   117  transferBalance200FinalizeBlock12          1
   118  transferNodeNothingFinalizeBlock12         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 `FinalizeBlock` 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 *Application) FinalizeBlock(_ context.Context, req *types.RequestFinalizeBlock) (*types.ResponseFinalizeBlock, error) {
   177  
   178      //...
   179    tx_results[0] := &types.ExecTxResult{
   180  			Code: CodeTypeOK,
   181  			// With every transaction we can emit a series of events. To make it simple, we just emit the same events.
   182  			Events: []types.Event{
   183  				{
   184  					Type: "app",
   185  					Attributes: []types.EventAttribute{
   186  						{Key: "creator", Value: "Cosmoshi Netowoko", Index: true},
   187  						{Key: "key", Value: key, Index: true},
   188  						{Key: "index_key", Value: "index is working", Index: true},
   189  						{Key: "noindex_key", Value: "index is working", Index: false},
   190  					},
   191  				},
   192  				{
   193  					Type: "app",
   194  					Attributes: []types.EventAttribute{
   195  						{Key: "creator", Value: "Cosmoshi", Index: true},
   196  						{Key: "key", Value: value, Index: true},
   197  						{Key: "index_key", Value: "index is working", Index: true},
   198  						{Key: "noindex_key", Value: "index is working", Index: false},
   199  					},
   200  				},
   201  			},
   202  		}
   203  
   204      block_events = []types.Event{
   205  			{
   206  				Type: "loan",
   207  				Attributes: []types.EventAttribute{
   208  					{	Key:   "account_no", Value: "1", Index: true},
   209  					{ Key:   "amount", Value: "200", Index: true },
   210  				},
   211  			},
   212  			{
   213  				Type: "loan",
   214  				Attributes: []types.EventAttribute{
   215  					{ Key:   "account_no", Value: "2",	Index: true },
   216  					{ Key:   "amount", Value: "300", Index: true},
   217  				},
   218  			},
   219  		}
   220      return &types.ResponseFinalizeBlock{TxResults: tx_results, Events: block_events}
   221  }
   222  ```
   223  
   224  If the indexer is not `null`, the transaction will be indexed. Each event is
   225  indexed using a composite key in the form of `{eventType}.{eventAttribute}={eventValue}`,
   226  e.g. `transfer.sender=bob`.
   227  
   228  ## Querying Transactions Events
   229  
   230  You can query for a paginated set of transaction by their events by calling the
   231  `/tx_search` RPC endpoint:
   232  
   233  ```bash
   234  curl "localhost:26657/tx_search?query=\"message.sender='cosmos1...'\"&prove=true"
   235  ```
   236  
   237  Check out [API docs](https://docs.cometbft.com/v0.38/rpc/#/Info/tx_search)
   238  for more information on query syntax and other options.
   239  
   240  ## Subscribing to Transactions
   241  
   242  Clients can subscribe to transactions with the given tags via WebSocket by providing
   243  a query to `/subscribe` RPC endpoint.
   244  
   245  ```json
   246  {
   247    "jsonrpc": "2.0",
   248    "method": "subscribe",
   249    "id": "0",
   250    "params": {
   251      "query": "message.sender='cosmos1...'"
   252    }
   253  }
   254  ```
   255  
   256  Check out [API docs](https://docs.cometbft.com/v0.38/rpc/#subscribe) for more information
   257  on query syntax and other options.
   258  
   259  ## Querying Block Events
   260  
   261  You can query for a paginated set of blocks by their events by calling the
   262  `/block_search` RPC endpoint:
   263  
   264  ```bash
   265  curl "localhost:26657/block_search?query=\"block.height > 10 AND val_set.num_changed > 0\""
   266  ```
   267  
   268  
   269  Storing the event sequence was introduced in CometBFT 0.34.26. Before that, up until Tendermint Core 0.34.26,
   270  the event sequence was not stored in the kvstore and events were stored only by height. That means that queries
   271  returned blocks and transactions whose event attributes match within the height but can match across different
   272  events on that height.
   273  This behavior was fixed with CometBFT 0.34.26+. However, if the data was indexed with earlier versions of
   274  Tendermint Core and not re-indexed, that data will be queried as if all the attributes within a height
   275  occurred within the same event.
   276  
   277  ## Event attribute value types
   278  
   279  Users can use anything as an event value. However, if the event attribute value is a number, the following needs to be taken into account:
   280  
   281  - Negative numbers will not be properly retrieved when querying the indexer.
   282  - Event values are converted to big floats (from the `big/math` package). The precision of the floating point number is set to the bit length
   283  of the integer it is supposed to represent, so that there is no loss of information due to insufficient precision. This was not present before CometBFT v0.38.x and all float values were ignored.
   284  - As of CometBFT v0.38.x, queries can contain floating point numbers as well.
   285  - Note that comparing to floats can be imprecise with a high number of decimals.
   286  
   287  [abci-events]: ../spec/abci/abci++_basic_concepts.md#events