Skip to content
This repository has been archived by the owner on Nov 16, 2022. It is now read-only.

chain: Add missing pieces on app.go + some refactor and comments #2093

Merged
merged 4 commits into from
Jul 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG_UNRELEASED.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

### Chain

- (impv) [\#2093](https://github.com/bandprotocol/bandchain/pull/2093) Add missing pieces on app.go + some refactor and comments.
- (feat) [\#2114](https://github.com/bandprotocol/bandchain/pull/2114) Add more unit test coverage and enhance code comments in pkg.
- (impv) [\#2072](https://github.com/bandprotocol/bandchain/pull/2072) Handle resolve request for emitter/flusher.
- (feat) [\#2111](https://github.com/bandprotocol/bandchain/pull/2111) Introduce the notion of active validators who are performing oracle tasks.
Expand Down
179 changes: 82 additions & 97 deletions chain/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,11 @@ const (
)

var (
// DefaultCLIHome default home directories for bandcli
// DefaultCLIHome is the default home directories for bandcli.
DefaultCLIHome = os.ExpandEnv("$HOME/.bandcli")

// DefaultNodeHome default home directories for bandd
// DefaultNodeHome is the default home directories for bandd.
DefaultNodeHome = os.ExpandEnv("$HOME/.bandd")

// ModuleBasics The module BasicManager is in charge of setting up basic,
// non-dependant module elements, such as codec registration
// and genesis verification.
// ModuleBasics is in charge of setting up basic, non-dependant module elements.
ModuleBasics = module.NewBasicManager(
genutil.AppModuleBasic{},
auth.AppModuleBasic{},
Expand All @@ -70,7 +66,6 @@ var (
evidence.AppModuleBasic{},
oracle.AppModuleBasic{},
)

// module account permissions
maccPerms = map[string][]string{
auth.FeeCollectorName: nil,
Expand All @@ -80,23 +75,21 @@ var (
staking.NotBondedPoolName: {supply.Burner, supply.Staking},
gov.ModuleName: {supply.Burner},
}
// module accounts that are allowed to receive tokens.
allowedReceivingModAcc = map[string]bool{
distr.ModuleName: true,
}
)

// BandApp extended ABCI application
// BandApp is the application of BandChain, extended base ABCI application.
type BandApp struct {
*bam.BaseApp
cdc *codec.Codec

cdc *codec.Codec
invCheckPeriod uint

// keys to access the substores
// Keys to access the substores.
keys map[string]*sdk.KVStoreKey
tKeys map[string]*sdk.TransientStoreKey

// subspaces
subspaces map[string]params.Subspace

// keepers
// Module keepers, publicly accessible to facilate testing and extending (see emitter).
AccountKeeper auth.AccountKeeper
BankKeeper bank.Keeper
SupplyKeeper supply.Keeper
Expand All @@ -110,16 +103,14 @@ type BandApp struct {
UpgradeKeeper upgrade.Keeper
EvidenceKeeper evidence.Keeper
OracleKeeper oracle.Keeper

// Decoder for unmarshaling []byte into sdk.Tx
TxDecoder sdk.TxDecoder
// Deliver Context that is set during BeginBlock and unset during EndBlock; primarily for gas refund
// Deliver context, set during InitGenesis/BeginBlock and cleared during Commit. It allows
// anyone with access to BandApp to read/mutate consensus state anytime. USE WITH CARE!
DeliverContext sdk.Context

// the module manager
// Module manager.
mm *module.Manager
}

// MakeCodec returns BandChain codec.
func MakeCodec() *codec.Codec {
var cdc = codec.New()
ModuleBasics.RegisterCodec(cdc)
Expand All @@ -129,19 +120,14 @@ func MakeCodec() *codec.Codec {
return cdc.Seal()
}

// SetBech32AddressPrefixesAndBip44CoinType sets the global Bech32 prefixes and HD wallet coin type.
func SetBech32AddressPrefixesAndBip44CoinType(config *sdk.Config) {
config.SetBech32PrefixForAccount(
Bech32MainPrefix,
Bech32MainPrefix+sdk.PrefixPublic,
)
config.SetBech32PrefixForValidator(
Bech32MainPrefix+sdk.PrefixValidator+sdk.PrefixOperator,
Bech32MainPrefix+sdk.PrefixValidator+sdk.PrefixOperator+sdk.PrefixPublic,
)
config.SetBech32PrefixForConsensusNode(
Bech32MainPrefix+sdk.PrefixValidator+sdk.PrefixConsensus,
Bech32MainPrefix+sdk.PrefixValidator+sdk.PrefixConsensus+sdk.PrefixPublic,
)
accountPrefix := Bech32MainPrefix
validatorPrefix := Bech32MainPrefix + sdk.PrefixValidator + sdk.PrefixOperator
consensusPrefix := Bech32MainPrefix + sdk.PrefixValidator + sdk.PrefixConsensus
config.SetBech32PrefixForAccount(accountPrefix, accountPrefix+sdk.PrefixPublic)
config.SetBech32PrefixForValidator(validatorPrefix, validatorPrefix+sdk.PrefixPublic)
config.SetBech32PrefixForConsensusNode(consensusPrefix, consensusPrefix+sdk.PrefixPublic)
config.SetCoinType(Bip44CoinType)
}

Expand All @@ -161,66 +147,56 @@ func NewBandApp(
evidence.StoreKey, oracle.StoreKey,
)
tKeys := sdk.NewTransientStoreKeys(params.TStoreKey)

app := &BandApp{
BaseApp: bApp,
cdc: cdc,
invCheckPeriod: invCheckPeriod,
keys: keys,
tKeys: tKeys,
subspaces: make(map[string]params.Subspace),
TxDecoder: auth.DefaultTxDecoder(cdc),
}

// init params keeper and subspaces
// Initialize params keeper and module subspaces.
app.ParamsKeeper = params.NewKeeper(cdc, keys[params.StoreKey], tKeys[params.TStoreKey])
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[mint.ModuleName] = app.ParamsKeeper.Subspace(mint.DefaultParamspace)
app.subspaces[distr.ModuleName] = app.ParamsKeeper.Subspace(distr.DefaultParamspace)
app.subspaces[slashing.ModuleName] = app.ParamsKeeper.Subspace(slashing.DefaultParamspace)
app.subspaces[evidence.ModuleName] = app.ParamsKeeper.Subspace(evidence.DefaultParamspace)
app.subspaces[gov.ModuleName] = app.ParamsKeeper.Subspace(gov.DefaultParamspace).WithKeyTable(gov.ParamKeyTable())
app.subspaces[crisis.ModuleName] = app.ParamsKeeper.Subspace(crisis.DefaultParamspace)
app.subspaces[oracle.ModuleName] = app.ParamsKeeper.Subspace(oracle.DefaultParamspace)

// add keepers
app.AccountKeeper = auth.NewAccountKeeper(cdc, keys[auth.StoreKey], app.subspaces[auth.ModuleName], auth.ProtoBaseAccount)
app.BankKeeper = bank.NewBaseKeeper(app.AccountKeeper, app.subspaces[bank.ModuleName], app.ModuleAccountAddrs())
authSubspace := app.ParamsKeeper.Subspace(auth.DefaultParamspace)
bankSubspace := app.ParamsKeeper.Subspace(bank.DefaultParamspace)
stakingSubspace := app.ParamsKeeper.Subspace(staking.DefaultParamspace)
mintSubspace := app.ParamsKeeper.Subspace(mint.DefaultParamspace)
distrSubspace := app.ParamsKeeper.Subspace(distr.DefaultParamspace)
slashingSubspace := app.ParamsKeeper.Subspace(slashing.DefaultParamspace)
evidenceSubspace := app.ParamsKeeper.Subspace(evidence.DefaultParamspace)
govSubspace := app.ParamsKeeper.Subspace(gov.DefaultParamspace).WithKeyTable(gov.ParamKeyTable())
crisisSubspace := app.ParamsKeeper.Subspace(crisis.DefaultParamspace)
oracleSubspace := app.ParamsKeeper.Subspace(oracle.DefaultParamspace)
// Add module keepers.
app.AccountKeeper = auth.NewAccountKeeper(cdc, keys[auth.StoreKey], authSubspace, auth.ProtoBaseAccount)
app.BankKeeper = bank.NewBaseKeeper(app.AccountKeeper, bankSubspace, app.BlacklistedAccAddrs())
app.SupplyKeeper = supply.NewKeeper(cdc, keys[supply.StoreKey], app.AccountKeeper, app.BankKeeper, maccPerms)
// Wrapped supply keeper allows burned tokens to be transferred to community pool
// wrappedSupplyKeeper overrides burn token behavior to instead transfer to community pool.
wrappedSupplyKeeper := bandsupply.WrapSupplyKeeperBurnToCommunityPool(app.SupplyKeeper)
stakingKeeper := staking.NewKeeper(cdc, keys[staking.StoreKey], &wrappedSupplyKeeper, app.subspaces[staking.ModuleName])
app.MintKeeper = mint.NewKeeper(cdc, keys[mint.StoreKey], app.subspaces[mint.ModuleName], &stakingKeeper, app.SupplyKeeper, auth.FeeCollectorName)
app.CrisisKeeper = crisis.NewKeeper(app.subspaces[crisis.ModuleName], invCheckPeriod, app.SupplyKeeper, auth.FeeCollectorName)
app.DistrKeeper = distr.NewKeeper(cdc, keys[distr.StoreKey], app.subspaces[distr.ModuleName], &stakingKeeper, app.SupplyKeeper, auth.FeeCollectorName, app.ModuleAccountAddrs())
// DistrKeeper must be set afterward due to the circular reference of supply-staking-distr
stakingKeeper := staking.NewKeeper(cdc, keys[staking.StoreKey], &wrappedSupplyKeeper, stakingSubspace)
app.MintKeeper = mint.NewKeeper(cdc, keys[mint.StoreKey], mintSubspace, &stakingKeeper, app.SupplyKeeper, auth.FeeCollectorName)
app.DistrKeeper = distr.NewKeeper(cdc, keys[distr.StoreKey], distrSubspace, &stakingKeeper, app.SupplyKeeper, auth.FeeCollectorName, app.ModuleAccountAddrs())
// DistrKeeper must be set afterward due to the circular reference between supply-staking-distr.
wrappedSupplyKeeper.SetDistrKeeper(&app.DistrKeeper)
app.SlashingKeeper = slashing.NewKeeper(cdc, keys[slashing.StoreKey], &stakingKeeper, app.subspaces[slashing.ModuleName])

// register the proposal types
app.CrisisKeeper = crisis.NewKeeper(crisisSubspace, invCheckPeriod, app.SupplyKeeper, auth.FeeCollectorName)
app.SlashingKeeper = slashing.NewKeeper(cdc, keys[slashing.StoreKey], &stakingKeeper, slashingSubspace)
app.UpgradeKeeper = upgrade.NewKeeper(skipUpgradeHeights, keys[upgrade.StoreKey], cdc)
app.OracleKeeper = oracle.NewKeeper(cdc, keys[oracle.StoreKey], filepath.Join(viper.GetString(cli.HomeFlag), "files"), auth.FeeCollectorName, oracleSubspace, app.SupplyKeeper, &stakingKeeper, app.DistrKeeper)
// Register the proposal types.
govRouter := gov.NewRouter()
govRouter.AddRoute(gov.RouterKey, gov.ProposalHandler).
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(cdc, keys[gov.StoreKey], app.subspaces[gov.ModuleName], app.SupplyKeeper, &stakingKeeper, govRouter)

// create evidence keeper with evidence router
evidenceKeeper := evidence.NewKeeper(cdc, keys[evidence.StoreKey], app.subspaces[evidence.ModuleName], &stakingKeeper, app.SlashingKeeper)
app.GovKeeper = gov.NewKeeper(cdc, keys[gov.StoreKey], govSubspace, app.SupplyKeeper, &stakingKeeper, govRouter)
// Create evidence keeper with evidence router.
evidenceKeeper := evidence.NewKeeper(cdc, keys[evidence.StoreKey], evidenceSubspace, &stakingKeeper, app.SlashingKeeper)
evidenceRouter := evidence.NewRouter()
evidenceKeeper.SetRouter(evidenceRouter)
app.EvidenceKeeper = *evidenceKeeper

app.UpgradeKeeper = upgrade.NewKeeper(skipUpgradeHeights, keys[upgrade.StoreKey], cdc)
app.OracleKeeper = oracle.NewKeeper(cdc, keys[oracle.StoreKey], filepath.Join(viper.GetString(cli.HomeFlag), "files"), auth.FeeCollectorName, app.subspaces[oracle.ModuleName], app.SupplyKeeper, &stakingKeeper, app.DistrKeeper)

// register the staking hooks
// NOTE: stakingKeeper above is passed by reference, so that it will contain these hooks
// 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()))

// NOTE: Any module instantiated in the module manager that is later modified
// must be passed by reference here.
// Create the module manager. 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.DeliverTx),
auth.NewAppModule(app.AccountKeeper),
Expand All @@ -236,35 +212,34 @@ func NewBandApp(
evidence.NewAppModule(app.EvidenceKeeper),
oracle.NewAppModule(app.OracleKeeper),
)
// 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.

// NOTE: oracle module intercepts fee pool and must run between mint and distr.
app.mm.SetOrderBeginBlockers(upgrade.ModuleName, mint.ModuleName, oracle.ModuleName, distr.ModuleName, slashing.ModuleName, staking.ModuleName)
app.mm.SetOrderEndBlockers(crisis.ModuleName, gov.ModuleName, staking.ModuleName, oracle.ModuleName)

// 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, mint.ModuleName, oracle.ModuleName, distr.ModuleName, slashing.ModuleName,
evidence.ModuleName, staking.ModuleName,
)
// NOTE: The oracle module must occur before staking so that jailed validators due to report
// downtime will not get included in staking module's ValidatorUpdate set.
app.mm.SetOrderEndBlockers(
crisis.ModuleName, gov.ModuleName, staking.ModuleName, oracle.ModuleName,
)
// NOTE: The genutils module must occur after staking so that pools are
// properly initialized with tokens from genesis accounts.
app.mm.SetOrderInitGenesis(
auth.ModuleName, distr.ModuleName, staking.ModuleName, bank.ModuleName, supply.ModuleName,
slashing.ModuleName, gov.ModuleName, mint.ModuleName, crisis.ModuleName,
genutil.ModuleName, evidence.ModuleName, oracle.ModuleName,
slashing.ModuleName, gov.ModuleName, mint.ModuleName, oracle.ModuleName, crisis.ModuleName,
genutil.ModuleName, evidence.ModuleName,
)

app.mm.RegisterInvariants(&app.CrisisKeeper)
app.mm.RegisterRoutes(app.Router(), app.QueryRouter())

// initialize stores
// Initialize stores.
app.MountKVStores(keys)
app.MountTransientStores(tKeys)

// initialize BaseApp
// initialize BaseApp.
app.SetInitChainer(app.InitChainer)
app.SetBeginBlocker(app.BeginBlocker)
app.SetAnteHandler(ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper, ante.DefaultSigVerificationGasConsumer))
app.SetEndBlocker(app.EndBlocker)

if loadLatest {
err := app.LoadLatestVersion(app.keys[bam.MainStoreKey])
if err != nil {
Expand All @@ -274,20 +249,21 @@ func NewBandApp(
return app
}

// Name returns the name of the App
// Name returns the name of the App.
func (app *BandApp) Name() string { return app.BaseApp.Name() }

// BeginBlocker application updates every begin block
// BeginBlocker application updates every begin block.
func (app *BandApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock {
app.DeliverContext = ctx
return app.mm.BeginBlock(ctx, req)
}

// EndBlocker application updates every end block
// EndBlocker application updates every end block.
func (app *BandApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock {
return app.mm.EndBlock(ctx, req)
}

// Commit overrides the default BaseApp's ABCI commit by adding DeliverContext clearing.
func (app *BandApp) Commit() (res abci.ResponseCommit) {
app.DeliverContext = sdk.Context{}
return app.BaseApp.Commit()
Expand Down Expand Up @@ -315,6 +291,15 @@ func (app *BandApp) ModuleAccountAddrs() map[string]bool {
return modAccAddrs
}

// BlacklistedAccAddrs returns all the app's module account addresses black listed for receiving tokens.
func (app *BandApp) BlacklistedAccAddrs() map[string]bool {
blacklistedAddrs := make(map[string]bool)
for acc := range maccPerms {
blacklistedAddrs[supply.NewModuleAddress(acc).String()] = !allowedReceivingModAcc[acc]
}
return blacklistedAddrs
}

// Codec returns the application's sealed codec.
func (app *BandApp) Codec() *codec.Codec {
return app.cdc
Expand Down
9 changes: 5 additions & 4 deletions chain/app/db_app.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ import (

type dbBandApp struct {
*BandApp
dbBand *db.BandDB
txNum int64
txDecoder sdk.TxDecoder
dbBand *db.BandDB
txNum int64
}

func NewDBBandApp(
Expand All @@ -37,7 +38,7 @@ func NewDBBandApp(
dbBand.DistrKeeper = app.DistrKeeper
dbBand.StakingKeeper = app.StakingKeeper
dbBand.OracleKeeper = app.OracleKeeper
return &dbBandApp{BandApp: app, dbBand: dbBand}
return &dbBandApp{BandApp: app, txDecoder: auth.DefaultTxDecoder(app.Codec()), dbBand: dbBand}
}

func (app *dbBandApp) InitChain(req abci.RequestInitChain) abci.ResponseInitChain {
Expand Down Expand Up @@ -151,7 +152,7 @@ func (app *dbBandApp) DeliverTx(req abci.RequestDeliverTx) (res abci.ResponseDel
return res
}

tx, err := app.TxDecoder(req.Tx)
tx, err := app.txDecoder(req.Tx)
if err != nil {
panic(err)
}
Expand Down
19 changes: 9 additions & 10 deletions chain/emitter/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,12 @@ import (
"github.com/bandprotocol/bandchain/chain/x/oracle"
)

type Message struct {
Key string
Value JsDict
}

// App extends the standard Band Cosmos-SDK application with Kafka emitter
// functionality to act as an event producer for all events in the blockchains.
type App struct {
*bandapp.BandApp
// Decoder for unmarshaling []byte into sdk.Tx.
txDecoder sdk.TxDecoder
// Main Kafka writer instance.
writer *kafka.Writer
// Temporary variables that are reset on every block.
Expand All @@ -42,11 +39,13 @@ func NewBandAppWithEmitter(
invCheckPeriod uint, skipUpgradeHeights map[int64]bool, home string,
baseAppOptions ...func(*bam.BaseApp),
) *App {
app := bandapp.NewBandApp(
logger, db, traceStore, loadLatest, invCheckPeriod, skipUpgradeHeights,
home, baseAppOptions...,
)
return &App{
BandApp: bandapp.NewBandApp(
logger, db, traceStore, loadLatest, invCheckPeriod, skipUpgradeHeights,
home, baseAppOptions...,
),
BandApp: app,
txDecoder: auth.DefaultTxDecoder(app.Codec()),
writer: kafka.NewWriter(kafka.WriterConfig{
Brokers: []string{"localhost:9092"}, // TODO: Remove hardcode
Topic: topic,
Expand Down Expand Up @@ -144,7 +143,7 @@ func (app *App) BeginBlock(req abci.RequestBeginBlock) abci.ResponseBeginBlock {
// DeliverTx calls into the underlying DeliverTx and emits relevant events to Kafka.
func (app *App) DeliverTx(req abci.RequestDeliverTx) abci.ResponseDeliverTx {
res := app.BandApp.DeliverTx(req)
tx, err := app.TxDecoder(req.Tx)
tx, err := app.txDecoder(req.Tx)
if err != nil {
return res
}
Expand Down
6 changes: 6 additions & 0 deletions chain/emitter/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ type EvMap map[string][]string
// JsDict is a type alias for JSON dictionary.
type JsDict map[string]interface{}

// Message is a simple wrapper data type for each message published to Kafka.
type Message struct {
Key string
Value JsDict
}

// atoi converts the given string into an int64. Panics on errors.
func atoi(val string) int64 {
res, err := strconv.ParseInt(val, 10, 64)
Expand Down