---
order: 3
---

# Sending Messages

**In this section you will learn how a user can send a message on the Forum Application.**

## CheckTx

In ABCI, the `CheckTx` method is used to ask the application to check the validity of an individual transaction before it is included in the mempool.
Every node runs CheckTx before letting a transaction into its local mempool.

The `CheckTx` method is responsible for performing any necessary validation checks on the transaction, such as verifying
the signature, checking for double spending, or enforcing application-specific rules. It is a lightweight and fast
operation, as it is meant to quickly determine whether a transaction is valid or not.

The method takes in a `CheckTxRequest` object, which contains the transaction to be checked (`req.Tx`) and any other
relevant information that the application needs to validate the transaction.

The `CheckTx` method should return a `CheckTxResponse` object, which indicates whether the transaction is valid or not.
If the transaction is valid, the response may include additional information about the transaction
such as the gas that the submitter is willing to spend executing the transaction.

**Following is the code for the `CheckTx` method:**

```go
// CheckTx handles validation of inbound transactions. If a transaction is not a valid message, or if a user
// does not exist in the database or if a user is banned it returns an error.
func (app *ForumApp) CheckTx(_ context.Context, req *abci.CheckTxRequest) (*abci.CheckTxResponse, error) {
	app.logger.Info("Executing Application CheckTx")

	// Parse the tx message
	msg, err := model.ParseMessage(req.Tx)
	if err != nil {
		app.logger.Info("CheckTx: failed to parse transaction message", "message", msg, "error", err)
		return &abci.CheckTxResponse{Code: CodeTypeInvalidTxFormat, Log: "Invalid transaction", Info: err.Error()}, nil
	}

	// Check for invalid sender
	if len(msg.Sender) == 0 {
		app.logger.Info("CheckTx: failed to parse transaction message", "message", msg, "error", "Sender is missing")
		return &abci.CheckTxResponse{Code: CodeTypeInvalidTxFormat, Log: "Invalid transaction", Info: "Sender is missing"}, nil
	}

	app.logger.Debug("searching for sender", "sender", msg.Sender)
	u, err := app.state.DB.FindUserByName(msg.Sender)

	if err != nil {
		if !errors.Is(err, badger.ErrKeyNotFound) {
			app.logger.Error("CheckTx: Error in check tx", "tx", string(req.Tx), "error", err)
			return &abci.CheckTxResponse{Code: CodeTypeEncodingError, Log: "Invalid transaction", Info: err.Error()}, nil
		}
		app.logger.Info("CheckTx: Sender not found", "sender", msg.Sender)
	} else if u != nil && u.Banned {
		return &abci.CheckTxResponse{Code: CodeTypeBanned, Log: "Invalid transaction", Info: "User is banned"}, nil
	}
	app.logger.Info("CheckTx: success checking tx", "message", msg.Message, "sender", msg.Sender)
	return &abci.CheckTxResponse{Code: CodeTypeOK, Log: "Valid transaction", Info: "Transaction validation succeeded"}, nil
}
```

**Explanation of code:**

`CheckTx` function parses the transaction message contained in `req.Tx` using the `model.ParseMessage` function. If
there is an error parsing the message, it prints an error message and returns a response with an error code indicating
an invalid transaction format.

Then, it searches for a user in the database using the `app.state.DB.FindUserByName` function. If the user is not found,
it prints a message indicating that the user was not found. If there is an error other than a key not found error,
it prints an error message and returns a response with an error code indicating an encoding error.

If the user is found and is not banned, it returns a response with a success code (`CodeTypeOK` which in CometBFT a `0`
code value to indicate success).

Finally, it prints a success message indicating the success of the check transaction.

*Tip: The function `CheckTx` is a stateless function that is primarily used by the application to check if a tx is
valid or not as per the application criteria (well-formed and from a valid user)*

Note: You will learn about different packages and functions like `app.state.DB.FindUserByName` in the upcoming sections.
In this section you will learn about the ABCI methods in the `ForumApp`.

## PrepareProposal

The `PrepareProposal` method is responsible for creating the contents of the proposed block, typically by selecting a
set of transactions that should be included in the next block. It may use various criteria to determine which transactions
to include, such as transaction fees, priority, or application-specific rules (as defined by the application).

The method takes in a `PrepareProposalRequest` object, which contains information about the current state of the blockchain,
such as the current height and the last committed block hash. It may also include other relevant information that the
application needs to generate the proposal.

The `PrepareProposal` method should return a `PrepareProposalResponse` object, which includes the proposed block contents.
This typically includes the list of transactions (txs) that should be included in the next block.

**Following is the code for the `PrepareProposal` method:**

