Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Injectable restrictions #24

Merged
merged 3 commits into from
Mar 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ Ref: https://keepachangelog.com/en/1.0.0/

## [Unreleased]

(x/bank) [#19](https://github.com/realiotech/cosmos-sdk/pull/19) Allow injection of restrictions on transfers using `AppendSendRestriction` or `PrependSendRestriction`.

# Realio Specific Releases

# Cosmos Specific Releases

## [v0.46.10](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.46.10) - 2022-02-16

### Improvements
Expand Down
89 changes: 18 additions & 71 deletions x/bank/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,31 +59,21 @@ var (
},
}
multiSendMsg3 = &types.MsgMultiSend{
Inputs: []types.Input{
types.NewInput(addr1, coins),
types.NewInput(addr4, coins),
},
Outputs: []types.Output{
types.NewOutput(addr2, coins),
types.NewOutput(addr3, coins),
},
}
multiSendMsg4 = &types.MsgMultiSend{
Inputs: []types.Input{
types.NewInput(addr2, coins),
},
Inputs: []types.Input{types.NewInput(addr2, coins)},
Outputs: []types.Output{
types.NewOutput(addr1, coins),
},
}
multiSendMsg5 = &types.MsgMultiSend{
Inputs: []types.Input{
types.NewInput(addr1, coins),
},
multiSendMsg4 = &types.MsgMultiSend{
Inputs: []types.Input{types.NewInput(addr1, coins)},
Outputs: []types.Output{
types.NewOutput(moduleAccAddr, coins),
},
}
invalidMultiSendMsg = &types.MsgMultiSend{
Inputs: []types.Input{types.NewInput(addr1, coins), types.NewInput(addr2, coins)},
Outputs: []types.Output{},
}
)

func TestSendNotEnoughBalance(t *testing.T) {
Expand Down Expand Up @@ -163,13 +153,22 @@ func TestMsgMultiSendWithAccounts(t *testing.T) {
},
{
desc: "wrong accSeq should not pass Simulate",
msgs: []sdk.Msg{multiSendMsg5},
msgs: []sdk.Msg{multiSendMsg4},
accNums: []uint64{0},
accSeqs: []uint64{0}, // wrong account sequence
expSimPass: false,
expPass: false,
privKeys: []cryptotypes.PrivKey{priv1},
},
{
desc: "multiple inputs not allowed",
msgs: []sdk.Msg{invalidMultiSendMsg},
accNums: []uint64{0},
accSeqs: []uint64{0},
expSimPass: false,
expPass: false,
privKeys: []cryptotypes.PrivKey{priv1},
},
}

for _, tc := range testCases {
Expand Down Expand Up @@ -234,58 +233,6 @@ func TestMsgMultiSendMultipleOut(t *testing.T) {
}
}

func TestMsgMultiSendMultipleInOut(t *testing.T) {
acc1 := &authtypes.BaseAccount{
Address: addr1.String(),
}
acc2 := &authtypes.BaseAccount{
Address: addr2.String(),
}
acc4 := &authtypes.BaseAccount{
Address: addr4.String(),
}

genAccs := []authtypes.GenesisAccount{acc1, acc2, acc4}
app := simapp.SetupWithGenesisAccounts(t, genAccs)
ctx := app.BaseApp.NewContext(false, tmproto.Header{})

require.NoError(t, testutil.FundAccount(app.BankKeeper, ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))))

require.NoError(t, testutil.FundAccount(app.BankKeeper, ctx, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))))

require.NoError(t, testutil.FundAccount(app.BankKeeper, ctx, addr4, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))))

app.Commit()

testCases := []appTestCase{
{
msgs: []sdk.Msg{multiSendMsg3},
accNums: []uint64{0, 2},
accSeqs: []uint64{0, 0},
expSimPass: true,
expPass: true,
privKeys: []cryptotypes.PrivKey{priv1, priv4},
expectedBalances: []expectedBalance{
{addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 32)}},
{addr4, sdk.Coins{sdk.NewInt64Coin("foocoin", 32)}},
{addr2, sdk.Coins{sdk.NewInt64Coin("foocoin", 52)}},
{addr3, sdk.Coins{sdk.NewInt64Coin("foocoin", 10)}},
},
},
}

