cosmos-sdk/x/mock/app.go

237 lines
6.9 KiB
Go

package mock
import (
"math/rand"
"os"
bam "github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
)
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
Cdc *wire.Codec // Cdc is public since the codec is passed into the module anyways
KeyMain *sdk.KVStoreKey
KeyAccount *sdk.KVStoreKey
// TODO: Abstract this out from not needing to be auth specifically
AccountMapper auth.AccountMapper
FeeCollectionKeeper auth.FeeCollectionKeeper
GenesisAccounts []auth.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 := wire.NewCodec()
sdk.RegisterWire(cdc)
wire.RegisterCrypto(cdc)
auth.RegisterWire(cdc)
// Create your application object
app := &App{
BaseApp: bam.NewBaseApp("mock", cdc, logger, db),
Cdc: cdc,
KeyMain: sdk.NewKVStoreKey("main"),
KeyAccount: sdk.NewKVStoreKey("acc"),
TotalCoinsSupply: sdk.Coins{},
}
// Define the accountMapper
app.AccountMapper = auth.NewAccountMapper(
app.Cdc,
app.KeyAccount,
auth.ProtoBaseAccount,
)
// Initialize the app. The chainers and blockers can be overwritten before
// calling complete setup.
app.SetInitChainer(app.InitChainer)
app.SetAnteHandler(auth.NewAnteHandler(app.AccountMapper, app.FeeCollectionKeeper))
return app
}
// CompleteSetup completes the application setup after the routes have been
// registered.
func (app *App) CompleteSetup(newKeys []*sdk.KVStoreKey) error {
newKeys = append(newKeys, app.KeyMain)
newKeys = append(newKeys, app.KeyAccount)
app.MountStoresIAVL(newKeys...)
err := app.LoadLatestVersion(app.KeyMain)
return err
}
// InitChainer performs custom logic for initialization.
func (app *App) InitChainer(ctx sdk.Context, _ abci.RequestInitChain) abci.ResponseInitChain {
// Load the genesis accounts
for _, genacc := range app.GenesisAccounts {
acc := app.AccountMapper.NewAccountWithAddress(ctx, genacc.GetAddress())
acc.SetCoins(genacc.GetCoins())
app.AccountMapper.SetAccount(ctx, acc)
}
return abci.ResponseInitChain{}
}
// CreateGenAccounts generates genesis accounts loaded with coins, and returns
// their addresses, pubkeys, and privkeys.
func CreateGenAccounts(numAccs int, genCoins sdk.Coins) (genAccs []auth.Account, addrs []sdk.AccAddress, pubKeys []crypto.PubKey, privKeys []crypto.PrivKey) {
for i := 0; i < numAccs; i++ {
privKey := crypto.GenPrivKeyEd25519()
pubKey := privKey.PubKey()
addr := sdk.AccAddress(pubKey.Address())
genAcc := &auth.BaseAccount{
Address: addr,
Coins: genCoins,
}
genAccs = append(genAccs, genAcc)
privKeys = append(privKeys, privKey)
pubKeys = append(pubKeys, pubKey)
addrs = append(addrs, addr)
}
return
}
// SetGenesis sets the mock app genesis accounts.
func SetGenesis(app *App, accs []auth.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 []int64, seq []int64, priv ...crypto.PrivKey) auth.StdTx {
// Make the transaction free
fee := auth.StdFee{
Amount: sdk.Coins{sdk.NewCoin("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,
AccountNumber: accnums[i],
Sequence: seq[i],
}
}
return auth.NewStdTx(msgs, fee, sigs, memo)
}
// GeneratePrivKeys generates a total n Ed25519 private keys.
func GeneratePrivKeys(n int) (keys []crypto.PrivKey) {
// TODO: Randomize this between ed25519 and secp256k1
keys = make([]crypto.PrivKey, n, n)
for i := 0; i < n; i++ {
keys[i] = crypto.GenPrivKeyEd25519()
}
return
}
// GeneratePrivKeyAddressPairs generates a total of n private key, address
// pairs.
func GeneratePrivKeyAddressPairs(n int) (keys []crypto.PrivKey, addrs []sdk.AccAddress) {
keys = make([]crypto.PrivKey, n, n)
addrs = make([]sdk.AccAddress, n, n)
for i := 0; i < n; i++ {
keys[i] = crypto.GenPrivKeyEd25519()
addrs[i] = sdk.AccAddress(keys[i].PubKey().Address())
}
return
}
// RandomSetGenesis set genesis accounts with random coin values using the
// provided addresses and coin denominations.
func RandomSetGenesis(r *rand.Rand, app *App, addrs []sdk.AccAddress, denoms []string) {
accts := make([]auth.Account, len(addrs), 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), 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.Plus(coins)
baseAcc := auth.NewBaseAccountWithAddress(addrs[i])
(&baseAcc).SetCoins(coins)
accts[i] = &baseAcc
}
app.GenesisAccounts = accts
}
// GetAllAccounts returns all accounts in the accountMapper.
func GetAllAccounts(mapper auth.AccountMapper, ctx sdk.Context) []auth.Account {
accounts := []auth.Account{}
appendAccount := func(acc auth.Account) (stop bool) {
accounts = append(accounts, acc)
return false
}
mapper.IterateAccounts(ctx, appendAccount)
return accounts
}
// GenSequenceOfTxs generates a set of signed transactions of messages, such
// that they differ only by having the sequence numbers incremented between
// every transaction.
func GenSequenceOfTxs(msgs []sdk.Msg, accnums []int64, initSeqNums []int64, numToGenerate int, priv ...crypto.PrivKey) []auth.StdTx {
txs := make([]auth.StdTx, numToGenerate, numToGenerate)
for i := 0; i < numToGenerate; i++ {
txs[i] = GenTx(msgs, accnums, initSeqNums, priv...)
incrementAllSequenceNumbers(initSeqNums)
}
return txs
}
func incrementAllSequenceNumbers(initSeqNums []int64) {
for i := 0; i < len(initSeqNums); i++ {
initSeqNums[i]++
}
}