```go
// PrepareProposal is used to prepare a proposal for the next block in the blockchain. The application can re-order, remove
// or add transactions.
func (app *ForumApp) PrepareProposal(_ context.Context, req *abci.PrepareProposalRequest) (*abci.PrepareProposalResponse, error) {
	app.logger.Info("Executing Application PrepareProposal")

	// Get the curse words from for all vote extensions received at the end of last height.
	voteExtensionCurseWords := app.getWordsFromVe(req.LocalLastCommit.Votes)

	curseWords := strings.Split(voteExtensionCurseWords, "|")
	if hasDuplicateWords(curseWords) {
		return nil, errors.New("duplicate words found")
	}

	// Prepare req puts the BanTx first, then adds the other transactions
	// ProcessProposal should verify this
	proposedTxs := make([][]byte, 0)
	finalProposal := make([][]byte, 0)
	bannedUsersString := make(map[string]struct{})
	for _, tx := range req.Txs {
		msg, err := model.ParseMessage(tx)
		if err != nil {
			// this should never happen since the tx should have been validated by CheckTx
			return nil, fmt.Errorf("failed to marshal tx in PrepareProposal: %w", err)
		}
		// Adding the curse words from vote extensions too
		if !hasCurseWord(msg.Message, voteExtensionCurseWords) {
			proposedTxs = append(proposedTxs, tx)
			continue
		}
		// If the message contains curse words then ban the user by
		// creating a "ban transaction" and adding it to the final proposal
		banTx := model.BanTx{UserName: msg.Sender}
		bannedUsersString[msg.Sender] = struct{}{}
		resultBytes, err := json.Marshal(banTx)
		if err != nil {
			// this should never happen since the ban tx should have been validated by CheckTx
			return nil, fmt.Errorf("failed to marshal ban tx in PrepareProposal: %w", err)
		}
		finalProposal = append(finalProposal, resultBytes)
	}

	// Need to loop again through the proposed Txs to make sure there is none left by a user that was banned
	// after the tx was accepted
	for _, tx := range proposedTxs {
		// there should be no error here as these are just transactions we have checked and added
		msg, err := model.ParseMessage(tx)
		if err != nil {
			// this should never happen since the tx should have been validated by CheckTx
			return nil, fmt.Errorf("failed to marshal tx in PrepareProposal: %w", err)
		}
		// If the user is banned then include this transaction in the final proposal
		if _, ok := bannedUsersString[msg.Sender]; !ok {
			finalProposal = append(finalProposal, tx)
		}
	}
	return &abci.PrepareProposalResponse{Txs: finalProposal}, nil
}
```

**Explanation of code:**

`PrepareProposal` function first retrieves curse words from for all vote extensions received at the end of last height.
Then, it iterates over the transactions in the proposal and checks if each transaction contains curse words. If a
transaction does not contain curse words, it adds it to the `proposedTxs` slice. If a transaction does contain curse words, it creates a ban transaction and adds
it to the `finalProposal` slice.

After iterating over all the transactions, it loops through the `proposedTxs` again to make sure there are no transactions
left from users who were banned after their transactions were accepted. The final set of transactions is stored in the
`finalProposal` slice, which is then returned as part of the `PrepareProposalResponse` response.

*Tip: The function `PrepareProposal` is used by state replication to indicate to the application to begin processing the tx.
Typically, the application is expected to order the tx and remove the tx from pool as defined by application logic.*

Note: You will learn about different packages and functions like `model.ParseMessage` in the upcoming sections.
In this section you will learn about `app.go` file only.

## ProcessProposal

The `ProcessProposal` method is used to process a proposal for the next block in the blockchain. It is called by
CometBFT to request the application to validate and potentially execute the proposed block.

The `ProcessProposal` method is responsible for performing any necessary validation checks on the proposed block, such
as verifying the validity of the included transactions, checking for double spending, or enforcing application-specific
rules (as defined by the application).

The method takes in a `ProcessProposalRequest` object, which contains the proposed block contents, including the list of
transactions (`req.Txs`) that are included in the block.

The `ProcessProposal` method should return a `ProcessProposalResponse` object, which includes a status if the proposed block
was accepted (`PROCESS_PROPOSAL_STATUS_ACCEPT`) or rejected (`PROCESS_PROPOSAL_STATUS_REJECT`)

**Following is the code for the `ProcessProposal` function:**

