Update Ethermint app/ Daemon to run functional TM node (#70)

* Updates eithermint app to new Cosmos SDK version and sets up base tendermint node commands

* Updated vague comment
This commit is contained in:
Austin Abell 2019-07-12 13:13:15 -04:00 committed by GitHub
parent 9803c1b80e
commit fbaa9466b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 209 additions and 134 deletions

View File

@ -1,22 +1,25 @@
package app
import (
"encoding/json"
"os"
"github.com/cosmos/ethermint/x/evm"
bam "github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/codec"
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/bank"
"github.com/cosmos/cosmos-sdk/x/crisis"
distr "github.com/cosmos/cosmos-sdk/x/distribution"
distrclient "github.com/cosmos/cosmos-sdk/x/distribution/client"
"github.com/cosmos/cosmos-sdk/x/genaccounts"
"github.com/cosmos/cosmos-sdk/x/genutil"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/mint"
"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"
@ -24,17 +27,14 @@ import (
"github.com/cosmos/ethermint/crypto"
evmtypes "github.com/cosmos/ethermint/x/evm/types"
"github.com/pkg/errors"
abci "github.com/tendermint/tendermint/abci/types"
tmcmn "github.com/tendermint/tendermint/libs/common"
dbm "github.com/tendermint/tendermint/libs/db"
tmlog "github.com/tendermint/tendermint/libs/log"
tmtypes "github.com/tendermint/tendermint/types"
)
const appName = "Ethermint"
// application multi-store keys
var (
// default home directories for the application CLI
DefaultCLIHome = os.ExpandEnv("$HOME/.emintcli")
@ -42,33 +42,32 @@ var (
// DefaultNodeHome sets the folder where the applcation data and configuration will be stored
DefaultNodeHome = os.ExpandEnv("$HOME/.emintd")
// ModuleBasics is in charge of setting up basic module elements
// The module BasicManager is in charge of setting up basic,
// non-dependant module elements, such as codec registration
// and genesis verification.
ModuleBasics = module.NewBasicManager(
genaccounts.AppModuleBasic{},
genutil.AppModuleBasic{},
auth.AppModuleBasic{},
bank.AppModuleBasic{},
params.AppModuleBasic{},
evm.AppModuleBasic{},
staking.AppModuleBasic{},
mint.AppModuleBasic{},
distr.AppModuleBasic{},
gov.NewAppModuleBasic(paramsclient.ProposalHandler, distrclient.ProposalHandler),
params.AppModuleBasic{},
crisis.AppModuleBasic{},
slashing.AppModuleBasic{},
supply.AppModuleBasic{},
)
storeKeyAccount = sdk.NewKVStoreKey("acc")
storeKeyStorage = sdk.NewKVStoreKey("contract_storage")
storeKeyMain = sdk.NewKVStoreKey("main")
storeKeyStake = sdk.NewKVStoreKey("stake")
storeKeySlashing = sdk.NewKVStoreKey("slashing")
storeKeyGov = sdk.NewKVStoreKey("gov")
storeKeySupply = sdk.NewKVStoreKey("supply")
storeKeyParams = sdk.NewKVStoreKey("params")
storeKeyTransParams = sdk.NewTransientStoreKey("transient_params")
)
// MakeCodec generates the necessary codecs for Amino
func MakeCodec() *codec.Codec {
var cdc = codec.New()
// TODO: Move this codec to module (Issue #12 https://github.com/ChainSafe/ethermint/issues/12)
crypto.RegisterCodec(cdc)
ModuleBasics.RegisterCodec(cdc)
sdk.RegisterCodec(cdc)
codec.RegisterCrypto(cdc)
@ -80,26 +79,40 @@ func MakeCodec() *codec.Codec {
// Tendermint consensus.
type EthermintApp struct {
*bam.BaseApp
cdc *codec.Codec
accountKey *sdk.KVStoreKey
storageKey *sdk.KVStoreKey
mainKey *sdk.KVStoreKey
stakeKey *sdk.KVStoreKey
slashingKey *sdk.KVStoreKey
govKey *sdk.KVStoreKey
supplyKey *sdk.KVStoreKey
paramsKey *sdk.KVStoreKey
tParamsKey *sdk.TransientStoreKey
invCheckPeriod uint
// keys to access the substores
keyMain *sdk.KVStoreKey
keyAccount *sdk.KVStoreKey
keySupply *sdk.KVStoreKey
keyStaking *sdk.KVStoreKey
tkeyStaking *sdk.TransientStoreKey
keySlashing *sdk.KVStoreKey
keyMint *sdk.KVStoreKey
keyDistr *sdk.KVStoreKey
tkeyDistr *sdk.TransientStoreKey
keyGov *sdk.KVStoreKey
keyParams *sdk.KVStoreKey
tkeyParams *sdk.TransientStoreKey
// TODO: Add evm module key
// keepers
accountKeeper auth.AccountKeeper
supplyKeeper supply.Keeper
bankKeeper bank.Keeper
stakeKeeper staking.Keeper
supplyKeeper supply.Keeper
stakingKeeper staking.Keeper
slashingKeeper slashing.Keeper
mintKeeper mint.Keeper
distrKeeper distr.Keeper
govKeeper gov.Keeper
crisisKeeper crisis.Keeper
paramsKeeper params.Keeper
// TODO: Include evm Keeper
// the module manager
mm *module.Manager
}
// NewEthermintApp returns a reference to a new initialized Ethermint
@ -108,28 +121,42 @@ type EthermintApp struct {
// TODO: Ethermint needs to support being bootstrapped as an application running
// in a sovereign zone and as an application running with a shared security model.
// For now, it will support only running as a sovereign application.
func NewEthermintApp(logger tmlog.Logger, db dbm.DB, baseAppOpts ...func(*bam.BaseApp)) *EthermintApp {
cdc := CreateCodec()
func NewEthermintApp(logger tmlog.Logger, db dbm.DB, loadLatest bool,
invCheckPeriod uint, baseAppOptions ...func(*bam.BaseApp)) *EthermintApp {
cdc := MakeCodec()
baseApp := bam.NewBaseApp(appName, logger, db, evmtypes.TxDecoder(cdc), baseAppOpts...)
app := &EthermintApp{
BaseApp: baseApp,
cdc: cdc,
accountKey: storeKeyAccount,
storageKey: storeKeyStorage,
mainKey: storeKeyMain,
stakeKey: storeKeyStake,
slashingKey: storeKeySlashing,
govKey: storeKeyGov,
supplyKey: storeKeySupply,
paramsKey: storeKeyParams,
tParamsKey: storeKeyTransParams,
baseApp := bam.NewBaseApp(appName, logger, db, evmtypes.TxDecoder(cdc), baseAppOptions...)
baseApp.SetAppVersion(version.Version)
var app = &EthermintApp{
BaseApp: baseApp,
cdc: cdc,
invCheckPeriod: invCheckPeriod,
keyMain: sdk.NewKVStoreKey(bam.MainStoreKey),
keyAccount: sdk.NewKVStoreKey(auth.StoreKey),
keyStaking: sdk.NewKVStoreKey(staking.StoreKey),
keySupply: sdk.NewKVStoreKey(supply.StoreKey),
tkeyStaking: sdk.NewTransientStoreKey(staking.TStoreKey),
keyMint: sdk.NewKVStoreKey(mint.StoreKey),
keyDistr: sdk.NewKVStoreKey(distr.StoreKey),
tkeyDistr: sdk.NewTransientStoreKey(distr.TStoreKey),
keySlashing: sdk.NewKVStoreKey(slashing.StoreKey),
keyGov: sdk.NewKVStoreKey(gov.StoreKey),
keyParams: sdk.NewKVStoreKey(params.StoreKey),
tkeyParams: sdk.NewTransientStoreKey(params.TStoreKey),
// TODO: Initialize evm module key
}
// Set params keeper and subspaces
app.paramsKeeper = params.NewKeeper(app.cdc, app.paramsKey, app.tParamsKey, params.DefaultCodespace)
// init params keeper and subspaces
app.paramsKeeper = params.NewKeeper(app.cdc, app.keyParams, app.tkeyParams, params.DefaultCodespace)
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)
govSubspace := app.paramsKeeper.Subspace(gov.DefaultParamspace)
crisisSubspace := app.paramsKeeper.Subspace(crisis.DefaultParamspace)
// account permissions
maccPerms := map[string][]string{
@ -141,88 +168,127 @@ func NewEthermintApp(logger tmlog.Logger, db dbm.DB, baseAppOpts ...func(*bam.Ba
gov.ModuleName: []string{supply.Burner},
}
// Add keepers
app.accountKeeper = auth.NewAccountKeeper(app.cdc, app.accountKey, authSubspace, auth.ProtoBaseAccount)
// add keepers
app.accountKeeper = auth.NewAccountKeeper(app.cdc, app.keyAccount, authSubspace, auth.ProtoBaseAccount)
app.bankKeeper = bank.NewBaseKeeper(app.accountKeeper, bankSubspace, bank.DefaultCodespace)
app.supplyKeeper = supply.NewKeeper(cdc, app.supplyKey, app.accountKeeper, app.bankKeeper, supply.DefaultCodespace, maccPerms)
app.supplyKeeper = supply.NewKeeper(app.cdc, app.keySupply, app.accountKeeper, app.bankKeeper, supply.DefaultCodespace, maccPerms)
stakingKeeper := staking.NewKeeper(app.cdc, app.keyStaking, app.tkeyStaking,
app.supplyKeeper, stakingSubspace, staking.DefaultCodespace)
app.mintKeeper = mint.NewKeeper(app.cdc, app.keyMint, mintSubspace, &stakingKeeper, app.supplyKeeper, auth.FeeCollectorName)
app.distrKeeper = distr.NewKeeper(app.cdc, app.keyDistr, distrSubspace, &stakingKeeper,
app.supplyKeeper, distr.DefaultCodespace, auth.FeeCollectorName)
app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, &stakingKeeper,
slashingSubspace, slashing.DefaultCodespace)
app.crisisKeeper = crisis.NewKeeper(crisisSubspace, invCheckPeriod, app.supplyKeeper, auth.FeeCollectorName)
// TODO: Instantiate evm Keeper
// register message handlers
app.Router().
// TODO: add remaining routes
AddRoute("stake", staking.NewHandler(app.stakeKeeper)).
AddRoute("slashing", slashing.NewHandler(app.slashingKeeper)).
AddRoute("gov", gov.NewHandler(app.govKeeper))
// 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))
app.govKeeper = gov.NewKeeper(app.cdc, app.keyGov, app.paramsKeeper, govSubspace,
app.supplyKeeper, &stakingKeeper, gov.DefaultCodespace, govRouter)
// initialize the underlying ABCI BaseApp
app.SetInitChainer(app.initChainer)
app.SetBeginBlocker(app.BeginBlocker)
app.SetEndBlocker(app.EndBlocker)
app.SetAnteHandler(NewAnteHandler(app.accountKeeper, app.supplyKeeper))
// 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()))
app.MountStores(
app.mainKey, app.accountKey, app.stakeKey, app.slashingKey,
app.govKey, app.supplyKey, app.paramsKey, app.storageKey,
app.mm = module.NewManager(
genaccounts.NewAppModule(app.accountKeeper),
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),
distr.NewAppModule(app.distrKeeper, app.supplyKeeper),
gov.NewAppModule(app.govKeeper, app.supplyKeeper),
mint.NewAppModule(app.mintKeeper),
slashing.NewAppModule(app.slashingKeeper, app.stakingKeeper),
staking.NewAppModule(app.stakingKeeper, app.distrKeeper, app.accountKeeper, app.supplyKeeper),
)
app.MountStore(app.tParamsKey, sdk.StoreTypeTransient)
if err := app.LoadLatestVersion(app.accountKey); err != nil {
tmcmn.Exit(err.Error())
// 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(mint.ModuleName, distr.ModuleName, slashing.ModuleName)
app.mm.SetOrderEndBlockers(gov.ModuleName, staking.ModuleName)
// genutils must occur after staking so that pools are properly
// initialized with tokens from genesis accounts.
app.mm.SetOrderInitGenesis(genaccounts.ModuleName, supply.ModuleName, distr.ModuleName,
staking.ModuleName, auth.ModuleName, bank.ModuleName, slashing.ModuleName,
gov.ModuleName, mint.ModuleName, crisis.ModuleName, genutil.ModuleName)
app.mm.RegisterInvariants(&app.crisisKeeper)
app.mm.RegisterRoutes(app.Router(), app.QueryRouter())
// initialize stores
app.MountStores(app.keyMain, app.keyAccount, app.keySupply, app.keyStaking,
app.keyMint, app.keyDistr, app.keySlashing, app.keyGov, app.keyParams,
app.tkeyParams, app.tkeyStaking, app.tkeyDistr)
// initialize BaseApp
app.SetInitChainer(app.InitChainer)
app.SetBeginBlocker(app.BeginBlocker)
app.SetAnteHandler(auth.NewAnteHandler(app.accountKeeper, app.supplyKeeper, auth.DefaultSigVerificationGasConsumer))
app.SetEndBlocker(app.EndBlocker)
if loadLatest {
err := app.LoadLatestVersion(app.keyMain)
if err != nil {
panic(err)
}
}
app.BaseApp.Seal()
return app
}
// BeginBlocker signals the beginning of a block. It performs application
// updates on the start of every block.
func (app *EthermintApp) BeginBlocker(
_ sdk.Context, _ abci.RequestBeginBlock,
) abci.ResponseBeginBlock {
// The genesis state of the blockchain is represented here as a map of raw json
// messages key'd by a identifier string.
type GenesisState map[string]json.RawMessage
return abci.ResponseBeginBlock{}
// application updates every begin block
func (app *EthermintApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock {
return app.mm.BeginBlock(ctx, req)
}
// EndBlocker signals the end of a block. It performs application updates on
// the end of every block.
func (app *EthermintApp) EndBlocker(
_ sdk.Context, _ abci.RequestEndBlock,
) abci.ResponseEndBlock {
return abci.ResponseEndBlock{}
// application updates every end block
func (app *EthermintApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock {
return app.mm.EndBlock(ctx, req)
}
// initChainer initializes the application blockchain with validators and other
// state data from TendermintCore.
func (app *EthermintApp) initChainer(
_ sdk.Context, req abci.RequestInitChain,
) abci.ResponseInitChain {
// application update at chain initialization
func (app *EthermintApp) InitChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
var genesisState GenesisState
app.cdc.MustUnmarshalJSON(req.AppStateBytes, &genesisState)
return app.mm.InitGenesis(ctx, genesisState)
}
var genesisState evm.GenesisState
stateJSON := req.AppStateBytes
// load a particular height
func (app *EthermintApp) LoadHeight(height int64) error {
return app.LoadVersion(height, app.keyMain)
}
err := app.cdc.UnmarshalJSON(stateJSON, &genesisState)
// ExportAppStateAndValidators exports the state of the application for a genesis
// file.
func (app *EthermintApp) ExportAppStateAndValidators(forZeroHeight bool, jailWhiteList []string,
) (appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) {
// Creates context with current height and checks txs for ctx to be usable by start of next block
ctx := app.NewContext(true, abci.Header{Height: app.LastBlockHeight()})
// Export genesis to be used by SDK modules
genState := app.mm.ExportGenesis(ctx)
appState, err = codec.MarshalJSONIndent(app.cdc, genState)
if err != nil {
panic(errors.Wrap(err, "failed to parse application genesis state"))
return nil, nil, err
}
// TODO: load the genesis accounts
// Write validators to staking module to be used by TM node
validators = staking.WriteValidators(ctx, app.stakingKeeper)
return abci.ResponseInitChain{}
}
// CreateCodec creates a new amino wire codec and registers all the necessary
// concrete types and interfaces needed for the application.
func CreateCodec() *codec.Codec {
cdc := codec.New()
// TODO: Add remaining codec registrations:
// bank, staking, distribution, slashing, and gov
crypto.RegisterCodec(cdc)
evmtypes.RegisterCodec(cdc)
auth.RegisterCodec(cdc)
sdk.RegisterCodec(cdc)
codec.RegisterCrypto(cdc)
return cdc
return appState, validators, nil
}

View File

@ -47,7 +47,7 @@ func newTestSetup() testSetup {
// nolint:errcheck
ms.LoadLatestVersion()
cdc := CreateCodec()
cdc := MakeCodec()
cdc.RegisterConcrete(&sdk.TestMsg{}, "test/TestMsg", nil)
// Set params keeper and subspaces

View File

@ -1,6 +1,9 @@
package main
import (
"encoding/json"
"io"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/x/genaccounts"
genaccscli "github.com/cosmos/cosmos-sdk/x/genaccounts/client/cli"
@ -12,6 +15,11 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli"
emintapp "github.com/cosmos/ethermint/app"
abci "github.com/tendermint/tendermint/abci/types"
dbm "github.com/tendermint/tendermint/libs/db"
tmlog "github.com/tendermint/tendermint/libs/log"
tmtypes "github.com/tendermint/tendermint/types"
)
func main() {
@ -43,8 +51,8 @@ func main() {
genaccscli.AddGenesisAccountCmd(ctx, cdc, emintapp.DefaultNodeHome, emintapp.DefaultCLIHome),
)
// TODO: Add export app state and TM validators commands
// server.AddCommands(ctx, cdc, rootCmd, newApp, exportAppStateAndTMValidators)
// Tendermint node base commands
server.AddCommands(ctx, cdc, rootCmd, newApp, exportAppStateAndTMValidators)
// prepare and add flags
executor := cli.PrepareBaseCmd(rootCmd, "EM", emintapp.DefaultNodeHome)
@ -54,26 +62,24 @@ func main() {
}
}
// func newApp(logger log.Logger, db dbm.DB, traceStore io.Writer) abci.Application {
// return emintapp.NewEthermintApp(logger, db)
// }
func newApp(logger tmlog.Logger, db dbm.DB, traceStore io.Writer) abci.Application {
return emintapp.NewEthermintApp(logger, db, true, 0)
}
// func exportAppStateAndTMValidators(
// logger log.Logger, db dbm.DB, traceStore io.Writer, height int64, forZeroHeight bool, jailWhiteList []string,
// ) (json.RawMessage, []tmtypes.GenesisValidator, error) {
func exportAppStateAndTMValidators(
logger tmlog.Logger, db dbm.DB, traceStore io.Writer, height int64, forZeroHeight bool, jailWhiteList []string,
) (json.RawMessage, []tmtypes.GenesisValidator, error) {
// // if height != -1 {
// // emintApp := emintapp.NewEthermintApp(logger, db)
// // err := emintApp.LoadHeight(height)
// // if err != nil {
// // return nil, nil, err
// // }
// // return emintApp.ExportAppStateAndValidators(forZeroHeight, jailWhiteList)
// // }
if height != -1 {
emintApp := emintapp.NewEthermintApp(logger, db, true, 0)
err := emintApp.LoadHeight(height)
if err != nil {
return nil, nil, err
}
return emintApp.ExportAppStateAndValidators(forZeroHeight, jailWhiteList)
}
// // emintApp := emintapp.NewEthermintApp(logger, db)
emintApp := emintapp.NewEthermintApp(logger, db, true, 0)
// // return emintApp.ExportAppStateAndValidators(forZeroHeight, jailWhiteList)
// // TODO: Unstub method
// return json.RawMessage{}, []tmtypes.GenesisValidator{}, nil
// }
return emintApp.ExportAppStateAndValidators(forZeroHeight, jailWhiteList)
}

2
go.mod
View File

@ -7,7 +7,7 @@ require (
github.com/aristanetworks/goarista v0.0.0-20181101003910-5bb443fba8e0 // indirect
github.com/btcsuite/btcd v0.0.0-20190629003639-c26ffa870fd8 // indirect
github.com/cespare/cp v1.1.1 // indirect
github.com/cosmos/cosmos-sdk v0.28.2-0.20190709220430-3f519832a7a5
github.com/cosmos/cosmos-sdk v0.28.2-0.20190711105643-280734d0e37f
github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d // indirect
github.com/deckarep/golang-set v1.7.1 // indirect
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712 // indirect

3
go.sum
View File

@ -45,6 +45,9 @@ github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8Nz
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/cosmos/cosmos-sdk v0.28.2-0.20190709220430-3f519832a7a5 h1:gakqjbZrqlUB1/rx8r/s86SVcRatOafVDfJF99yBcng=
github.com/cosmos/cosmos-sdk v0.28.2-0.20190709220430-3f519832a7a5/go.mod h1:qzvnGkt2+ynMpjmf9/dws/94/qM87awRbuyvF7r2R8Q=
github.com/cosmos/cosmos-sdk v0.28.2-0.20190711105643-280734d0e37f h1:jmVM19bsHZRVVe8rugzfILuL3VPgCj5b6941I20Naw0=
github.com/cosmos/cosmos-sdk v0.28.2-0.20190711105643-280734d0e37f/go.mod h1:qzvnGkt2+ynMpjmf9/dws/94/qM87awRbuyvF7r2R8Q=
github.com/cosmos/cosmos-sdk v0.35.0 h1:EPeie1aKHwnXtTzKggvabG7aAPN+DDmju2xquvjFwao=
github.com/cosmos/go-bip39 v0.0.0-20180618194314-52158e4697b8 h1:Iwin12wRQtyZhH6FV3ykFcdGNlYEzoeR0jN8Vn+JWsI=
github.com/cosmos/go-bip39 v0.0.0-20180618194314-52158e4697b8/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y=
github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d h1:49RLWk1j44Xu4fjHb6JFYmeUnDORVwHNkDxaQ0ctCVU=