* query-lifecycle and started modules-interfaces * query-lifecycle first draft done * module interfaces first draft * rest and intro skeletons * rest and intro done * small edits and links * comments * revisions * cli.md comments * comments * minor edits * better flow for query lifecycle * add transactions into core * hans comments * add transactions into core * checkout master-docs files * deleted some * remove modules readme * cli.md comments * comments * module-interfaces comments * Merge PR #4857: Add Context concept doc * working * working * finish messages and queries * handler * querier * last comments! * punctuation * querier2 * consolidate intro * querier * workiiiing * refactor for new module interface * karoly review * working on baseapp doc * baseapp work * reorg * almost there * finish first draft * remove old files * finish intro * workinnn * initial commit after rebase * query-lifecycle and started modules-interfaces * query-lifecycle first draft done * module interfaces first draft * rest and intro skeletons * rest and intro done * small edits and links * comments * revisions * cli.md comments * comments * minor edits * better flow for query lifecycle * checkout master-docs files * deleted some * remove modules readme * cli.md comments * comments * module-interfaces comments * keeper * genesis * finish * Apply suggestions from code review Co-Authored-By: Hans Schoenburg <hschoenburg@users.noreply.github.com> * hans review * Update docs/core/baseapp.md Co-Authored-By: Hans Schoenburg <hschoenburg@users.noreply.github.com> * working * last comment * workin * Apply suggestions from code review * encoding and node * almost finish store * finish docs * fixes * fede comments + permalinks * hans review * add more permalinks * update docs theme version (#5239) * R4R: Docs Cleanup (#5246) * start * work * work * work * remove table of content * links intro * fix links * remove junk * cleanup * cleanup * work * finish cleanup * addback readmes * remove nft * fix links * remove dup * remove dup * remove dup * remove dup * remove dup * fix links * add subscribe events * refine rest * index page * sidebar * theme version * theme version * testing netlify * theme version * tooltip example * version * testing code embedding * reverting back * theme version * version * version * version * readme and version * cleanup * redo app anatomy * modules readme, theme version * theme version * fix modules list * theme version * new snippets * modules readme * update docs readme * modify synopsis * version * fix yaml * version * version * version * version * version * version * version * version * version * version * add hide banner * version * version * version * small fixes * modules readme, version * remove hotkeys dep, version * version * version * version * version * version * version * version * slight notice * fix links and hide * permalinks * small clean * version * resolve conflicts, add google analytics * fix merge remants * version * changelog 1/2 * Changelog: docs UI * version * remove merge conflicts * Code: Update link for Contributing to the docs to docs_readme * HTML/CSS: Update layout of homepage footer to match new layout in Figma * version * final modifs * modules, version * modules readme * link to module list from homepage * version * building modules link * version * version * fonts * version * version * fix link * fix package.json * links in explore sdk section * core concepts * version * change delimeters for frontmatter * frontmatter in comments * version * temp add tiny-cookie * fixed link issues * fixed styling issues, copy * hide frontmatter * hide frontmatter * layout fixes, padded ascii diagram * fira sans font for code * scrollbar color * move synopsis from frontmatter * move synopsis from frontmatter * code styling in synopsis fix * tutorial link * active headers * 404 fix * homepage links fix * fix link in footer * misc fixes * version * prerequisite links on mobile * version * version * Fix footer links * version * Fix permalink popup * Update version * package-lock.json * Update Questions section in the footer * Config for Algolia Docsearch * Update version * Update to the latest version of the theme * Use docs-staging as a branch for staging website * Update version * Add google analytics * Remove {hide} from Pre-Requisite Readings * Replace Riot with Discord Co-Authored-By: billy rennekamp <billy.rennekamp@gmail.com> * Fix yaml syntax error in docs * Fix formatting in keyring.md Co-authored-by: Gloria Zhao <gzhao408@berkeley.edu> Co-authored-by: gamarin <gautier@tendermint.com> Co-authored-by: Jack Zampolin <jack.zampolin@gmail.com> Co-authored-by: Hans Schoenburg <hschoenburg@users.noreply.github.com> Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Co-authored-by: Alexander Bezobchuk <alexanderbez@users.noreply.github.com> Co-authored-by: billy rennekamp <billy.rennekamp@gmail.com>
4.7 KiB
Invariants
An invariant is a property of the application that should always be true. In the context of the Cosmos SDK, an Invariant is a function that checks for a particular invariant. These functions are useful to detect bugs early on and act upon them to limit their potential consequences (e.g. by halting the chain). They are also useful in the development process of the application to detect bugs via simulations. {synopsis}
Pre-requisite Readings
- Keepers {prereq}
Implementing Invariants
An Invariant is a function that checks for a particular invariant within a module. Module Invariants must follow the Invariants type:
+++ 7d7821b9af/types/invariant.go (L9)
where the string return value is the invariant message, which can be used when printing logs, and the bool return value is the actual result of the invariant check.
In practice, each module implements Invariants in a ./internal/keeper/invariants.go file within the module's folder. The standard is to implement one Invariant function per logical grouping of invariants with the following model:
// Example for an Invariant that checks balance-related invariants
func BalanceInvariants(k Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
// Implement checks for balance-related invariants
}
}
Additionally, module developers should generally implement an AllInvariants function that runs all the Invariants functions of the module:
// AllInvariants runs all invariants of the module.
// In this example, the module implements two Invariants: BalanceInvariants and DepositsInvariants
func AllInvariants(k Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
res, stop := BalanceInvariants(k)(ctx)
if stop {
return res, stop
}
return DepositsInvariant(k)(ctx)
}
}
Finally, module developers need to implement the RegisterInvariants method as part of the AppModule interface. Indeed, the RegisterInvariants method of the module, implemented in the module.go file, typically only defers the call to a RegisterInvariants method implemented in internal/keeper/invariants.go. The RegisterInvariants method registers a route for each Invariant function in the InvariantRegistry:
// RegisterInvariants registers all staking invariants
func RegisterInvariants(ir sdk.InvariantRegistry, k Keeper) {
ir.RegisterRoute(types.ModuleName, "module-accounts",
BalanceInvariants(k))
ir.RegisterRoute(types.ModuleName, "nonnegative-power",
DepositsInvariant(k))
}
For more, see an example of Invariants implementation from the staking module.
Invariant Registry
The InvariantRegistry is a registry where the Invariants of all the modules of an application are registered. There is only one InvariantRegistry per application, meaning module developers need not implement their own InvariantRegistry when building a module. All module developers need to do is to register their modules' invariants in the InvariantRegistry, as explained in the section above. The rest of this section gives more information on the InvariantRegistry itself, and does not contain anything directly relevant to module developers.
At its core, the InvariantRegistry is defined in the SDK as an interface:
+++ 7d7821b9af/types/invariant.go (L14-L17)
Typically, this interface is implemented in the keeper of a specific module. The most used implementation of an InvariantRegistry can be found in the crisis module:
+++ 7d7821b9af/x/crisis/internal/keeper/keeper.go (L45-L49)
The InvariantRegistry is therefore typically instantiated by instantiating the keeper of the crisis module in the application's constructor function.
Invariants can be checked manually via messages, but most often they are checked automatically at the end of each block. Here is an example from the crisis module:
+++ 7d7821b9af/x/crisis/abci.go (L7-L14)
In both cases, if one of the Invariants returns false, the InvariantRegistry can trigger special logic (e.g. have the application panic and print the Invariants message in the log).
Next {hide}
Learn about genesis functionalities {hide}