```go
// ProcessProposal validates the proposed block and the transactions and return a status if it was accepted or rejected.
func (app *ForumApp) ProcessProposal(_ context.Context, req *abci.ProcessProposalRequest) (*abci.ProcessProposalResponse, error) {
	app.logger.Info("Executing Application ProcessProposal")

	bannedUsers := make(map[string]struct{}, 0)

	finishedBanTxIdx := len(req.Txs)
	for i, tx := range req.Txs {
		if !isBanTx(tx) {
			finishedBanTxIdx = i
			break
		}
		var parsedBan model.BanTx
		err := json.Unmarshal(tx, &parsedBan)
		if err != nil {
			return &abci.ProcessProposalResponse{Status: abci.PROCESS_PROPOSAL_STATUS_REJECT}, err
		}
		bannedUsers[parsedBan.UserName] = struct{}{}
	}

	for _, tx := range req.Txs[finishedBanTxIdx:] {
		// From this point on, there should be no BanTxs anymore
		// If there is one, ParseMessage will return an error as the
		// format of the two transactions is different.
		msg, err := model.ParseMessage(tx)
		if err != nil {
			return &abci.ProcessProposalResponse{Status: abci.PROCESS_PROPOSAL_STATUS_REJECT}, err
		}
		if _, ok := bannedUsers[msg.Sender]; ok {
			// sending us a tx from a banned user
			return &abci.ProcessProposalResponse{Status: abci.PROCESS_PROPOSAL_STATUS_REJECT}, nil
		}
	}
	return &abci.ProcessProposalResponse{Status: abci.PROCESS_PROPOSAL_STATUS_ACCEPT}, nil
}
```

**Explanation of code:**

`ProcessProposal` function initializes an empty map called `bannedUsers` to keep track of banned user names.

Then, it iterates through the transactions and checks if each transaction is a ban transaction using the `isBanTx` function.
If it is a ban transaction, it parses the transaction into a `BanTx` struct and adds the banned user's name to the `bannedUsers` map.
If it is not a ban transaction, it breaks out of the loop and records the index of the last ban transaction.

After that, it iterates through the remaining transactions (starting from the index after the last ban transaction) and
parses each transaction using the `model.ParseMessage` function. If any banned user attempts to send a transaction,
it rejects the proposal.

Finally, if there are no banned users found in the transactions, it accepts the proposal.

*Tip: The function `ProcessProposal` is used by state replication to indicate to the application to process the tx.
The application can process a tx in accordance to the logic defined by the application. Although the application can
perform 'optimistic execution', the application is not mandated to do so.*

Note: You will learn about different packages and functions like `isBanTx` in the upcoming sections. In this section
you will learn about `app.go` file only.

## FinalizeBlock

The `FinalizeBlock` method is used to finalize a block in the blockchain. It is called by CometBFT after the validators have agreed on the
next block and it is ready to be added to the blockchain.

The `FinalizeBlock` method takes in a `FinalizeBlockRequest` object, which contains information about the block being finalized.
It performs any necessary processing or validation on the block, such as updating the application state, or performing
additional computations.

After processing the block, the method returns a `FinalizeBlockResponse` object, which typically includes the results
of the block finalization process, such as the transaction results, validator set updates, consensus parameters updates
or the new hash of the application state.

**Following is the code for the `FinalizeBlock` function:**

```go
// FinalizeBlock Deliver the decided block to the Application.
func (app *ForumApp) FinalizeBlock(_ context.Context, req *abci.FinalizeBlockRequest) (*abci.FinalizeBlockResponse, error) {
	app.logger.Info("Executing Application FinalizeBlock")

	// Iterate over Tx in current block
	app.onGoingBlock = app.state.DB.GetDB().NewTransaction(true)
	respTxs := make([]*abci.ExecTxResult, len(req.Txs))
	finishedBanTxIdx := len(req.Txs)
	for i, tx := range req.Txs {
		var err error

		if !isBanTx(tx) {
			finishedBanTxIdx = i
			break
		}
		banTx := new(model.BanTx)
		err = json.Unmarshal(tx, &banTx)
		if err != nil {
			// since we did this in ProcessProposal this should never happen here
			return nil, err
		}
		err = UpdateOrSetUser(app.state.DB, banTx.UserName, true, app.onGoingBlock)
		if err != nil {
			return nil, err
		}
		respTxs[i] = &abci.ExecTxResult{Code: CodeTypeOK}
	}

	for idx, tx := range req.Txs[finishedBanTxIdx:] {
		// From this point on, there should be no BanTxs anymore
		// If there is one, ParseMessage will return an error as the
		// format of the two transactions is different.
		msg, err := model.ParseMessage(tx)
		i := idx + finishedBanTxIdx
		if err != nil {
			// since we did this in ProcessProposal this should never happen here
			return nil, err
		}

		// Check if this sender already existed; if not, add the user too
		err = UpdateOrSetUser(app.state.DB, msg.Sender, false, app.onGoingBlock)
		if err != nil {
			return nil, err
		}
		// Add the message for this sender
		message, err := model.AppendToExistingMessages(app.state.DB, *msg)
		if err != nil {
			return nil, err
		}
		err = app.onGoingBlock.Set([]byte(msg.Sender+"msg"), []byte(message))
		if err != nil {
			return nil, err
		}
		chatHistory, err := model.AppendToChat(app.state.DB, *msg)
		if err != nil {
			return nil, err
		}
		// Append messages to chat history
		err = app.onGoingBlock.Set([]byte("history"), []byte(chatHistory))
		if err != nil {
			return nil, err
		}
		// This adds the user to the DB, but the data is not committed nor persisted until Commit is called
		respTxs[i] = &abci.ExecTxResult{Code: abci.CodeTypeOK}
		app.state.Size++
	}
	app.state.Height = req.Height

	response := &abci.FinalizeBlockResponse{TxResults: respTxs, AppHash: app.state.Hash()}
	return response, nil
}
```

