From a7557b1d1029fcf9c112f3dc0cf94d158e197bc7 Mon Sep 17 00:00:00 2001 From: Jayden Lee <41176085+tkxkd0159@users.noreply.github.com> Date: Mon, 6 Feb 2023 12:04:16 +0900 Subject: [PATCH] feat!: add MultiSend deactivation (#876) * feat!: add MultiSend deactivation * add CHANGELOG * emit error instead of panic --- CHANGELOG.md | 2 + simapp/app.go | 2 +- x/bankplus/keeper/inactive_test.go | 2 +- x/bankplus/keeper/keeper.go | 36 +++++++++---- x/bankplus/keeper/keeper_test.go | 84 ++++++++++++++++++++++++++++-- 5 files changed, 109 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 745a40b75f..653a2b36ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -61,6 +61,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Breaking Changes * (rest) [\#807](https://github.com/line/lbm-sdk/pull/807) remove legacy REST API * (codec) [\#833](https://github.com/line/lbm-sdk/pull/833) Fix foundation amino codec +* (x/bank) [\#876](https://github.com/line/lbm-sdk/pull/876) Add `MultiSend` deactivation + ### Build, CI * (ci) [\#829](https://github.com/line/lbm-sdk/pull/829) automate release process diff --git a/simapp/app.go b/simapp/app.go index a72f2509ff..0813f09620 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -289,7 +289,7 @@ func NewSimApp( appCodec, keys[authtypes.StoreKey], app.GetSubspace(authtypes.ModuleName), authtypes.ProtoBaseAccount, maccPerms, ) app.BankKeeper = bankpluskeeper.NewBaseKeeper( - appCodec, keys[banktypes.StoreKey], app.AccountKeeper, app.GetSubspace(banktypes.ModuleName), app.BlockedAddrs()) + appCodec, keys[banktypes.StoreKey], app.AccountKeeper, app.GetSubspace(banktypes.ModuleName), app.BlockedAddrs(), false) stakingKeeper := stakingkeeper.NewKeeper( appCodec, keys[stakingtypes.StoreKey], app.AccountKeeper, app.BankKeeper, app.GetSubspace(stakingtypes.ModuleName), ) diff --git a/x/bankplus/keeper/inactive_test.go b/x/bankplus/keeper/inactive_test.go index 684e466cc1..aa0a4a5f47 100644 --- a/x/bankplus/keeper/inactive_test.go +++ b/x/bankplus/keeper/inactive_test.go @@ -36,7 +36,7 @@ func setupKeeper(storeKey *sdk.KVStoreKey) BaseKeeper { accountKeeper := accountkeeper.NewAccountKeeper(cdc, accountStoreKey, accountSubspace, accounttypes.ProtoBaseAccount, nil) bankSubspace := paramtypes.NewSubspace(cdc, amino, storeKey, testTransientStoreKey, banktypes.StoreKey) - return NewBaseKeeper(cdc, storeKey, accountKeeper, bankSubspace, nil) + return NewBaseKeeper(cdc, storeKey, accountKeeper, bankSubspace, nil, false) } func setupContext(t *testing.T, storeKey *sdk.KVStoreKey) sdk.Context { diff --git a/x/bankplus/keeper/keeper.go b/x/bankplus/keeper/keeper.go index 2261c319e4..9165af91cf 100644 --- a/x/bankplus/keeper/keeper.go +++ b/x/bankplus/keeper/keeper.go @@ -24,22 +24,24 @@ type Keeper interface { type BaseKeeper struct { bankkeeper.BaseKeeper - ak types.AccountKeeper - cdc codec.Codec - storeKey sdk.StoreKey - inactiveAddrs map[string]bool + ak types.AccountKeeper + cdc codec.Codec + storeKey sdk.StoreKey + inactiveAddrs map[string]bool + deactMultiSend bool } func NewBaseKeeper( cdc codec.Codec, storeKey sdk.StoreKey, ak types.AccountKeeper, paramSpace paramtypes.Subspace, - blockedAddr map[string]bool, + blockedAddr map[string]bool, deactMultiSend bool, ) BaseKeeper { return BaseKeeper{ - BaseKeeper: bankkeeper.NewBaseKeeper(cdc, storeKey, ak, paramSpace, blockedAddr), - ak: ak, - cdc: cdc, - storeKey: storeKey, - inactiveAddrs: map[string]bool{}, + BaseKeeper: bankkeeper.NewBaseKeeper(cdc, storeKey, ak, paramSpace, blockedAddr), + ak: ak, + cdc: cdc, + storeKey: storeKey, + inactiveAddrs: map[string]bool{}, + deactMultiSend: deactMultiSend, } } @@ -133,3 +135,17 @@ func (keeper BaseKeeper) DeleteFromInactiveAddr(ctx sdk.Context, address sdk.Acc func (keeper BaseKeeper) IsInactiveAddr(address sdk.AccAddress) bool { return keeper.inactiveAddrs[address.String()] } + +func (keeper BaseKeeper) InputOutputCoins(ctx sdk.Context, inputs []types.Input, outputs []types.Output) error { + if keeper.deactMultiSend { + return sdkerrors.ErrNotSupported.Wrap("MultiSend was deactivated") + } + + for _, out := range outputs { + if keeper.inactiveAddrs[out.Address] { + return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "%s is not allowed to receive funds", out.Address) + } + } + + return keeper.BaseSendKeeper.InputOutputCoins(ctx, inputs, outputs) +} diff --git a/x/bankplus/keeper/keeper_test.go b/x/bankplus/keeper/keeper_test.go index 0fbb290567..2d273ee69d 100644 --- a/x/bankplus/keeper/keeper_test.go +++ b/x/bankplus/keeper/keeper_test.go @@ -63,7 +63,7 @@ func (suite *IntegrationTestSuite) TestSupply_SendCoins() { ) keeper := bankpluskeeper.NewBaseKeeper( appCodec, app.GetKey(types.StoreKey), authKeeper, - app.GetSubspace(types.ModuleName), make(map[string]bool), + app.GetSubspace(types.ModuleName), make(map[string]bool), false, ) baseAcc := authKeeper.NewAccountWithAddress(ctx, authtypes.NewModuleAddress("baseAcc")) @@ -134,7 +134,7 @@ func (suite *IntegrationTestSuite) TestInactiveAddrOfSendCoins() { keeper := bankpluskeeper.NewBaseKeeper( appCodec, app.GetKey(types.StoreKey), authKeeper, - app.GetSubspace(types.ModuleName), make(map[string]bool), + app.GetSubspace(types.ModuleName), make(map[string]bool), false, ) // set initial balances @@ -186,7 +186,7 @@ func (suite *IntegrationTestSuite) TestInitializeBankPlus() { { keeper := bankpluskeeper.NewBaseKeeper( appCodec, app.GetKey(types.StoreKey), authKeeper, - app.GetSubspace(types.ModuleName), make(map[string]bool), + app.GetSubspace(types.ModuleName), make(map[string]bool), false, ) // add blocked address @@ -197,7 +197,7 @@ func (suite *IntegrationTestSuite) TestInitializeBankPlus() { { keeper := bankpluskeeper.NewBaseKeeper( appCodec, app.GetKey(types.StoreKey), authKeeper, - app.GetSubspace(types.ModuleName), make(map[string]bool), + app.GetSubspace(types.ModuleName), make(map[string]bool), false, ) keeper.InitializeBankPlus(ctx) suite.Require().True(keeper.IsInactiveAddr(blockedAcc.GetAddress())) @@ -223,7 +223,7 @@ func (suite *IntegrationTestSuite) TestSendCoinsFromModuleToAccount_Blacklist() ) keeper := bankpluskeeper.NewBaseKeeper( appCodec, app.GetKey(types.StoreKey), authKeeper, - app.GetSubspace(types.ModuleName), map[string]bool{addr1.String(): true}) + app.GetSubspace(types.ModuleName), map[string]bool{addr1.String(): true}, false) suite.Require().NoError(keeper.MintCoins(ctx, minttypes.ModuleName, initCoins)) suite.Require().Error(keeper.SendCoinsFromModuleToAccount( @@ -231,6 +231,80 @@ func (suite *IntegrationTestSuite) TestSendCoinsFromModuleToAccount_Blacklist() )) } +func (suite *IntegrationTestSuite) TestInputOutputCoins() { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, ocproto.Header{Height: 1}) + appCodec := app.AppCodec() + + // add module accounts to supply keeper + maccPerms := simapp.GetMaccPerms() + maccPerms[holder] = nil + maccPerms[authtypes.Burner] = []string{authtypes.Burner} + maccPerms[authtypes.Minter] = []string{authtypes.Minter} + + authKeeper := authkeeper.NewAccountKeeper( + appCodec, app.GetKey(types.StoreKey), app.GetSubspace(types.ModuleName), + authtypes.ProtoBaseAccount, maccPerms, + ) + keeper := bankpluskeeper.NewBaseKeeper( + appCodec, app.GetKey(types.StoreKey), authKeeper, + app.GetSubspace(types.ModuleName), make(map[string]bool), false, + ) + + baseAcc := authKeeper.NewAccountWithAddress(ctx, authtypes.NewModuleAddress("baseAcc")) + authKeeper.SetModuleAccount(ctx, holderAcc) + authKeeper.SetModuleAccount(ctx, burnerAcc) + authKeeper.SetAccount(ctx, baseAcc) + + // set initial balances + suite. + Require(). + NoError(keeper.MintCoins(ctx, minttypes.ModuleName, initCoins)) + suite. + Require(). + NoError(keeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, baseAcc.GetAddress(), initCoins)) + suite. + Require(). + NoError(keeper.MintCoins(ctx, minttypes.ModuleName, initCoins)) + suite. + Require(). + NoError(keeper.SendCoinsFromModuleToModule(ctx, minttypes.ModuleName, holderAcc.GetName(), initCoins)) + + input := []types.Input{types.NewInput(baseAcc.GetAddress(), initCoins), types.NewInput(holderAcc.GetAddress(), initCoins)} + output := []types.Output{types.NewOutput(burnerAcc.GetAddress(), initCoins), types.NewOutput(burnerAcc.GetAddress(), initCoins)} + + targetKeeper := func(isDeact bool) bankpluskeeper.BaseKeeper { + return bankpluskeeper.NewBaseKeeper( + appCodec, app.GetKey(types.StoreKey), authKeeper, + app.GetSubspace(types.ModuleName), make(map[string]bool), isDeact, + ) + } + tcs := map[string]struct { + deactMultiSend bool + }{ + "MultiSend Off": { + true, + }, + "MultiSend On": { + false, + }, + } + + for name, tc := range tcs { + tc := tc + suite.T().Run(name, func(t *testing.T) { + if tc.deactMultiSend { + suite.Panics(func() { + _ = targetKeeper(tc.deactMultiSend).InputOutputCoins(ctx, input, output) + }) + } else { + err := targetKeeper(tc.deactMultiSend).InputOutputCoins(ctx, input, output) + suite.Assert().NoError(err) + } + }) + } +} + func TestKeeperTestSuite(t *testing.T) { suite.Run(t, new(IntegrationTestSuite)) }