AppChain Setup
After integrating the memlogger-enabled Cosmos SDK, you need to add streaming listeners to your chain’s application code. This enables real-time state change tracking.
Overview
The setup involves modifying your chain’s app.go file to:
- Enable in-memory listeners on all KV stores
- Attach the debug change logger to the streaming manager
- Configure the streaming manager in your base app
Code Changes
Step 1: Add Required Imports
Add these imports to your app.go:
import (
// ... your existing imports ...
storetypes "cosmossdk.io/store/types"
streamingabci "cosmossdk.io/store/streaming/abci"
)Step 2: Add Streaming Listener Configuration
Find where your baseApp is initialized (typically after baseapp.NewBaseApp(...)), and add this code block immediately after:
// Always enable in-memory listeners on all KV stores so we can retrieve the
// per-block change set at commit time, regardless of external streaming config.
{
var exposeStoreKeys []storetypes.StoreKey
for _, k := range keys {
exposeStoreKeys = append(exposeStoreKeys, k)
}
bApp.CommitMultiStore().AddListeners(exposeStoreKeys)
// Append our in-process debug change logger to the streaming manager so it
// receives the commit-time change set and logs a summary.
sm := bApp.StreamingManager()
sm.ABCIListeners = append(sm.ABCIListeners, &streamingabci.DebugChangeLogger{})
bApp.SetStreamingManager(sm)
}Complete Example
Here’s a complete example of the integration. The code should be placed right after your baseApp initialization:
// Create base app
bApp := baseapp.NewBaseApp(
appName,
logger,
db,
txConfig.TxDecoder(),
baseAppOptions...,
)
// ========== ADD THIS BLOCK ==========
// Enable in-memory streaming listeners for state change tracking
{
var exposeStoreKeys []storetypes.StoreKey
for _, k := range keys {
exposeStoreKeys = append(exposeStoreKeys, k)
}
bApp.CommitMultiStore().AddListeners(exposeStoreKeys)
// Add debug change logger to streaming manager
sm := bApp.StreamingManager()
sm.ABCIListeners = append(sm.ABCIListeners, &streamingabci.DebugChangeLogger{})
bApp.SetStreamingManager(sm)
}
// ====================================
// Continue with rest of app initialization...Reference Implementation
For a complete working example, see the EVM chain integration:
- Repository: bft-labs/evm
- Release: v0.5.0-bft-labs-memlogger
- Commit: 9ba9acdfb37bd1d73b7e13b2534278a9fd60a0a1
This commit shows exactly how to set up app.go in a real-world chain.
Understanding the Code
Store Keys Collection
var exposeStoreKeys []storetypes.StoreKey
for _, k := range keys {
exposeStoreKeys = append(exposeStoreKeys, k)
}This collects all KV store keys from your application, ensuring every state change is tracked.
Adding Listeners
bApp.CommitMultiStore().AddListeners(exposeStoreKeys)Registers listeners on all stores to capture state changes during block commits.
Debug Change Logger
sm.ABCIListeners = append(sm.ABCIListeners, &streamingabci.DebugChangeLogger{})Adds the debug change logger that will output detailed state change information to the memlogger.
Verification
After making these changes, rebuild your chain:
# Build your chain
go build -o ./build/chaind ./cmd/chaind
# Verify the build succeeded
./build/chaind versionWhat Gets Tracked
With this setup enabled, the following information is captured for each block:
- Store changes: All KV store write operations
- Change sets: Complete diff of state changes per block
- Consensus events: Critical ABCI events
- Timing information: When changes occurred
Next Steps
Now that your application is configured, proceed to:
- Node Configuration - Configure config.toml and app.toml settings
Troubleshooting
Build Errors
If you encounter build errors:
# Ensure dependencies are updated
go mod tidy
go mod vendor # if using vendoring
# Clean build cache
go clean -cacheMissing Imports
If imports are not found:
- Verify you’re using the memlogger-enabled Cosmos SDK
- Check your go.mod replace directive
- Run
go mod download
Runtime Errors
If you see runtime errors about streaming:
- Verify the code is placed AFTER baseApp initialization
- Ensure
keysvariable is defined and populated - Check that you’re using the correct
bAppvariable name