**Explanation of code:**

`FinalizeBlock` function iterates over the transactions (`req.Txs`) in the block. If a transaction is a ban transaction (`isBanTx(tx)`),
it updates or sets a user in the application's database and assigns a response code. If it is not a ban transaction, the loop breaks.

After the ban transactions, the method parses the remaining transactions using `model.ParseMessage(tx)`. It updates or sets
the sender as a user in the database, appends the message to the existing messages, appends the message to the chat history,
and assigns a response code. Finally, it updates the blockchain state and returns the response object.

*Tip: The function `FinalizeBlock` finalizes processing of a tx. All the state change that happen in this function are finalized.
However, they are not yet persisted to database. This is done in next step, i.e. `Commit`*

Note: You will learn about different packages and functions like `model.AppendToExistingMsgs` in the upcoming sections.
In this section you will learn about `app.go` file only.

## Commit

The `Commit` method is used to persist the changes made to the application state during the FinalizeBlock method.

After calling `FinalizeBlock`, the state changes are finalized but not yet persisted to the database. The `Commit` method
is responsible for persisting these changes to the database, ensuring that they are durable and can be retrieved later.

Typically, the `Commit` method updates the application's blockchain state by saving the modified data to a persistent
storage system, such as a database or a file. This allows the application to maintain a consistent and reliable state
across different blocks in the blockchain.

The Commit method takes in a `CommitRequest` object and returns a `CommitResponse` object.

**Following is the code for the `Commit` function:**

```go
// Commit the application state.
func (app *ForumApp) Commit(_ context.Context, _ *abci.CommitRequest) (*abci.CommitResponse, error) {
	app.logger.Info("Executing Application Commit")

	if err := app.onGoingBlock.Commit(); err != nil {
		return nil, err
	}
	err := saveState(&app.state)
	if err != nil {
		return nil, err
	}
	return &abci.CommitResponse{}, nil
}
```

**Explanation of code:**

The `Commit` method takes in a `context.Context` object and a `*abci.CommitRequest` object as parameters. It returns
a `*abci.CommitResponse` object and an error.

Inside the method, it calls the Commit method on `app.onGoingBlock`, which is an instance of a block object. This commits
the state changes made during the `FinalizeBlock` method to the underlying storage system. If there's an error during
the `commit`, it returns the error in the `Commit` method.

After the state changes are committed, the `saveState` function is called with a pointer to `app.state.` This function
is responsible for persisting the updated state to a persistent storage system.

Finally, the method returns an empty `*abci.CommitResponse` object and a `nil` error.

## Signature verification

The tutorial does not include the logic for verifying transaction signatures. However, in a real-world application, it
is important to validate transaction signatures to ensure that the users sending messages are legitimate and not trying
to exploit the system. If implemented, signature verification would typically be carried out using the `CheckTx`, `ProcessProposal`, and `FinalizeBlock`
methods to confirm the validity of transactions from a signature perspective. While our tutorial app is simplified for
educational purposes, a fully functional application should include signature verification as an essential part of its core logic.

An example signature verification code could be something like:

```go
func isValidSignature(tx Transaction) bool {
    pubKey := tx.PubKey
    signature := tx.Signature
    message := tx.Message

    // Use the cryptographic library to verify the signature
    return crypto.VerifySignature(pubKey, message, signature)
}
```

and then in `CheckTx` the signature could be verified:

```go
func (app *ForumApp) CheckTx(req types.CheckTxRequest) types.CheckTxResponse {
    tx := req.Tx
    // Extract the transaction fields, including the signature and the public key
    // Verify the signature
    if !isValidSignature(tx) {
        return types.CheckTxResponse{
            Code: code.InvalidSignature,
            Log:  "Invalid transaction signature",
        }
    }

    // some other validation...

    return types.CheckTxResponse{Code: code.OK}
}
```

---------------

*In the next session, you will learn about how user can [**Query Message**](4.query-message.md) in the Forum Application.*
