cosmos-sdk/x/mock/app.go

320 lines
8.7 KiB
Go
Raw Normal View History

package mock
import (
"bytes"
"fmt"
"math/rand"
"os"
"sort"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/ed25519"
"github.com/tendermint/tendermint/crypto/secp256k1"
"github.com/tendermint/tendermint/libs/log"
dbm "github.com/tendermint/tm-db"
2018-12-10 06:27:25 -08:00
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/x/auth"
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
2018-12-20 11:09:43 -08:00
"github.com/cosmos/cosmos-sdk/x/params"
)
const chainID = ""
// App extends an ABCI application, but with most of its parameters exported.
// They are exported for convenience in creating helper functions, as object
// capabilities aren't needed for testing.
type App struct {
*bam.BaseApp
2019-06-28 13:11:27 -07:00
Cdc *codec.Codec // Cdc is public since the codec is passed into the module anyways
KeyMain *sdk.KVStoreKey
KeyAccount *sdk.KVStoreKey
KeyParams *sdk.KVStoreKey
TKeyParams *sdk.TransientStoreKey
// TODO: Abstract this out from not needing to be auth specifically
2019-06-28 13:11:27 -07:00
AccountKeeper auth.AccountKeeper
ParamsKeeper params.Keeper
GenesisAccounts []authexported.Account
TotalCoinsSupply sdk.Coins
}
// NewApp partially constructs a new app on the memstore for module and genesis
// testing.
func NewApp() *App {
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app")
db := dbm.NewMemDB()
// Create the cdc with some standard codecs
cdc := createCodec()
// Create your application object
app := &App{
2018-07-18 16:24:16 -07:00
BaseApp: bam.NewBaseApp("mock", logger, db, auth.DefaultTxDecoder(cdc)),
Cdc: cdc,
KeyMain: sdk.NewKVStoreKey(bam.MainStoreKey),
KeyAccount: sdk.NewKVStoreKey(auth.StoreKey),
2018-12-20 11:09:43 -08:00
KeyParams: sdk.NewKVStoreKey("params"),
TKeyParams: sdk.NewTransientStoreKey("transient_params"),
2019-03-07 16:55:08 -08:00
TotalCoinsSupply: sdk.NewCoins(),
}
2019-06-28 13:11:27 -07:00
// define keepers
Merge PR #4206: Param Change Proposal * Add params error types * Update param module keeper to take a codespace * Update imports * Implement SetRaw and SetRawWithSubkey * Implement ParamChange and update aliases * Add types codec * Implement ParameterChangeProposal * Implement TestParameterChangeProposal * Fix linting errors * Update tags * Implement content * Updata params aliases * Finish params handler and proposal types * Move deposit and vote logic to types package * Move proposal type to types package * Move errors to types package * Update proposal * Move gov messages to types package * Minor updates to naming * Move keys to types package * Move codec to types package * Move proposal types to types package * Update aliases * Add governance alias types * Implement governance router * Update gov aliases * Update gov keeper * Update private functions needed for the keeper * Update godocs * Update the gov message handler * Update Gaia app * Make updates to auth * Update the message codec in the keeper * Update gov end blocker * Update types tests * Minor tweaks * Add legacy genesis logic * Update gov aliases * Move gov keys to types package * Revertt to using gov/types in params * Implement params handler test * Update governance tests * Fix endblocker tests * Fix governance querier tests * Add seal support to gov router * Update simulationCreateMsgSubmitProposal * Disable software upgrade proposals * Move params keys to types package * Implement param module proposal client logic * Update gov client logic * Update gaia app client hooks * Fix linting errors * Fix ValidateBasic * Remove legacy files * Update paramchange to use strings * Update paramchange cli cmd * Update ValidateBasic and errors * Use PostCommands when adding child cmds * Fix codec logic * Update params client and handler * Update IsValidProposalType * Update SubmitProposal to test exec * Implement TestGaiaCLISubmitParamChangeProposal * Implement TestSubmitParamChangeProposal * Update swagger.yaml * Update gaiacli.md * Update gov spec docs * Fix linting errors * Fix unit tests * Add pending log entries * Update docs * Update docs * Update client/lcd/swagger-ui/swagger.yaml Co-Authored-By: alexanderbez <alexanderbez@users.noreply.github.com> * Update docs/cosmos-hub/gaiacli.md Co-Authored-By: alexanderbez <alexanderbez@users.noreply.github.com> * Update cmd/gaia/cli_test/test_helpers.go Co-Authored-By: alexanderbez <alexanderbez@users.noreply.github.com> * Update client/lcd/test_helpers.go Co-Authored-By: alexanderbez <alexanderbez@users.noreply.github.com> * Update docs/cosmos-hub/gaiacli.md Co-Authored-By: alexanderbez <alexanderbez@users.noreply.github.com> * Update docs/cosmos-hub/gaiacli.md Co-Authored-By: alexanderbez <alexanderbez@users.noreply.github.com> * Update docs/cosmos-hub/gaiacli.md Co-Authored-By: alexanderbez <alexanderbez@users.noreply.github.com> * Update x/gov/types/proposal.go Co-Authored-By: alexanderbez <alexanderbez@users.noreply.github.com> * Update docs/cosmos-hub/gaiacli.md Co-Authored-By: alexanderbez <alexanderbez@users.noreply.github.com> * Update docs/cosmos-hub/gaiacli.md Co-Authored-By: alexanderbez <alexanderbez@users.noreply.github.com> * Address PR comments * Update docs/cosmos-hub/gaiacli.md Co-Authored-By: alexanderbez <alexanderbez@users.noreply.github.com> * Update gov docs to include quorum notes * Add logs to handleParameterChangeProposal * Update docs/spec/governance/02_state.md Co-Authored-By: alexanderbez <alexanderbez@users.noreply.github.com> * Support and use new StatusFailed when proposal passes but fails exec * Add docs/notes warning on param validity * Update docs * Update docs/spec/governance/02_state.md Co-Authored-By: alexanderbez <alexanderbez@users.noreply.github.com> * Update docs/spec/governance/02_state.md Co-Authored-By: alexanderbez <alexanderbez@users.noreply.github.com> * Minor doc update * Update x/gov/client/cli/tx.go Co-Authored-By: alexanderbez <alexanderbez@users.noreply.github.com> * Fix usage of fromAddr * Rige code style suggestion * Update x/params/types/proposal.go Co-Authored-By: alexanderbez <alexanderbez@users.noreply.github.com> * Fix CI lint errors * Update NewModuleClient godoc * Add godoc to rtr.Seal() call * Rename files * Rename NewProposalHandler
2019-04-30 09:31:38 -07:00
app.ParamsKeeper = params.NewKeeper(app.Cdc, app.KeyParams, app.TKeyParams, params.DefaultCodespace)
2018-12-20 11:09:43 -08:00
app.AccountKeeper = auth.NewAccountKeeper(
app.Cdc,
app.KeyAccount,
2018-12-20 11:09:43 -08:00
app.ParamsKeeper.Subspace(auth.DefaultParamspace),
auth.ProtoBaseAccount,
)
2019-06-28 13:11:27 -07:00
2019-08-15 08:19:16 -07:00
supplyKeeper := NewDummySupplyKeeper(app.AccountKeeper)
// Initialize the app. The chainers and blockers can be overwritten before
// calling complete setup.
app.SetInitChainer(app.InitChainer)
2019-06-28 13:11:27 -07:00
app.SetAnteHandler(auth.NewAnteHandler(app.AccountKeeper, supplyKeeper, auth.DefaultSigVerificationGasConsumer))
// Not sealing for custom extension
return app
}
// CompleteSetup completes the application setup after the routes have been
// registered.
func (app *App) CompleteSetup(newKeys ...sdk.StoreKey) error {
2018-12-20 11:09:43 -08:00
newKeys = append(
newKeys,
2019-06-28 13:11:27 -07:00
app.KeyMain, app.KeyAccount, app.KeyParams, app.TKeyParams,
2018-12-20 11:09:43 -08:00
)
for _, key := range newKeys {
switch key.(type) {
case *sdk.KVStoreKey:
app.MountStore(key, sdk.StoreTypeIAVL)
case *sdk.TransientStoreKey:
app.MountStore(key, sdk.StoreTypeTransient)
default:
return fmt.Errorf("unsupported StoreKey: %+v", key)
}
}
err := app.LoadLatestVersion(app.KeyMain)
return err
}
// InitChainer performs custom logic for initialization.
2018-08-31 15:22:37 -07:00
// nolint: errcheck
func (app *App) InitChainer(ctx sdk.Context, _ abci.RequestInitChain) abci.ResponseInitChain {
2019-06-28 13:11:27 -07:00
// Load the genesis accounts
for _, genacc := range app.GenesisAccounts {
acc := app.AccountKeeper.NewAccountWithAddress(ctx, genacc.GetAddress())
acc.SetCoins(genacc.GetCoins())
app.AccountKeeper.SetAccount(ctx, acc)
}
2019-06-28 13:11:27 -07:00
auth.InitGenesis(ctx, app.AccountKeeper, auth.DefaultGenesisState())
2018-12-20 11:09:43 -08:00
return abci.ResponseInitChain{}
}
// Type that combines an Address with the privKey and pubKey to that address
type AddrKeys struct {
Address sdk.AccAddress
PubKey crypto.PubKey
PrivKey crypto.PrivKey
}
func NewAddrKeys(address sdk.AccAddress, pubKey crypto.PubKey,
privKey crypto.PrivKey) AddrKeys {
return AddrKeys{
Address: address,
PubKey: pubKey,
PrivKey: privKey,
}
}
// implement `Interface` in sort package.
type AddrKeysSlice []AddrKeys
func (b AddrKeysSlice) Len() int {
return len(b)
}
// Sorts lexographically by Address
func (b AddrKeysSlice) Less(i, j int) bool {
// bytes package already implements Comparable for []byte.
switch bytes.Compare(b[i].Address.Bytes(), b[j].Address.Bytes()) {
case -1:
return true
case 0, 1:
return false
default:
panic("not fail-able with `bytes.Comparable` bounded [-1, 1].")
}
}
func (b AddrKeysSlice) Swap(i, j int) {
b[j], b[i] = b[i], b[j]
}
// CreateGenAccounts generates genesis accounts loaded with coins, and returns
// their addresses, pubkeys, and privkeys.
func CreateGenAccounts(numAccs int, genCoins sdk.Coins) (genAccs []authexported.Account,
addrs []sdk.AccAddress, pubKeys []crypto.PubKey, privKeys []crypto.PrivKey) {
addrKeysSlice := AddrKeysSlice{}
for i := 0; i < numAccs; i++ {
privKey := secp256k1.GenPrivKey()
pubKey := privKey.PubKey()
2018-07-09 01:47:38 -07:00
addr := sdk.AccAddress(pubKey.Address())
addrKeysSlice = append(addrKeysSlice, NewAddrKeys(addr, pubKey, privKey))
}
sort.Sort(addrKeysSlice)
for i := range addrKeysSlice {
addrs = append(addrs, addrKeysSlice[i].Address)
pubKeys = append(pubKeys, addrKeysSlice[i].PubKey)
privKeys = append(privKeys, addrKeysSlice[i].PrivKey)
genAccs = append(genAccs, &auth.BaseAccount{
Address: addrKeysSlice[i].Address,
Coins: genCoins,
})
}
return
}
// SetGenesis sets the mock app genesis accounts.
func SetGenesis(app *App, accs []authexported.Account) {
// Pass the accounts in via the application (lazy) instead of through
// RequestInitChain.
app.GenesisAccounts = accs
app.InitChain(abci.RequestInitChain{})
app.Commit()
}
// GenTx generates a signed mock transaction.
func GenTx(msgs []sdk.Msg, accnums []uint64, seq []uint64, priv ...crypto.PrivKey) auth.StdTx {
// Make the transaction free
fee := auth.StdFee{
2019-03-07 16:55:08 -08:00
Amount: sdk.NewCoins(sdk.NewInt64Coin("foocoin", 0)),
Gas: 100000,
}
sigs := make([]auth.StdSignature, len(priv))
memo := "testmemotestmemo"
for i, p := range priv {
sig, err := p.Sign(auth.StdSignBytes(chainID, accnums[i], seq[i], fee, msgs, memo))
if err != nil {
panic(err)
}
sigs[i] = auth.StdSignature{
PubKey: p.PubKey(),
Signature: sig,
}
}
return auth.NewStdTx(msgs, fee, sigs, memo)
}
// GeneratePrivKeys generates a total n secp256k1 private keys.
func GeneratePrivKeys(n int) (keys []crypto.PrivKey) {
// TODO: Randomize this between ed25519 and secp256k1
keys = make([]crypto.PrivKey, n)
for i := 0; i < n; i++ {
keys[i] = secp256k1.GenPrivKey()
}
return
}
// GeneratePrivKeyAddressPairs generates a total of n private key, address
// pairs.
2018-07-09 01:47:38 -07:00
func GeneratePrivKeyAddressPairs(n int) (keys []crypto.PrivKey, addrs []sdk.AccAddress) {
keys = make([]crypto.PrivKey, n)
addrs = make([]sdk.AccAddress, n)
for i := 0; i < n; i++ {
if rand.Int63()%2 == 0 {
keys[i] = secp256k1.GenPrivKey()
} else {
keys[i] = ed25519.GenPrivKey()
}
addrs[i] = sdk.AccAddress(keys[i].PubKey().Address())
}
return
}
// GeneratePrivKeyAddressPairsFromRand generates a total of n private key, address
// pairs using the provided randomness source.
func GeneratePrivKeyAddressPairsFromRand(rand *rand.Rand, n int) (keys []crypto.PrivKey, addrs []sdk.AccAddress) {
keys = make([]crypto.PrivKey, n)
addrs = make([]sdk.AccAddress, n)
for i := 0; i < n; i++ {
secret := make([]byte, 32)
_, err := rand.Read(secret)
if err != nil {
panic("Could not read randomness")
}
if rand.Int63()%2 == 0 {
keys[i] = secp256k1.GenPrivKeySecp256k1(secret)
} else {
keys[i] = ed25519.GenPrivKeyFromSecret(secret)
}
2018-07-09 01:47:38 -07:00
addrs[i] = sdk.AccAddress(keys[i].PubKey().Address())
}
return
}
// RandomSetGenesis set genesis accounts with random coin values using the
// provided addresses and coin denominations.
2018-08-31 15:22:37 -07:00
// nolint: errcheck
2018-07-09 01:47:38 -07:00
func RandomSetGenesis(r *rand.Rand, app *App, addrs []sdk.AccAddress, denoms []string) {
accts := make([]authexported.Account, len(addrs))
randCoinIntervals := []BigInterval{
{sdk.NewIntWithDecimal(1, 0), sdk.NewIntWithDecimal(1, 1)},
{sdk.NewIntWithDecimal(1, 2), sdk.NewIntWithDecimal(1, 3)},
{sdk.NewIntWithDecimal(1, 40), sdk.NewIntWithDecimal(1, 50)},
}
for i := 0; i < len(accts); i++ {
coins := make([]sdk.Coin, len(denoms))
// generate a random coin for each denomination
for j := 0; j < len(denoms); j++ {
coins[j] = sdk.Coin{Denom: denoms[j],
Amount: RandFromBigInterval(r, randCoinIntervals),
}
}
app.TotalCoinsSupply = app.TotalCoinsSupply.Add(coins)
baseAcc := auth.NewBaseAccountWithAddress(addrs[i])
(&baseAcc).SetCoins(coins)
accts[i] = &baseAcc
}
2018-07-10 11:46:28 -07:00
app.GenesisAccounts = accts
}
func createCodec() *codec.Codec {
cdc := codec.New()
sdk.RegisterCodec(cdc)
codec.RegisterCrypto(cdc)
auth.RegisterCodec(cdc)
return cdc
}