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

feat: add bankplus function to restrict to send coin to inactive smart contract. #400

Merged
merged 18 commits into from
Jan 10, 2022
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* (x/feegrant) [\#380] (https://github.com/line/lbm-sdk/pull/380) Feegrant module
* (x/wasm) [\#395] (https://github.com/line/lbm-sdk/pull/395) Add the instantiate_permission in the CodeInfoResponse
* (x/consortium) [\#406] (https://github.com/line/lbm-sdk/pull/406) Add CreateValidator access control feature
* (x/bank) [\#400] (https://github.com/line/lbm-sdk/pull/400) add `bankplus` function to restrict to send coin to inactive smart contract.

### Improvements
* (slashing) [\#347](https://github.com/line/lbm-sdk/pull/347) Introduce VoterSetCounter
Expand Down
34 changes: 34 additions & 0 deletions docs/core/proto-docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,9 @@

- [Msg](#lbm.bank.v1.Msg)

- [lbm/bankplus/v1/bankplus.proto](#lbm/bankplus/v1/bankplus.proto)
- [InactiveAddr](#lbm.bankplus.v1.InactiveAddr)

- [lbm/base/abci/v1/abci.proto](#lbm/base/abci/v1/abci.proto)
- [ABCIMessageLog](#lbm.base.abci.v1.ABCIMessageLog)
- [Attribute](#lbm.base.abci.v1.Attribute)
Expand Down Expand Up @@ -4853,6 +4856,37 @@ Msg defines the bank Msg service.



<a name="lbm/bankplus/v1/bankplus.proto"></a>
<p align="right"><a href="#top">Top</a></p>

## lbm/bankplus/v1/bankplus.proto



<a name="lbm.bankplus.v1.InactiveAddr"></a>

### InactiveAddr
InactiveAddr models the blocked address for the bankplus module


| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `address` | [string](#string) | | |





<!-- end messages -->

<!-- end enums -->

<!-- end HasExtensions -->

<!-- end services -->



<a name="lbm/base/abci/v1/abci.proto"></a>
<p align="right"><a href="#top">Top</a></p>

Expand Down
13 changes: 13 additions & 0 deletions proto/lbm/bankplus/v1/bankplus.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
syntax = "proto3";
package lbm.bankplus.v1;

import "gogoproto/gogo.proto";

option go_package = "github.com/line/lbm-sdk/x/bankplus/types";

// InactiveAddr models the blocked address for the bankplus module
message InactiveAddr {
option (gogoproto.equal) = true;

string address = 1;
}
30 changes: 25 additions & 5 deletions simapp/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ import (
"github.com/line/lbm-sdk/x/bank"
bankkeeper "github.com/line/lbm-sdk/x/bank/keeper"
banktypes "github.com/line/lbm-sdk/x/bank/types"
"github.com/line/lbm-sdk/x/bankplus"
bankpluskeeper "github.com/line/lbm-sdk/x/bankplus/keeper"
"github.com/line/lbm-sdk/x/capability"
capabilitykeeper "github.com/line/lbm-sdk/x/capability/keeper"
capabilitytypes "github.com/line/lbm-sdk/x/capability/types"
Expand Down Expand Up @@ -146,6 +148,11 @@ var (
govtypes.ModuleName: {authtypes.Burner},
ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner},
}

// module accounts that are allowed to receive tokens
allowedReceivingModAcc = map[string]bool{
distrtypes.ModuleName: true,
}
)

var (
Expand Down Expand Up @@ -263,9 +270,8 @@ func NewSimApp(
app.AccountKeeper = authkeeper.NewAccountKeeper(
appCodec, keys[authtypes.StoreKey], app.GetSubspace(authtypes.ModuleName), authtypes.ProtoBaseAccount, maccPerms,
)
app.BankKeeper = bankkeeper.NewBaseKeeper(
appCodec, keys[banktypes.StoreKey], app.AccountKeeper, app.GetSubspace(banktypes.ModuleName), app.ModuleAccountAddrs(),
)
app.BankKeeper = bankpluskeeper.NewBaseKeeper(
appCodec, keys[banktypes.StoreKey], app.AccountKeeper, app.GetSubspace(banktypes.ModuleName), app.BlockedAddrs())
stakingKeeper := stakingkeeper.NewKeeper(
appCodec, keys[stakingtypes.StoreKey], app.AccountKeeper, app.BankKeeper, app.GetSubspace(stakingtypes.ModuleName),
)
Expand Down Expand Up @@ -352,7 +358,7 @@ func NewSimApp(
),
auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts),
vesting.NewAppModule(app.AccountKeeper, app.BankKeeper),
bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper),
bankplus.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper),
capability.NewAppModule(appCodec, *app.CapabilityKeeper),
crisis.NewAppModule(&app.CrisisKeeper, skipGenesisInvariants),
feegrant.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry),
Expand Down Expand Up @@ -405,7 +411,7 @@ func NewSimApp(
// transactions
app.sm = module.NewSimulationManager(
auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts),
bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper),
bankplus.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper),
capability.NewAppModule(appCodec, *app.CapabilityKeeper),
feegrant.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry),
gov.NewAppModule(appCodec, app.GovKeeper, app.AccountKeeper, app.BankKeeper),
Expand Down Expand Up @@ -450,6 +456,9 @@ func NewSimApp(
// `loadLatest` is set to true.
ctx := app.BaseApp.NewUncachedContext(true, ocproto.Header{})
app.CapabilityKeeper.InitializeAndSeal(ctx)

// Initialize the keeper of bankkeeper
app.BankKeeper.(bankpluskeeper.Keeper).InitializeBankPlus(ctx)
}

app.ScopedIBCKeeper = scopedIBCKeeper
Expand Down Expand Up @@ -508,6 +517,17 @@ func (app *SimApp) ModuleAccountAddrs() map[string]bool {
return modAccAddrs
}

// BlockedAddrs returns all the app's module account addresses that are not
// allowed to receive external tokens.
func (app *SimApp) BlockedAddrs() map[string]bool {
blockedAddrs := make(map[string]bool)
for acc := range maccPerms {
blockedAddrs[authtypes.NewModuleAddress(acc).String()] = !allowedReceivingModAcc[acc]
}

return blockedAddrs
}

// LegacyAmino returns SimApp's amino codec.
//
// NOTE: This is solely to be used for testing purposes as it may be desirable
Expand Down
8 changes: 4 additions & 4 deletions simapp/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ func TestSimAppExportAndBlockedAddrs(t *testing.T) {
app := NewSimApp(log.NewOCLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encCfg, EmptyAppOptions{})

for acc := range maccPerms {
require.True(
t,
ex, _ := allowedReceivingModAcc[acc]
require.Equal(t,
!ex,
app.BankKeeper.BlockedAddr(app.AccountKeeper.GetModuleAddress(acc)),
"ensure that blocked addresses are properly set in bank keeper",
)
"ensure that blocked addresses are properly set in bank keeper")
}

genesisState := NewDefaultGenesisState(encCfg.Marshaler)
Expand Down
52 changes: 52 additions & 0 deletions x/bankplus/keeper/inactive.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package keeper

import (
sdk "github.com/line/lbm-sdk/types"
"github.com/line/lbm-sdk/x/bankplus/types"
)

// Keys for bankplus store but this prefix must not be overlap with bank key prefix.
var inactiveAddrsKeyPrefix = []byte{0xa0}

// inactiveAddrKey key of a specific inactiveAddr from store
func inactiveAddrKey(addr sdk.AccAddress) []byte {
return append(inactiveAddrsKeyPrefix, addr.Bytes()...)
}

//nolint:deadcode,unused
// isStoredInactiveAddr checks if the address is stored or not as blocked address
func (keeper BaseKeeper) isStoredInactiveAddr(ctx sdk.Context, address sdk.AccAddress) bool {
store := ctx.KVStore(keeper.storeKey)
bz := store.Get(inactiveAddrKey(address))
return bz != nil
}

// addToInactiveAddr adds a blocked address to the store.
func (keeper BaseKeeper) addToInactiveAddr(ctx sdk.Context, address sdk.AccAddress) {
store := ctx.KVStore(keeper.storeKey)
blockedCAddr := types.InactiveAddr{Address: address.String()}
bz := keeper.cdc.MustMarshalBinaryBare(&blockedCAddr)
store.Set(inactiveAddrKey(address), bz)
}

// deleteFromInactiveAddr deletes blocked address from store
func (keeper BaseKeeper) deleteFromInactiveAddr(ctx sdk.Context, address sdk.AccAddress) {
store := ctx.KVStore(keeper.storeKey)
store.Delete(inactiveAddrKey(address))
}

// loadAllInactiveAddrs loads all blocked address and set to `inactiveAddr`.
// This function is executed when the app is initiated and save all inactive address in caches
// in order to prevent to query to store in every time to send
func (keeper BaseKeeper) loadAllInactiveAddrs(ctx sdk.Context) {
store := ctx.KVStore(keeper.storeKey)
iterator := sdk.KVStorePrefixIterator(store, inactiveAddrsKeyPrefix)

defer iterator.Close()
for ; iterator.Valid(); iterator.Next() {
var bAddr types.InactiveAddr
keeper.cdc.MustUnmarshalBinaryBare(iterator.Value(), &bAddr)

keeper.inactiveAddrs[bAddr.Address] = true
}
}
79 changes: 79 additions & 0 deletions x/bankplus/keeper/inactive_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package keeper

import (
"github.com/line/lbm-sdk/codec"
codectypes "github.com/line/lbm-sdk/codec/types"
"github.com/line/lbm-sdk/store"
sdk "github.com/line/lbm-sdk/types"
accountkeeper "github.com/line/lbm-sdk/x/auth/keeper"
accounttypes "github.com/line/lbm-sdk/x/auth/types"
banktypes "github.com/line/lbm-sdk/x/bank/types"
paramtypes "github.com/line/lbm-sdk/x/params/types"
"github.com/line/ostracon/libs/log"
ostproto "github.com/line/ostracon/proto/ostracon/types"
"github.com/line/tm-db/v2/memdb"
"github.com/stretchr/testify/require"
"math/rand"
"testing"
)

func genAddress() sdk.AccAddress {
b := make([]byte, 20)
rand.Read(b)
return sdk.BytesToAccAddress(b)
}

func setupKeeper(storeKey *sdk.KVStoreKey) BaseKeeper {
registry := codectypes.NewInterfaceRegistry()
cdc := codec.NewProtoCodec(registry)
amino := codec.NewLegacyAmino()

accountStoreKey := sdk.NewKVStoreKey(accounttypes.StoreKey)
accountSubspace := paramtypes.NewSubspace(cdc, amino, accountStoreKey, accounttypes.ModuleName)
accountKeeper := accountkeeper.NewAccountKeeper(cdc, accountStoreKey, accountSubspace, accounttypes.ProtoBaseAccount, nil)

bankSubspace := paramtypes.NewSubspace(cdc, amino, storeKey, banktypes.StoreKey)
return NewBaseKeeper(cdc, storeKey, accountKeeper, bankSubspace, nil)
}

func setupContext(t *testing.T, storeKey *sdk.KVStoreKey) sdk.Context {
db := memdb.NewDB()
stateStore := store.NewCommitMultiStore(db)
stateStore.MountStoreWithDB(storeKey, sdk.StoreTypeIAVL, db)
require.NoError(t, stateStore.LoadLatestVersion())

return sdk.NewContext(stateStore, ostproto.Header{}, false, log.NewNopLogger())
}

func TestInactiveAddr(t *testing.T) {
storeKey := sdk.NewKVStoreKey(banktypes.StoreKey)
bankKeeper := setupKeeper(storeKey)
ctx := setupContext(t, storeKey)

addr := genAddress()

require.Equal(t, 0, len(bankKeeper.inactiveAddrs))

bankKeeper.addToInactiveAddr(ctx, addr)
require.True(t, bankKeeper.isStoredInactiveAddr(ctx, addr))

// duplicate addition, no error expects.
bankKeeper.addToInactiveAddr(ctx, addr)
require.True(t, bankKeeper.isStoredInactiveAddr(ctx, addr))

bankKeeper.deleteFromInactiveAddr(ctx, addr)
require.False(t, bankKeeper.isStoredInactiveAddr(ctx, addr))

addr2 := genAddress()
require.False(t, bankKeeper.isStoredInactiveAddr(ctx, addr2))

// expect no error
bankKeeper.deleteFromInactiveAddr(ctx, addr2)

// test loadAllInactiveAddrs
bankKeeper.addToInactiveAddr(ctx, addr)
bankKeeper.addToInactiveAddr(ctx, addr2)
require.Equal(t, 0, len(bankKeeper.inactiveAddrs))
bankKeeper.loadAllInactiveAddrs(ctx)
require.Equal(t, 2, len(bankKeeper.inactiveAddrs))
}
Loading