Synopsis
This document describes
BaseApp, the abstraction that implements the core functionalities of a Cosmos SDK application.Pre-requisite Readings
Introduction
BaseApp is a base type that implements the core of a Cosmos SDK application, namely:
- The Application Blockchain Interface, for the state-machine to communicate with the underlying consensus engine (e.g. CometBFT).
- Service Routers, to route messages and queries to the appropriate module.
- Different states, as the state-machine can have different volatile states updated based on the ABCI message received.
BaseApp is to provide the fundamental layer of a Cosmos SDK application
that developers can easily extend to build their own custom application. Usually,
developers will create a custom type for their application, like so:
BaseApp gives the former access to all of BaseApp’s methods.
This allows developers to compose their custom application with the modules they want, while not
having to concern themselves with the hard work of implementing the ABCI, the service routers and state
management logic.
Type Definition
TheBaseApp type holds many important parameters for any Cosmos SDK based application.
Note: Not all parameters are described, only the most important ones. Refer to the type definition for the full list.First, the important parameters that are initialized during the bootstrapping of the application:
CommitMultiStore: This is the main store of the application, which holds the canonical state that is committed at the end of each block. This store is not cached, meaning it is not used to update the application’s volatile (un-committed) states. TheCommitMultiStoreis a multi-store, meaning a store of stores. Each module of the application uses one or multipleKVStoresin the multi-store to persist their subset of the state.- Database: The
dbis used by theCommitMultiStoreto handle data persistence. MsgService Router: ThemsgServiceRouterfacilitates the routing ofsdk.Msgrequests to the appropriate moduleMsgservice for processing. Here asdk.Msgrefers to the transaction component that needs to be processed by a service in order to update the application state, and not to ABCI message which implements the interface between the application and the underlying consensus engine.- gRPC Query Router: The
grpcQueryRouterfacilitates the routing of gRPC queries to the appropriate module for it to be processed. These queries are not ABCI messages themselves, but they are relayed to the relevant module’s gRPCQueryservice. TxDecoder: It is used to decode raw transaction bytes relayed by the underlying CometBFT engine.AnteHandler: This handler is used to handle signature verification, fee payment, and other pre-message execution checks when a transaction is received. It’s executed duringCheckTx/RecheckTxandDeliverTx.InitChainer,BeginBlockerandEndBlocker: These are the functions executed when the application receives theInitChain,BeginBlockandEndBlockABCI messages from the underlying CometBFT engine.
checkState: This state is updated duringCheckTx, and reset onCommit.deliverState: This state is updated duringDeliverTx, and set tonilonCommitand gets re-initialized on BeginBlock.processProposalState: This state is updated duringProcessProposal.prepareProposalState: This state is updated duringPrepareProposal.
voteInfos: This parameter carries the list of validators whose precommit is missing, either because they did not vote or because the proposer did not include their vote. This information is carried by the and can be used by the application for various things like punishing absent validators.minGasPrices: This parameter defines the minimum gas prices accepted by the node. This is a local parameter, meaning each full-node can set a differentminGasPrices. It is used in theAnteHandlerduringCheckTx, mainly as a spam protection mechanism. The transaction enters the mempool only if the gas prices of the transaction are greater than one of the minimum gas price inminGasPrices(e.g. ifminGasPrices == 1uatom,1photon, thegas-priceof the transaction must be greater than1uatomOR1photon).appVersion: Version of the application. It is set in the application’s constructor function.
Constructor
BaseApp constructor function is pretty straightforward. The only thing worth noting is the
possibility to provide additional options
to the BaseApp, which will execute them in order. The options are generally setter functions
for important parameters, like SetPruning() to set pruning options or SetMinGasPrices() to set
the node’s min-gas-prices.
Naturally, developers can add additional options based on their application’s needs.
State Updates
TheBaseApp maintains four primary volatile states and a root or main state. The main state
is the canonical state of the application and the volatile states, checkState, deliverState, prepareProposalState, processPreposalState,
are used to handle state transitions in-between the main state made during Commit.
Internally, there is only a single CommitMultiStore which we refer to as the main or root state.
From this root state, we derive four volatile states by using a mechanism called store branching (performed by CacheWrap function).
The types can be illustrated as follows:

InitChain State Updates
DuringInitChain, the four volatile states, checkState, prepareProposalState, processProposalState
and deliverState are set by branching the root CommitMultiStore. Any subsequent reads and writes happen
on branched versions of the CommitMultiStore.
To avoid unnecessary roundtrip to the main state, all reads to the branched store are cached.

