Single-node local chain
Use a single-node chain for the fastest local development loop. It gives you one validator with predictable state so you can quickly test queries and transactions.Start
- Chain ID:
demo - Pre-funded accounts:
alice,bob - Default denomination:
stake
Stop
PressCtrl+C in the terminal running make start.
Reset chain state
make start resets state automatically. There is no separate reset command.
Localnet (multi-node)
Localnet runs four nodes in Docker to give you a setup closer to a real network than the single-node chain.scripts/localnet/init.sh creates a genesis transaction for node0 only, so the network is one validator plus three full nodes, not four validators. The chain ID is example-localnet, and each node has a single key named validator rather than the alice and bob accounts used by make start.
Before you begin, note that this section needs Docker running, and that the following host ports must be free: 26656, 26657, 1317, 9090 for node0, then 26666, 26667, 1318, 9091 for node1, 26676, 26677, 1319, 9092 for node2, and 26686, 26687, 1320, 9093 for node3.
Confirm the network is healthy
Each node exposes its own RPC port. Check that every node has found the other three and that they are advancing together:"n_peers":"3" and a block height that climbs on repeated calls.
Send a transaction
The localnet uses a different chain ID and key name thanmake start, so the commands in the CLI reference below need adjusting. Run them inside a container:
CLI reference
Once the chain is running, these are the core CLI commands you’ll use to inspect state and submit transactions.Query commands
Use query commands to read module state without changing anything on-chain.Transaction commands
Use transaction commands to submit state-changing messages to the chain.Updating module parameters
Counter params are governance-gated.MsgUpdateParams accepts only the gov module address as its
authority, so there is no direct CLI command for it: signing update-params with a user key such as
alice always fails with ErrInvalidSigner. Params change through a governance proposal instead.
Look up the gov module address for your chain, which is the only valid authority:
proposal.json containing the message, using that address as authority. On the local demo
chain the value is cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn:
deposit must meet the chain’s min_deposit, which is 10000000stake locally. Check it with
exampled query gov params. Then submit and vote:
exampled query gov proposals.
The local chain uses the default 48 hour
voting_period, so a proposal submitted this way sits in
PROPOSAL_STATUS_VOTING_PERIOD for two days and the params do not change during a normal dev session.genesis.json before make start does not work, because scripts/local_node.sh deletes the whole
home directory on every run. Let make start create the chain first, then stop it and edit in place:
PROPOSAL_STATUS_PASSED and exampled query counter params reflects the new values.
exampled tx gov draft-proposal can generate a skeleton, but it is an interactive terminal picker rather
than a scriptable command. Its top-level list offers only text, community-pool-spend,
software-upgrade, cancel-software-upgrade, and other, and choosing other opens a scroll-only list
of fully qualified message type URLs that typing does not filter. Writing the JSON by hand, as above, is
the more direct path.
Useful flags
These flags are the ones you’ll use most often while iterating locally.Node Configuration
When you runmake start, the chain creates ~/.exampleapp/config/ automatically and initializes two config files inside it:
app.toml
The most common settings to change during development:config.toml
The settings most likely to change during development:Unit tests
Start here when you want fast feedback on module logic without running a chain. These tests isolate the keeper and gRPC servers from the rest of the app. The unit test logic lives in the counter keeper package onmain: the shared suite setup is in x/counter/keeper/keeper_test.go, message-path tests are in x/counter/keeper/msg_server_test.go, and query-path tests are in x/counter/keeper/query_server_test.go.
The keeper test suite covers the keeper, msg server, and query server in isolation using an in-memory store and a mock bank keeper. No running chain is required.
E2E tests
Run E2E tests when you want to verify the full request path against a real node. They give you higher confidence than unit tests, but take longer to complete. The E2E logic lives onmain in tests/counter_test.go, which starts an in-process network, builds signed transactions, and verifies query results. The shared network fixture it uses is defined in tests/test_helpers.go.
The E2E test suite starts a real in-process validator network and submits actual transactions against it. This tests the full stack: transaction encoding, message routing, keeper logic, and query responses.
Simulation tests
Simulation tests stress the chain with randomized activity to catch edge cases that targeted tests can miss. In this repo, that simulation flow is built withsimsx, the Cosmos SDK’s higher-level simulation framework for defining random on-chain activity at the module level.
The top-level simulation test commands on main run through sim_test.go. The counter module’s simsx registration lives in x/counter/module.go, the random MsgAdd generation lives in x/counter/simulation/msg_factory.go, and randomized counter genesis lives in x/counter/simulation/genesis.go.
In practice, simsx lets each module describe three things: how to generate random starting state, which operations can happen during simulation, and how often each operation should be chosen. For x/counter, that means generating a random initial counter value, registering MsgAdd as a simulation operation, and assigning it a weight so the simulator knows how frequently to try it relative to other module operations.
When you run a simulation target, the test harness repeatedly builds app instances, creates random accounts and balances, generates random transactions from the registered module operations, and executes them over many blocks. That makes simsx useful for catching issues that are hard to cover with hand-written tests, like state machine bugs, unexpected panics, invariant violations, and non-deterministic behavior across runs.
Simulation runs the chain with randomly generated transactions to detect non-determinism and invariant violations.
sims build tag, which the Makefile targets handle automatically.
Each of these runs the simulation across 38 built-in seeds, so expect roughly ten minutes per target. The Makefile deliberately uses smaller values than the SDK defaults of 500 blocks and 200 operations per block, which across 38 seeds take hours. To simulate more deeply, override them:
Lint
Linting is the quickest way to catch style problems and common code-quality issues before CI or code review does. The lint commands are defined in the repo Makefile, which installsgolangci-lint and runs it across the full module tree.
golangci-lint across the repository. To auto-fix issues where possible: