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 = &param.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(&parammodel.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  		&parammodel.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 = &param.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  }