app/app.go
package app
import (
"encoding/json"
"io"
"os"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/log"
dbm "github.com/tendermint/tm-db"
bam "github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/version"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/auth/vesting"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/crisis"
distr "github.com/cosmos/cosmos-sdk/x/distribution"
"github.com/cosmos/cosmos-sdk/x/evidence"
"github.com/cosmos/cosmos-sdk/x/genutil"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/params"
paramsclient "github.com/cosmos/cosmos-sdk/x/params/client"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/cosmos/cosmos-sdk/x/staking"
"github.com/cosmos/cosmos-sdk/x/supply"
"github.com/cosmos/cosmos-sdk/x/upgrade"
upgradeclient "github.com/cosmos/cosmos-sdk/x/upgrade/client"
"github.com/mesg-foundation/engine/protobuf/types"
"github.com/mesg-foundation/engine/x/credit"
"github.com/mesg-foundation/engine/x/execution"
"github.com/mesg-foundation/engine/x/instance"
"github.com/mesg-foundation/engine/x/ownership"
"github.com/mesg-foundation/engine/x/process"
"github.com/mesg-foundation/engine/x/runner"
"github.com/mesg-foundation/engine/x/service"
)
const appName = "engine"
var (
// DefaultCLIHome is the default home directories for the application CLI
DefaultCLIHome = os.ExpandEnv("$HOME/.mesg-cli")
// DefaultNodeHome sets the folder where the application data and configuration will be stored
DefaultNodeHome = os.ExpandEnv("$HOME/.mesg-node")
// ModuleBasics The module BasicManager is in charge of setting up basic,
// non-dependant module elements, such as codec registration
// and genesis verification.
ModuleBasics = module.NewBasicManager(
genutil.AppModuleBasic{},
auth.AppModuleBasic{},
bank.AppModuleBasic{},
staking.AppModuleBasic{},
distr.AppModuleBasic{},
params.AppModuleBasic{},
slashing.AppModuleBasic{},
supply.AppModuleBasic{},
gov.NewAppModuleBasic(paramsclient.ProposalHandler, distr.ProposalHandler, upgradeclient.ProposalHandler),
upgrade.AppModuleBasic{},
evidence.AppModuleBasic{},
crisis.AppModuleBasic{},
// Engine's AppModuleBasic
credit.AppModuleBasic{},
ownership.AppModuleBasic{},
instance.AppModuleBasic{},
process.AppModuleBasic{},
runner.AppModuleBasic{},
service.AppModuleBasic{},
execution.AppModuleBasic{},
)
// module account permissions
maccPerms = map[string][]string{
auth.FeeCollectorName: nil,
distr.ModuleName: nil,
staking.BondedPoolName: {supply.Burner, supply.Staking},
staking.NotBondedPoolName: {supply.Burner, supply.Staking},
gov.ModuleName: {supply.Burner},
}
)
// MakeCodec creates the application codec. The codec is sealed before it is
// returned.
func MakeCodec() *codec.Codec {
var cdc = codec.New()
ModuleBasics.RegisterCodec(cdc)
vesting.RegisterCodec(cdc)
sdk.RegisterCodec(cdc)
codec.RegisterCrypto(cdc)
types.RegisterCodec(cdc)
return cdc.Seal()
}
// NewApp extended ABCI application
type NewApp struct {
*bam.BaseApp
cdc *codec.Codec
invCheckPeriod uint
// keys to access the substores
keys map[string]*sdk.KVStoreKey
tKeys map[string]*sdk.TransientStoreKey
// subspaces
subspaces map[string]params.Subspace
// keepers
accountKeeper auth.AccountKeeper
bankKeeper bank.Keeper
stakingKeeper staking.Keeper
slashingKeeper slashing.Keeper
distrKeeper distr.Keeper
supplyKeeper supply.Keeper
paramsKeeper params.Keeper
govKeeper gov.Keeper
upgradeKeeper upgrade.Keeper
evidenceKeeper evidence.Keeper
crisisKeeper crisis.Keeper
// Engine's keepers
creditKeeper credit.Keeper
ownershipKeeper ownership.Keeper
instanceKeeper instance.Keeper
processKeeper process.Keeper
runnerKeeper runner.Keeper
serviceKeeper service.Keeper
executionKeeper execution.Keeper
// Module Manager
mm *module.Manager
// simulation manager
sm *module.SimulationManager
}
// verify app interface at compile time
var _ simapp.App = (*NewApp)(nil)
// NewInitApp is a constructor function for engineApp
func NewInitApp(
logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
invCheckPeriod uint, skipUpgradeHeights map[int64]bool, baseAppOptions ...func(*bam.BaseApp),
) (*NewApp, error) {
// First define the top level codec that will be shared by the different modules
cdc := MakeCodec()
// BaseApp handles interactions with Tendermint through the ABCI protocol
bApp := bam.NewBaseApp(appName, logger, db, auth.DefaultTxDecoder(cdc), baseAppOptions...)
bApp.SetCommitMultiStoreTracer(traceStore)
bApp.SetAppVersion(version.Version)
keys := sdk.NewKVStoreKeys(
bam.MainStoreKey,
auth.StoreKey,
staking.StoreKey,
supply.StoreKey,
distr.StoreKey,
slashing.StoreKey,
params.StoreKey,
gov.StoreKey,
upgrade.StoreKey,
evidence.StoreKey,
// Engine's module keys
credit.ModuleName,
ownership.ModuleName,
instance.ModuleName,
process.ModuleName,
runner.ModuleName,
service.ModuleName,
execution.ModuleName,
)
tKeys := sdk.NewTransientStoreKeys(staking.TStoreKey, params.TStoreKey)
// Here you initialize your application with the store keys it requires
var app = &NewApp{
BaseApp: bApp,
cdc: cdc,
invCheckPeriod: invCheckPeriod,
keys: keys,
tKeys: tKeys,
subspaces: make(map[string]params.Subspace),
}
// The ParamsKeeper handles parameter storage for the application
app.paramsKeeper = params.NewKeeper(app.cdc, keys[params.StoreKey], tKeys[params.TStoreKey])
// Set specific supspaces
app.subspaces[auth.ModuleName] = app.paramsKeeper.Subspace(auth.DefaultParamspace)
app.subspaces[bank.ModuleName] = app.paramsKeeper.Subspace(bank.DefaultParamspace)
app.subspaces[staking.ModuleName] = app.paramsKeeper.Subspace(staking.DefaultParamspace)
app.subspaces[distr.ModuleName] = app.paramsKeeper.Subspace(distr.DefaultParamspace)
app.subspaces[slashing.ModuleName] = app.paramsKeeper.Subspace(slashing.DefaultParamspace)
app.subspaces[gov.ModuleName] = app.paramsKeeper.Subspace(gov.DefaultParamspace)
app.subspaces[evidence.ModuleName] = app.paramsKeeper.Subspace(evidence.DefaultParamspace)
app.subspaces[crisis.ModuleName] = app.paramsKeeper.Subspace(crisis.DefaultParamspace)
app.subspaces[credit.ModuleName] = app.paramsKeeper.Subspace(credit.DefaultParamspace)
// The AccountKeeper handles address -> account lookups
app.accountKeeper = auth.NewAccountKeeper(
app.cdc,
keys[auth.StoreKey],
app.subspaces[auth.ModuleName],
auth.ProtoBaseAccount,
)
// The BankKeeper allows you perform sdk.Coins interactions
app.bankKeeper = bank.NewBaseKeeper(
app.accountKeeper,
app.subspaces[bank.ModuleName],
app.ModuleAccountAddrs(),
)
// The SupplyKeeper collects transaction fees and renders them to the fee distribution module
app.supplyKeeper = supply.NewKeeper(
app.cdc,
keys[supply.StoreKey],
app.accountKeeper,
app.bankKeeper,
maccPerms,
)
// The staking keeper
stakingKeeper := staking.NewKeeper(
app.cdc,
keys[staking.StoreKey],
app.supplyKeeper,
app.subspaces[staking.ModuleName],
)
app.distrKeeper = distr.NewKeeper(
app.cdc,
keys[distr.StoreKey],
app.subspaces[distr.ModuleName],
&stakingKeeper,
app.supplyKeeper,
auth.FeeCollectorName,
app.ModuleAccountAddrs(),
)
app.slashingKeeper = slashing.NewKeeper(
app.cdc,
keys[slashing.StoreKey],
&stakingKeeper,
app.subspaces[slashing.ModuleName],
)
app.crisisKeeper = crisis.NewKeeper(
app.subspaces[crisis.ModuleName],
invCheckPeriod,
app.supplyKeeper,
auth.FeeCollectorName,
)
app.upgradeKeeper = upgrade.NewKeeper(
skipUpgradeHeights,
keys[upgrade.StoreKey],
app.cdc,
)
// create evidence keeper with evidence router
evidenceKeeper := evidence.NewKeeper(
app.cdc,
keys[evidence.StoreKey],
app.subspaces[evidence.ModuleName],
&stakingKeeper,
app.slashingKeeper,
)
evidenceRouter := evidence.NewRouter()
// register evidence routes
evidenceKeeper.SetRouter(evidenceRouter)
app.evidenceKeeper = *evidenceKeeper
// register the proposal types
govRouter := gov.NewRouter()
govRouter.
AddRoute(gov.RouterKey, gov.ProposalHandler).
AddRoute(params.RouterKey, params.NewParamChangeProposalHandler(app.paramsKeeper)).
AddRoute(distr.RouterKey, distr.NewCommunityPoolSpendProposalHandler(app.distrKeeper)).
AddRoute(upgrade.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.upgradeKeeper))
app.govKeeper = gov.NewKeeper(
app.cdc,
keys[gov.StoreKey],
app.subspaces[gov.ModuleName].WithKeyTable(gov.ParamKeyTable()),
app.supplyKeeper,
&stakingKeeper,
govRouter,
)
// register the staking hooks
// NOTE: stakingKeeper above is passed by reference, so that it will contain these hooks
app.stakingKeeper = *stakingKeeper.SetHooks(
staking.NewMultiStakingHooks(
app.distrKeeper.Hooks(),
app.slashingKeeper.Hooks()),
)
// Engine's module keepers
app.creditKeeper = credit.NewKeeper(app.cdc, app.accountKeeper, keys[credit.StoreKey], app.subspaces[credit.ModuleName])
app.ownershipKeeper = ownership.NewKeeper(app.cdc, keys[ownership.StoreKey], app.bankKeeper)
app.serviceKeeper = service.NewKeeper(app.cdc, keys[service.StoreKey], app.ownershipKeeper)
app.instanceKeeper = instance.NewKeeper(app.cdc, keys[instance.StoreKey], app.serviceKeeper)
app.processKeeper = process.NewKeeper(app.cdc, keys[process.StoreKey], app.instanceKeeper, app.ownershipKeeper)
app.runnerKeeper = runner.NewKeeper(app.cdc, keys[runner.StoreKey], app.instanceKeeper, app.ownershipKeeper)
app.executionKeeper = execution.NewKeeper(
app.cdc,
keys[execution.StoreKey],
app.serviceKeeper,
app.instanceKeeper,
app.runnerKeeper,
app.processKeeper,
app.creditKeeper,
)
// NOTE: Any module instantiated in the module manager that is later modified
// must be passed by reference here.
app.mm = module.NewManager(
genutil.NewAppModule(app.accountKeeper, app.stakingKeeper, app.BaseApp.DeliverTx),
auth.NewAppModule(app.accountKeeper),
bank.NewAppModule(app.bankKeeper, app.accountKeeper),
crisis.NewAppModule(&app.crisisKeeper),
supply.NewAppModule(app.supplyKeeper, app.accountKeeper),
gov.NewAppModule(app.govKeeper, app.accountKeeper, app.supplyKeeper),
distr.NewAppModule(app.distrKeeper, app.accountKeeper, app.supplyKeeper, app.stakingKeeper),
slashing.NewAppModule(app.slashingKeeper, app.accountKeeper, app.stakingKeeper),
// Engine's modules
credit.NewAppModule(app.creditKeeper),
ownership.NewAppModule(app.ownershipKeeper),
instance.NewAppModule(app.instanceKeeper),
process.NewAppModule(app.processKeeper),
runner.NewAppModule(app.runnerKeeper, app.instanceKeeper),
service.NewAppModule(app.serviceKeeper),
execution.NewAppModule(app.executionKeeper),
staking.NewAppModule(app.stakingKeeper, app.accountKeeper, app.supplyKeeper),
upgrade.NewAppModule(app.upgradeKeeper),
evidence.NewAppModule(app.evidenceKeeper),
)
// During begin block slashing happens after distr.BeginBlocker so that
// there is nothing left over in the validator fee pool, so as to keep the
// CanWithdrawInvariant invariant.
app.mm.SetOrderBeginBlockers(upgrade.ModuleName, distr.ModuleName, slashing.ModuleName)
app.mm.SetOrderEndBlockers(crisis.ModuleName, gov.ModuleName, staking.ModuleName)
// Sets the order of Genesis - Order matters, genutil is to always come last
// NOTE: The genutils module must occur after staking so that pools are
// properly initialized with tokens from genesis accounts.
app.mm.SetOrderInitGenesis(
distr.ModuleName,
staking.ModuleName,
auth.ModuleName,
bank.ModuleName,
slashing.ModuleName,
gov.ModuleName,
// Engine's modules
credit.ModuleName,
ownership.ModuleName,
instance.ModuleName,
process.ModuleName,
runner.ModuleName,
service.ModuleName,
execution.ModuleName,
supply.ModuleName,
crisis.ModuleName,
genutil.ModuleName,
evidence.ModuleName,
)
// register all module routes and module queriers
app.mm.RegisterRoutes(app.Router(), app.QueryRouter())
// The initChainer handles translating the genesis.json file into initial state for the network
app.SetInitChainer(app.InitChainer)
app.SetBeginBlocker(app.BeginBlocker)
app.SetEndBlocker(app.EndBlocker)
// The AnteHandler handles signature verification and transaction pre-processing
app.SetAnteHandler(
auth.NewAnteHandler(
app.accountKeeper,
app.supplyKeeper,
auth.DefaultSigVerificationGasConsumer,
),
)
// initialize stores
app.MountKVStores(keys)
app.MountTransientStores(tKeys)
if loadLatest {
if err := app.LoadLatestVersion(app.keys[bam.MainStoreKey]); err != nil {
return nil, err
}
}
return app, nil
}
// GenesisState represents chain state at the start of the chain. Any initial state (account balances) are stored here.
type GenesisState map[string]json.RawMessage
// NewDefaultGenesisState generates the default state for the application.
func NewDefaultGenesisState() GenesisState {
return ModuleBasics.DefaultGenesis()
}
// InitChainer application update at chain initialization
func (app *NewApp) InitChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
var genesisState simapp.GenesisState
app.cdc.MustUnmarshalJSON(req.AppStateBytes, &genesisState)
return app.mm.InitGenesis(ctx, genesisState)
}
// BeginBlocker application updates every begin block
func (app *NewApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock {
return app.mm.BeginBlock(ctx, req)
}
// EndBlocker application updates every end block
func (app *NewApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock {
return app.mm.EndBlock(ctx, req)
}
// LoadHeight loads a particular height
func (app *NewApp) LoadHeight(height int64) error {
return app.LoadVersion(height, app.keys[bam.MainStoreKey])
}
// ModuleAccountAddrs returns all the app's module account addresses.
func (app *NewApp) ModuleAccountAddrs() map[string]bool {
modAccAddrs := make(map[string]bool)
for acc := range maccPerms {
modAccAddrs[supply.NewModuleAddress(acc).String()] = true
}
return modAccAddrs
}
// Codec returns the application's sealed codec.
func (app *NewApp) Codec() *codec.Codec {
return app.cdc
}
// SimulationManager implements the SimulationApp interface
func (app *NewApp) SimulationManager() *module.SimulationManager {
return app.sm
}
// GetMaccPerms returns a mapping of the application's module account permissions.
func GetMaccPerms() map[string][]string {
modAccPerms := make(map[string][]string)
for k, v := range maccPerms {
modAccPerms[k] = v
}
return modAccPerms
}