# Gas - Incentivize Players
Make sure you have everything you need before proceeding:
- You understand the concept of gas.
- Go is installed.
- You have the checkers blockchain codebase with the game wager and its handling. If not, follow the previous steps or check out the relevant version (opens new window).
In this section, you will:
- Add transaction fees.
- Set fees and add metering.
- Do integration tests.
Players can start playing checkers with your Cosmos blockchain. Transaction fees are paid by the players themselves, at least the fee related to transporting the serialized bytes and the other gas-metered parts like bank
.
Your blockchain is taking shape, but you need to take care of peripheral concerns. For instance, how do you make sure that participants pay their fair share of the costs they impose on the network?
Next, you should add your own gas metering to reflect the costs that different transactions impose, or you can add costs to discourage spam.
# Some initial thoughts
To continue developing your checkers blockchain:
- At what junctures can you charge gas?
- At what junctures can you not charge gas, and what do you do about it?
- Are there new errors to report back?
- What event should you emit?
# Code needs
Before diving into the specifics, ask yourself:
- What Ignite CLI commands, if any, will assist you?
- How do you adjust what Ignite CLI created for you?
- Where do you make your changes?
- How would you unit-test these new elements?
- How would you use Ignite CLI to locally run a one-node blockchain and interact with it via the CLI to see what you get?
# New data
These values provide examples but you can, and should, set your own. Save them as new constants:
# Add handling
Add a line that consumes the designated amount of gas in each relevant handler:
When handling a game creation:
When handling a move:
When handling a game rejection:
You do not meter gas in your EndBlock
handler because it is not called by a player sending a transaction. Instead, it is a service rendered by the network. If you want to account for the gas cost of a game expiration, you have to devise a way to pre-collect it from players as part of the other messages.
As part of your code optimization, avoid calling ConsumeGas
with a fixed gas cost (for instance k
) from within a loop. Each pass of the loop uses computation resources (c
) on each node. If you know the number of times your code loops (n
), you know running the full loop will use n*c
computation resources.
Now consider the case of a user who sent a transaction without enough gas. The transaction will fail anyway, but at what point will it fail?
- If you call
ConsumeGas(k)
within the loop, the transaction will fail during one of the passes (them
th pass). This means that the node has already usedm*c
computation resources. - If you call
ConsumeGas(n*k)
once before the loop, the transaction will fail immediately, and the node will have used0
computation resources.
Choosing option 2 improves the effectiveness of your blockchain, and potentially protects it from spam and denial-of-service attacks.
Additionally, making only a single call to ConsumeGas
slightly saves computation resources of the node.
# Integration tests
Now you must add tests that confirm the gas consumption. However, it is not possible to differentiate the gas cost that BaseApp is incurring on your messages from the gas cost your module imposes on top of it. Also, you cannot distinguish via the descriptor unless it panics (opens new window). Nevertheless, you can add a lame test:
Now add tests for a play (opens new window) and a reject (opens new window).
# Interact via the CLI
Here, you want to confirm that gas is consumed by different actions. The difficulty is that Alice's and Bob's balances in stake
tokens change not only because of the gas used but also depending on the gas price. An easy measurement is to use --dry-run
:
Let's say this returns 54322
, which is the estimated gas used. Now comment out the .ConsumeGas
line in msg_server_create_game.go
, save it, wait a few minutes for Ignite CLI to rebuild, and try again:
Say, this time you get 54312
. This is good: the 10
gas is no longer part of the estimation, as expected. Uncomment the .ConsumeGas
line. You can try --dry-run
on play and reject too.
Note how a difference of 10
is insignificant compared to the 54312
of the other gas costs. This is where you have to decide how to adjust your gas costs so that they are meaningful concerning the costs they impose on the network.
Estimating with --dry-run
is a good start. Now have Alice create a game and check the gas used in the transaction:
This mentions:
You could impose a --gas-prices
and then check balances, but this would obfuscate the gas consumption which is what you want to confirm.
As before, comment the .ConsumeGas
line msg_server_create_game.go
and wait for Ignite CLI to rebuild. Then try again:
This mentions:
There is only a difference of 4
. The rest of the system likely had some under-the-hood initializations, such as Merkle tree creations, which may falsify the early results. Create 10 more games without .Consume
ing gas and only look at the gas_used
. It should stabilize at a certain value:
This mentions:
Put back the .ConsumeGas
line and rebuild. Then try again:
This mentions a difference of 10
:
That is sufficient confirmation.
# Next up
Make your checkers blockchain more user-friendly by helping players avoid bad transactions via a query that tests a move. Just follow the exercise in the next section.