github.com/lino-network/lino@v0.6.11/x/account/manager/manager_test.go (about) 1 package manager 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "path/filepath" 8 "testing" 9 "time" 10 11 wire "github.com/cosmos/cosmos-sdk/codec" 12 sdk "github.com/cosmos/cosmos-sdk/types" 13 "github.com/stretchr/testify/mock" 14 "github.com/stretchr/testify/suite" 15 abci "github.com/tendermint/tendermint/abci/types" 16 "github.com/tendermint/tendermint/crypto" 17 "github.com/tendermint/tendermint/crypto/secp256k1" 18 19 parammodel "github.com/lino-network/lino/param" 20 param "github.com/lino-network/lino/param/mocks" 21 "github.com/lino-network/lino/testsuites" 22 "github.com/lino-network/lino/testutils" 23 "github.com/lino-network/lino/types" 24 linotypes "github.com/lino-network/lino/types" 25 "github.com/lino-network/lino/x/account/model" 26 acctypes "github.com/lino-network/lino/x/account/types" 27 ) 28 29 var ( 30 storeKeyStr = "testAccountStore" 31 kvStoreKey = sdk.NewKVStoreKey(storeKeyStr) 32 ) 33 34 type AccountStoreDumper struct{} 35 36 func (dumper AccountStoreDumper) NewDumper() *testutils.Dumper { 37 return model.NewAccountDumper(model.NewAccountStorage(kvStoreKey)) 38 } 39 40 type AccountManagerTestSuite struct { 41 testsuites.GoldenTestSuite 42 am AccountManager 43 ph *param.ParamKeeper 44 45 // mock data 46 userWithoutBalance model.AccountInfo 47 48 userWithBalance model.AccountInfo 49 userWithBalanceSaving types.Coin 50 registerFee types.Coin 51 52 unreg model.AccountInfo 53 54 unregSaving types.Coin 55 } 56 57 func TestAccountManagerTestSuite(t *testing.T) { 58 suite.Run(t, &AccountManagerTestSuite{ 59 GoldenTestSuite: testsuites.NewGoldenTestSuite(AccountStoreDumper{}, kvStoreKey), 60 }) 61 } 62 63 func (suite *AccountManagerTestSuite) SetupTest() { 64 suite.SetupCtx(0, time.Unix(0, 0), kvStoreKey) 65 suite.ph = ¶m.ParamKeeper{} 66 suite.am = NewAccountManager(kvStoreKey, suite.ph) 67 68 // background 69 suite.userWithoutBalance = model.AccountInfo{ 70 Username: types.AccountKey("userwithoutbalance"), 71 SigningKey: sampleKeys()[0], 72 TransactionKey: sampleKeys()[1], 73 } 74 suite.userWithoutBalance.Address = sdk.AccAddress(suite.userWithoutBalance.TransactionKey.Address()) 75 76 suite.userWithBalance = model.AccountInfo{ 77 Username: types.AccountKey("userwithbalance"), 78 SigningKey: sampleKeys()[2], 79 TransactionKey: sampleKeys()[3], 80 } 81 suite.userWithBalance.Address = sdk.AccAddress(suite.userWithBalance.TransactionKey.Address()) 82 83 suite.unreg = model.AccountInfo{ 84 Username: types.AccountKey("unreg"), 85 SigningKey: sampleKeys()[4], 86 TransactionKey: sampleKeys()[5], 87 } 88 suite.unreg.Address = sdk.AccAddress(suite.unreg.TransactionKey.Address()) 89 90 suite.userWithBalanceSaving = types.NewCoinFromInt64(1000 * types.Decimals) 91 suite.unregSaving = types.NewCoinFromInt64(1 * types.Decimals) 92 suite.registerFee = types.NewCoinFromInt64(100 * types.Decimals) 93 94 err := suite.am.GenesisAccount(suite.Ctx, suite.userWithoutBalance.Username, suite.userWithoutBalance.SigningKey, suite.userWithoutBalance.TransactionKey) 95 suite.NoError(err) 96 97 err = suite.am.GenesisAccount(suite.Ctx, suite.userWithBalance.Username, suite.userWithBalance.SigningKey, suite.userWithBalance.TransactionKey) 98 suite.NoError(err) 99 err = suite.am.addCoinToUsername(suite.Ctx, suite.userWithBalance.Username, suite.userWithBalanceSaving) 100 suite.NoError(err) 101 102 suite.am.addCoinToAddress(suite.Ctx, sdk.AccAddress(suite.unreg.TransactionKey.Address()), suite.unregSaving) 103 104 suite.ph.On("GetAccountParam", mock.Anything).Return(¶mmodel.AccountParam{ 105 RegisterFee: suite.registerFee, 106 MinimumBalance: types.NewCoinFromInt64(0), 107 MaxNumFrozenMoney: 10, 108 }, nil).Maybe() 109 } 110 111 func (suite *AccountManagerTestSuite) TestInitGenesis() { 112 suite.NextBlock(time.Unix(123, 0)) 113 am := suite.am 114 ctx := suite.Ctx 115 116 total := linotypes.NewCoinFromInt64(2000000) 117 118 am.InitGenesis(ctx, total, []model.Pool{ 119 { 120 Name: linotypes.InflationValidatorPool, 121 Balance: linotypes.NewCoinFromInt64(123), 122 }, 123 { 124 Name: linotypes.AccountVestingPool, 125 Balance: linotypes.NewCoinFromInt64(1000000), 126 }, 127 }) 128 129 supply := am.GetSupply(ctx) 130 suite.Equal(model.Supply{ 131 LastYearTotal: total, 132 Total: total, 133 ChainStartTime: ctx.BlockTime().Unix(), 134 LastInflationTime: ctx.BlockTime().Unix(), 135 }, supply) 136 137 pool1, err := am.GetPool(ctx, linotypes.InflationValidatorPool) 138 suite.Nil(err) 139 suite.Equal(linotypes.NewCoinFromInt64(123), pool1) 140 141 pool2, err := am.GetPool(ctx, linotypes.AccountVestingPool) 142 suite.Nil(err) 143 suite.Equal(linotypes.NewCoinFromInt64(1000000), pool2) 144 145 _, err = am.GetPool(ctx, "not-a-pool") 146 suite.NotNil(err) 147 148 suite.Panics(func() { 149 am.InitGenesis(ctx, total, nil) 150 }) 151 152 suite.Golden() 153 } 154 155 func (suite *AccountManagerTestSuite) TestMoveFromPools() { 156 initBackground := func() { 157 suite.NextBlock(time.Unix(123, 0)) 158 am := suite.am 159 ctx := suite.Ctx 160 161 total := linotypes.NewCoinFromInt64(2000000) 162 163 am.InitGenesis(ctx, total, []model.Pool{ 164 { 165 Name: linotypes.InflationValidatorPool, 166 Balance: linotypes.NewCoinFromInt64(123), 167 }, 168 { 169 Name: linotypes.AccountVestingPool, 170 Balance: linotypes.NewCoinFromInt64(1000000), 171 }, 172 }) 173 } 174 cases := []struct { 175 name string 176 pool linotypes.PoolName 177 to linotypes.AccOrAddr 178 amount linotypes.Coin 179 expectedErr sdk.Error 180 expectedBalance linotypes.Coin 181 expectedPoolLeft linotypes.Coin 182 }{ 183 { 184 name: "move negative amount", 185 pool: linotypes.AccountVestingPool, 186 to: linotypes.NewAccOrAddrFromAcc(types.AccountKey("userwithoutbalance")), 187 amount: linotypes.NewCoinFromInt64(-1), 188 expectedErr: acctypes.ErrNegativeMoveAmount(linotypes.NewCoinFromInt64(-1)), 189 }, 190 { 191 name: "pool not enough", 192 pool: linotypes.InflationValidatorPool, 193 to: linotypes.NewAccOrAddrFromAcc(types.AccountKey("userwithoutbalance")), 194 amount: linotypes.NewCoinFromInt64(124), 195 expectedErr: acctypes.ErrPoolNotEnough(linotypes.InflationValidatorPool), 196 }, 197 { 198 name: "pool not exists", 199 pool: "poolnotexists", 200 to: linotypes.NewAccOrAddrFromAcc(types.AccountKey("userwithoutbalance")), 201 amount: linotypes.NewCoinFromInt64(124), 202 expectedErr: acctypes.ErrPoolNotFound("poolnotexists"), 203 }, 204 { 205 name: "succ move to account", 206 pool: linotypes.InflationValidatorPool, 207 to: linotypes.NewAccOrAddrFromAcc(types.AccountKey("userwithoutbalance")), 208 amount: linotypes.NewCoinFromInt64(100), 209 expectedBalance: linotypes.NewCoinFromInt64(100), 210 expectedPoolLeft: linotypes.NewCoinFromInt64(23), 211 }, 212 { 213 name: "succ move to addr", 214 pool: linotypes.AccountVestingPool, 215 to: linotypes.NewAccOrAddrFromAddr(suite.userWithoutBalance.Address), 216 amount: linotypes.NewCoinFromInt64(1000000), 217 expectedBalance: linotypes.NewCoinFromInt64(1000000), 218 expectedPoolLeft: linotypes.NewCoinFromInt64(0), 219 }, 220 } 221 222 for _, tc := range cases { 223 suite.Run(tc.name, func() { 224 suite.SetupTest() 225 initBackground() 226 err := suite.am.MoveFromPool(suite.Ctx, tc.pool, tc.to, tc.amount) 227 suite.Equal(tc.expectedErr, err) 228 if tc.expectedErr == nil { 229 if tc.to.IsAddr { 230 bank, err := suite.am.GetBankByAddress(suite.Ctx, tc.to.Addr) 231 suite.Nil(err) 232 suite.Equal(tc.expectedBalance, bank.Saving) 233 } else { 234 bank, err := suite.am.GetBank(suite.Ctx, tc.to.AccountKey) 235 suite.Nil(err) 236 suite.Equal(tc.expectedBalance, bank.Saving) 237 } 238 pool, err := suite.am.GetPool(suite.Ctx, tc.pool) 239 suite.Nil(err) 240 suite.Equal(tc.expectedPoolLeft, pool) 241 } 242 suite.Golden() 243 }) 244 } 245 } 246 247 func (suite *AccountManagerTestSuite) TestMoveToPools() { 248 initBackground := func() { 249 suite.NextBlock(time.Unix(123, 0)) 250 am := suite.am 251 ctx := suite.Ctx 252 253 total := linotypes.NewCoinFromInt64(2000000) 254 255 am.InitGenesis(ctx, total, []model.Pool{ 256 { 257 Name: linotypes.InflationValidatorPool, 258 Balance: linotypes.NewCoinFromInt64(123), 259 }, 260 { 261 Name: linotypes.AccountVestingPool, 262 Balance: linotypes.NewCoinFromInt64(1000000), 263 }, 264 }) 265 } 266 cases := []struct { 267 name string 268 pool linotypes.PoolName 269 from linotypes.AccOrAddr 270 amount linotypes.Coin 271 expectedErr sdk.Error 272 expectedBalance linotypes.Coin 273 expectedPoolLeft linotypes.Coin 274 }{ 275 { 276 name: "move negative amount", 277 pool: linotypes.AccountVestingPool, 278 from: linotypes.NewAccOrAddrFromAcc(types.AccountKey("userwithbalance")), 279 amount: linotypes.NewCoinFromInt64(-1), 280 expectedErr: acctypes.ErrNegativeMoveAmount(linotypes.NewCoinFromInt64(-1)), 281 }, 282 { 283 name: "balance not enough", 284 pool: linotypes.InflationValidatorPool, 285 from: linotypes.NewAccOrAddrFromAcc(suite.userWithBalance.Username), 286 amount: suite.userWithBalanceSaving.Plus(linotypes.NewCoinFromInt64(1)), 287 expectedErr: acctypes.ErrAccountSavingCoinNotEnough(), 288 }, 289 { 290 name: "pool not exists", 291 pool: "poolnotexists", 292 from: linotypes.NewAccOrAddrFromAcc(types.AccountKey("userwithbalance")), 293 amount: linotypes.NewCoinFromInt64(1), 294 expectedErr: acctypes.ErrPoolNotFound("poolnotexists"), 295 }, 296 { 297 name: "succ move from account", 298 pool: linotypes.InflationValidatorPool, 299 from: linotypes.NewAccOrAddrFromAcc(types.AccountKey("userwithbalance")), 300 amount: suite.userWithBalanceSaving, 301 expectedBalance: linotypes.NewCoinFromInt64(0), 302 expectedPoolLeft: suite.userWithBalanceSaving.Plus(linotypes.NewCoinFromInt64(123)), 303 }, 304 { 305 name: "succ move from addr", 306 pool: linotypes.AccountVestingPool, 307 from: linotypes.NewAccOrAddrFromAddr(suite.userWithBalance.Address), 308 amount: suite.userWithBalanceSaving.Minus(linotypes.NewCoinFromInt64(1)), 309 expectedBalance: linotypes.NewCoinFromInt64(1), 310 expectedPoolLeft: linotypes.NewCoinFromInt64(1000000).Plus(suite.userWithBalanceSaving.Minus(linotypes.NewCoinFromInt64(1))), 311 }, 312 } 313 314 for _, tc := range cases { 315 suite.Run(tc.name, func() { 316 suite.SetupTest() 317 initBackground() 318 err := suite.am.MoveToPool(suite.Ctx, tc.pool, tc.from, tc.amount) 319 suite.Equal(tc.expectedErr, err) 320 if tc.expectedErr == nil { 321 if tc.from.IsAddr { 322 bank, err := suite.am.GetBankByAddress(suite.Ctx, tc.from.Addr) 323 suite.Nil(err) 324 suite.Equal(tc.expectedBalance, bank.Saving) 325 } else { 326 bank, err := suite.am.GetBank(suite.Ctx, tc.from.AccountKey) 327 suite.Nil(err) 328 suite.Equal(tc.expectedBalance, bank.Saving) 329 } 330 pool, err := suite.am.GetPool(suite.Ctx, tc.pool) 331 suite.Nil(err) 332 suite.Equal(tc.expectedPoolLeft, pool) 333 } 334 suite.Golden() 335 }) 336 } 337 } 338 339 func (suite *AccountManagerTestSuite) TestBetweenPools() { 340 initBackground := func() { 341 suite.NextBlock(time.Unix(123, 0)) 342 am := suite.am 343 ctx := suite.Ctx 344 345 total := linotypes.NewCoinFromInt64(2000000) 346 347 am.InitGenesis(ctx, total, []model.Pool{ 348 { 349 Name: linotypes.InflationValidatorPool, 350 Balance: linotypes.NewCoinFromInt64(123), 351 }, 352 { 353 Name: linotypes.AccountVestingPool, 354 Balance: linotypes.NewCoinFromInt64(1000000), 355 }, 356 }) 357 } 358 cases := []struct { 359 name string 360 from linotypes.PoolName 361 to linotypes.PoolName 362 amount linotypes.Coin 363 expectedErr sdk.Error 364 expectedFrom linotypes.Coin 365 expectedTo linotypes.Coin 366 }{ 367 { 368 name: "move negative amount", 369 from: linotypes.AccountVestingPool, 370 to: linotypes.AccountVestingPool, 371 amount: linotypes.NewCoinFromInt64(-1), 372 expectedErr: acctypes.ErrNegativeMoveAmount(linotypes.NewCoinFromInt64(-1)), 373 }, 374 { 375 name: "from pool not exists", 376 from: "poolnotexists", 377 to: linotypes.AccountVestingPool, 378 amount: linotypes.NewCoinFromInt64(1), 379 expectedErr: acctypes.ErrPoolNotFound("poolnotexists"), 380 }, 381 { 382 name: "to pool not exists", 383 from: linotypes.AccountVestingPool, 384 to: "poolnotexists", 385 amount: linotypes.NewCoinFromInt64(1), 386 expectedErr: acctypes.ErrPoolNotFound("poolnotexists"), 387 }, 388 { 389 name: "balance not enough", 390 from: linotypes.InflationValidatorPool, 391 to: linotypes.AccountVestingPool, 392 amount: linotypes.NewCoinFromInt64(124), 393 expectedErr: acctypes.ErrPoolNotEnough(linotypes.InflationValidatorPool), 394 }, 395 { 396 name: "succ", 397 from: linotypes.InflationValidatorPool, 398 to: linotypes.AccountVestingPool, 399 amount: linotypes.NewCoinFromInt64(1), 400 expectedFrom: linotypes.NewCoinFromInt64(122), 401 expectedTo: linotypes.NewCoinFromInt64(1000001), 402 }, 403 } 404 405 for _, tc := range cases { 406 suite.Run(tc.name, func() { 407 suite.SetupTest() 408 initBackground() 409 err := suite.am.MoveBetweenPools(suite.Ctx, tc.from, tc.to, tc.amount) 410 suite.Equal(tc.expectedErr, err) 411 if tc.expectedErr == nil { 412 poolFrom, _ := suite.am.GetPool(suite.Ctx, tc.from) 413 suite.Equal(tc.expectedFrom, poolFrom) 414 poolTo, _ := suite.am.GetPool(suite.Ctx, tc.to) 415 suite.Equal(tc.expectedTo, poolTo) 416 } 417 suite.Golden() 418 }) 419 } 420 } 421 422 // test mint schedule 423 func (suite *AccountManagerTestSuite) TestMint() { 424 // Genesis 425 init := int64(123) 426 suite.NextBlock(time.Unix(init, 0)) 427 am := suite.am 428 429 total := linotypes.MustLinoToCoin("10000000000") 430 am.InitGenesis(suite.Ctx, total, []model.Pool{ 431 { 432 Name: linotypes.InflationValidatorPool, 433 Balance: linotypes.NewCoinFromInt64(0), 434 }, 435 { 436 Name: linotypes.InflationDeveloperPool, 437 Balance: linotypes.NewCoinFromInt64(0), 438 }, 439 { 440 Name: linotypes.InflationConsumptionPool, 441 Balance: linotypes.NewCoinFromInt64(0), 442 }, 443 { 444 Name: linotypes.AccountVestingPool, 445 Balance: total, 446 }, 447 }) 448 449 // param 450 rate := sdk.MustNewDecFromStr("0.065") 451 cc := sdk.MustNewDecFromStr("0.10") 452 dev := sdk.MustNewDecFromStr("0.75") 453 val := sdk.MustNewDecFromStr("0.15") 454 suite.ph.On("GetGlobalAllocationParam", mock.Anything).Return( 455 ¶mmodel.GlobalAllocationParam{ 456 GlobalGrowthRate: rate, 457 ContentCreatorAllocation: cc, 458 DeveloperAllocation: dev, 459 ValidatorAllocation: val, 460 }) 461 462 computeHourly := func(total linotypes.Coin, growth sdk.Dec) (linotypes.Coin, linotypes.Coin, linotypes.Coin) { 463 amount := linotypes.DecToCoin(total.ToDec().Mul(growth).Mul( 464 linotypes.NewDecFromRat(1, nHourOfOneYear))) 465 ccAmount := linotypes.DecToCoin(amount.ToDec().Mul(cc)) 466 valAmount := linotypes.DecToCoin(amount.ToDec().Mul(val)) 467 devAmount := amount.Minus(ccAmount).Minus(valAmount) 468 return ccAmount, valAmount, devAmount 469 } 470 471 getPools := func(ctx sdk.Context) (linotypes.Coin, linotypes.Coin, linotypes.Coin) { 472 cpool, _ := suite.am.GetPool(ctx, linotypes.InflationConsumptionPool) 473 vpool, _ := suite.am.GetPool(ctx, linotypes.InflationValidatorPool) 474 dpool, _ := suite.am.GetPool(ctx, linotypes.InflationDeveloperPool) 475 return cpool, vpool, dpool 476 } 477 478 checkPool := func(ctx sdk.Context, cc, val, dev linotypes.Coin) { 479 cpool, vpool, dpool := getPools(ctx) 480 suite.Equal(cc, cpool) 481 suite.Equal(val, vpool) 482 suite.Equal(dev, dpool) 483 } 484 485 // test first hour 486 firstYearOneHourCC := linotypes.MustLinoToCoin("7415.01255") 487 firstYearOneHourVal := linotypes.MustLinoToCoin("11122.51882") 488 firstYearOneHourDev := linotypes.MustLinoToCoin("55612.59411") 489 base := total 490 t := init + nSecOfOneHour 491 suite.NextBlock(time.Unix(t, 0)) 492 err := am.Mint(suite.Ctx) 493 suite.Nil(err) 494 checkPool(suite.Ctx, firstYearOneHourCC, firstYearOneHourVal, firstYearOneHourDev) 495 496 // same time again, won't mint 497 err = am.Mint(suite.Ctx) 498 suite.Nil(err) 499 checkPool(suite.Ctx, firstYearOneHourCC, firstYearOneHourVal, firstYearOneHourDev) 500 501 // test first 50 hours 502 for ; t <= init+50*nSecOfOneHour; t += 5 { 503 suite.NextBlock(time.Unix(t, 0)) 504 err := am.Mint(suite.Ctx) 505 suite.Nil(err) 506 if (t-init)%nSecOfOneHour == 0 { 507 n := (t - init) / nSecOfOneHour 508 checkPool(suite.Ctx, 509 linotypes.DecToCoin(firstYearOneHourCC.ToDec().Mul(sdk.NewDec(n))), 510 linotypes.DecToCoin(firstYearOneHourVal.ToDec().Mul(sdk.NewDec(n))), 511 linotypes.DecToCoin(firstYearOneHourDev.ToDec().Mul(sdk.NewDec(n))), 512 ) 513 } 514 } 515 516 // first year, 123 + nSecOfOneHour * nHourOfOneYear, is the first year 517 // math check 518 hourSum := firstYearOneHourCC.Plus(firstYearOneHourVal).Plus(firstYearOneHourDev) 519 oneYearComputedMint := linotypes.DecToCoin(hourSum.ToDec().Mul(sdk.NewDec(nHourOfOneYear))) 520 oneYearTotal := linotypes.MustLinoToCoin("10649999999.95768") 521 suite.Equal(oneYearTotal.Minus(base), oneYearComputedMint) 522 523 t = init + nSecOfOneHour*nHourOfOneYear 524 suite.NextBlock(time.Unix(t, 0)) 525 err = suite.am.Mint(suite.Ctx) 526 suite.Nil(err) 527 supply := suite.am.GetSupply(suite.Ctx) 528 suite.Equal(oneYearTotal, supply.LastYearTotal) 529 suite.Equal(oneYearTotal, supply.Total) 530 // cc1, val1, dev1 := getPools(suite.Ctx) 531 // fmt.Println(cc1, val1, dev1) 532 // fmt.Println(cc1.Plus(val1).Plus(dev1)) 533 534 // second year, 123 + 2 * (nSecOfOneHour * nHourOfOneYear), is the second year 535 // next year first hour 536 base = oneYearTotal 537 lastYearCC, lastYearVal, lastYearDev := getPools(suite.Ctx) 538 ccAmount, valAmount, devAmount := computeHourly(base, rate) 539 t += nSecOfOneHour 540 suite.NextBlock(time.Unix(t, 0)) 541 err = suite.am.Mint(suite.Ctx) 542 suite.Nil(err) 543 checkPool(suite.Ctx, 544 lastYearCC.Plus(ccAmount), 545 lastYearVal.Plus(valAmount), 546 lastYearDev.Plus(devAmount), 547 ) 548 } 549 550 func (suite *AccountManagerTestSuite) TestDoesAccountExist() { 551 testCases := []struct { 552 testName string 553 user types.AccountKey 554 expectResult bool 555 }{ 556 { 557 testName: "user does exists", 558 user: suite.userWithBalance.Username, 559 expectResult: true, 560 }, 561 { 562 testName: "user doesn't exists", 563 user: suite.userWithoutBalance.Username, 564 expectResult: true, 565 }, 566 } 567 for _, tc := range testCases { 568 res := suite.am.DoesAccountExist(suite.Ctx, tc.user) 569 suite.Equal( 570 tc.expectResult, res, 571 "%s: does account exist for user %s, expect %t, got %t", tc.testName, tc.user, tc.expectResult, res) 572 } 573 } 574 575 func (suite *AccountManagerTestSuite) TestAddCoinToAddress() { 576 userWithBalance := suite.userWithBalance 577 unreg := suite.unreg 578 emptyAddress := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) 579 580 testCases := []struct { 581 testName string 582 address sdk.AccAddress 583 amount types.Coin 584 expectBank *model.AccountBank 585 }{ 586 { 587 testName: "add coin to bank which is linked to username", 588 address: sdk.AccAddress(userWithBalance.TransactionKey.Address()), 589 amount: c100, 590 expectBank: &model.AccountBank{ 591 Saving: suite.userWithBalanceSaving.Plus(c100), 592 PubKey: userWithBalance.TransactionKey, 593 Username: userWithBalance.Username, 594 }, 595 }, 596 { 597 testName: "add coin to bank which is not linked to username", 598 address: sdk.AccAddress(unreg.TransactionKey.Address()), 599 amount: c100, 600 expectBank: &model.AccountBank{ 601 Saving: suite.unregSaving.Plus(c100), 602 }, 603 }, 604 { 605 testName: "add coin to empty bank", 606 address: emptyAddress, 607 amount: c100, 608 expectBank: &model.AccountBank{ 609 Saving: c100, 610 }, 611 }, 612 } 613 614 for _, tc := range testCases { 615 suite.am.addCoinToAddress(suite.Ctx, tc.address, tc.amount) 616 suite.checkBankKVByAddress(tc.testName, tc.address, tc.expectBank) 617 } 618 } 619 620 func (suite *AccountManagerTestSuite) TestAddCoinToUsername() { 621 userWithBalance := suite.userWithBalance 622 unreg := suite.unreg 623 624 testCases := []struct { 625 testName string 626 username types.AccountKey 627 amount types.Coin 628 expectErr sdk.Error 629 expectBank *model.AccountBank 630 }{ 631 { 632 testName: "add coin to created username", 633 username: userWithBalance.Username, 634 amount: c100, 635 expectErr: nil, 636 expectBank: &model.AccountBank{ 637 Saving: suite.userWithBalanceSaving.Plus(c100), 638 PubKey: userWithBalance.TransactionKey, 639 Username: userWithBalance.Username, 640 }, 641 }, 642 { 643 testName: "add coin to unregister username", 644 username: unreg.Username, 645 amount: c100, 646 expectErr: acctypes.ErrAccountNotFound(unreg.Username), 647 expectBank: nil, 648 }, 649 } 650 651 for _, tc := range testCases { 652 err := suite.am.addCoinToUsername(suite.Ctx, tc.username, tc.amount) 653 suite.Equal( 654 tc.expectErr, err, 655 "%s: failed to add coin to user %s, expect err %v, got %v", 656 tc.testName, tc.username, tc.expectErr, err) 657 if tc.expectBank != nil { 658 suite.checkBankKVByUsername(tc.testName, tc.username, tc.expectBank) 659 } 660 } 661 } 662 663 func (suite *AccountManagerTestSuite) TestMinusCoinFromAddress() { 664 userWithBalance := suite.userWithBalance 665 userWithoutBalance := suite.userWithoutBalance 666 unreg := suite.unreg 667 emptyAddress := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) 668 669 testCases := []struct { 670 testName string 671 address sdk.AccAddress 672 amount types.Coin 673 expectErr sdk.Error 674 expectBank *model.AccountBank 675 }{ 676 { 677 testName: "minus coin from address with sufficient balance", 678 address: userWithBalance.Address, 679 expectErr: nil, 680 amount: coin100, 681 expectBank: &model.AccountBank{ 682 Saving: suite.userWithBalanceSaving.Minus(coin100), 683 PubKey: userWithBalance.TransactionKey, 684 Username: userWithBalance.Username, 685 }, 686 }, 687 { 688 testName: "minus coin from address without sufficient balance", 689 address: userWithoutBalance.Address, 690 expectErr: acctypes.ErrAccountSavingCoinNotEnough(), 691 amount: coin1, 692 expectBank: &model.AccountBank{ 693 PubKey: userWithoutBalance.TransactionKey, 694 Saving: types.NewCoinFromInt64(0), 695 Username: userWithoutBalance.Username, 696 }, 697 }, 698 { 699 testName: "minus saving coin exceeds the coin address hold", 700 address: userWithBalance.Address, 701 expectErr: acctypes.ErrAccountSavingCoinNotEnough(), 702 amount: suite.userWithBalanceSaving, 703 expectBank: &model.AccountBank{ 704 Saving: suite.userWithBalanceSaving.Minus(coin100), 705 PubKey: userWithBalance.TransactionKey, 706 Username: userWithBalance.Username, 707 }, 708 }, 709 { 710 testName: "minus saving coin from unregister address", 711 address: sdk.AccAddress(unreg.TransactionKey.Address()), 712 expectErr: nil, 713 amount: coin100, 714 expectBank: &model.AccountBank{ 715 Saving: suite.unregSaving.Minus(coin100), 716 }, 717 }, 718 { 719 testName: "minus saving coin from empty address", 720 address: emptyAddress, 721 expectErr: acctypes.ErrAccountBankNotFound(emptyAddress), 722 amount: coin1, 723 expectBank: nil, 724 }, 725 } 726 for _, tc := range testCases { 727 err := suite.am.minusCoinFromAddress(suite.Ctx, tc.address, tc.amount) 728 suite.Equal( 729 tc.expectErr, err, 730 "%s: failed to minus coin from address %s, expect err %v, got %v", 731 tc.testName, tc.address, tc.expectErr, err) 732 if tc.expectBank != nil { 733 suite.checkBankKVByAddress(tc.testName, tc.address, tc.expectBank) 734 } 735 } 736 } 737 738 func (suite *AccountManagerTestSuite) TestMinusCoinFromUsername() { 739 userWithBalance := suite.userWithBalance 740 userWithoutBalance := suite.userWithoutBalance 741 unreg := suite.unreg 742 743 testCases := []struct { 744 testName string 745 username types.AccountKey 746 amount types.Coin 747 expectErr sdk.Error 748 expectBank *model.AccountBank 749 }{ 750 { 751 testName: "minus coin from user with sufficient balance", 752 username: userWithBalance.Username, 753 expectErr: nil, 754 amount: coin100, 755 expectBank: &model.AccountBank{ 756 Saving: suite.userWithBalanceSaving.Minus(coin100), 757 PubKey: userWithBalance.TransactionKey, 758 Username: userWithBalance.Username, 759 }, 760 }, 761 { 762 testName: "minus coin from user without sufficient balance", 763 username: userWithoutBalance.Username, 764 expectErr: acctypes.ErrAccountSavingCoinNotEnough(), 765 amount: coin1, 766 expectBank: &model.AccountBank{ 767 PubKey: userWithoutBalance.TransactionKey, 768 Saving: types.NewCoinFromInt64(0), 769 Username: userWithoutBalance.Username, 770 }, 771 }, 772 { 773 testName: "minus saving coin exceeds the coin user hold", 774 username: userWithBalance.Username, 775 expectErr: acctypes.ErrAccountSavingCoinNotEnough(), 776 amount: suite.userWithBalanceSaving, 777 expectBank: &model.AccountBank{ 778 Saving: suite.userWithBalanceSaving.Minus(coin100), 779 PubKey: userWithBalance.TransactionKey, 780 Username: userWithBalance.Username, 781 }, 782 }, 783 { 784 testName: "minus saving coin from unregister account", 785 username: unreg.Username, 786 expectErr: acctypes.ErrAccountNotFound(unreg.Username), 787 amount: coin1, 788 expectBank: nil, 789 }, 790 } 791 for _, tc := range testCases { 792 err := suite.am.minusCoinFromUsername(suite.Ctx, tc.username, tc.amount) 793 suite.Equal( 794 tc.expectErr, err, 795 "%s: failed to minus coin from user %s, expect err %v, got %v", 796 tc.testName, tc.username, tc.expectErr, err) 797 if tc.expectBank != nil { 798 suite.checkBankKVByUsername(tc.testName, tc.username, tc.expectBank) 799 } 800 } 801 } 802 803 func (suite *AccountManagerTestSuite) TestCreateAccount() { 804 userWithBalance := suite.userWithBalance 805 unreg := suite.unreg 806 807 txKeyWithEmptyAddress := secp256k1.GenPrivKey().PubKey() 808 signingKey := secp256k1.GenPrivKey().PubKey() 809 txKey := secp256k1.GenPrivKey().PubKey() 810 811 testCases := []struct { 812 testName string 813 username types.AccountKey 814 signingKey crypto.PubKey 815 txKey crypto.PubKey 816 expectErr sdk.Error 817 expectInfo *model.AccountInfo 818 expectBank *model.AccountBank 819 }{ 820 { 821 testName: "create account with registered username", 822 username: userWithBalance.Username, 823 signingKey: userWithBalance.SigningKey, 824 txKey: userWithBalance.TransactionKey, 825 expectErr: acctypes.ErrAccountAlreadyExists(userWithBalance.Username), 826 expectInfo: &userWithBalance, 827 expectBank: &model.AccountBank{ 828 Saving: suite.userWithBalanceSaving, 829 PubKey: userWithBalance.TransactionKey, 830 Username: userWithBalance.Username, 831 }, 832 }, 833 { 834 testName: "create account with bank linked to other username", 835 username: unreg.Username, 836 signingKey: unreg.SigningKey, 837 txKey: userWithBalance.TransactionKey, 838 expectErr: acctypes.ErrAddressAlreadyTaken(sdk.AccAddress(userWithBalance.TransactionKey.Address()).String()), 839 expectInfo: nil, 840 expectBank: &model.AccountBank{ 841 Saving: suite.userWithBalanceSaving, 842 PubKey: userWithBalance.TransactionKey, 843 Username: userWithBalance.Username, 844 }, 845 }, 846 { 847 testName: "create account with exist address", 848 username: unreg.Username, 849 signingKey: unreg.SigningKey, 850 txKey: unreg.TransactionKey, 851 expectErr: nil, 852 expectInfo: &unreg, 853 expectBank: &model.AccountBank{ 854 Saving: suite.unregSaving, 855 PubKey: unreg.TransactionKey, 856 Username: unreg.Username, 857 }, 858 }, 859 { 860 testName: "create account with empty address", 861 username: "test1", 862 signingKey: signingKey, 863 txKey: txKeyWithEmptyAddress, 864 expectErr: nil, 865 expectInfo: &model.AccountInfo{ 866 Username: "test1", 867 SigningKey: signingKey, 868 TransactionKey: txKeyWithEmptyAddress, 869 Address: sdk.AccAddress(txKeyWithEmptyAddress.Address()), 870 }, 871 expectBank: &model.AccountBank{ 872 Saving: types.NewCoinFromInt64(0), 873 PubKey: txKeyWithEmptyAddress, 874 Username: "test1", 875 }, 876 }, 877 { 878 testName: "create account without signing key", 879 username: "test2", 880 signingKey: nil, 881 txKey: txKey, 882 expectErr: nil, 883 expectInfo: &model.AccountInfo{ 884 Username: "test2", 885 TransactionKey: txKey, 886 Address: sdk.AccAddress(txKey.Address()), 887 }, 888 expectBank: &model.AccountBank{ 889 Saving: types.NewCoinFromInt64(0), 890 PubKey: txKey, 891 Username: "test2", 892 }, 893 }, 894 } 895 // normal test 896 for _, tc := range testCases { 897 err := suite.am.GenesisAccount(suite.Ctx, tc.username, tc.signingKey, tc.txKey) 898 suite.Equal( 899 tc.expectErr, err, 900 "%s: failed to create account for user %s, expect err %v, got %v", 901 tc.testName, tc.username, tc.expectErr, err) 902 if tc.expectBank != nil { 903 suite.checkBankKVByAddress(tc.testName, sdk.AccAddress(tc.txKey.Address()), tc.expectBank) 904 } 905 if tc.expectInfo != nil { 906 suite.checkInfoKVByUsername(tc.testName, tc.username, tc.expectInfo) 907 } 908 } 909 } 910 911 func TestUpdateJSONMeta(t *testing.T) { 912 ctx, am := setupTest(t, 1) 913 914 accKey := types.AccountKey("accKey") 915 createTestAccount(ctx, am, string(accKey)) 916 917 testCases := []struct { 918 testName string 919 username types.AccountKey 920 JSONMeta string 921 }{ 922 { 923 testName: "normal update", 924 username: accKey, 925 JSONMeta: "{'link':'https://lino.network'}", 926 }, 927 } 928 for _, tc := range testCases { 929 err := am.UpdateJSONMeta(ctx, tc.username, tc.JSONMeta) 930 if err != nil { 931 t.Errorf("%s: failed to update json meta, got err %v", tc.testName, err) 932 } 933 934 accMeta := am.storage.GetMeta(ctx, tc.username) 935 if tc.JSONMeta != accMeta.JSONMeta { 936 t.Errorf("%s: diff json meta, got %v, want %v", tc.testName, accMeta.JSONMeta, tc.JSONMeta) 937 } 938 } 939 } 940 941 func (suite *AccountManagerTestSuite) TestRegisterAccount() { 942 suite.am.storage.SetPool(suite.Ctx, &model.Pool{ 943 Name: types.InflationValidatorPool, 944 Balance: types.MustLinoToCoin("10000000000"), 945 }) 946 947 txPrivKeys := []crypto.PrivKey{secp256k1.GenPrivKey(), secp256k1.GenPrivKey()} 948 signingPrivKeys := []crypto.PrivKey{secp256k1.GenPrivKey(), secp256k1.GenPrivKey()} 949 950 testCases := []struct { 951 testName string 952 referrer types.AccOrAddr 953 registerFee types.Coin 954 username types.AccountKey 955 signingKey crypto.PubKey 956 txKey crypto.PubKey 957 expectErr sdk.Error 958 accInfo *model.AccountInfo 959 accBank *model.AccountBank 960 }{ 961 { 962 testName: "register username already exists", 963 referrer: types.NewAccOrAddrFromAcc(suite.userWithBalance.Username), 964 registerFee: suite.registerFee, 965 username: suite.userWithoutBalance.Username, 966 signingKey: secp256k1.GenPrivKey().PubKey(), 967 txKey: secp256k1.GenPrivKey().PubKey(), 968 expectErr: acctypes.ErrAccountAlreadyExists(suite.userWithoutBalance.Username), 969 accInfo: &suite.userWithoutBalance, 970 accBank: &model.AccountBank{ 971 Saving: types.NewCoinFromInt64(0), 972 Username: suite.userWithoutBalance.Username, 973 PubKey: suite.userWithoutBalance.TransactionKey, 974 }, 975 }, 976 { 977 testName: "register fee not enough", 978 referrer: types.NewAccOrAddrFromAcc(suite.userWithBalance.Username), 979 registerFee: suite.registerFee.Minus(types.NewCoinFromInt64(1)), 980 username: "test1", 981 signingKey: secp256k1.GenPrivKey().PubKey(), 982 txKey: secp256k1.GenPrivKey().PubKey(), 983 expectErr: acctypes.ErrRegisterFeeInsufficient(), 984 accInfo: nil, 985 accBank: nil, 986 }, 987 { 988 testName: "register success", 989 referrer: types.NewAccOrAddrFromAcc(suite.userWithBalance.Username), 990 registerFee: suite.registerFee, 991 username: "test1", 992 signingKey: signingPrivKeys[0].PubKey(), 993 txKey: txPrivKeys[0].PubKey(), 994 expectErr: nil, 995 accInfo: &model.AccountInfo{ 996 Username: "test1", 997 SigningKey: signingPrivKeys[0].PubKey(), 998 TransactionKey: txPrivKeys[0].PubKey(), 999 Address: sdk.AccAddress(txPrivKeys[0].PubKey().Address()), 1000 }, 1001 accBank: &model.AccountBank{ 1002 Saving: types.NewCoinFromInt64(0), 1003 Username: "test1", 1004 PubKey: txPrivKeys[0].PubKey(), 1005 }, 1006 }, 1007 { 1008 testName: "register with same transaction private key", 1009 referrer: types.NewAccOrAddrFromAcc(suite.userWithBalance.Username), 1010 registerFee: suite.registerFee, 1011 username: "test2", 1012 signingKey: signingPrivKeys[0].PubKey(), 1013 txKey: txPrivKeys[0].PubKey(), 1014 expectErr: acctypes.ErrAddressAlreadyTaken( 1015 sdk.AccAddress(txPrivKeys[0].PubKey().Address()).String()), 1016 accInfo: nil, 1017 accBank: nil, 1018 }, 1019 { 1020 testName: "referrer is address", 1021 referrer: types.NewAccOrAddrFromAddr( 1022 sdk.AccAddress(suite.userWithBalance.TransactionKey.Address())), 1023 registerFee: suite.registerFee, 1024 username: "test3", 1025 signingKey: signingPrivKeys[1].PubKey(), 1026 txKey: txPrivKeys[1].PubKey(), 1027 expectErr: nil, 1028 accInfo: &model.AccountInfo{ 1029 Username: "test3", 1030 SigningKey: signingPrivKeys[1].PubKey(), 1031 TransactionKey: txPrivKeys[1].PubKey(), 1032 Address: sdk.AccAddress(txPrivKeys[1].PubKey().Address()), 1033 }, 1034 accBank: &model.AccountBank{ 1035 Saving: types.NewCoinFromInt64(0), 1036 Username: "test3", 1037 PubKey: txPrivKeys[1].PubKey(), 1038 }, 1039 }, 1040 } 1041 for _, tc := range testCases { 1042 err := suite.am.RegisterAccount(suite.Ctx, tc.referrer, tc.registerFee, tc.username, tc.signingKey, tc.txKey) 1043 suite.Equal(tc.expectErr, err) 1044 bank, _ := suite.am.GetBank(suite.Ctx, tc.username) 1045 suite.Equal(tc.accBank, bank) 1046 info, _ := suite.am.GetInfo(suite.Ctx, tc.username) 1047 suite.Equal(tc.accInfo, info) 1048 } 1049 } 1050 1051 func (suite *AccountManagerTestSuite) TestMoveCoinAccOrAddr() { 1052 testCases := []struct { 1053 testName string 1054 sender types.AccOrAddr 1055 amount types.Coin 1056 receiver types.AccOrAddr 1057 expectErr sdk.Error 1058 expectSenderBalance types.Coin 1059 expectReceiverBalance types.Coin 1060 }{ 1061 { 1062 testName: "negative amount", 1063 sender: types.NewAccOrAddrFromAcc("movecointest"), 1064 receiver: types.NewAccOrAddrFromAcc(suite.userWithoutBalance.Username), 1065 amount: types.NewCoinFromInt64(-1), 1066 expectErr: acctypes.ErrNegativeMoveAmount(types.NewCoinFromInt64(-1)), 1067 expectSenderBalance: types.Coin{}, 1068 expectReceiverBalance: types.NewCoinFromInt64(0), 1069 }, 1070 { 1071 testName: "sender doesnt exist", 1072 sender: types.NewAccOrAddrFromAcc("movecointest"), 1073 receiver: types.NewAccOrAddrFromAcc(suite.userWithoutBalance.Username), 1074 amount: types.NewCoinFromInt64(1), 1075 expectErr: acctypes.ErrAccountNotFound("movecointest"), 1076 expectSenderBalance: types.Coin{}, 1077 expectReceiverBalance: types.NewCoinFromInt64(0), 1078 }, 1079 { 1080 testName: "receiver doesnt exist", 1081 sender: types.NewAccOrAddrFromAcc(suite.userWithBalance.Username), 1082 receiver: types.NewAccOrAddrFromAcc("movecointest"), 1083 amount: types.NewCoinFromInt64(1), 1084 expectErr: acctypes.ErrAccountNotFound("movecointest"), 1085 expectSenderBalance: suite.userWithBalanceSaving.Minus(types.NewCoinFromInt64(1)), 1086 expectReceiverBalance: types.Coin{}, 1087 }, 1088 { 1089 testName: "send from username to username", 1090 sender: types.NewAccOrAddrFromAcc(suite.userWithBalance.Username), 1091 receiver: types.NewAccOrAddrFromAcc(suite.userWithoutBalance.Username), 1092 amount: types.NewCoinFromInt64(1), 1093 expectErr: nil, 1094 expectSenderBalance: suite.userWithBalanceSaving.Minus(types.NewCoinFromInt64(2)), 1095 expectReceiverBalance: types.NewCoinFromInt64(1), 1096 }, 1097 { 1098 testName: "send from username to address", 1099 sender: types.NewAccOrAddrFromAcc(suite.userWithBalance.Username), 1100 receiver: types.NewAccOrAddrFromAddr( 1101 sdk.AccAddress(suite.userWithoutBalance.TransactionKey.Address())), 1102 amount: types.NewCoinFromInt64(1), 1103 expectErr: nil, 1104 expectSenderBalance: suite.userWithBalanceSaving.Minus(types.NewCoinFromInt64(3)), 1105 expectReceiverBalance: types.NewCoinFromInt64(2), 1106 }, 1107 { 1108 testName: "send from address to address", 1109 sender: types.NewAccOrAddrFromAddr( 1110 sdk.AccAddress(suite.userWithBalance.TransactionKey.Address())), 1111 receiver: types.NewAccOrAddrFromAddr( 1112 sdk.AccAddress(suite.userWithoutBalance.TransactionKey.Address())), 1113 amount: types.NewCoinFromInt64(1), 1114 expectErr: nil, 1115 expectSenderBalance: suite.userWithBalanceSaving.Minus(types.NewCoinFromInt64(4)), 1116 expectReceiverBalance: types.NewCoinFromInt64(3), 1117 }, 1118 { 1119 testName: "send from address to user", 1120 sender: types.NewAccOrAddrFromAddr( 1121 sdk.AccAddress(suite.userWithBalance.TransactionKey.Address())), 1122 receiver: types.NewAccOrAddrFromAcc(suite.userWithoutBalance.Username), 1123 amount: types.NewCoinFromInt64(1), 1124 expectErr: nil, 1125 expectSenderBalance: suite.userWithBalanceSaving.Minus(types.NewCoinFromInt64(5)), 1126 expectReceiverBalance: types.NewCoinFromInt64(4), 1127 }, 1128 } 1129 for _, tc := range testCases { 1130 err := suite.am.MoveCoin(suite.Ctx, tc.sender, tc.receiver, tc.amount) 1131 suite.Equal(tc.expectErr, err) 1132 if !tc.sender.IsAddr { 1133 saving, _ := suite.am.GetSavingFromUsername(suite.Ctx, tc.sender.AccountKey) 1134 suite.Equal(tc.expectSenderBalance, saving) 1135 } else { 1136 saving, _ := suite.am.GetSavingFromAddress(suite.Ctx, tc.sender.Addr) 1137 suite.Equal(tc.expectSenderBalance, saving) 1138 } 1139 if !tc.receiver.IsAddr { 1140 saving, _ := suite.am.GetSavingFromUsername(suite.Ctx, tc.receiver.AccountKey) 1141 suite.Equal(tc.expectReceiverBalance, saving) 1142 } else { 1143 saving, _ := suite.am.GetSavingFromAddress(suite.Ctx, tc.receiver.Addr) 1144 suite.Equal(tc.expectReceiverBalance, saving) 1145 } 1146 } 1147 } 1148 1149 func (suite *AccountManagerTestSuite) TestCheckSigningPubKeyOwnerByAddress() { 1150 txPrivKeys := []crypto.PrivKey{secp256k1.GenPrivKey(), secp256k1.GenPrivKey()} 1151 testCases := []struct { 1152 testName string 1153 address sdk.AccAddress 1154 signKey crypto.PubKey 1155 isPaid bool 1156 expectErr sdk.Error 1157 expectAccBank *model.AccountBank 1158 }{ 1159 { 1160 testName: "bank doesn't exist", 1161 address: sdk.AccAddress(txPrivKeys[0].PubKey().Address()), 1162 signKey: txPrivKeys[0].PubKey(), 1163 isPaid: false, 1164 expectErr: acctypes.ErrAccountBankNotFound( 1165 sdk.AccAddress(txPrivKeys[0].PubKey().Address())), 1166 expectAccBank: nil, 1167 }, 1168 { 1169 testName: "set bank to paid address", 1170 address: sdk.AccAddress(txPrivKeys[0].PubKey().Address()), 1171 signKey: txPrivKeys[0].PubKey(), 1172 isPaid: true, 1173 expectErr: nil, 1174 expectAccBank: &model.AccountBank{ 1175 Saving: types.NewCoinFromInt64(0), 1176 PubKey: txPrivKeys[0].PubKey(), 1177 }, 1178 }, 1179 { 1180 testName: "signing key mismatch", 1181 address: sdk.AccAddress(suite.unreg.TransactionKey.Address()), 1182 signKey: txPrivKeys[0].PubKey(), 1183 isPaid: false, 1184 expectErr: sdk.ErrInvalidPubKey( 1185 fmt.Sprintf("PubKey does not match Signer address %s", sdk.AccAddress(suite.unreg.TransactionKey.Address()))), 1186 expectAccBank: &model.AccountBank{ 1187 Saving: suite.unregSaving, 1188 }, 1189 }, 1190 { 1191 testName: "set public key to bank without public key info", 1192 address: sdk.AccAddress(suite.unreg.TransactionKey.Address()), 1193 signKey: suite.unreg.TransactionKey, 1194 isPaid: false, 1195 expectErr: nil, 1196 expectAccBank: &model.AccountBank{ 1197 PubKey: suite.unreg.TransactionKey, 1198 Saving: suite.unregSaving, 1199 }, 1200 }, 1201 { 1202 testName: "check public key from registered account", 1203 address: sdk.AccAddress(suite.userWithoutBalance.TransactionKey.Address()), 1204 signKey: suite.userWithoutBalance.TransactionKey, 1205 isPaid: false, 1206 expectErr: nil, 1207 expectAccBank: &model.AccountBank{ 1208 PubKey: suite.userWithoutBalance.TransactionKey, 1209 Saving: types.NewCoinFromInt64(0), 1210 Username: suite.userWithoutBalance.Username, 1211 }, 1212 }, 1213 } 1214 for _, tc := range testCases { 1215 err := suite.am.CheckSigningPubKeyOwnerByAddress(suite.Ctx, tc.address, tc.signKey, tc.isPaid) 1216 suite.Equal(tc.expectErr, err, "%s", tc.testName) 1217 1218 bank, _ := suite.am.storage.GetBank(suite.Ctx, tc.address) 1219 suite.Equal(tc.expectAccBank, bank, "%s", tc.testName) 1220 } 1221 } 1222 1223 func (suite *AccountManagerTestSuite) TestCheckSigningPubKeyOwner() { 1224 txPrivKeys := []crypto.PrivKey{secp256k1.GenPrivKey(), secp256k1.GenPrivKey()} 1225 1226 testCases := []struct { 1227 testName string 1228 username types.AccountKey 1229 signKey crypto.PubKey 1230 expectErr sdk.Error 1231 expectSigner types.AccountKey 1232 }{ 1233 { 1234 testName: "account info doesn't exist", 1235 username: suite.unreg.Username, 1236 signKey: txPrivKeys[0].PubKey(), 1237 expectErr: acctypes.ErrAccountNotFound(suite.unreg.Username), 1238 expectSigner: "", 1239 }, 1240 { 1241 testName: "public key mismatch", 1242 username: suite.userWithBalance.Username, 1243 signKey: txPrivKeys[0].PubKey(), 1244 expectErr: acctypes.ErrCheckAuthenticatePubKeyOwner(suite.userWithBalance.Username), 1245 expectSigner: "", 1246 }, 1247 { 1248 testName: "verify by signing key", 1249 username: suite.userWithBalance.Username, 1250 signKey: suite.userWithBalance.SigningKey, 1251 expectErr: nil, 1252 expectSigner: suite.userWithBalance.Username, 1253 }, 1254 { 1255 testName: "verify by transaction key", 1256 username: suite.userWithBalance.Username, 1257 signKey: suite.userWithBalance.SigningKey, 1258 expectErr: nil, 1259 expectSigner: suite.userWithBalance.Username, 1260 }, 1261 } 1262 for _, tc := range testCases { 1263 signer, err := suite.am.CheckSigningPubKeyOwner(suite.Ctx, tc.username, tc.signKey) 1264 suite.Equal(tc.expectErr, err) 1265 suite.Equal(tc.expectSigner, signer) 1266 } 1267 } 1268 1269 func TestIncreaseSequenceByOne(t *testing.T) { 1270 ctx, am := setupTest(t, 1) 1271 user1 := types.AccountKey("user1") 1272 1273 createTestAccount(ctx, am, string(user1)) 1274 1275 addr, err := am.GetAddress(ctx, user1) 1276 if err != nil { 1277 t.Errorf("TestIncreaseSequenceByOne: failed to get address, got err %v", err) 1278 } 1279 1280 testCases := []struct { 1281 testName string 1282 increaseTimes int 1283 expectSequence uint64 1284 }{ 1285 { 1286 testName: "increase seq once", 1287 increaseTimes: 1, 1288 expectSequence: 1, 1289 }, 1290 { 1291 testName: "increase seq 100 times", 1292 increaseTimes: 100, 1293 expectSequence: 101, 1294 }, 1295 } 1296 1297 for _, tc := range testCases { 1298 for i := 0; i < tc.increaseTimes; i++ { 1299 err = am.IncreaseSequenceByOne(ctx, addr) 1300 if err != nil { 1301 panic(err) 1302 } 1303 } 1304 seq, err := am.GetSequence(ctx, addr) 1305 if err != nil { 1306 t.Errorf("%s: failed to get sequence, got err %v", tc.testName, err) 1307 } 1308 if seq != tc.expectSequence { 1309 t.Errorf("%s: diff seq, got %v, want %v", tc.testName, seq, tc.expectSequence) 1310 } 1311 } 1312 } 1313 1314 func TestAddFrozenMoney(t *testing.T) { 1315 ctx, am := setupTest(t, 1) 1316 user1 := types.AccountKey("user1") 1317 1318 createTestAccount(ctx, am, string(user1)) 1319 addr, err := am.GetAddress(ctx, user1) 1320 if err != nil { 1321 t.Errorf("TestAddFrozenMoney: failed to get address, got err %v", err) 1322 } 1323 1324 testCases := []struct { 1325 testName string 1326 frozenAmount types.Coin 1327 startAt int64 1328 interval int64 1329 times int64 1330 expectNumOfFrozenAmount int 1331 }{ 1332 { 1333 testName: "add the first 100 frozen money", 1334 frozenAmount: types.NewCoinFromInt64(100), 1335 startAt: 1000000, 1336 interval: 10 * 3600, 1337 times: 5, 1338 expectNumOfFrozenAmount: 1, 1339 }, 1340 { 1341 testName: "add the second 100 frozen money, clear the first one", 1342 frozenAmount: types.NewCoinFromInt64(100), 1343 startAt: 1200000, 1344 interval: 10 * 3600, 1345 times: 5, 1346 expectNumOfFrozenAmount: 1, 1347 }, 1348 { 1349 testName: "add the third 100 frozen money", 1350 frozenAmount: types.NewCoinFromInt64(100), 1351 startAt: 1300000, 1352 interval: 10 * 3600, 1353 times: 5, 1354 expectNumOfFrozenAmount: 2, 1355 }, 1356 { 1357 testName: "add the fourth 100 frozen money, clear the second one", 1358 frozenAmount: types.NewCoinFromInt64(100), 1359 startAt: 1400000, 1360 interval: 10 * 3600, 1361 times: 5, 1362 expectNumOfFrozenAmount: 2, 1363 }, 1364 { 1365 testName: "add the fifth 100 frozen money, clear the third and fourth ones", 1366 frozenAmount: types.NewCoinFromInt64(100), 1367 startAt: 1600000, 1368 interval: 10 * 3600, 1369 times: 5, 1370 expectNumOfFrozenAmount: 1, 1371 }, // this one is used to re-produce the out-of-bound bug. 1372 } 1373 1374 for _, tc := range testCases { 1375 ctx = ctx.WithBlockHeader(abci.Header{ChainID: "Lino", Height: 1, Time: time.Unix(tc.startAt, 0)}) 1376 err := am.AddFrozenMoney(ctx, user1, tc.frozenAmount, tc.startAt, tc.interval, tc.times) 1377 if err != nil { 1378 t.Errorf("%s: failed to add frozen money, got err %v", tc.testName, err) 1379 } 1380 1381 accountBank, err := am.storage.GetBank(ctx, addr) 1382 if err != nil { 1383 t.Errorf("%s: failed to get bank, got err %v", tc.testName, err) 1384 } 1385 if len(accountBank.FrozenMoneyList) != tc.expectNumOfFrozenAmount { 1386 t.Errorf("%s: diff num of frozen money, got %v, want %v", tc.testName, len(accountBank.FrozenMoneyList), tc.expectNumOfFrozenAmount) 1387 } 1388 } 1389 } 1390 1391 func (suite *AccountManagerTestSuite) TestRecoverAccount() { 1392 txPrivKeys := []crypto.PrivKey{secp256k1.GenPrivKey()} 1393 err := suite.am.AddFrozenMoney(suite.Ctx, suite.userWithBalance.Username, types.NewCoinFromInt64(1), 0, 100, 10) 1394 suite.Nil(err) 1395 testCases := []struct { 1396 testName string 1397 username types.AccountKey 1398 newTxPubKey crypto.PubKey 1399 newSigningPubKey crypto.PubKey 1400 expectErr sdk.Error 1401 oldAddr sdk.AccAddress 1402 expectOldBank *model.AccountBank 1403 expectNewBank *model.AccountBank 1404 expectInfo *model.AccountInfo 1405 }{ 1406 { 1407 testName: "username doesn't exist", 1408 username: suite.unreg.Username, 1409 newTxPubKey: secp256k1.GenPrivKey().PubKey(), 1410 newSigningPubKey: nil, 1411 expectErr: acctypes.ErrAccountNotFound(suite.unreg.Username), 1412 oldAddr: sdk.AccAddress(suite.unreg.TransactionKey.Address()), 1413 expectOldBank: &model.AccountBank{ 1414 Saving: suite.unregSaving, 1415 }, 1416 expectNewBank: nil, 1417 expectInfo: nil, 1418 }, 1419 { 1420 testName: "new bank linked to other account", 1421 username: suite.userWithoutBalance.Username, 1422 newTxPubKey: suite.userWithBalance.TransactionKey, 1423 newSigningPubKey: nil, 1424 expectErr: acctypes.ErrAddressAlreadyTaken( 1425 sdk.AccAddress(suite.userWithBalance.TransactionKey.Address()).String()), 1426 oldAddr: sdk.AccAddress(suite.userWithoutBalance.TransactionKey.Address()), 1427 expectOldBank: &model.AccountBank{ 1428 Username: suite.userWithoutBalance.Username, 1429 PubKey: suite.userWithoutBalance.TransactionKey, 1430 Saving: types.NewCoinFromInt64(0), 1431 }, 1432 expectNewBank: &model.AccountBank{ 1433 Username: suite.userWithBalance.Username, 1434 PubKey: suite.userWithBalance.TransactionKey, 1435 Saving: suite.userWithBalanceSaving, 1436 FrozenMoneyList: []model.FrozenMoney{ 1437 { 1438 Amount: types.NewCoinFromInt64(1), 1439 StartAt: 0, 1440 Interval: 100, 1441 Times: 10, 1442 }, 1443 }, 1444 }, 1445 expectInfo: &suite.userWithoutBalance, 1446 }, 1447 { 1448 testName: "recover to empty address", 1449 username: suite.userWithoutBalance.Username, 1450 newTxPubKey: txPrivKeys[0].PubKey(), 1451 newSigningPubKey: nil, 1452 expectErr: nil, 1453 oldAddr: sdk.AccAddress(suite.userWithoutBalance.TransactionKey.Address()), 1454 expectOldBank: &model.AccountBank{ 1455 PubKey: suite.userWithoutBalance.TransactionKey, 1456 Saving: types.NewCoinFromInt64(0), 1457 }, 1458 expectNewBank: &model.AccountBank{ 1459 Username: suite.userWithoutBalance.Username, 1460 PubKey: txPrivKeys[0].PubKey(), 1461 Saving: types.NewCoinFromInt64(0), 1462 }, 1463 expectInfo: &model.AccountInfo{ 1464 Username: suite.userWithoutBalance.Username, 1465 TransactionKey: txPrivKeys[0].PubKey(), 1466 SigningKey: nil, 1467 Address: sdk.AccAddress(txPrivKeys[0].PubKey().Address()), 1468 }, 1469 }, 1470 { 1471 testName: "recover to non empty address", 1472 username: suite.userWithBalance.Username, 1473 newTxPubKey: suite.unreg.TransactionKey, 1474 newSigningPubKey: nil, 1475 expectErr: nil, 1476 oldAddr: sdk.AccAddress(suite.userWithBalance.TransactionKey.Address()), 1477 expectOldBank: &model.AccountBank{ 1478 PubKey: suite.userWithBalance.TransactionKey, 1479 Saving: types.NewCoinFromInt64(0), 1480 }, 1481 expectNewBank: &model.AccountBank{ 1482 Username: suite.userWithBalance.Username, 1483 PubKey: suite.unreg.TransactionKey, 1484 Saving: suite.unregSaving.Plus(suite.userWithBalanceSaving), 1485 FrozenMoneyList: []model.FrozenMoney{ 1486 { 1487 Amount: types.NewCoinFromInt64(1), 1488 StartAt: 0, 1489 Interval: 100, 1490 Times: 10, 1491 }, 1492 }, 1493 }, 1494 expectInfo: &model.AccountInfo{ 1495 Username: suite.userWithBalance.Username, 1496 TransactionKey: suite.unreg.TransactionKey, 1497 SigningKey: nil, 1498 Address: sdk.AccAddress(suite.unreg.TransactionKey.Address()), 1499 }, 1500 }, 1501 } 1502 for _, tc := range testCases { 1503 err := suite.am.RecoverAccount(suite.Ctx, tc.username, tc.newTxPubKey, tc.newSigningPubKey) 1504 suite.Equal(tc.expectErr, err, "%s", tc.testName) 1505 oldBank, _ := suite.am.GetBankByAddress(suite.Ctx, tc.oldAddr) 1506 suite.Equal(tc.expectOldBank, oldBank, "%s", tc.testName) 1507 newBank, _ := suite.am.GetBankByAddress(suite.Ctx, sdk.AccAddress(tc.newTxPubKey.Address())) 1508 suite.Equal(tc.expectNewBank, newBank, "%s", tc.testName) 1509 info, _ := suite.am.GetInfo(suite.Ctx, tc.username) 1510 suite.Equal(tc.expectInfo, info, "%s", tc.testName) 1511 } 1512 } 1513 1514 func (suite *AccountManagerTestSuite) checkInfoKVByUsername(testName string, username types.AccountKey, info *model.AccountInfo) { 1515 infoPtr, err := suite.am.storage.GetInfo(suite.Ctx, username) 1516 suite.Nil(err, "%s, failed to get info, got err %v", testName, err) 1517 suite.Equal(info, infoPtr, "%s: diff info, got %v, want %v", testName, *infoPtr, info) 1518 } 1519 1520 func (suite *AccountManagerTestSuite) checkBankKVByAddress(testName string, address sdk.AccAddress, bank *model.AccountBank) { 1521 bankPtr, err := suite.am.storage.GetBank(suite.Ctx, address) 1522 suite.Nil(err, "%s, failed to get account bank, got err %v", testName, err) 1523 suite.Equal(bank, bankPtr, "%s: diff bank, got %v, want %v", testName, *bankPtr, bank) 1524 } 1525 1526 func (suite *AccountManagerTestSuite) checkBankKVByUsername(testName string, username types.AccountKey, bank *model.AccountBank) { 1527 info, err := suite.am.storage.GetInfo(suite.Ctx, username) 1528 suite.Nil(err, "%s, failed to get info, got err %v", testName, err) 1529 suite.checkBankKVByAddress(testName, info.Address, bank) 1530 } 1531 1532 func (suite *AccountManagerTestSuite) TestImportExport() { 1533 // background data 1534 suite.NextBlock(time.Unix(123, 0)) 1535 am := suite.am 1536 ctx := suite.Ctx 1537 total := linotypes.NewCoinFromInt64(2000000) 1538 am.InitGenesis(ctx, total, []model.Pool{ 1539 { 1540 Name: linotypes.InflationValidatorPool, 1541 Balance: linotypes.NewCoinFromInt64(123), 1542 }, 1543 { 1544 Name: linotypes.AccountVestingPool, 1545 Balance: linotypes.NewCoinFromInt64(1000000), 1546 }, 1547 }) 1548 err := am.UpdateJSONMeta(ctx, suite.userWithoutBalance.Username, `{"key":"value"}`) 1549 suite.Nil(err) 1550 1551 cdc := wire.New() 1552 wire.RegisterCrypto(cdc) 1553 1554 dir, err2 := ioutil.TempDir("", "test") 1555 suite.Require().Nil(err2) 1556 defer os.RemoveAll(dir) // clean up 1557 1558 tmpfn := filepath.Join(dir, "tmpfile") 1559 err2 = suite.am.ExportToFile(suite.Ctx, cdc, tmpfn) 1560 suite.Nil(err2) 1561 1562 // reset state 1563 suite.SetupCtx(0, time.Unix(0, 0), kvStoreKey) 1564 suite.ph = ¶m.ParamKeeper{} 1565 suite.am = NewAccountManager(kvStoreKey, suite.ph) 1566 err2 = suite.am.ImportFromFile(suite.Ctx, cdc, tmpfn) 1567 suite.Nil(err2) 1568 1569 suite.Golden() 1570 } 1571 1572 // cdc := wire.New() 1573 // wire.RegisterCrypto(cdc) 1574 // keys := make([]crypto.PubKey, 0) 1575 // for i := 0 ; i < 10; i++ { 1576 // keys = append(keys, secp256k1.GenPrivKey().PubKey()) 1577 // } 1578 // fmt.Print(string(cdc.MustMarshalJSON(keys))) 1579 func sampleKeys() []crypto.PubKey { 1580 json := ` 1581 [{"type":"tendermint/PubKeySecp256k1","value":"Aot3u5m7vuxUOszkS6IZW5XYVu6ATvZsfSQIjtQo9tML"},{"type":"tendermint/PubKeySecp256k1","value":"AoFqbXKmblwKVggqb8Cqo30gRKs9EfqwhOhuyOKlGCuD"},{"type":"tendermint/PubKeySecp256k1","value":"Aj/1EOLKUKUPhp+mx3fLNoZOEEsY+tjPeTW4nOPbqwwq"},{"type":"tendermint/PubKeySecp256k1","value":"A1SxTVyDiXljmHeimniCQiNZQ3dcDsgppP0gDCMgJtdp"},{"type":"tendermint/PubKeySecp256k1","value":"Ax8b6HzTh9el9/NfE8fI4awCvMZWGQkjl+rYOGWeGJc9"},{"type":"tendermint/PubKeySecp256k1","value":"A4r+RjYEc2V9p43J4CovoktRTXNY9vvcQbx0aOW9bhoq"},{"type":"tendermint/PubKeySecp256k1","value":"AwFSpofxlQGAQv167WveHyeUvTh/3fukkJU7gkEW+iMm"},{"type":"tendermint/PubKeySecp256k1","value":"AjglddkWGGlMZck7uvWMDCtyqpNWSBy9HmnJV9vPnu2k"},{"type":"tendermint/PubKeySecp256k1","value":"A+KW7obJ0BpKqUWmY33svTBxGdTfRhmOym7A5imWWwGm"},{"type":"tendermint/PubKeySecp256k1","value":"A6P8IUdt9DKrYCe3/Tflt7DBdgFokRcCKkixt+UbhjZ8"}] 1582 ` 1583 1584 keys := make([]crypto.PubKey, 0) 1585 cdc := wire.New() 1586 wire.RegisterCrypto(cdc) 1587 cdc.MustUnmarshalJSON([]byte(json), &keys) 1588 return keys 1589 }