Skip to content

Commit

Permalink
Merge pull request #24 from realiotech/injectable-restrictions
Browse files Browse the repository at this point in the history
Injectable restrictions
  • Loading branch information
jiujiteiro authored Mar 7, 2023
2 parents 712188a + f85200a commit 2abf658
Show file tree
Hide file tree
Showing 14 changed files with 1,201 additions and 175 deletions.
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

0 comments on commit 2abf658

Please sign in to comment.