-
Notifications
You must be signed in to change notification settings - Fork 585
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.go
is a big topic and not every detail will be covered here. For more information, check out theBaseApp
sections 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:
app
is the custom blockchain application that is initialized inapp.go
and returned by the constructor functionNewSimApp
. -
Cosmos SDK: calling to
app
'sModuleManager
functionsSetOrderBeginBlockers
andSetOrderEndBlockers
will specify the order on which theBeginBlocker
andEndBlocker
implementations of each module should be called onBeginBlock
andEndBlock
respectively. -
Cosmos SDK: calls to
SetBeginBlocker
andSetEndBlocker
will set the functions to be called onBeginBlock
andEndBlock
respectively.
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
NewRootCommand
creates a new root command forsimd
, the chain binary implementing the CometBFT ABCI application. -
Cosmos SDK: inside
NewRootCommand
two relevant things happen:- a call to
client.ReadPersistentCommandFlags
will 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
initRootCommand
will add the commands to the binary and it is passing thenewApp
function asAppCreator
.newApp
returns the custom blockchain application returned by theNewSimApp
constructor function inapp.go
.
- a call to
-
Cosmos SDK: inside
server.AddCommands
there's a call toStartCmd
to which theappCreator
funtion is passed. -
Cosmos SDK:
StartCmd
runs the application in-process with CometBFT (i.e. both the ABCI application and the CometBFT node run in the same process). -
Cosmos SDK: inside
startInProcess
theappCreator
application constructor function is invoked and a call to CometBFT'sNewNode
is executed to create a new CometBFT node. TheNewNode
function 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 theBeginBlock
function of the ABCI interface will call intoapp.beginBlocker
, which is actually theBeginBlocker
method. -
Cosmos SDK: inside
BeginBlocker
a call toModuleManager
'sBeginBlock
will execute allBeginBlock
functions of theAppModule
interface 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:27000
For 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 send
a transaction including thex/bank
MsgSend
is broadcasted. The broadcast happens when callingBroadcastTx
on the client context. Depending on the broadcast mode, methodsBroadcastTxSync
orBroadcastTxAsync
on the client context are called. Each method will eventually call the respective broadcast function on the CometBFT HTTP RPC client (BroadcastTxSync
orBroadcastTxAsync
). -
CometBFT: these are the implementations of
BroadcastTxSync
andBroadcastTxAsync
in 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
BroadcastTxSync
andBroadcastTxAsync
methods on the HTTP RPC server callTxMempool
'sCheckTx
method. -
CometBFT: inside
TxMempool
'sCheckTx
proxyAppConn.CheckTxSync
is called. TheproxyAppConn
is instantiated with the ABCI local client creator that was passed in the Cosmos SDK when invokingNewNode
(i.e.proxyAppConn
is an ABCI local client). -
CometBFT: the ABCI local client calls
CheckTx
on 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
'sCheckTx
logic is executed, including a call torunTx
passing in themode
argumentrunTxModeCheck
. 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
), -
validateBasicTxMsgs
is executed.
- the messages included in the transaction are retrieved (in our case, there's only one message,
-
CosmosSDK: in
validateBasicTxMsgs
, theValidateBasic
method of each message in the transaction is invoked. -
CometBFT: if all the messages in the transaction pass validation (and therefore
proxyAppConn.CheckTxSync
returns 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 theEndBlock
function of the ABCI interface will call intoapp.endBlocker
, which is actuallyEndBlocker
. -
Cosmos SDK: inside
EndBlocker
a call toModuleManager
'sEndBlock
will execute allBeginBlock
functions of theAppModule
interface 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
'senterCommit
tryFinalizeCommit
is called. -
CometBFT: in
tryFinalizeCommit
finalizeCommit
is called. -
CometBFT: in
finalizeCommit
BlockExecutor
's ApplyBlock` is called. -
CometBFT: in
ApplyBlock
execBlockOnProxyApp
is called. -
CometBFT: in
execBlockOnProxyApp
proxyAppConn.DeliverTxAsync
. (proxyAppConn
is here again an ABCI local client). -
CometBFT: the ABCI local client calls
DeliverTx
on 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
'sDeliverTx
logic is executed, including a call torunTx
passing in themode
argumentrunTxModeDeliver
. -
Cosmos SDK: inside
runTx
:- the messages included in the transaction are retrieved (in our case, there's only one message,
MsgSend
), -
runMsgs
is 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.