CheckTx State Updates
DuringCheckTx, the checkState, which is based off of the last committed state from the root
store, is used for any reads and writes. Here we only execute the AnteHandler and verify a service router
exists for every message in the transaction. Note, when we execute the AnteHandler, we branch
the already branched checkState.
This has the side effect that if the AnteHandler fails, the state transitions won’t be reflected in the checkState
— i.e. checkState is only updated on success.

PrepareProposal State Updates
DuringPrepareProposal, the prepareProposalState is set by branching the root CommitMultiStore.
The prepareProposalState is used for any reads and writes that occur during the PrepareProposal phase.
The function uses the Select() method of the mempool to iterate over the transactions. runTx is then called,
which encodes and validates each transaction and from there the AnteHandler is executed.
If successful, valid transactions are returned inclusive of the events, tags, and data generated
during the execution of the proposal.
The described behavior is that of the default handler, applications have the flexibility to define their own
custom mempool handlers.

ProcessProposal State Updates
DuringProcessProposal, the processProposalState is set based off of the last committed state
from the root store and is used to process a signed proposal received from a validator.
In this state, runTx is called and the AnteHandler is executed and the context used in this state is built with information
from the header and the main state, including the minimum gas prices, which are also set.
Again we want to highlight that the described behavior is that of the default handler and applications have the flexibility to define their own
custom mempool handlers.

BeginBlock State Updates
DuringBeginBlock, the deliverState is set for use in subsequent DeliverTx ABCI messages. The
deliverState is based off of the last committed state from the root store and is branched.
Note, the deliverState is set to nil on Commit.

DeliverTx State Updates
The state flow forDeliverTx is nearly identical to CheckTx except state transitions occur on
the deliverState and messages in a transaction are executed. Similarly to CheckTx, state transitions
occur on a doubly branched state — deliverState. Successful message execution results in
writes being committed to deliverState. Note, if message execution fails, state transitions from
the AnteHandler are persisted.

Commit State Updates
DuringCommit all the state transitions that occurred in the deliverState are finally written to
the root CommitMultiStore which in turn is committed to disk and results in a new application
root hash. These state transitions are now considered final. Finally, the checkState is set to the
newly committed state and deliverState is set to nil to be reset on BeginBlock.

