Synopsis
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.Prerequisite Readings
Implementing Invariants
An Invariant is a function that checks for a particular invariant within a module. Module Invariants must follow the Invariant type:
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 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:
AllInvariants function that runs all the Invariants functions of the module:
RegisterInvariants method as part of the AppModule interface. Indeed, the RegisterInvariants method of the module, implemented in the module/module.go file, typically only defers the call to a RegisterInvariants method implemented in the keeper/invariants.go file. The RegisterInvariants method registers a route for each Invariant function in the InvariantRegistry:
Invariants implementation from the staking module.
Invariant Registry
TheInvariantRegistry 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 Cosmos SDK as an interface:
keeper of a specific module. The most used implementation of an InvariantRegistry can be found in the crisis module. Note that x/crisis has been moved to ./contrib/x/crisis in Cosmos SDK next and is no longer part of the core SDK.
See the crisis module README for the updated import path.
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:
Invariants returns false, the InvariantRegistry can trigger special logic (e.g. have the application panic and print the Invariants message in the log).