Transactions are objects created by end-users to trigger state changes in the application.
# Pre-requisite Readings
When users want to interact with an application and make state changes (e.g. sending coins), they create transactions. Each of a transaction's
Msgs must be signed using the private key associated with the appropriate account(s), before the transaction is broadcasted to the network. A transaction must then be included in a block, validated, and approved by the network through the consensus process. To read more about the lifecycle of a transaction, click here.
# Type Definition
Transaction objects are SDK types that implement the
It contains the following methods:
- GetMsgs: unwraps the transaction and returns a list of its
Msgs - one transaction may have one or multiple
Msgs, which are defined by module developers.
- ValidateBasic: includes lightweight, stateless checks used by ABCI messages
DeliverTxto make sure transactions are not invalid. For example, the
auth(opens new window) module's
ValidateBasicfunction checks that its transactions are signed by the correct number of signers and that the fees do not exceed what the user's maximum. Note that this function is to be distinct from the
Msgs, which perform basic validity checks on messages only. For example, when
runTxis checking a transaction created from the
auth(opens new window) module, it first runs
ValidateBasicon each message, then runs the
authmodule AnteHandler which calls
ValidateBasicfor the transaction itself.
As a developer, you should rarely manipulate
Tx directly, as
Tx is really an intermediate type used for transaction generation. Instead, developers should prefer the
TxBuilder interface, which you can learn more about below.
# Signing Transactions
Every message in a transaction must be signed by the addresses specified by its
GetSigners. The SDK currently allows signing transactions in two different ways.
The most used implementation of the
Tx interface is the Protobuf
Tx message, which is used in
Because Protobuf serialization is not deterministic, the SDK uses an additional
TxRaw type to denote the pinned bytes over which a transaction is signed. Any user can generate a valid
auth_info for a transaction, and serialize these two messages using Protobuf.
TxRaw then pins the user's exact binary representation of
auth_info, called respectively
auth_info_bytes. The document that is signed by all signers of the transaction is
SignDoc (deterministically serialized using ADR-027):
Once signed by all signers, the
signatures are gathered into
TxRaw, whose serialized bytes are broadcasted over the network.
The legacy implemention of the
Tx interface is the
StdTx struct from
The document signed by all signers is
which is encoded into bytes using Amino JSON. Once all signatures are gathered into
StdTx is serialized using Amino JSON, and these bytes are broadcasted over the network.
# Other Sign Modes
Other sign modes, most notably
SIGN_MODE_TEXTUAL, are being discussed. If you wish to learn more about them, please refer to ADR-020.
# Transaction Process
The process of an end-user sending a transaction is:
- decide on the messages to put into the transaction,
- generate the transaction using the SDK's
- broadcast the transaction using one of the available interfaces.
The next paragraphs will describe each of these components, in this order.
Msgs are not to be confused with ABCI Messages (opens new window) which define interactions between the Tendermint and application layers.
Msgs) are module-specific objects that trigger state transitions within the scope of the module they belong to. Module developers define the messages for their module by adding methods to the Protobuf
Msg service, and also implement the corresponding
Msgs in a module are defined as methods in the [
Msg service] inside each module's
tx.proto file. Since
Msgs are module-specific, each module needs a to process all of its message types and trigger state changes within the module's scope. This design puts more responsibility on module developers, allowing application developers to reuse common functionalities without having to implement state transition logic repetitively. To achieve this, Protobuf generates a
MsgServer interface for each module, and the module developer needs to implement this interface. The methods on the
MsgServer interface corresponds on how to handle each of the different
To learn more about
Msg services and how to implement
MsgServer, click here.
While messages contain the information for state transition logic, a transaction's other metadata and relevant information are stored in the
# Transaction Generation
TxBuilder interface contains data closely related with the generation of transactions, which an end-user can freely set to generate the desired transaction:
Msgs, the array of messages included in the transaction.
GasLimit, option chosen by the users for how to calculate how much gas they will need to pay.
Memo, to send with the transaction.
FeeAmount, the maximum amount the user is willing to pay in fees.
TimeoutHeight, block height until which the transaction is valid.
Signatures, the array of signatures from all signers of the transaction.
As there are currently two sign modes for signing transactions, there are also two implementations of
- wrapper (opens new window) for creating transactions for
- StdTxBuilder (opens new window) for
However, the two implementation of
TxBuilder should be hidden away from end-users, as they should prefer using the overarching
TxConfig is an app-wide configuration for managing transactions. Most importantly, it holds the information about whether to sign each transaction with
SIGN_MODE_LEGACY_AMINO_JSON. By calling
txBuilder := txConfig.NewTxBuilder(), a new
TxBuilder will be created with the appropriate sign mode.
TxBuilder is correctly populated with the setters exposed above,
TxConfig will also take care of correctly encoding the bytes (again, either using
SIGN_MODE_LEGACY_AMINO_JSON). Here's a pseudo-code snippet of how to generate and encode a transaction, using the
# Broadcasting the Transaction
Once the transaction bytes are generated, there are currently three ways of broadcasting it.
Application developers create entrypoints to the application by creating a command-line interface and/or REST interface, typically found in the application's
./cmd folder. These interfaces allow users to interact with the application through command-line.
For the command-line interface, module developers create subcommands to add as children to the application top-level transaction command
TxCmd. CLI commands actually bundle all the steps of transaction processing into one simple command: creating messages, generating transactions and broadcasting. For concrete examples, see the Interacting with a Node section. An example transaction made using CLI looks like:
gRPC (opens new window) is introduced in Cosmos SDK 0.40 as the main component for the SDK's RPC layer. The principal usage of gRPC is in the context of modules'
Query services. However, the SDK also exposes a few other module-agnostic gRPC services, one of them being the
Tx service exposes a handful of utility functions, such as simulating a transaction or querying a transaction, and also one method to broadcast transactions.
An example of broadcasting a transaction is shown in TODO (opens new window). Please note that the
BroadcastTx endpoint takes
TxRaw, not bytes.
Each gRPC method has its corresponding REST endpoint, generated using gRPC-gateway (opens new window). Therefore, instead of using gRPC, you can also use HTTP to broadcast the same transaction, on the
POST /cosmos/tx/v1beta1/broadcast_tx endpoint.
An example can be seen here TODO (opens new window)
Learn about the context