Skip to content

Commit

Permalink
docs(core): add core documentation and principles (#21511)
Browse files Browse the repository at this point in the history
Co-authored-by: Aaron Craelius <[email protected]>
(cherry picked from commit 6fc677f)

# Conflicts:
#	core/README.md
#	core/appmodule/doc.go
#	core/appmodule/environment.go
#	core/appmodule/genesis.go
#	core/appmodule/migrations.go
#	core/appmodule/module.go
#	core/appmodule/v2/environment.go
#	core/appmodule/v2/genesis.go
#	core/appmodule/v2/handlers.go
#	core/appmodule/v2/migrations.go
#	core/appmodule/v2/module.go
#	core/appmodule/v2/tx_validator.go
#	core/context/context.go
#	core/context/server_context.go
#	core/gas/service.go
#	core/legacy/amino.go
#	core/registry/legacy.go
#	core/transaction/service.go
#	core/transaction/transaction.go
#	server/v2/stf/stf_router_test.go
  • Loading branch information
julienrbrt authored and mergify[bot] committed Sep 3, 2024
1 parent 7d5ab19 commit 10663c5
Show file tree
Hide file tree
Showing 38 changed files with 778 additions and 47 deletions.
19 changes: 19 additions & 0 deletions core/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Cosmos SDK Core

The [cosmossdk.io/core](https://pkg.go.dev/cosmossdk.io/core) Go module defines essential APIs and interfaces for the Cosmos SDK ecosystem. It serves as a foundation for building modular blockchain applications.

Key features and principles:

1. Provides stable, long-term maintained APIs for module development and app composition.
2. Focuses on interface definitions without implementation details.
3. Implementations are housed in the runtime(/v2) or individual modules.
4. Modules depend solely on core APIs for maximum compatibility.
5. New API additions undergo thorough consideration to maintain stability.
6. Adheres to a no-breaking-changes policy for reliable dependency management.
7. Aimed to have zero dependencies, ensuring a lightweight and self-contained foundation.

The core module offers the [appmodule](https://pkg.go.dev/cosmossdk.io/core/appmodule) and [appmodule/v2](https://pkg.go.dev/cosmossdk.io/core/appmodule/v2) packages that include APIs to describe how modules can be written.
Additionally, it contains all core services APIs that can be used in modules to interact with the SDK, majoritarily via the `appmodule.Environment` struct.
Last but not least, it provides codecs and packages for the Cosmos SDK's core types (think of, for instance, logger, store interface or an address codec).

Developers and contributors approach core API design with careful deliberation, ensuring that additions provide significant value while maintaining the module's stability and simplicity.
4 changes: 4 additions & 0 deletions core/appmodule/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Package appmodule defines what is needed for an module to be used in the Cosmos SDK (runtime).
// It is equivalent to the appmodulev2 package, but less flexible to stay compatible with baseapp instead of server/v2.
// If you are looking at integrating dependency injection into your module please see depinject appconfig documentation.
package appmodule
9 changes: 9 additions & 0 deletions core/appmodule/environment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package appmodule

import (
appmodulev2 "cosmossdk.io/core/appmodule/v2"
)

// Environment is used to get all services to their respective module.
// Contract: All fields of environment are always populated by runtime.
type Environment = appmodulev2.Environment
59 changes: 59 additions & 0 deletions core/appmodule/genesis.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package appmodule

import (
"context"
"encoding/json"
"io"

appmodulev2 "cosmossdk.io/core/appmodule/v2"
)

// HasGenesisBasics is the legacy interface for stateless genesis methods.
type HasGenesisBasics interface {
DefaultGenesis() json.RawMessage
ValidateGenesis(json.RawMessage) error
}

// HasGenesis defines a custom genesis handling API implementation.
type HasGenesis = appmodulev2.HasGenesis

// HasABCIGenesis defines a custom genesis handling API implementation for ABCI.
// (stateful genesis methods which returns validator updates)
// Most modules should not implement this interface.
type HasABCIGenesis = appmodulev2.HasABCIGenesis

// HasGenesisAuto is the extension interface that modules should implement to handle
// genesis data and state initialization.
// WARNING: This interface is experimental and may change at any time and has been dropped in v2.
type HasGenesisAuto interface {
appmodulev2.AppModule

// DefaultGenesis writes the default genesis for this module to the target.
DefaultGenesis(GenesisTarget) error

// ValidateGenesis validates the genesis data read from the source.
ValidateGenesis(GenesisSource) error

// InitGenesis initializes module state from the genesis source.
InitGenesis(context.Context, GenesisSource) error

// ExportGenesis exports module state to the genesis target.
ExportGenesis(context.Context, GenesisTarget) error
}

// GenesisSource is a source for genesis data in JSON format. It may abstract over a
// single JSON object or separate files for each field in a JSON object that can
// be streamed over. Modules should open a separate io.ReadCloser for each field that
// is required. When fields represent arrays they can efficiently be streamed
// over. If there is no data for a field, this function should return nil, nil. It is
// important that the caller closes the reader when done with it.
type GenesisSource = func(field string) (io.ReadCloser, error)

// GenesisTarget is a target for writing genesis data in JSON format. It may
// abstract over a single JSON object or JSON in separate files that can be
// streamed over. Modules should open a separate io.WriteCloser for each field
// and should prefer writing fields as arrays when possible to support efficient
// iteration. It is important the caller closers the writer AND checks the error
// when done with it. It is expected that a stream of JSON data is written
// to the writer.
type GenesisTarget = func(field string) (io.WriteCloser, error)
20 changes: 20 additions & 0 deletions core/appmodule/migrations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package appmodule

import (
appmodulev2 "cosmossdk.io/core/appmodule/v2"
)

// HasConsensusVersion is the interface for declaring a module consensus version.
type HasConsensusVersion = appmodulev2.HasConsensusVersion

// HasMigrations is implemented by a module which upgrades or has upgraded to a new consensus version.
type HasMigrations = appmodulev2.HasMigrations

// MigrationRegistrar is the interface for registering in-place store migrations.
type MigrationRegistrar = appmodulev2.MigrationRegistrar

// MigrationHandler is the migration function that each module registers.
type MigrationHandler = appmodulev2.MigrationHandler

// VersionMap is a map of moduleName -> version
type VersionMap = appmodulev2.VersionMap
72 changes: 72 additions & 0 deletions core/appmodule/module.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package appmodule

import (
"context"

appmodulev2 "cosmossdk.io/core/appmodule/v2"
"cosmossdk.io/core/legacy"
)

// AppModule is a tag interface for app module implementations to use as a basis
// for extension interfaces. It provides no functionality itself, but is the
// type that all valid app modules should provide so that they can be identified
// by other modules (usually via depinject) as app modules.
type AppModule = appmodulev2.AppModule

// HasPreBlocker is the extension interface that modules should implement to run
// custom logic before BeginBlock.
type HasPreBlocker = appmodulev2.HasPreBlocker

// HasBeginBlocker is the extension interface that modules should implement to run
// custom logic before transaction processing in a block.
type HasBeginBlocker = appmodulev2.HasBeginBlocker

// HasEndBlocker is the extension interface that modules should implement to run
// custom logic after transaction processing in a block.
type HasEndBlocker = appmodulev2.HasEndBlocker

// HasRegisterInterfaces is the interface for modules to register their msg types.
type HasRegisterInterfaces = appmodulev2.HasRegisterInterfaces

// ValidatorUpdate defines a validator update.
type ValidatorUpdate = appmodulev2.ValidatorUpdate

// HasServices is the extension interface that modules should implement to register
// implementations of services defined in .proto files.
// This API is supported by the Cosmos SDK module managers but is excluded from core to limit dependencies.
// type HasServices interface {
// AppModule

// // RegisterServices registers the module's services with the app's service
// // registrar.
// //
// // Two types of services are currently supported:
// // - read-only gRPC query services, which are the default.
// // - transaction message services, which must have the protobuf service
// // option "cosmos.msg.v1.service" (defined in "cosmos/msg/v1/service.proto")
// // set to true.
// //
// // The service registrar will figure out which type of service you are
// // implementing based on the presence (or absence) of protobuf options. You
// // do not need to specify this in golang code.
// RegisterServices(grpc.ServiceRegistrar) error
// }

// HasPrepareCheckState is an extension interface that contains information about the AppModule
// and PrepareCheckState.
type HasPrepareCheckState interface {
appmodulev2.AppModule
PrepareCheckState(context.Context) error
}

// HasPrecommit is an extension interface that contains information about the appmodule.AppModule and Precommit.
type HasPrecommit interface {
appmodulev2.AppModule
Precommit(context.Context) error
}

// HasAminoCodec is an extension interface that module must implement to support JSON encoding and decoding of its types
// through amino. This is used in genesis & the CLI client.
type HasAminoCodec interface {
RegisterLegacyAminoCodec(legacy.Amino)
}
3 changes: 3 additions & 0 deletions core/appmodule/v2/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Package appmodule defines what is needed for an module to be used in the Cosmos SDK (runtime/v2).
// If you are looking at integrating dependency injection into your module please see depinject appconfig documentation.
package appmodulev2
29 changes: 29 additions & 0 deletions core/appmodule/v2/environment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package appmodulev2

import (
"cosmossdk.io/core/branch"
"cosmossdk.io/core/event"
"cosmossdk.io/core/gas"
"cosmossdk.io/core/header"
"cosmossdk.io/core/log"
"cosmossdk.io/core/router"
"cosmossdk.io/core/store"
"cosmossdk.io/core/transaction"
)

// Environment is used to get all services to their respective module.
// Contract: All fields of environment are always populated by runtime.
type Environment struct {
Logger log.Logger

BranchService branch.Service
EventService event.Service
GasService gas.Service
HeaderService header.Service
QueryRouterService router.Service
MsgRouterService router.Service
TransactionService transaction.Service

KVStoreService store.KVStoreService
MemStoreService store.MemoryStoreService
}
37 changes: 37 additions & 0 deletions core/appmodule/v2/genesis.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package appmodulev2

import (
"context"
"encoding/json"
)

// HasGenesis defines a custom genesis handling API implementation.
// WARNING: this API is meant as a short-term solution to allow for the
// migration of existing modules to the new app module API.
// It is intended to be replaced by an automatic genesis with collections/orm.
type HasGenesis interface {
AppModule

DefaultGenesis() json.RawMessage
ValidateGenesis(data json.RawMessage) error
InitGenesis(ctx context.Context, data json.RawMessage) error
ExportGenesis(ctx context.Context) (json.RawMessage, error)
}

// HasABCIGenesis defines a custom genesis handling API implementation for ABCI.
// (stateful genesis methods which returns validator updates)
// Most modules should not implement this interface.
type HasABCIGenesis interface {
AppModule

DefaultGenesis() json.RawMessage
ValidateGenesis(data json.RawMessage) error
InitGenesis(ctx context.Context, data json.RawMessage) ([]ValidatorUpdate, error)
ExportGenesis(ctx context.Context) (json.RawMessage, error)
}

// GenesisDecoder is an alternative to the InitGenesis method.
// It is implemented by the genutil module to decode genTxs.
type GenesisDecoder interface {
DecodeGenesisJSON(data json.RawMessage) ([]json.RawMessage, error)
}
62 changes: 62 additions & 0 deletions core/appmodule/v2/handlers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package appmodulev2

import (
"context"

transaction "cosmossdk.io/core/transaction"
)

type (
// PreMsgHandler is a handler that is executed before Handler. If it errors the execution reverts.
PreMsgHandler = func(ctx context.Context, msg transaction.Msg) error
// Handler handles the state transition of the provided message.
Handler = func(ctx context.Context, msg transaction.Msg) (msgResp transaction.Msg, err error)
// PostMsgHandler runs after Handler, only if Handler does not error. If PostMsgHandler errors
// then the execution is reverted.
PostMsgHandler = func(ctx context.Context, msg, msgResp transaction.Msg) error
)

// msg handler

type PreMsgRouter interface {
// RegisterPreHandler will register a specific message handler hooking into the message with
// the provided name.
RegisterPreHandler(msgName string, handler PreMsgHandler)
// RegisterGlobalPreHandler will register a global message handler hooking into any message
// being executed.
RegisterGlobalPreHandler(handler PreMsgHandler)
}

type HasPreMsgHandlers interface {
RegisterPreMsgHandlers(router PreMsgRouter)
}

type MsgRouter interface {
Register(msgName string, handler Handler)
}

type HasMsgHandlers interface {
RegisterMsgHandlers(router MsgRouter)
}

type PostMsgRouter interface {
// RegisterPostHandler will register a specific message handler hooking after the execution of message with
// the provided name.
RegisterPostHandler(msgName string, handler PostMsgHandler)
// RegisterGlobalPostHandler will register a global message handler hooking after the execution of any message.
RegisterGlobalPostHandler(handler PostMsgHandler)
}

type HasPostMsgHandlers interface {
RegisterPostMsgHandlers(router PostMsgRouter)
}

// query handler

type QueryRouter interface {
Register(queryName string, handler Handler)
}

type HasQueryHandlers interface {
RegisterQueryHandlers(router QueryRouter)
}
41 changes: 41 additions & 0 deletions core/appmodule/v2/migrations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package appmodulev2

import "context"

// HasConsensusVersion is the interface for declaring a module consensus version.
type HasConsensusVersion interface {
// ConsensusVersion is a sequence number for state-breaking change of the
// module. It should be incremented on each consensus-breaking change
// introduced by the module. To avoid wrong/empty versions, the initial version
// should be set to 1.
ConsensusVersion() uint64
}

// HasMigrations is implemented by a module which upgrades or has upgraded to a new consensus version.
type HasMigrations interface {
AppModule
HasConsensusVersion

// RegisterMigrations registers the module's migrations with the app's migrator.
RegisterMigrations(MigrationRegistrar) error
}

// MigrationRegistrar is the interface for registering in-place store migrations.
type MigrationRegistrar interface {
// Register registers an in-place store migration for a module. The
// handler is a migration script to perform in-place migrations from version
// `fromVersion` to version `fromVersion+1`.
//
// EACH TIME a module's ConsensusVersion increments, a new migration MUST
// be registered using this function. If a migration handler is missing for
// a particular function, the upgrade logic (see RunMigrations function)
// will panic. If the ConsensusVersion bump does not introduce any store
// changes, then a no-op function must be registered here.
Register(moduleName string, fromVersion uint64, handler MigrationHandler) error
}

// MigrationHandler is the migration function that each module registers.
type MigrationHandler func(context.Context) error

// VersionMap is a map of moduleName -> version
type VersionMap map[string]uint64
Loading

0 comments on commit 10663c5

Please sign in to comment.