for _, tc := range testCases {
header := tmproto.Header{Height: app.LastBlockHeight() + 1}
txGen := simapp.MakeTestEncodingConfig().TxConfig
_, _, err := simapp.SignCheckDeliver(t, txGen, app.BaseApp, header, tc.msgs, "", tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...)
require.NoError(t, err)

for _, eb := range tc.expectedBalances {
simapp.CheckBalance(t, app, eb.addr, eb.coins)
}
}
}

func TestMsgMultiSendDependent(t *testing.T) {
acc1 := authtypes.NewBaseAccountWithAddress(addr1)
acc2 := authtypes.NewBaseAccountWithAddress(addr2)
Expand Down Expand Up @@ -314,7 +261,7 @@ func TestMsgMultiSendDependent(t *testing.T) {
},
},
{
msgs: []sdk.Msg{multiSendMsg4},
msgs: []sdk.Msg{multiSendMsg3},
accNums: []uint64{1},
accSeqs: []uint64{0},
expSimPass: true,
Expand Down
12 changes: 12 additions & 0 deletions x/bank/keeper/export_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package keeper

// This file exists in the keeper package to expose some private things
// for the purpose of testing in the keeper_test package.

func (k BaseSendKeeper) SetSendRestriction(restriction SendRestrictionFn) {
k.sendRestriction.Fn = restriction
}

func (k BaseSendKeeper) GetSendRestrictionFn() SendRestrictionFn {
return k.sendRestriction.Fn
}
17 changes: 2 additions & 15 deletions x/bank/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,6 @@ type BaseKeeper struct {
mintCoinsRestrictionFn MintingRestrictionFn
}

type MintingRestrictionFn func(ctx sdk.Context, coins sdk.Coins) error

// GetPaginatedTotalSupply queries for the supply, ignoring 0 coins, with a given pagination
func (k BaseKeeper) GetPaginatedTotalSupply(ctx sdk.Context, pagination *query.PageRequest) (sdk.Coins, *query.PageResponse, error) {
store := ctx.KVStore(k.storeKey)
Expand Down Expand Up @@ -112,7 +110,7 @@ func NewBaseKeeper(
cdc: cdc,
storeKey: storeKey,
paramSpace: paramSpace,
mintCoinsRestrictionFn: func(ctx sdk.Context, coins sdk.Coins) error { return nil },
mintCoinsRestrictionFn: NoOpMintingRestrictionFn,
}
}

Expand All @@ -122,18 +120,7 @@ func NewBaseKeeper(
//
// bankKeeper.WithMintCoinsRestriction(restriction1).WithMintCoinsRestriction(restriction2)
func (k BaseKeeper) WithMintCoinsRestriction(check MintingRestrictionFn) BaseKeeper {
oldRestrictionFn := k.mintCoinsRestrictionFn
k.mintCoinsRestrictionFn = func(ctx sdk.Context, coins sdk.Coins) error {
err := check(ctx, coins)
if err != nil {
return err
}
err = oldRestrictionFn(ctx, coins)
if err != nil {
return err
}
return nil
}
k.mintCoinsRestrictionFn = check.Then(k.mintCoinsRestrictionFn)
return k
}

Expand Down
69 changes: 32 additions & 37 deletions x/bank/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -354,14 +354,13 @@ func (suite *IntegrationTestSuite) TestInputOutputNewAccount() {
suite.Require().Nil(app.AccountKeeper.GetAccount(ctx, addr2))
suite.Require().Empty(app.BankKeeper.GetAllBalances(ctx, addr2))

inputs := []types.Input{
{Address: addr1.String(), Coins: sdk.NewCoins(newFooCoin(30), newBarCoin(10))},
}
input := types.Input{Address: addr1.String(), Coins: sdk.NewCoins(newFooCoin(30), newBarCoin(10))}

outputs := []types.Output{
{Address: addr2.String(), Coins: sdk.NewCoins(newFooCoin(30), newBarCoin(10))},
}

suite.Require().NoError(app.BankKeeper.InputOutputCoins(ctx, inputs, outputs))
suite.Require().NoError(app.BankKeeper.InputOutputCoins(ctx, input, outputs))

expected := sdk.NewCoins(newFooCoin(30), newBarCoin(10))
acc2Balances := app.BankKeeper.GetAllBalances(ctx, addr2)
Expand All @@ -385,30 +384,26 @@ func (suite *IntegrationTestSuite) TestInputOutputCoins() {
acc3 := app.AccountKeeper.NewAccountWithAddress(ctx, addr3)
app.AccountKeeper.SetAccount(ctx, acc3)

inputs := []types.Input{
{Address: addr1.String(), Coins: sdk.NewCoins(newFooCoin(30), newBarCoin(10))},
{Address: addr1.String(), Coins: sdk.NewCoins(newFooCoin(30), newBarCoin(10))},
}
input := types.Input{Address: addr1.String(), Coins: sdk.NewCoins(newFooCoin(60), newBarCoin(20))}

outputs := []types.Output{
{Address: addr2.String(), Coins: sdk.NewCoins(newFooCoin(30), newBarCoin(10))},
{Address: addr3.String(), Coins: sdk.NewCoins(newFooCoin(30), newBarCoin(10))},
}

suite.Require().Error(app.BankKeeper.InputOutputCoins(ctx, inputs, []types.Output{}))
suite.Require().Error(app.BankKeeper.InputOutputCoins(ctx, inputs, outputs))
suite.Require().Error(app.BankKeeper.InputOutputCoins(ctx, input, []types.Output{}))
suite.Require().Error(app.BankKeeper.InputOutputCoins(ctx, input, outputs))

suite.Require().NoError(testutil.FundAccount(app.BankKeeper, ctx, addr1, balances))

insufficientInputs := []types.Input{
{Address: addr1.String(), Coins: sdk.NewCoins(newFooCoin(300), newBarCoin(100))},
{Address: addr1.String(), Coins: sdk.NewCoins(newFooCoin(300), newBarCoin(100))},
}
insufficientInput := types.Input{Address: addr1.String(), Coins: sdk.NewCoins(newFooCoin(300), newBarCoin(100))}

insufficientOutputs := []types.Output{
{Address: addr2.String(), Coins: sdk.NewCoins(newFooCoin(300), newBarCoin(100))},
{Address: addr3.String(), Coins: sdk.NewCoins(newFooCoin(300), newBarCoin(100))},
}
suite.Require().Error(app.BankKeeper.InputOutputCoins(ctx, insufficientInputs, insufficientOutputs))
suite.Require().NoError(app.BankKeeper.InputOutputCoins(ctx, inputs, outputs))
suite.Require().Error(app.BankKeeper.InputOutputCoins(ctx, insufficientInput, insufficientOutputs))
suite.Require().NoError(app.BankKeeper.InputOutputCoins(ctx, input, outputs))

acc1Balances := app.BankKeeper.GetAllBalances(ctx, addr1)
expected := sdk.NewCoins(newFooCoin(30), newBarCoin(10))
Expand Down Expand Up @@ -602,58 +597,59 @@ func (suite *IntegrationTestSuite) TestMsgMultiSendEvents() {
app.AccountKeeper.SetAccount(ctx, acc)
app.AccountKeeper.SetAccount(ctx, acc2)

coins := sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50), sdk.NewInt64Coin(barDenom, 100))
newCoins := sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50))
newCoins2 := sdk.NewCoins(sdk.NewInt64Coin(barDenom, 100))
inputs := []types.Input{
{Address: addr.String(), Coins: newCoins},
{Address: addr2.String(), Coins: newCoins2},
}
input := types.Input{Address: addr.String(), Coins: coins}
outputs := []types.Output{
{Address: addr3.String(), Coins: newCoins},
{Address: addr4.String(), Coins: newCoins2},
}

suite.Require().Error(app.BankKeeper.InputOutputCoins(ctx, inputs, outputs))
suite.Require().Error(app.BankKeeper.InputOutputCoins(ctx, input, outputs))

events := ctx.EventManager().ABCIEvents()
suite.Require().Equal(0, len(events))

// Set addr's coins but not addr2's coins
suite.Require().NoError(testutil.FundAccount(app.BankKeeper, ctx, addr, sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50))))
suite.Require().Error(app.BankKeeper.InputOutputCoins(ctx, inputs, outputs))
suite.Require().NoError(testutil.FundAccount(app.BankKeeper, ctx, addr, newCoins))
suite.Require().Error(app.BankKeeper.InputOutputCoins(ctx, input, outputs))

