-
Couldn't load subscription status.
- Fork 729
Transaction flow
This document attempts to provide a trace through the codebases of CometBFT and Cosmos SDK to show some key code parts that are executed as a transaction flows through the system and becomes part of a block. This is not by any means giving a complete, detailed step by step trace; this document simply offers links to certain relevant parts of the code that should help the reader navigate through the codebases and explore in more detail, if necessary.
To illustrate with a concrete example how a transaction is executed a blockchain was run locally using Cosmos SDK simd sample application binary and a bank transfer from one account to another was performed. Please check out the logs generated by the local chain, since they contains extra comments explaining some key actions that happen through the generation of the block. The transaction with MsgSend is executed in block at height 6, so feel free also to check blocks 5, 6, 7, and the transaction JSON files.
This document is updated for CometBFT v0.37 and Cosmos SDK v0.47.
- Useful resources
- Application wiring
- Application bootstrapping
- Begin block
- Broadcasting a transaction
- Adding a transaction to the mempool
- End block
- Committing the block
The information in the links below should give extra context and more colour to the ideas touched upon in this document:
- A Blockchain App Architecture. Good high-level explanation of the application architecture underlying blockchains built with the Cosmos SDK.
- What is CometBFT.
- Byzantine Consensus Algorithm. This is a good explanation of the round-based protocol that is run to determine the next block.
- ABCI section in the CometBFT documentation.
- Transaction lifecycle. Good explanation of the lifecycle of a transaction from creation to committed state changes.
- Creating a built-in application in Go. This is a nice tutorial to gain some hands-on experience writing and simple ABCI application.
- How to read CometBFT logs.
Application wiring in
app.gois a big topic and not every detail will be covered here. For more information, check out theBaseAppsections in the Developer Portal and the Cosmos SDK documentation, and the Anatomy of a Cosmos SDK Application section of the Cosmos SDK documentation. Here we will focus on the wiring related to the logic executed at the beginning and end of every block.
BaseApp is a boilerplate implementation of the core of a Cosmos SDK application. This abstraction implements functionalities that every Cosmos application-specific chain needs, starting with an implementation of Application Blockchain Interface (ABCI), which allows the state machine communicate with the underlying consensus engine (e.g. CometBFT).
BeginBlocker and EndBlocker are functions part of the BeginBlockAppModule and BeginBlockAppModule interfaces respectively, and developers of SDK modules can optionally implement them to add automatic execution of logic to their module at the beginning and at the end of each block respectively (i.e. when the BeginBlock and EndBlock ABCI messages are received from the underlying consensus engine). Read the section BeginBlocker and EndBlocker in the Cosmos SDK documentation for more information.
-
Cosmos SDK:
appis the custom blockchain application that is initialized inapp.goand returned by the constructor functionNewSimApp. -
Cosmos SDK: calling to
app'sModuleManagerfunctionsSetOrderBeginBlockersandSetOrderEndBlockerswill specify the order on which theBeginBlockerandEndBlockerimplementations of each module should be called onBeginBlockandEndBlockrespectively. -
Cosmos SDK: calls to
SetBeginBlockerandSetEndBlockerwill set the functions to be called onBeginBlockandEndBlockrespectively.
When the application bootstraps, we can execute transactions and queries. The Node Client section of the Cosmos SDK documentation gives details of how the full node starts. Here we will focus to explore sections of the codebase where the application initializes and connects to the ABCI client and the CometBFT HTTP RPC server. The ABCI client will allow the underlying consensus engine to communicate with the ABCI application (to send ABCI messages like CheckTx or DeliverTx); and the RPC server will be used by the application to broadcast transactions to the CometBFT node.
-
Cosmos SDK: calling
NewRootCommandcreates a new root command forsimd, the chain binary implementing the CometBFT ABCI application. -
Cosmos SDK: inside
NewRootCommandtwo relevant things happen:- a call to
client.ReadPersistentCommandFlagswill create a CometBFT HTTP RPC client. This is the client used by the application to broadcast transactions to the CometBFT RPC server. - a call to
initRootCommandwill add the commands to the binary and it is passing thenewAppfunction asAppCreator.newAppreturns the custom blockchain application returned by theNewSimAppconstructor function inapp.go.
- a call to
-
Cosmos SDK: inside
server.AddCommandsthere's a call toStartCmdto which theappCreatorfuntion is passed. -
Cosmos SDK:
StartCmdruns the application in-process with CometBFT (i.e. both the ABCI application and the CometBFT node run in the same process). -
Cosmos SDK: inside
startInProcesstheappCreatorapplication constructor function is invoked and a call to CometBFT'sNewNodeis executed to create a new CometBFT node. TheNewNodefunction receives as argument the ABCI local client creator with the ABCI server application (i.e. the custom blockchain application implementing the ABCI interface) with which CometBFT will communicate duringBeginBlock,CheckTx, etc.
On a new block the ABCI client (i.e. CometBFT) will send a BeginBlock request to the ABCI server (i.e. the application) to give the opportunity to run logic at the beginning of every block. CometBFT sends the current block hash and header to the application, before it sends any of the transactions.
-
Cosmos SDK:
BaseApp's implementation of theBeginBlockfunction of the ABCI interface will call intoapp.beginBlocker, which is actually theBeginBlockermethod. -
Cosmos SDK: inside
BeginBlockera call toModuleManager'sBeginBlockwill execute allBeginBlockfunctions of theAppModuleinterface implemented in the modules wired up in the application.
For illustration purposes we are going to submit a transaction to perform a bank transfer between 2 accounts. This is the CLI command I used with the blockchain running locally:
> simd tx bank send cosmos13tktw8hvst7w5rns0v5kt4cxqeaa6yvt380j34 cosmos15k5g0h7zjf78wmq9q88ujwzf2cyxeudrt48zw0 100stake \
--keyring-backend test \
--chain-id chain1 \
--home ../../gm/chain1 \
--node http://localhost:27000For more information on how to submit transactions, check the section Generating, Signing and Broadcasting Transactions of the Cosmos SDK documentation.
-
Cosmos SDK: when we use the CLI command
simd tx bank senda transaction including thex/bankMsgSendis broadcasted. The broadcast happens when callingBroadcastTxon the client context. Depending on the broadcast mode, methodsBroadcastTxSyncorBroadcastTxAsyncon the client context are called. Each method will eventually call the respective broadcast function on the CometBFT HTTP RPC client (BroadcastTxSyncorBroadcastTxAsync). -
CometBFT: these are the implementations of
BroadcastTxSyncandBroadcastTxAsyncin the HTTP RPC client. - CometBFT: on the HTTP RPC server side, these are the implementations that handle the broadcast request in both synchronous and asynchronous mode. The functions handling RPC requests are registered here based on a map of RPC routes.
To learn more about ABCI methods and messages, check out the Methods and Types scetion of CometBFT documentation.
The CheckTx ABCI method controls what transactions are considered for inclusion in a block. CometBFT's mempool first checks the validity of a transaction with CheckTx, and only relays valid transactions to its peers.
-
CometBFT: both
BroadcastTxSyncandBroadcastTxAsyncmethods on the HTTP RPC server callTxMempool'sCheckTxmethod. -
CometBFT: inside
TxMempool'sCheckTxproxyAppConn.CheckTxSyncis called. TheproxyAppConnis instantiated with the ABCI local client creator that was passed in the Cosmos SDK when invokingNewNode(i.e.proxyAppConnis an ABCI local client). -
CometBFT: the ABCI local client calls
CheckTxon the application. An instance of the application was passed to the constructor function of the ABCI local client when instantiating the CometBFT ABCI client in-process in the Cosmos SDK. -
Cosmos SDK:
BaseApp'sCheckTxlogic is executed, including a call torunTxpassing in themodeargumentrunTxModeCheck. For a full list of all possible modes, check the values forrunTxMode. -
Cosmos SDK: inside
runTx:- the messages included in the transaction are retrieved (in our case, there's only one message,
MsgSend), -
validateBasicTxMsgsis executed.
- the messages included in the transaction are retrieved (in our case, there's only one message,
-
CosmosSDK: in
validateBasicTxMsgs, theValidateBasicmethod of each message in the transaction is invoked. -
CometBFT: if all the messages in the transaction pass validation (and therefore
proxyAppConn.CheckTxSyncreturns no error), then the transaction is added to the mempool.
EndBlock ABCI method is called after all the transactions for the current block have been delivered, but prior to the block's Commit message.
-
Cosmos SDK:
BaseApp's implementation of theEndBlockfunction of the ABCI interface will call intoapp.endBlocker, which is actuallyEndBlocker. -
Cosmos SDK: inside
EndBlockera call toModuleManager'sEndBlockwill execute allBeginBlockfunctions of theAppModuleinterface implemented in the modules wired up in the application.
Two stages of voting are required to successfully commit a block; they are called pre-vote and pre-commit. A block is committed when more than 2/3 of validators pre-commit for the same block in the same round.
The DeliverTx ABCI method delivers transactions from CometBFT to the application.
- CometBFT: after more than 2/3 of validators pre-commit for the block, then the block is committed.
-
CometBFT: in
State'senterCommittryFinalizeCommitis called. -
CometBFT: in
tryFinalizeCommitfinalizeCommitis called. -
CometBFT: in
finalizeCommitBlockExecutor's ApplyBlock` is called. -
CometBFT: in
ApplyBlockexecBlockOnProxyAppis called. -
CometBFT: in
execBlockOnProxyAppproxyAppConn.DeliverTxAsync. (proxyAppConnis here again an ABCI local client). -
CometBFT: the ABCI local client calls
DeliverTxon the application. An instance of the application was passed to the constructor function of the ABCI local client when instantiating the CometBFT ABCI client in-process in the Cosmos SDK. -
Cosmos SDK:
BaseApp'sDeliverTxlogic is executed, including a call torunTxpassing in themodeargumentrunTxModeDeliver. -
Cosmos SDK: inside
runTx:- the messages included in the transaction are retrieved (in our case, there's only one message,
MsgSend), -
runMsgsis invoked.
- the messages included in the transaction are retrieved (in our case, there's only one message,
-
CosmosSDK: in
runMsgs: - CosmosSDK: the state changes caused by executing the message are written.