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 }