* 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>
5.9 KiB
Keepers
Keepers refer to a Cosmos SDK abstraction whose role is to manage access to the subset of the state defined by various modules. Keepers are module-specific, i.e. the subset of state defined by a module can only be accessed by a keeper defined in said module. If a module needs to access the subset of state defined by another module, a reference to the second module's internal keeper needs to be passed to the first one. This is done in app.go during the instantiation of module keepers. {synopsis}
Pre-requisite Readings
- Introduction to SDK Modules {prereq}
Motivation
The Cosmos SDK is a framework that makes it easy for developers to build complex decentralised applications from scratch, mainly by composing modules together. As the ecosystem of open source modules for the Cosmos SDK expands, it will become increasingly likely that some of these modules contain vulnerabilities, as a result of the negligence or malice of their developer.
The Cosmos SDK adopts an object-capabilities-based approach to help developers better protect their application from unwanted inter-module interactions, and keepers are at the core of this approach. A keeper can be thought of quite literally as the gatekeeper of a module's store(s). Each store (typically an IAVL Store) defined within a module comes with a storeKey, which grants unlimited access to it. The module's keeper holds this storeKey (which should otherwise remain unexposed), and defines methods for reading and writing to the store(s).
The core idea behind the object-capabilities approach is to only reveal what is necessary to get the work done. In practice, this means that instead of handling permissions of modules through access-control lists, module keepers are passed a reference to the specific instance of the other modules' keepers that they need to access (this is done in the application's constructor function). As a consequence, a module can only interact with the subset of state defined in another module via the methods exposed by the instance of the other module's keeper. This is a great way for developers to control the interactions that their own module can have with modules developed by external developers.
Type Definition
keepers are generally implemented in a internal/keeper/keeper.go file located in the module's folder. By convention, the type keeper of a module is simply named Keeper and usually follows the following structure:
type Keeper struct {
// External keepers, if any
// Store key(s)
// codec
}
For example, here is the [type definition of the keeper from the nameservice tutorial:
+++ 86a27321cf/nameservice/x/nameservice/internal/keeper/keeper.go (L10-L17)
Let us go through the different parameters:
- An expected
keeperis akeeperexternal to a module that is required by the internalkeeperof said module. Externalkeepers are listed in the internalkeeper's type definition as interfaces. These interfaces are themselves defined in ainternal/types/expected_keepers.gofile within the module's folder. In this context, interfaces are used to reduce the number of dependencies, as well as to facilitate the maintenance of the module itself. storeKeys grant access to the store(s) of the multistore managed by the module. They should always remain unexposed to external modules.- A codec
cdc, used to marshall and unmarshall struct to/from[]byte.
Of course, it is possible to define different types of internal keepers for the same module (e.g. a read-only keeper). Each type of keeper comes with its own constructor function, which is called from the application's constructor function. This is where keepers are instantiated, and where developers make sure to pass correct instances of modules' keepers to other modules that require it.
Implementing Methods
Keepers primarily expose getter and setter methods for the store(s) managed by their module. These methods should remain as simple as possible and strictly be limited to getting or setting the requested value, as validity checks should have already been performed via the ValidateBasic() method of the message and the handler when keepers' methods are called.
Typically, a getter method will present with the following signature
func (k Keeper) Get(ctx sdk.Context, key string) returnType
and go through the following steps:
- Retrieve the appropriate store from the
ctxusing thestoreKey. This is done through theKVStore(storeKey sdk.StoreKeymethod of thectx. - If it exists, get the
[]bytevalue stored at location[]byte(key)using theGet(key []byte)method of the store. - Unmarshall the retrieved value from
[]bytetoreturnTypeusing the codeccdc. Return the value.
Similarly, a setter method will present with the following signature
func (k Keeper) Set(ctx sdk.Context, key string, value valueType)
and go through the following steps:
- Retrieve the appropriate store from the
ctxusing thestoreKey. This is done through theKVStore(storeKey sdk.StoreKeymethod of thectx. - Marhsall
valueto[]byteusing the codeccdc. - Set the encoded value in the store at location
keyusing theSet(key []byte, value []byte)method of the store.
For more, see an example of keeper's methods implementation from the nameservice tutorial.
Next {hide}
Learn about invariants {hide}