github.com/lino-network/lino@v0.6.11/test/test_util.go (about)

     1  package test
     2  
     3  import (
     4  	"encoding/json"
     5  	"os"
     6  	"strconv"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  
    13  	"github.com/lino-network/lino/app"
    14  	"github.com/lino-network/lino/param"
    15  	"github.com/lino-network/lino/types"
    16  	accmn "github.com/lino-network/lino/x/account/manager"
    17  	accmodel "github.com/lino-network/lino/x/account/model"
    18  	acctypes "github.com/lino-network/lino/x/account/types"
    19  	bandwidthmn "github.com/lino-network/lino/x/bandwidth/manager"
    20  	bandwidthmodel "github.com/lino-network/lino/x/bandwidth/model"
    21  	"github.com/lino-network/lino/x/post"
    22  	valmodel "github.com/lino-network/lino/x/validator/model"
    23  
    24  	wire "github.com/cosmos/cosmos-sdk/codec"
    25  	sdk "github.com/cosmos/cosmos-sdk/types"
    26  	"github.com/cosmos/cosmos-sdk/x/auth"
    27  	abci "github.com/tendermint/tendermint/abci/types"
    28  	"github.com/tendermint/tendermint/crypto/secp256k1"
    29  	"github.com/tendermint/tendermint/libs/log"
    30  	dbm "github.com/tendermint/tm-db"
    31  )
    32  
    33  // construct some global keys and addrs.
    34  var (
    35  	GenesisUser            = "genesis"
    36  	GenesisPriv            = secp256k1.GenPrivKey()
    37  	GenesisTransactionPriv = secp256k1.GenPrivKey()
    38  	GenesisAppPriv         = secp256k1.GenPrivKey()
    39  	GenesisAddr            = GenesisPriv.PubKey().Address()
    40  
    41  	DefaultNumOfVal  = 22
    42  	GenesisTotalCoin = types.NewCoinFromInt64(10000000000 * types.Decimals)
    43  	CoinPerValidator = types.NewCoinFromInt64(100000000 * types.Decimals)
    44  
    45  	PenaltyMissVote       = types.NewCoinFromInt64(20000 * types.Decimals)
    46  	ChangeParamMinDeposit = types.NewCoinFromInt64(100000 * types.Decimals)
    47  
    48  	ProposalDecideSec            int64 = 24 * 7 * 3600
    49  	ParamChangeExecutionSec      int64 = 24 * 3600
    50  	CoinReturnIntervalSec        int64 = 24 * 7 * 3600
    51  	CoinReturnTimes              int64 = 7
    52  	ConsumptionFrictionRate            = types.NewDecFromRat(5, 100)
    53  	ConsumptionFreezingPeriodSec int64 = 24 * 7 * 3600
    54  	PostIntervalSec              int64 = 600
    55  )
    56  
    57  func loggerAndDB() (log.Logger, dbm.DB) {
    58  	logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app")
    59  	db := dbm.NewMemDB()
    60  	return logger, db
    61  }
    62  
    63  func NewTestLinoBlockchain(t *testing.T, numOfValidators int, beginBlockTime time.Time) *app.LinoBlockchain {
    64  	logger, db := loggerAndDB()
    65  	lb := app.NewLinoBlockchain(logger, db, nil)
    66  	genesisState := app.GenesisState{
    67  		GenesisPools: app.GenesisPools{
    68  			Pools: []app.GenesisPool{
    69  				{Name: types.InflationDeveloperPool},
    70  				{Name: types.InflationValidatorPool},
    71  				{Name: types.InflationConsumptionPool},
    72  				{Name: types.VoteStakeInPool},
    73  				{Name: types.VoteStakeReturnPool},
    74  				{Name: types.VoteFrictionPool},
    75  				{
    76  					Name: types.DevIDAReservePool,
    77  				},
    78  				{
    79  					Name:   types.AccountVestingPool,
    80  					Amount: GenesisTotalCoin,
    81  				},
    82  			},
    83  			Total: GenesisTotalCoin,
    84  		},
    85  		InitCoinPrice: types.NewMiniDollar(1200),
    86  		Accounts:      []app.GenesisAccount{},
    87  	}
    88  
    89  	// Generate 21 validators
    90  	for i := 0; i < numOfValidators; i++ {
    91  		genesisAcc := app.GenesisAccount{
    92  			Name:        "validator" + strconv.Itoa(i),
    93  			Coin:        CoinPerValidator,
    94  			TxKey:       secp256k1.GenPrivKey().PubKey(),
    95  			SignKey:     secp256k1.GenPrivKey().PubKey(),
    96  			IsValidator: true,
    97  			ValPubKey:   secp256k1.GenPrivKey().PubKey(),
    98  		}
    99  		genesisState.Accounts = append(genesisState.Accounts, genesisAcc)
   100  	}
   101  
   102  	initLNO := GetGenesisAccountCoin(numOfValidators)
   103  	genesisAcc := app.GenesisAccount{
   104  		Name:        GenesisUser,
   105  		Coin:        initLNO,
   106  		TxKey:       GenesisPriv.PubKey(),
   107  		SignKey:     GenesisTransactionPriv.PubKey(),
   108  		IsValidator: false,
   109  		ValPubKey:   GenesisPriv.PubKey(),
   110  	}
   111  	cdc := app.MakeCodec()
   112  	genesisState.Accounts = append(genesisState.Accounts, genesisAcc)
   113  	result, err := wire.MarshalJSONIndent(cdc, genesisState)
   114  	assert.Nil(t, err)
   115  
   116  	lb.InitChain(abci.RequestInitChain{
   117  		Time: beginBlockTime, ChainId: "Lino", AppStateBytes: json.RawMessage(result)})
   118  	lb.BeginBlock(abci.RequestBeginBlock{
   119  		Header: abci.Header{Height: 1, ChainID: "Lino", Time: beginBlockTime}})
   120  	lb.EndBlock(abci.RequestEndBlock{})
   121  	lb.Commit()
   122  	bandwidthmn.BandwidthManagerTestMode = true
   123  	return lb
   124  }
   125  
   126  // CheckGlobalAllocation - check global allocation parameter
   127  func CheckGlobalAllocation(t *testing.T, lb *app.LinoBlockchain, expectAllocation param.GlobalAllocationParam) {
   128  	ctx := lb.BaseApp.NewContext(true, abci.Header{ChainID: "Lino", Time: time.Unix(0, 0)})
   129  	ph := param.NewParamHolder(lb.CapKeyParamStore)
   130  	allocation := ph.GetGlobalAllocationParam(ctx)
   131  	assert.Equal(t, expectAllocation, *allocation)
   132  }
   133  
   134  // CheckBalance - check account balance
   135  func CheckBalance(t *testing.T, accountName string, lb *app.LinoBlockchain, expectBalance types.Coin) {
   136  	ctx := lb.BaseApp.NewContext(true, abci.Header{ChainID: "Lino", Time: time.Unix(0, 0)})
   137  	ph := param.NewParamHolder(lb.CapKeyParamStore)
   138  	accManager := accmn.NewAccountManager(lb.CapKeyAccountStore, ph)
   139  	saving, err := accManager.GetSavingFromUsername(ctx, types.AccountKey(accountName))
   140  	assert.Nil(t, err)
   141  	assert.Equal(t, expectBalance.Amount.Int64(), saving.Amount.Int64())
   142  }
   143  
   144  // CheckAccountInfo - check account balance
   145  func CheckAccountInfo(t *testing.T, accountName string, lb *app.LinoBlockchain, expectInfo accmodel.AccountInfo) {
   146  	ctx := lb.BaseApp.NewContext(true, abci.Header{ChainID: "Lino", Time: time.Unix(0, 0)})
   147  	ph := param.NewParamHolder(lb.CapKeyParamStore)
   148  	accManager := accmn.NewAccountManager(lb.CapKeyAccountStore, ph)
   149  	info, err := accManager.GetInfo(ctx, types.AccountKey(accountName))
   150  	assert.Nil(t, err)
   151  	assert.Equal(t, expectInfo, *info)
   152  }
   153  
   154  // CheckOncallValidatorList - check if account is in oncall validator set or not
   155  func CheckOncallValidatorList(
   156  	t *testing.T, accountName string, isInOnCallValidatorList bool, lb *app.LinoBlockchain) {
   157  	ctx := lb.BaseApp.NewContext(true, abci.Header{ChainID: "Lino", Time: time.Unix(0, 0)})
   158  	vs := valmodel.NewValidatorStorage(lb.CapKeyValStore)
   159  	lst := vs.GetValidatorList(ctx)
   160  	index := types.FindAccountInList(types.AccountKey(accountName), lst.Oncall)
   161  	if isInOnCallValidatorList {
   162  		assert.True(t, index > -1)
   163  	} else {
   164  		assert.True(t, index == -1)
   165  	}
   166  }
   167  
   168  func CheckStandbyValidatorList(
   169  	t *testing.T, accountName string, isInStandbyValidatorList bool, lb *app.LinoBlockchain) {
   170  	ctx := lb.BaseApp.NewContext(true, abci.Header{ChainID: "Lino", Time: time.Unix(0, 0)})
   171  	vs := valmodel.NewValidatorStorage(lb.CapKeyValStore)
   172  	lst := vs.GetValidatorList(ctx)
   173  	index := types.FindAccountInList(types.AccountKey(accountName), lst.Standby)
   174  	if isInStandbyValidatorList {
   175  		assert.True(t, index > -1)
   176  	} else {
   177  		assert.True(t, index == -1)
   178  	}
   179  }
   180  
   181  func CheckJailValidatorList(
   182  	t *testing.T, accountName string, isInJailValidatorList bool, lb *app.LinoBlockchain) {
   183  	ctx := lb.BaseApp.NewContext(true, abci.Header{ChainID: "Lino", Time: time.Unix(0, 0)})
   184  	vs := valmodel.NewValidatorStorage(lb.CapKeyValStore)
   185  	lst := vs.GetValidatorList(ctx)
   186  	index := types.FindAccountInList(types.AccountKey(accountName), lst.Jail)
   187  	if isInJailValidatorList {
   188  		assert.True(t, index > -1)
   189  	} else {
   190  		assert.True(t, index == -1)
   191  	}
   192  }
   193  
   194  func CheckReceivedVotes(
   195  	t *testing.T, accountName string, votes types.Coin, lb *app.LinoBlockchain) {
   196  	ctx := lb.BaseApp.NewContext(true, abci.Header{ChainID: "Lino", Time: time.Unix(0, 0)})
   197  	vs := valmodel.NewValidatorStorage(lb.CapKeyValStore)
   198  	val, err := vs.GetValidator(ctx, types.AccountKey(accountName))
   199  	assert.Nil(t, err)
   200  	assert.Equal(t, votes, val.ReceivedVotes)
   201  
   202  }
   203  
   204  // CheckAppBandwidthInfo
   205  func CheckAppBandwidthInfo(
   206  	t *testing.T, info bandwidthmodel.AppBandwidthInfo, username types.AccountKey, lb *app.LinoBlockchain) {
   207  	ctx := lb.BaseApp.NewContext(true, abci.Header{ChainID: "Lino", Time: time.Unix(0, 0)})
   208  	bs := bandwidthmodel.NewBandwidthStorage(lb.CapKeyBandwidthStore)
   209  	res, err := bs.GetAppBandwidthInfo(ctx, username)
   210  	assert.Nil(t, err)
   211  	assert.Equal(t, info, *res)
   212  }
   213  
   214  // CheckCurBlockInfo
   215  func CheckCurBlockInfo(
   216  	t *testing.T, info bandwidthmodel.BlockInfo, lb *app.LinoBlockchain) {
   217  	ctx := lb.BaseApp.NewContext(true, abci.Header{ChainID: "Lino", Time: time.Unix(0, 0)})
   218  	bs := bandwidthmodel.NewBandwidthStorage(lb.CapKeyBandwidthStore)
   219  	res, err := bs.GetBlockInfo(ctx)
   220  	assert.Nil(t, err)
   221  	assert.Equal(t, info, *res)
   222  }
   223  
   224  // CreateAccount - register account on test blockchain
   225  func CreateAccount(
   226  	t *testing.T, accountName string, lb *app.LinoBlockchain, seq uint64,
   227  	txPriv, signPriv secp256k1.PrivKeySecp256k1,
   228  	numOfLino string) {
   229  
   230  	registerMsg := acctypes.NewRegisterV2Msg(
   231  		types.NewAccOrAddrFromAcc(types.AccountKey(GenesisUser)), accountName, numOfLino,
   232  		txPriv.PubKey(), signPriv.PubKey())
   233  	SignCheckDeliverWithMultiSig(t, lb, registerMsg,
   234  		[]uint64{seq, 0}, true,
   235  		[]secp256k1.PrivKeySecp256k1{GenesisTransactionPriv, txPriv}, 0)
   236  }
   237  
   238  // CreateAccountWithTime - register account on test blockchain
   239  func CreateAccountWithTime(
   240  	t *testing.T, accountName string, lb *app.LinoBlockchain, seq uint64,
   241  	txPriv, signPriv secp256k1.PrivKeySecp256k1,
   242  	numOfLino string, blockTime int64) {
   243  
   244  	registerMsg := acctypes.NewRegisterV2Msg(
   245  		types.NewAccOrAddrFromAcc(types.AccountKey(GenesisUser)), accountName, numOfLino,
   246  		txPriv.PubKey(), signPriv.PubKey())
   247  	SignCheckDeliverWithMultiSig(t, lb, registerMsg,
   248  		[]uint64{seq, 0}, true,
   249  		[]secp256k1.PrivKeySecp256k1{GenesisTransactionPriv, txPriv}, blockTime)
   250  }
   251  
   252  // GetGenesisAccountCoin - get genesis account coin
   253  func GetGenesisAccountCoin(numOfValidator int) types.Coin {
   254  	coinPerValidator, _ := CoinPerValidator.ToInt64()
   255  	genesisToken, _ := GenesisTotalCoin.ToInt64()
   256  	initLNO := genesisToken - int64(numOfValidator)*coinPerValidator
   257  	initCoin := types.NewCoinFromInt64(initLNO)
   258  	return initCoin
   259  }
   260  
   261  // SignCheckTxShouldFail - sign transaction, it's checkTx should fail
   262  func SignCheckTxFail(t *testing.T, lb *app.LinoBlockchain, msg sdk.Msg, seq uint64, priv secp256k1.PrivKeySecp256k1) {
   263  	// Sign the tx
   264  	tx := genTx(msg, []uint64{seq}, []secp256k1.PrivKeySecp256k1{priv})
   265  	// checkTx should always pass.
   266  	res := lb.Check(tx)
   267  	require.False(t, res.IsOK(), res.Log)
   268  }
   269  
   270  // SignCheckDeliver - sign transaction, simulate and commit a block
   271  func SignCheckDeliver(t *testing.T, lb *app.LinoBlockchain, msg sdk.Msg, seq uint64,
   272  	expPass bool, priv secp256k1.PrivKeySecp256k1, headTime int64) {
   273  	// Sign the tx
   274  	tx := genTx(msg, []uint64{seq}, []secp256k1.PrivKeySecp256k1{priv})
   275  	// checkTx should always pass.
   276  	res := lb.Check(tx)
   277  	require.True(t, res.IsOK(), res.Log)
   278  
   279  	// Simulate a Block
   280  	lb.BeginBlock(abci.RequestBeginBlock{
   281  		Header: abci.Header{
   282  			Height: lb.LastBlockHeight() + 1, ChainID: "Lino", Time: time.Unix(headTime, 0)}})
   283  	res = lb.Deliver(tx)
   284  	if expPass {
   285  		require.True(t, res.IsOK(), res.Log)
   286  	} else {
   287  		require.False(t, res.IsOK(), res.Log)
   288  	}
   289  	lb.EndBlock(abci.RequestEndBlock{})
   290  	lb.Commit()
   291  }
   292  
   293  // SignCheckDeliverWithMultiSig - sign transaction with multi sig, simulate and commit a block
   294  func SignCheckDeliverWithMultiSig(
   295  	t *testing.T, lb *app.LinoBlockchain, msg sdk.Msg, seqs []uint64,
   296  	expPass bool, privs []secp256k1.PrivKeySecp256k1, headTime int64) {
   297  	// Sign the tx
   298  	tx := genTx(msg, seqs, privs)
   299  	// XXX(yumin): API changed after upgrad-1, new field tx, passing nil, not sure
   300  	// about what is the right way..
   301  	res := lb.Simulate(nil, tx)
   302  	if expPass {
   303  		require.True(t, res.IsOK(), res.Log)
   304  	} else {
   305  		require.False(t, res.IsOK(), res.Log)
   306  	}
   307  
   308  	// Simulate a Block
   309  	lb.BeginBlock(abci.RequestBeginBlock{
   310  		Header: abci.Header{
   311  			Height: lb.LastBlockHeight() + 1, ChainID: "Lino", Time: time.Unix(headTime, 0)}})
   312  	res = lb.Deliver(tx)
   313  	if expPass {
   314  		require.True(t, res.IsOK(), res.Log)
   315  	} else {
   316  		require.False(t, res.IsOK(), res.Log)
   317  	}
   318  	lb.EndBlock(abci.RequestEndBlock{})
   319  	lb.Commit()
   320  }
   321  
   322  // SignCheckDeliverWithFee - sign transaction with fee, simulate and commit a block
   323  func SignCheckDeliverWithFee(t *testing.T, lb *app.LinoBlockchain, msg sdk.Msg, seq uint64,
   324  	expPass bool, priv secp256k1.PrivKeySecp256k1, headTime int64, fee auth.StdFee) {
   325  	// Sign the tx
   326  	tx := genTxWithFee(msg, seq, priv, fee)
   327  	// XXX(yumin): API changed after upgrad-1, new field tx, passing nil, not sure
   328  	// about what is the right way..
   329  	res := lb.Simulate(nil, tx)
   330  	if expPass {
   331  		require.True(t, res.IsOK(), res.Log)
   332  	} else {
   333  		require.False(t, res.IsOK(), res.Log)
   334  	}
   335  
   336  	// Simulate a Block
   337  	lb.BeginBlock(abci.RequestBeginBlock{
   338  		Header: abci.Header{
   339  			Height: lb.LastBlockHeight() + 1, ChainID: "Lino", Time: time.Unix(headTime, 0)}})
   340  	res = lb.Deliver(tx)
   341  	if expPass {
   342  		require.True(t, res.IsOK(), res.Log)
   343  	} else {
   344  		require.False(t, res.IsOK(), res.Log)
   345  	}
   346  	lb.EndBlock(abci.RequestEndBlock{})
   347  	lb.Commit()
   348  }
   349  
   350  // RepeatSignCheckDeliver - sign same transaction repeatly, simulate and commit a block
   351  func RepeatSignCheckDeliver(t *testing.T, lb *app.LinoBlockchain, msg sdk.Msg, seq uint64,
   352  	expPass bool, priv secp256k1.PrivKeySecp256k1, headTime int64, times int) {
   353  
   354  	// Simulate a Block
   355  	lb.BeginBlock(abci.RequestBeginBlock{
   356  		Header: abci.Header{
   357  			Height: lb.LastBlockHeight() + 1, ChainID: "Lino", Time: time.Unix(headTime, 0)}})
   358  
   359  	for i := 0; i < times; i++ {
   360  		tx := genTx(msg, []uint64{seq + uint64(i)}, []secp256k1.PrivKeySecp256k1{priv})
   361  		res := lb.Deliver(tx)
   362  		if expPass {
   363  			require.True(t, res.IsOK(), res.Log)
   364  		} else {
   365  			require.False(t, res.IsOK(), res.Log)
   366  		}
   367  	}
   368  	lb.EndBlock(abci.RequestEndBlock{})
   369  	lb.Commit()
   370  }
   371  
   372  // SimulateOneBlock - simulate a empty block and commit
   373  func SimulateOneBlock(lb *app.LinoBlockchain, headTime int64) {
   374  	lb.BeginBlock(abci.RequestBeginBlock{
   375  		Header: abci.Header{
   376  			Height: lb.LastBlockHeight() + 1, ChainID: "Lino", Time: time.Unix(headTime, 0)}})
   377  	lb.EndBlock(abci.RequestEndBlock{})
   378  	lb.Commit()
   379  }
   380  
   381  func genTx(msg sdk.Msg, seq []uint64, priv []secp256k1.PrivKeySecp256k1) auth.StdTx {
   382  	sigs := []auth.StdSignature{}
   383  	for i, priv := range priv {
   384  		bz, _ := priv.Sign(
   385  			auth.StdSignBytes(
   386  				"Lino", 0, seq[i], auth.StdFee{
   387  					Amount: sdk.NewCoins(sdk.NewCoin(types.LinoCoinDenom, sdk.NewInt(10000000)))}, []sdk.Msg{msg}, ""))
   388  		sigs = append(sigs, auth.StdSignature{
   389  			PubKey:    priv.PubKey(),
   390  			Signature: bz,
   391  		})
   392  	}
   393  	return auth.NewStdTx([]sdk.Msg{msg}, auth.StdFee{Amount: sdk.NewCoins(sdk.NewCoin(types.LinoCoinDenom, sdk.NewInt(10000000)))}, sigs, "")
   394  }
   395  
   396  func genTxWithFee(msg sdk.Msg, seq uint64, priv secp256k1.PrivKeySecp256k1, fee auth.StdFee) auth.StdTx {
   397  	bz, _ := priv.Sign(auth.StdSignBytes("Lino", 0, seq, fee, []sdk.Msg{msg}, ""))
   398  	sigs := []auth.StdSignature{{
   399  		PubKey:    priv.PubKey(),
   400  		Signature: bz,
   401  	}}
   402  	return auth.NewStdTx([]sdk.Msg{msg}, fee, sigs, "")
   403  }
   404  
   405  // CreateTestPost - create a test post
   406  func CreateTestPost(
   407  	t *testing.T, lb *app.LinoBlockchain,
   408  	username, postID string, seq uint64, priv secp256k1.PrivKeySecp256k1, publishTime int64) {
   409  
   410  	msg := post.CreatePostMsg{
   411  		PostID:    postID,
   412  		Title:     string(make([]byte, 50)),
   413  		Content:   string(make([]byte, 1000)),
   414  		Author:    types.AccountKey(username),
   415  		CreatedBy: types.AccountKey(username),
   416  	}
   417  	SignCheckDeliver(t, lb, msg, seq, true, priv, publishTime)
   418  }