ParamStore
DuringInitChain, the RequestInitChain provides ConsensusParams which contains parameters
related to block execution such as maximum gas and size in addition to evidence parameters. If these
parameters are non-nil, they are set in the BaseApp’s ParamStore. Behind the scenes, the ParamStore
is managed by an x/consensus_params module. This allows the parameters to be tweaked via
on-chain governance.
Service Routers
When messages and queries are received by the application, they must be routed to the appropriate module in order to be processed. Routing is done viaBaseApp, which holds a msgServiceRouter for messages, and a grpcQueryRouter for queries.
Msg Service Router
sdk.Msgs need to be routed after they are extracted from transactions, which are sent from the underlying CometBFT engine via the CheckTx and DeliverTx ABCI messages. To do so, BaseApp holds a msgServiceRouter which maps fully-qualified service methods (string, defined in each module’s Protobuf Msg service) to the appropriate module’s MsgServer implementation.
The default msgServiceRouter included in BaseApp is stateless. However, some applications may want to make use of more stateful routing mechanisms such as allowing governance to disable certain routes or point them to new modules for upgrade purposes. For this reason, the sdk.Context is also passed into each route handler inside msgServiceRouter. For a stateless router that doesn’t want to make use of this, you can just ignore the ctx.
The application’s msgServiceRouter is initialized with all the routes using the application’s module manager (via the RegisterServices method), which itself is initialized with all the application’s modules in the application’s constructor.
gRPC Query Router
Similar tosdk.Msgs, queries need to be routed to the appropriate module’s Query service. To do so, BaseApp holds a grpcQueryRouter, which maps modules’ fully-qualified service methods (string, defined in their Protobuf Query gRPC) to their QueryServer implementation. The grpcQueryRouter is called during the initial stages of query processing, which can be either by directly sending a gRPC query to the gRPC endpoint, or via the Query ABCI message on the CometBFT RPC endpoint.
Just like the msgServiceRouter, the grpcQueryRouter is initialized with all the query routes using the application’s module manager (via the RegisterServices method), which itself is initialized with all the application’s modules in the application’s constructor.
Main ABCI 1.0 Messages
The Application-Blockchain Interface (ABCI) is a generic interface that connects a state-machine with a consensus engine to form a functional full-node. It can be wrapped in any language, and needs to be implemented by each application-specific blockchain built on top of an ABCI-compatible consensus engine like CometBFT. The consensus engine handles two main tasks:- The networking logic, which mainly consists in gossiping block parts, transactions and consensus votes.
- The consensus logic, which results in the deterministic ordering of transactions in the form of blocks.
[]bytes, and relayed to the application via the ABCI to be decoded and processed. At keys moments in the networking and consensus processes (e.g. beginning of a block, commit of a block, reception of an unconfirmed transaction, …), the consensus engine emits ABCI messages for the state-machine to act on.
Developers building on top of the Cosmos SDK need not implement the ABCI themselves, as BaseApp comes with a built-in implementation of the interface. Let us go through the main ABCI messages that BaseApp implements:
Prepare Proposal
ThePrepareProposal function is part of the new methods introduced in Application Blockchain Interface (ABCI++) in CometBFT and is an important part of the application’s overall governance system. In the Cosmos SDK, it allows the application to have more fine-grained control over the transactions that are processed, and ensures that only valid transactions are committed to the blockchain.
Here is how the PrepareProposal function can be implemented:
- Extract the
sdk.Msgs from the transaction. - Perform stateful checks by calling
Validate()on each of thesdk.Msg’s. This is done after stateless checks as stateful checks are more computationally expensive. IfValidate()fails,PrepareProposalreturns before running further checks, which saves resources. - Perform any additional checks that are specific to the application, such as checking account balances, or ensuring that certain conditions are met before a transaction is proposed.hey are processed by the consensus engine, if necessary.
- Return the updated transactions to be processed by the consensus engine
CheckTx(), PrepareProposal process sdk.Msgs, so it can directly update the state. However, unlike DeliverTx(), it does not commit the state updates. It’s important to exercise caution when using PrepareProposal as incorrect coding could affect the overall liveness of the network.
It’s important to note that PrepareProposal complements the ProcessProposal method which is executed after this method. The combination of these two methods means that it is possible to guarantee that no invalid transactions are ever committed. Furthermore, such a setup can give rise to other interesting use cases such as Oracles, threshold decryption and more.
PrepareProposal returns a response to the underlying consensus engine of type abci.ResponseCheckTx. The response contains:
Code (uint32): Response Code.0if successful.Data ([]byte): Result bytes, if any.Log (string):The output of the application’s logger. May be non-deterministic.Info (string):Additional information. May be non-deterministic.
Process Proposal
TheProcessProposal function is called by the BaseApp as part of the ABCI message flow, and is executed during the BeginBlock phase of the consensus process. The purpose of this function is to give more control to the application for block validation, allowing it to check all transactions in a proposed block before the validator sends the prevote for the block. It allows a validator to perform application-dependent work in a proposed block, enabling features such as immediate block execution, and allows the Application to reject invalid blocks.
The ProcessProposal function performs several key tasks, including:
- Validating the proposed block by checking all transactions in it.
- Checking the proposed block against the current state of the application, to ensure that it is valid and that it can be executed.
- Updating the application’s state based on the proposal, if it is valid and passes all checks.
- Returning a response to CometBFT indicating the result of the proposal processing.
ProcessProposal is an important part of the application’s overall governance system. It is used to manage the network’s parameters and other key aspects of its operation. It also ensures that the coherence property is adhered to i.e. all honest validators must accept a proposal by an honest proposer.
It’s important to note that ProcessProposal complements the PrepareProposal method which enables the application to have more fine-grained transaction control by allowing it to reorder, drop, delay, modify, and even add transactions as they see necessary. The combination of these two methods means that it is possible to guarantee that no invalid transactions are ever committed. Furthermore, such a setup can give rise to other interesting use cases such as Oracles, threshold decryption and more.
CometBFT calls it when it receives a proposal and the CometBFT algorithm has not locked on a value. The Application cannot modify the proposal at this point but can reject it if it is invalid. If that is the case, CometBFT will prevote nil on the proposal, which has strong liveness implications for CometBFT. As a general rule, the Application SHOULD accept a prepared proposal passed via ProcessProposal, even if a part of the proposal is invalid (e.g., an invalid transaction); the Application can ignore the invalid part of the prepared proposal at block execution time.
However, developers must exercise greater caution when using these methods. Incorrectly coding these methods could affect liveness as CometBFT is unable to receive 2/3 valid precommits to finalize a block.
ProcessProposal returns a response to the underlying consensus engine of type abci.ResponseCheckTx. The response contains:
Code (uint32): Response Code.0if successful.Data ([]byte): Result bytes, if any.Log (string):The output of the application’s logger. May be non-deterministic.Info (string):Additional information. May be non-deterministic.
CheckTx
CheckTx is sent by the underlying consensus engine when a new unconfirmed (i.e. not yet included in a valid block)
transaction is received by a full-node. The role of CheckTx is to guard the full-node’s mempool
(where unconfirmed transactions are stored until they are included in a block) from spam transactions.
Unconfirmed transactions are relayed to peers only if they pass CheckTx.
CheckTx() can perform both stateful and stateless checks, but developers should strive to
make the checks lightweight because gas fees are not charged for the resources (CPU, data load…) used during the CheckTx.
In the Cosmos SDK, after decoding transactions, CheckTx() is implemented
to do the following checks:
- Extract the
sdk.Msgs from the transaction. - Optionally perform stateless checks by calling
ValidateBasic()on each of thesdk.Msgs. This is done first, as stateless checks are less computationally expensive than stateful checks. IfValidateBasic()fail,CheckTxreturns before running stateful checks, which saves resources. This check is still performed for messages that have not yet migrated to the new message validation mechanism defined in RFC 001 and still have aValidateBasic()method. - Perform non-module related stateful checks on the account. This step is mainly about checking
that the
sdk.Msgsignatures are valid, that enough fees are provided and that the sending account has enough funds to pay for said fees. Note that no precisegascounting occurs here, assdk.Msgs are not processed. Usually, theAnteHandlerwill check that thegasprovided with the transaction is superior to a minimum reference gas amount based on the raw transaction size, in order to avoid spam with transactions that provide 0 gas.
CheckTx does not process sdk.Msgs - they only need to be processed when the canonical state need to be updated, which happens during DeliverTx.
Steps 2. and 3. are performed by the AnteHandler in the RunTx()
function, which CheckTx() calls with the runTxModeCheck mode. During each step of CheckTx(), a
special volatile state called checkState is updated. This state is used to keep
track of the temporary changes triggered by the CheckTx() calls of each transaction without modifying
the main canonical state. For example, when a transaction goes through CheckTx(), the
transaction’s fees are deducted from the sender’s account in checkState. If a second transaction is
received from the same account before the first is processed, and the account has consumed all its
funds in checkState during the first transaction, the second transaction will fail CheckTx() and
be rejected. In any case, the sender’s account will not actually pay the fees until the transaction
is actually included in a block, because checkState never gets committed to the main state. The
checkState is reset to the latest state of the main state each time a blocks gets committed.
CheckTx returns a response to the underlying consensus engine of type abci.ResponseCheckTx.
The response contains:
Code (uint32): Response Code.0if successful.Data ([]byte): Result bytes, if any.Log (string):The output of the application’s logger. May be non-deterministic.Info (string):Additional information. May be non-deterministic.GasWanted (int64): Amount of gas requested for transaction. It is provided by users when they generate the transaction.GasUsed (int64): Amount of gas consumed by transaction. DuringCheckTx, this value is computed by multiplying the standard cost of a transaction byte by the size of the raw transaction. Next is an example:
Events ([]cmn.KVPair): Key-Value tags for filtering and indexing transactions (eg. by account). Seeevents for more.Codespace (string): Namespace for the Code.
RecheckTx
AfterCommit, CheckTx is run again on all transactions that remain in the node’s local mempool
excluding the transactions that are included in the block. To prevent the mempool from rechecking all transactions
every time a block is committed, the configuration option mempool.recheck=false can be set. As of
Tendermint v0.32.1, an additional Type parameter is made available to the CheckTx function that
indicates whether an incoming transaction is new (CheckTxType_New), or a recheck (CheckTxType_Recheck).
This allows certain checks like signature verification can be skipped during CheckTxType_Recheck.
DeliverTx
When the underlying consensus engine receives a block proposal, each transaction in the block needs to be processed by the application. To that end, the underlying consensus engine sends aDeliverTx message to the application for each transaction in a sequential order.
Before the first transaction of a given block is processed, a volatile state called deliverState is initialized during BeginBlock. This state is updated each time a transaction is processed via DeliverTx, and committed to the main state when the block is committed, after what it is set to nil.
DeliverTx performs the exact same steps as CheckTx, with a little caveat at step 3 and the addition of a fifth step:
- The
AnteHandlerdoes not check that the transaction’sgas-pricesis sufficient. That is because themin-gas-pricesvaluegas-pricesis checked against is local to the node, and therefore what is enough for one full-node might not be for another. This means that the proposer can potentially include transactions for free, although they are not incentivised to do so, as they earn a bonus on the total fee of the block they propose. - For each
sdk.Msgin the transaction, route to the appropriate module’s ProtobufMsgservice. Additional stateful checks are performed, and the branched multistore held indeliverState’scontextis updated by the module’skeeper. If theMsgservice returns successfully, the branched multistore held incontextis written todeliverStateCacheMultiStore.
GasConsumed. You can find the default cost of each operation:
GasConsumed > GasWanted, the function returns with Code != 0 and DeliverTx fails.
DeliverTx returns a response to the underlying consensus engine of type abci.ResponseDeliverTx. The response contains:
Code (uint32): Response Code.0if successful.Data ([]byte): Result bytes, if any.Log (string):The output of the application’s logger. May be non-deterministic.Info (string):Additional information. May be non-deterministic.GasWanted (int64): Amount of gas requested for transaction. It is provided by users when they generate the transaction.GasUsed (int64): Amount of gas consumed by transaction. DuringDeliverTx, this value is computed by multiplying the standard cost of a transaction byte by the size of the raw transaction, and by adding gas each time a read/write to the store occurs.Events ([]cmn.KVPair): Key-Value tags for filtering and indexing transactions (eg. by account). Seeevents for more.Codespace (string): Namespace for the Code.
RunTx, AnteHandler, RunMsgs, PostHandler
RunTx
RunTx is called from CheckTx/DeliverTx to handle the transaction, with runTxModeCheck or runTxModeDeliver as parameter to differentiate between the two modes of execution. Note that when RunTx receives a transaction, it has already been decoded.
The first thing RunTx does upon being called is to retrieve the context’s CacheMultiStore by calling the getContextForTx() function with the appropriate mode (either runTxModeCheck or runTxModeDeliver). This CacheMultiStore is a branch of the main store, with cache functionality (for query requests), instantiated during BeginBlock for DeliverTx and during the Commit of the previous block for CheckTx. After that, two defer func() are called for gas management. They are executed when runTx returns and make sure gas is actually consumed, and will throw errors, if any.
After that, RunTx() calls ValidateBasic(), when available and for backward compatibility, on each sdk.Msgin the Tx, which runs preliminary stateless validity checks. If any sdk.Msg fails to pass ValidateBasic(), RunTx() returns with an error.
Then, the anteHandler of the application is run (if it exists). In preparation of this step, both the checkState/deliverState’s context and context’s CacheMultiStore are branched using the cacheTxContext() function.
RunTx not to commit the changes made to the state during the execution of anteHandler if it ends up failing. It also prevents the module implementing the anteHandler from writing to state, which is an important part of the object-capabilities of the Cosmos SDK.
Finally, the RunMsgs() function is called to process the sdk.Msgs in the Tx. In preparation of this step, just like with the anteHandler, both the checkState/deliverState’s context and context’s CacheMultiStore are branched using the cacheTxContext() function.
AnteHandler
TheAnteHandler is a special handler that implements the AnteHandler interface and is used to authenticate the transaction before the transaction’s internal messages are processed.
AnteHandler is theoretically optional, but still a very important component of public blockchain networks. It serves 3 primary purposes:
- Be a primary line of defense against spam and second line of defense (the first one being the mempool) against transaction replay with fees deduction and
sequencechecking. - Perform preliminary stateful validity checks like ensuring signatures are valid or that the sender has enough funds to pay for fees.
- Play a role in the incentivisation of stakeholders via the collection of transaction fees.
BaseApp holds an anteHandler as parameter that is initialized in the application’s constructor. The most widely used anteHandler is the auth module.
Click here for more on the anteHandler.
RunMsgs
RunMsgs is called from RunTx with runTxModeCheck as parameter to check the existence of a route for each message the transaction, and with runTxModeDeliver to actually process the sdk.Msgs.
First, it retrieves the sdk.Msg’s fully-qualified type name, by checking the type_url of the Protobuf Any representing the sdk.Msg. Then, using the application’s msgServiceRouter, it checks for the existence of Msg service method related to that type_url. At this point, if mode == runTxModeCheck, RunMsgs returns. Otherwise, if mode == runTxModeDeliver, the Msg service RPC is executed, before RunMsgs returns.
PostHandler
PostHandler is similar to AnteHandler, but it, as the name suggests, executes custom post tx processing logic after RunMsgs is called. PostHandler receives the Result of the the RunMsgs in order to enable this customizable behavior.
Like AnteHandlers, PostHandlers are theoretically optional, one use case for PostHandlers is transaction tips (enabled by default in simapp).
Other use cases like unused gas refund can also be enabled by PostHandlers.
PostHandlers fail, the state from runMsgs is also reverted, effectively making the transaction fail.
Other ABCI Messages
InitChain
TheInitChain ABCI message is sent from the underlying CometBFT engine when the chain is first started. It is mainly used to initialize parameters and state like:
- Consensus Parameters via
setConsensusParams. checkStateanddeliverStateviasetState.- The block gas meter, with infinite gas to process genesis transactions.
InitChain(req abci.RequestInitChain) method of BaseApp calls the initChainer() of the application in order to initialize the main state of the application from the genesis file and, if defined, call the InitGenesis function of each of the application’s modules.
BeginBlock
TheBeginBlock ABCI message is sent from the underlying CometBFT engine when a block proposal created by the correct proposer is received, before DeliverTx is run for each transaction in the block. It allows developers to have logic be executed at the beginning of each block. In the Cosmos SDK, the BeginBlock(req abci.RequestBeginBlock) method does the following:
-
Initialize
deliverStatewith the latest header using thereq abci.RequestBeginBlockpassed as parameter via thesetStatefunction.This function also resets the main gas meter. -
Initialize the block gas meter with the
maxGaslimit. Thegasconsumed within the block cannot go abovemaxGas. This parameter is defined in the application’s consensus parameters. -
Run the application’s
beginBlocker(), which mainly runs theBeginBlocker()method of each of the application’s modules. -
Set the
VoteInfosof the application, i.e. the list of validators whose precommit for the previous block was included by the proposer of the current block. This information is carried into theContextso that it can be used duringDeliverTxandEndBlock.
EndBlock
TheEndBlock ABCI message is sent from the underlying CometBFT engine after DeliverTx as been run for each transaction in the block. It allows developers to have logic be executed at the end of each block. In the Cosmos SDK, the bulk EndBlock(req abci.RequestEndBlock) method is to run the application’s EndBlocker(), which mainly runs the EndBlocker() method of each of the application’s modules.
Commit
TheCommit ABCI message is sent from the underlying CometBFT engine after the full-node has received precommits from 2/3+ of validators (weighted by voting power). On the BaseApp end, the Commit(res abci.ResponseCommit) function is implemented to commit all the valid state transitions that occurred during BeginBlock, DeliverTx and EndBlock and to reset state for the next block.
To commit state-transitions, the Commit function calls the Write() function on deliverState.ms, where deliverState.ms is a branched multistore of the main store app.cms. Then, the Commit function sets checkState to the latest header (obtained from deliverState.ctx.BlockHeader) and deliverState to nil.
Finally, Commit returns the hash of the commitment of app.cms back to the underlying consensus engine. This hash is used as a reference in the header of the next block.
Info
TheInfo ABCI message is a simple query from the underlying consensus engine, notably used to sync the latter with the application during a handshake that happens on startup. When called, the Info(res abci.ResponseInfo) function from BaseApp will return the application’s name, version and the hash of the last commit of app.cms.
Query
TheQuery ABCI message is used to serve queries received from the underlying consensus engine, including queries received via RPC like CometBFT RPC. It used to be the main entrypoint to build interfaces with the application, but with the introduction of gRPC queries in Cosmos SDK v0.40, its usage is more limited. The application must respect a few rules when implementing the Query method, which are outlined here.
Each CometBFT query comes with a path, which is a string which denotes what to query. If the path matches a gRPC fully-qualified service method, then BaseApp will defer the query to the grpcQueryRouter and let it handle it like explained above. Otherwise, the path represents a query that is not (yet) handled by the gRPC router. BaseApp splits the path string with the / delimiter. By convention, the first element of the split string (split[0]) contains the category of query (app, p2p, store or custom ). The BaseApp implementation of the Query(req abci.RequestQuery) method is a simple dispatcher serving these 4 main categories of queries:
- Application-related queries like querying the application’s version, which are served via the
handleQueryAppmethod. - Direct queries to the multistore, which are served by the
handlerQueryStoremethod. These direct queries are different from custom queries which go throughapp.queryRouter, and are mainly used by third-party service provider like block explorers. - P2P queries, which are served via the
handleQueryP2Pmethod. These queries return eitherapp.addrPeerFilterorapp.ipPeerFilterthat contain the list of peers filtered by address or IP respectively. These lists are first initialized viaoptionsinBaseApp’s constructor.