mesg-foundation/core

View on GitHub
app/app.go

Summary

Maintainability
C
7 hrs
Test Coverage
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
}