events = ctx.EventManager().ABCIEvents()
suite.Require().Equal(8, len(events)) // 7 events because account funding causes extra minting + coin_spent + coin_recv events
suite.Require().Equal(6, len(events)) // 6 events because account funding causes extra minting + coin_spent + coin_recv events

event1 := sdk.Event{
Type: sdk.EventTypeMessage,
Type: types.EventTypeCoinReceived,
Attributes: []abci.EventAttribute{},
}
event1.Attributes = append(
event1.Attributes,
abci.EventAttribute{Key: []byte(types.AttributeKeySender), Value: []byte(addr.String())},
abci.EventAttribute{Key: []byte(types.AttributeKeyReceiver), Value: []byte(addr.String())},
abci.EventAttribute{Key: []byte(sdk.AttributeKeyAmount), Value: []byte(newCoins.String())},
)
suite.Require().Equal(abci.Event(event1), events[7])

suite.Require().Equal(abci.Event(event1), events[3])

// Set addr's coins and addr2's coins
suite.Require().NoError(testutil.FundAccount(app.BankKeeper, ctx, addr, sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50))))
suite.Require().NoError(testutil.FundAccount(app.BankKeeper, ctx, addr, sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50), sdk.NewInt64Coin(barDenom, 100))))
newCoins = sdk.NewCoins(sdk.NewInt64Coin(fooDenom, 50))

