github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/x/mock/app.go (about)

     1  package mock
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"math/rand"
     7  	"os"
     8  	"sort"
     9  
    10  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec/types"
    11  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/mpt"
    12  
    13  	abci "github.com/fibonacci-chain/fbc/libs/tendermint/abci/types"
    14  	"github.com/fibonacci-chain/fbc/libs/tendermint/crypto"
    15  	"github.com/fibonacci-chain/fbc/libs/tendermint/crypto/ed25519"
    16  	"github.com/fibonacci-chain/fbc/libs/tendermint/crypto/secp256k1"
    17  	"github.com/fibonacci-chain/fbc/libs/tendermint/libs/log"
    18  	dbm "github.com/fibonacci-chain/fbc/libs/tm-db"
    19  
    20  	bam "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/baseapp"
    21  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec"
    22  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
    23  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth"
    24  	authexported "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth/exported"
    25  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/params"
    26  )
    27  
    28  const chainID = ""
    29  
    30  // App extends an ABCI application, but with most of its parameters exported.
    31  // They are exported for convenience in creating helper functions, as object
    32  // capabilities aren't needed for testing.
    33  type App struct {
    34  	*bam.BaseApp
    35  	Cdc        *codec.CodecProxy // Cdc is public since the codec is passed into the module anyways
    36  	KeyMain    *sdk.KVStoreKey
    37  	KeyAccount *sdk.KVStoreKey
    38  	KeyAccMpt  *sdk.KVStoreKey
    39  	KeyParams  *sdk.KVStoreKey
    40  	TKeyParams *sdk.TransientStoreKey
    41  
    42  	// TODO: Abstract this out from not needing to be auth specifically
    43  	AccountKeeper auth.AccountKeeper
    44  	ParamsKeeper  params.Keeper
    45  
    46  	GenesisAccounts  []authexported.Account
    47  	TotalCoinsSupply sdk.Coins
    48  }
    49  
    50  // NewApp partially constructs a new app on the memstore for module and genesis
    51  // testing.
    52  func NewApp() *App {
    53  	logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app")
    54  	db := dbm.NewMemDB()
    55  
    56  	// Create the cdc with some standard codecs
    57  	cdcP := createCodec()
    58  	cdc := cdcP.GetCdc()
    59  
    60  	// Create your application object
    61  	app := &App{
    62  		BaseApp:          bam.NewBaseApp("mock", logger, db, auth.DefaultTxDecoder(cdc)),
    63  		Cdc:              cdcP,
    64  		KeyMain:          sdk.NewKVStoreKey(bam.MainStoreKey),
    65  		KeyAccount:       sdk.NewKVStoreKey(auth.StoreKey),
    66  		KeyAccMpt:        sdk.NewKVStoreKey(mpt.StoreKey),
    67  		KeyParams:        sdk.NewKVStoreKey("params"),
    68  		TKeyParams:       sdk.NewTransientStoreKey("transient_params"),
    69  		TotalCoinsSupply: sdk.NewCoins(),
    70  	}
    71  
    72  	// define keepers
    73  	app.ParamsKeeper = params.NewKeeper(app.Cdc.GetCdc(), app.KeyParams, app.TKeyParams)
    74  
    75  	app.AccountKeeper = auth.NewAccountKeeper(
    76  		app.Cdc.GetCdc(),
    77  		app.KeyAccount,
    78  		app.KeyAccMpt,
    79  		app.ParamsKeeper.Subspace(auth.DefaultParamspace),
    80  		auth.ProtoBaseAccount,
    81  	)
    82  
    83  	supplyKeeper := NewDummySupplyKeeper(app.AccountKeeper)
    84  
    85  	// Initialize the app. The chainers and blockers can be overwritten before
    86  	// calling complete setup.
    87  	app.SetInitChainer(app.InitChainer)
    88  	app.SetAnteHandler(auth.NewAnteHandler(app.AccountKeeper, supplyKeeper, auth.DefaultSigVerificationGasConsumer))
    89  
    90  	// Not sealing for custom extension
    91  
    92  	return app
    93  }
    94  
    95  // CompleteSetup completes the application setup after the routes have been
    96  // registered.
    97  func (app *App) CompleteSetup(newKeys ...sdk.StoreKey) error {
    98  	newKeys = append(
    99  		newKeys,
   100  		app.KeyMain, app.KeyAccount, app.KeyParams, app.TKeyParams,
   101  	)
   102  
   103  	for _, key := range newKeys {
   104  		switch key.(type) {
   105  		case *sdk.KVStoreKey:
   106  			if key.Name() == mpt.StoreKey {
   107  				app.MountStore(key, sdk.StoreTypeMPT)
   108  			} else {
   109  				app.MountStore(key, sdk.StoreTypeIAVL)
   110  			}
   111  		case *sdk.TransientStoreKey:
   112  			app.MountStore(key, sdk.StoreTypeTransient)
   113  		default:
   114  			return fmt.Errorf("unsupported StoreKey: %+v", key)
   115  		}
   116  	}
   117  
   118  	err := app.LoadLatestVersion(app.KeyMain)
   119  
   120  	return err
   121  }
   122  
   123  // InitChainer performs custom logic for initialization.
   124  func (app *App) InitChainer(ctx sdk.Context, _ abci.RequestInitChain) abci.ResponseInitChain {
   125  
   126  	// Load the genesis accounts
   127  	for _, genacc := range app.GenesisAccounts {
   128  		acc := app.AccountKeeper.NewAccountWithAddress(ctx, genacc.GetAddress())
   129  		acc.SetCoins(genacc.GetCoins())
   130  		app.AccountKeeper.SetAccount(ctx, acc)
   131  	}
   132  
   133  	auth.InitGenesis(ctx, app.AccountKeeper, auth.DefaultGenesisState())
   134  
   135  	return abci.ResponseInitChain{}
   136  }
   137  
   138  // Type that combines an Address with the privKey and pubKey to that address
   139  type AddrKeys struct {
   140  	Address sdk.AccAddress
   141  	PubKey  crypto.PubKey
   142  	PrivKey crypto.PrivKey
   143  }
   144  
   145  func NewAddrKeys(address sdk.AccAddress, pubKey crypto.PubKey,
   146  	privKey crypto.PrivKey) AddrKeys {
   147  
   148  	return AddrKeys{
   149  		Address: address,
   150  		PubKey:  pubKey,
   151  		PrivKey: privKey,
   152  	}
   153  }
   154  
   155  // implement `Interface` in sort package.
   156  type AddrKeysSlice []AddrKeys
   157  
   158  func (b AddrKeysSlice) Len() int {
   159  	return len(b)
   160  }
   161  
   162  // Sorts lexographically by Address
   163  func (b AddrKeysSlice) Less(i, j int) bool {
   164  	// bytes package already implements Comparable for []byte.
   165  	switch bytes.Compare(b[i].Address.Bytes(), b[j].Address.Bytes()) {
   166  	case -1:
   167  		return true
   168  	case 0, 1:
   169  		return false
   170  	default:
   171  		panic("not fail-able with `bytes.Comparable` bounded [-1, 1].")
   172  	}
   173  }
   174  
   175  func (b AddrKeysSlice) Swap(i, j int) {
   176  	b[j], b[i] = b[i], b[j]
   177  }
   178  
   179  // CreateGenAccounts generates genesis accounts loaded with coins, and returns
   180  // their addresses, pubkeys, and privkeys.
   181  func CreateGenAccounts(numAccs int, genCoins sdk.Coins) (genAccs []authexported.Account,
   182  	addrs []sdk.AccAddress, pubKeys []crypto.PubKey, privKeys []crypto.PrivKey) {
   183  
   184  	addrKeysSlice := AddrKeysSlice{}
   185  
   186  	for i := 0; i < numAccs; i++ {
   187  		privKey := secp256k1.GenPrivKey()
   188  		pubKey := privKey.PubKey()
   189  		addr := sdk.AccAddress(pubKey.Address())
   190  
   191  		addrKeysSlice = append(addrKeysSlice, NewAddrKeys(addr, pubKey, privKey))
   192  	}
   193  
   194  	sort.Sort(addrKeysSlice)
   195  
   196  	for i := range addrKeysSlice {
   197  		addrs = append(addrs, addrKeysSlice[i].Address)
   198  		pubKeys = append(pubKeys, addrKeysSlice[i].PubKey)
   199  		privKeys = append(privKeys, addrKeysSlice[i].PrivKey)
   200  		genAccs = append(genAccs, &auth.BaseAccount{
   201  			Address: addrKeysSlice[i].Address,
   202  			Coins:   genCoins,
   203  		})
   204  	}
   205  
   206  	return
   207  }
   208  
   209  // SetGenesis sets the mock app genesis accounts.
   210  func SetGenesis(app *App, accs []authexported.Account) {
   211  	// Pass the accounts in via the application (lazy) instead of through
   212  	// RequestInitChain.
   213  	app.GenesisAccounts = accs
   214  
   215  	app.InitChain(abci.RequestInitChain{})
   216  	app.Commit(abci.RequestCommit{})
   217  }
   218  
   219  // GenTx generates a signed mock transaction.
   220  func GenTx(msgs []sdk.Msg, accnums []uint64, seq []uint64, priv ...crypto.PrivKey) *auth.StdTx {
   221  	// Make the transaction free
   222  	fee := auth.StdFee{
   223  		Amount: sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 1)),
   224  		Gas:    100000,
   225  	}
   226  
   227  	sigs := make([]auth.StdSignature, len(priv))
   228  	memo := "testmemotestmemo"
   229  
   230  	for i, p := range priv {
   231  		sig, err := p.Sign(auth.StdSignBytes(chainID, accnums[i], seq[i], fee, msgs, memo))
   232  		if err != nil {
   233  			panic(err)
   234  		}
   235  
   236  		sigs[i] = auth.StdSignature{
   237  			PubKey:    p.PubKey(),
   238  			Signature: sig,
   239  		}
   240  	}
   241  
   242  	return auth.NewStdTx(msgs, fee, sigs, memo)
   243  }
   244  
   245  // GeneratePrivKeys generates a total n secp256k1 private keys.
   246  func GeneratePrivKeys(n int) (keys []crypto.PrivKey) {
   247  	// TODO: Randomize this between ed25519 and secp256k1
   248  	keys = make([]crypto.PrivKey, n)
   249  	for i := 0; i < n; i++ {
   250  		keys[i] = secp256k1.GenPrivKey()
   251  	}
   252  
   253  	return
   254  }
   255  
   256  // GeneratePrivKeyAddressPairs generates a total of n private key, address
   257  // pairs.
   258  func GeneratePrivKeyAddressPairs(n int) (keys []crypto.PrivKey, addrs []sdk.AccAddress) {
   259  	keys = make([]crypto.PrivKey, n)
   260  	addrs = make([]sdk.AccAddress, n)
   261  	for i := 0; i < n; i++ {
   262  		if rand.Int63()%2 == 0 {
   263  			keys[i] = secp256k1.GenPrivKey()
   264  		} else {
   265  			keys[i] = ed25519.GenPrivKey()
   266  		}
   267  		addrs[i] = sdk.AccAddress(keys[i].PubKey().Address())
   268  	}
   269  	return
   270  }
   271  
   272  // GeneratePrivKeyAddressPairsFromRand generates a total of n private key, address
   273  // pairs using the provided randomness source.
   274  func GeneratePrivKeyAddressPairsFromRand(rand *rand.Rand, n int) (keys []crypto.PrivKey, addrs []sdk.AccAddress) {
   275  	keys = make([]crypto.PrivKey, n)
   276  	addrs = make([]sdk.AccAddress, n)
   277  	for i := 0; i < n; i++ {
   278  		secret := make([]byte, 32)
   279  		_, err := rand.Read(secret)
   280  		if err != nil {
   281  			panic("Could not read randomness")
   282  		}
   283  		if rand.Int63()%2 == 0 {
   284  			keys[i] = secp256k1.GenPrivKeySecp256k1(secret)
   285  		} else {
   286  			keys[i] = ed25519.GenPrivKeyFromSecret(secret)
   287  		}
   288  		addrs[i] = sdk.AccAddress(keys[i].PubKey().Address())
   289  	}
   290  	return
   291  }
   292  
   293  // RandomSetGenesis set genesis accounts with random coin values using the
   294  // provided addresses and coin denominations.
   295  func RandomSetGenesis(r *rand.Rand, app *App, addrs []sdk.AccAddress, denoms []string) {
   296  	accts := make([]authexported.Account, len(addrs))
   297  	randCoinIntervals := []BigInterval{
   298  		{sdk.NewIntWithDecimal(1, 0), sdk.NewIntWithDecimal(1, 1)},
   299  		{sdk.NewIntWithDecimal(1, 2), sdk.NewIntWithDecimal(1, 3)},
   300  		{sdk.NewIntWithDecimal(1, 40), sdk.NewIntWithDecimal(1, 50)},
   301  	}
   302  
   303  	for i := 0; i < len(accts); i++ {
   304  		coins := make([]sdk.Coin, len(denoms))
   305  
   306  		// generate a random coin for each denomination
   307  		for j := 0; j < len(denoms); j++ {
   308  			coins[j] = sdk.Coin{Denom: denoms[j],
   309  				Amount: RandFromBigInterval(r, randCoinIntervals).ToDec(),
   310  			}
   311  		}
   312  
   313  		app.TotalCoinsSupply = app.TotalCoinsSupply.Add(coins...)
   314  		baseAcc := auth.NewBaseAccountWithAddress(addrs[i])
   315  
   316  		(&baseAcc).SetCoins(coins)
   317  		accts[i] = &baseAcc
   318  	}
   319  	app.GenesisAccounts = accts
   320  }
   321  
   322  func createCodec() *codec.CodecProxy {
   323  	cdc := codec.New()
   324  	sdk.RegisterCodec(cdc)
   325  	codec.RegisterCrypto(cdc)
   326  	auth.RegisterCodec(cdc)
   327  	reg := types.NewInterfaceRegistry()
   328  	proc := codec.NewProtoCodec(reg)
   329  	return codec.NewCodecProxy(proc, cdc)
   330  }