github.com/Finschia/finschia-sdk@v0.48.1/x/bank/app_test.go (about)

     1  package bank_test
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/stretchr/testify/require"
     7  	tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
     8  
     9  	"github.com/Finschia/finschia-sdk/crypto/keys/secp256k1"
    10  	cryptotypes "github.com/Finschia/finschia-sdk/crypto/types"
    11  	"github.com/Finschia/finschia-sdk/simapp"
    12  	sdk "github.com/Finschia/finschia-sdk/types"
    13  	authtypes "github.com/Finschia/finschia-sdk/x/auth/types"
    14  	"github.com/Finschia/finschia-sdk/x/bank/types"
    15  )
    16  
    17  type (
    18  	expectedBalance struct {
    19  		addr  sdk.AccAddress
    20  		coins sdk.Coins
    21  	}
    22  
    23  	appTestCase struct {
    24  		desc             string
    25  		expSimPass       bool
    26  		expPass          bool
    27  		msgs             []sdk.Msg
    28  		accNums          []uint64
    29  		accSeqs          []uint64
    30  		privKeys         []cryptotypes.PrivKey
    31  		expectedBalances []expectedBalance
    32  	}
    33  )
    34  
    35  var (
    36  	priv1 = secp256k1.GenPrivKey()
    37  	addr1 = sdk.AccAddress(priv1.PubKey().Address())
    38  	priv2 = secp256k1.GenPrivKey()
    39  	addr2 = sdk.AccAddress(priv2.PubKey().Address())
    40  	addr3 = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address())
    41  	priv4 = secp256k1.GenPrivKey()
    42  	addr4 = sdk.AccAddress(priv4.PubKey().Address())
    43  
    44  	coins     = sdk.Coins{sdk.NewInt64Coin("foocoin", 10)}
    45  	halfCoins = sdk.Coins{sdk.NewInt64Coin("foocoin", 5)}
    46  
    47  	sendMsg1 = types.NewMsgSend(addr1, addr2, coins)
    48  
    49  	multiSendMsg1 = &types.MsgMultiSend{
    50  		Inputs:  []types.Input{types.NewInput(addr1, coins)},
    51  		Outputs: []types.Output{types.NewOutput(addr2, coins)},
    52  	}
    53  	multiSendMsg2 = &types.MsgMultiSend{
    54  		Inputs: []types.Input{types.NewInput(addr1, coins)},
    55  		Outputs: []types.Output{
    56  			types.NewOutput(addr2, halfCoins),
    57  			types.NewOutput(addr3, halfCoins),
    58  		},
    59  	}
    60  	multiSendMsg3 = &types.MsgMultiSend{
    61  		Inputs: []types.Input{
    62  			types.NewInput(addr1, coins),
    63  			types.NewInput(addr4, coins),
    64  		},
    65  		Outputs: []types.Output{
    66  			types.NewOutput(addr2, coins),
    67  			types.NewOutput(addr3, coins),
    68  		},
    69  	}
    70  	multiSendMsg4 = &types.MsgMultiSend{
    71  		Inputs: []types.Input{
    72  			types.NewInput(addr2, coins),
    73  		},
    74  		Outputs: []types.Output{
    75  			types.NewOutput(addr1, coins),
    76  		},
    77  	}
    78  	multiSendMsg5 = &types.MsgMultiSend{
    79  		Inputs: []types.Input{
    80  			types.NewInput(addr1, coins),
    81  		},
    82  		Outputs: []types.Output{
    83  			types.NewOutput(moduleAccAddr, coins),
    84  		},
    85  	}
    86  )
    87  
    88  func TestSendNotEnoughBalance(t *testing.T) {
    89  	acc := &authtypes.BaseAccount{
    90  		Address: addr1.String(),
    91  	}
    92  
    93  	genAccs := []authtypes.GenesisAccount{acc}
    94  	app := simapp.SetupWithGenesisAccounts(genAccs)
    95  	ctx := app.BaseApp.NewContext(false, tmproto.Header{})
    96  
    97  	require.NoError(t, simapp.FundAccount(app, ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 67))))
    98  
    99  	app.Commit()
   100  
   101  	res1 := app.AccountKeeper.GetAccount(ctx, addr1)
   102  	require.NotNil(t, res1)
   103  	require.Equal(t, acc, res1.(*authtypes.BaseAccount))
   104  
   105  	origAccNum := res1.GetAccountNumber()
   106  	origSeq := res1.GetSequence()
   107  
   108  	sendMsg := types.NewMsgSend(addr1, addr2, sdk.Coins{sdk.NewInt64Coin("foocoin", 100)})
   109  	header := tmproto.Header{Height: app.LastBlockHeight() + 1}
   110  	txGen := simapp.MakeTestEncodingConfig().TxConfig
   111  	_, _, err := simapp.SignCheckDeliver(t, txGen, app.BaseApp, header, []sdk.Msg{sendMsg}, "", []uint64{origAccNum}, []uint64{origSeq}, false, false, priv1)
   112  	require.Error(t, err)
   113  
   114  	simapp.CheckBalance(t, app, addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 67)})
   115  
   116  	res2 := app.AccountKeeper.GetAccount(app.NewContext(true, tmproto.Header{}), addr1)
   117  	require.NotNil(t, res2)
   118  
   119  	require.Equal(t, res2.GetAccountNumber(), origAccNum)
   120  	require.Equal(t, res2.GetSequence(), origSeq+1)
   121  }
   122  
   123  func TestMsgMultiSendWithAccounts(t *testing.T) {
   124  	acc := &authtypes.BaseAccount{
   125  		Address: addr1.String(),
   126  	}
   127  
   128  	genAccs := []authtypes.GenesisAccount{acc}
   129  	app := simapp.SetupWithGenesisAccounts(genAccs)
   130  	ctx := app.BaseApp.NewContext(false, tmproto.Header{})
   131  
   132  	require.NoError(t, simapp.FundAccount(app, ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 67))))
   133  
   134  	app.Commit()
   135  
   136  	res1 := app.AccountKeeper.GetAccount(ctx, addr1)
   137  	require.NotNil(t, res1)
   138  	require.Equal(t, acc, res1.(*authtypes.BaseAccount))
   139  
   140  	testCases := []appTestCase{
   141  		{
   142  			desc:       "make a valid tx",
   143  			msgs:       []sdk.Msg{multiSendMsg1},
   144  			accNums:    []uint64{0},
   145  			accSeqs:    []uint64{0},
   146  			expSimPass: true,
   147  			expPass:    true,
   148  			privKeys:   []cryptotypes.PrivKey{priv1},
   149  			expectedBalances: []expectedBalance{
   150  				{addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 57)}},
   151  				{addr2, sdk.Coins{sdk.NewInt64Coin("foocoin", 10)}},
   152  			},
   153  		},
   154  		{
   155  			desc:       "wrong accNum should pass Simulate, but not Deliver",
   156  			msgs:       []sdk.Msg{multiSendMsg1, multiSendMsg2},
   157  			accNums:    []uint64{1}, // wrong account number
   158  			accSeqs:    []uint64{1},
   159  			expSimPass: true, // doesn't check signature
   160  			expPass:    false,
   161  			privKeys:   []cryptotypes.PrivKey{priv1},
   162  		},
   163  		{
   164  			desc:       "wrong accSeq should not pass Simulate",
   165  			msgs:       []sdk.Msg{multiSendMsg5},
   166  			accNums:    []uint64{0},
   167  			accSeqs:    []uint64{0}, // wrong account sequence
   168  			expSimPass: false,
   169  			expPass:    false,
   170  			privKeys:   []cryptotypes.PrivKey{priv1},
   171  		},
   172  	}
   173  
   174  	for _, tc := range testCases {
   175  		header := tmproto.Header{Height: app.LastBlockHeight() + 1}
   176  		txGen := simapp.MakeTestEncodingConfig().TxConfig
   177  		_, _, err := simapp.SignCheckDeliver(t, txGen, app.BaseApp, header, tc.msgs, "", tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...)
   178  		if tc.expPass {
   179  			require.NoError(t, err)
   180  		} else {
   181  			require.Error(t, err)
   182  		}
   183  
   184  		for _, eb := range tc.expectedBalances {
   185  			simapp.CheckBalance(t, app, eb.addr, eb.coins)
   186  		}
   187  	}
   188  }
   189  
   190  func TestMsgMultiSendMultipleOut(t *testing.T) {
   191  	acc1 := &authtypes.BaseAccount{
   192  		Address: addr1.String(),
   193  	}
   194  	acc2 := &authtypes.BaseAccount{
   195  		Address: addr2.String(),
   196  	}
   197  
   198  	genAccs := []authtypes.GenesisAccount{acc1, acc2}
   199  	app := simapp.SetupWithGenesisAccounts(genAccs)
   200  	ctx := app.BaseApp.NewContext(false, tmproto.Header{})
   201  
   202  	require.NoError(t, simapp.FundAccount(app, ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))))
   203  
   204  	require.NoError(t, simapp.FundAccount(app, ctx, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))))
   205  
   206  	app.Commit()
   207  
   208  	testCases := []appTestCase{
   209  		{
   210  			msgs:       []sdk.Msg{multiSendMsg2},
   211  			accNums:    []uint64{0},
   212  			accSeqs:    []uint64{0},
   213  			expSimPass: true,
   214  			expPass:    true,
   215  			privKeys:   []cryptotypes.PrivKey{priv1},
   216  			expectedBalances: []expectedBalance{
   217  				{addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 32)}},
   218  				{addr2, sdk.Coins{sdk.NewInt64Coin("foocoin", 47)}},
   219  				{addr3, sdk.Coins{sdk.NewInt64Coin("foocoin", 5)}},
   220  			},
   221  		},
   222  	}
   223  
   224  	for _, tc := range testCases {
   225  		header := tmproto.Header{Height: app.LastBlockHeight() + 1}
   226  		txGen := simapp.MakeTestEncodingConfig().TxConfig
   227  		_, _, err := simapp.SignCheckDeliver(t, txGen, app.BaseApp, header, tc.msgs, "", tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...)
   228  		require.NoError(t, err)
   229  
   230  		for _, eb := range tc.expectedBalances {
   231  			simapp.CheckBalance(t, app, eb.addr, eb.coins)
   232  		}
   233  	}
   234  }
   235  
   236  func TestMsgMultiSendMultipleInOut(t *testing.T) {
   237  	acc1 := &authtypes.BaseAccount{
   238  		Address: addr1.String(),
   239  	}
   240  	acc2 := &authtypes.BaseAccount{
   241  		Address: addr2.String(),
   242  	}
   243  	acc4 := &authtypes.BaseAccount{
   244  		Address: addr4.String(),
   245  	}
   246  
   247  	genAccs := []authtypes.GenesisAccount{acc1, acc2, acc4}
   248  	app := simapp.SetupWithGenesisAccounts(genAccs)
   249  	ctx := app.BaseApp.NewContext(false, tmproto.Header{})
   250  
   251  	require.NoError(t, simapp.FundAccount(app, ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))))
   252  
   253  	require.NoError(t, simapp.FundAccount(app, ctx, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))))
   254  
   255  	require.NoError(t, simapp.FundAccount(app, ctx, addr4, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))))
   256  
   257  	app.Commit()
   258  
   259  	testCases := []appTestCase{
   260  		{
   261  			msgs:       []sdk.Msg{multiSendMsg3},
   262  			accNums:    []uint64{0, 2},
   263  			accSeqs:    []uint64{0, 0},
   264  			expSimPass: true,
   265  			expPass:    true,
   266  			privKeys:   []cryptotypes.PrivKey{priv1, priv4},
   267  			expectedBalances: []expectedBalance{
   268  				{addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 32)}},
   269  				{addr4, sdk.Coins{sdk.NewInt64Coin("foocoin", 32)}},
   270  				{addr2, sdk.Coins{sdk.NewInt64Coin("foocoin", 52)}},
   271  				{addr3, sdk.Coins{sdk.NewInt64Coin("foocoin", 10)}},
   272  			},
   273  		},
   274  	}
   275  
   276  	for _, tc := range testCases {
   277  		header := tmproto.Header{Height: app.LastBlockHeight() + 1}
   278  		txGen := simapp.MakeTestEncodingConfig().TxConfig
   279  		_, _, err := simapp.SignCheckDeliver(t, txGen, app.BaseApp, header, tc.msgs, "", tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...)
   280  		require.NoError(t, err)
   281  
   282  		for _, eb := range tc.expectedBalances {
   283  			simapp.CheckBalance(t, app, eb.addr, eb.coins)
   284  		}
   285  	}
   286  }
   287  
   288  func TestMsgMultiSendDependent(t *testing.T) {
   289  	acc1 := authtypes.NewBaseAccountWithAddress(addr1)
   290  	acc2 := authtypes.NewBaseAccountWithAddress(addr2)
   291  	err := acc2.SetAccountNumber(1)
   292  	require.NoError(t, err)
   293  
   294  	genAccs := []authtypes.GenesisAccount{acc1, acc2}
   295  	app := simapp.SetupWithGenesisAccounts(genAccs)
   296  	ctx := app.BaseApp.NewContext(false, tmproto.Header{})
   297  
   298  	require.NoError(t, simapp.FundAccount(app, ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))))
   299  
   300  	app.Commit()
   301  
   302  	testCases := []appTestCase{
   303  		{
   304  			msgs:       []sdk.Msg{multiSendMsg1},
   305  			accNums:    []uint64{0},
   306  			accSeqs:    []uint64{0},
   307  			expSimPass: true,
   308  			expPass:    true,
   309  			privKeys:   []cryptotypes.PrivKey{priv1},
   310  			expectedBalances: []expectedBalance{
   311  				{addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 32)}},
   312  				{addr2, sdk.Coins{sdk.NewInt64Coin("foocoin", 10)}},
   313  			},
   314  		},
   315  		{
   316  			msgs:       []sdk.Msg{multiSendMsg4},
   317  			accNums:    []uint64{1},
   318  			accSeqs:    []uint64{0},
   319  			expSimPass: true,
   320  			expPass:    true,
   321  			privKeys:   []cryptotypes.PrivKey{priv2},
   322  			expectedBalances: []expectedBalance{
   323  				{addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 42)}},
   324  			},
   325  		},
   326  	}
   327  
   328  	for _, tc := range testCases {
   329  		header := tmproto.Header{Height: app.LastBlockHeight() + 1}
   330  		txGen := simapp.MakeTestEncodingConfig().TxConfig
   331  		_, _, err := simapp.SignCheckDeliver(t, txGen, app.BaseApp, header, tc.msgs, "", tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...)
   332  		require.NoError(t, err)
   333  
   334  		for _, eb := range tc.expectedBalances {
   335  			simapp.CheckBalance(t, app, eb.addr, eb.coins)
   336  		}
   337  	}
   338  }