suite.Require().NoError(testutil.FundAccount(app.BankKeeper, ctx, addr2, sdk.NewCoins(sdk.NewInt64Coin(barDenom, 100))))
newCoins2 = sdk.NewCoins(sdk.NewInt64Coin(barDenom, 100))

suite.Require().NoError(app.BankKeeper.InputOutputCoins(ctx, inputs, outputs))
suite.Require().NoError(app.BankKeeper.InputOutputCoins(ctx, input, outputs))

events = ctx.EventManager().ABCIEvents()
suite.Require().Equal(28, len(events)) // 25 due to account funding + coin_spent + coin_recv events
suite.Require().Equal(24, len(events)) // 24 due to account funding + coin_spent + coin_recv events

event2 := sdk.Event{
Type: sdk.EventTypeMessage,
Type: types.EventTypeCoinReceived,
Attributes: []abci.EventAttribute{},
}
event2.Attributes = append(
event2.Attributes,
abci.EventAttribute{Key: []byte(types.AttributeKeySender), Value: []byte(addr2.String())},
abci.EventAttribute{Key: []byte(types.AttributeKeyReceiver), Value: []byte(addr2.String())},
abci.EventAttribute{Key: []byte(sdk.AttributeKeyAmount), Value: []byte(newCoins2.String())},
)
event3 := sdk.Event{
Type: types.EventTypeTransfer,
Expand All @@ -678,11 +674,10 @@ func (suite *IntegrationTestSuite) TestMsgMultiSendEvents() {
event4.Attributes,
abci.EventAttribute{Key: []byte(sdk.AttributeKeyAmount), Value: []byte(newCoins2.String())},
)
// events are shifted due to the funding account events
suite.Require().Equal(abci.Event(event1), events[21])
suite.Require().Equal(abci.Event(event2), events[23])
suite.Require().Equal(abci.Event(event3), events[25])
suite.Require().Equal(abci.Event(event4), events[27])
//events are shifted due to the funding account events
suite.Require().Equal(abci.Event(event2), events[15])
suite.Require().Equal(abci.Event(event3), events[21])
suite.Require().Equal(abci.Event(event4), events[23])
}

func (suite *IntegrationTestSuite) TestSpendableCoins() {
Expand Down
2 changes: 1 addition & 1 deletion x/bank/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func (k msgServer) MultiSend(goCtx context.Context, msg *types.MsgMultiSend) (*t
}
}

err := k.InputOutputCoins(ctx, msg.Inputs, msg.Outputs)
err := k.InputOutputCoins(ctx, msg.Inputs[0], msg.Outputs)
if err != nil {
return nil, err
}
Expand Down
Loading