Skip to content

Commit

Permalink
Problem: fee collection not compatible with parallel execution (#237)
Browse files Browse the repository at this point in the history
* Problem: no efficient way to collect fee

Solution:
- support an idea of virtual account in bank module, where the incoming
  coins are accumulated in a per-tx object store first, then accumulate
  and credit to the real account at end blocker.

  it's nesserary to support parallel tx execution, where we try not to
  access shared states.

more efficient sum

support SendCoinsFromModuleToAccountVirtual

fix test

fix test

* fix lint

* fix test

* fix test

* fix test

* fix test

* fix test

* fix mock keeper

* try fix lint

* try fix lint

* reuse code

* try fix linter

* Update x/bank/keeper/send.go

Signed-off-by: yihuang <[email protected]>

* algin panic call

* fix error handling

* try fix lint

* nolintlint generate falst postiive

---------

Signed-off-by: yihuang <[email protected]>
  • Loading branch information
yihuang authored Mar 28, 2024
1 parent 4d32911 commit 9ef65ec
Show file tree
Hide file tree
Showing 24 changed files with 353 additions and 19 deletions.
1 change: 0 additions & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ linters:
- ineffassign
- misspell
- nakedret
- nolintlint
- staticcheck
- revive
- stylecheck
Expand Down
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ Ref: https://keepachangelog.com/en/1.0.0/
### Features

* (baseapp) [#205](https://github.com/crypto-org-chain/cosmos-sdk/pull/205) Add `TxExecutor` baseapp option, add `TxIndex`/`TxCount`/`MsgIndex`/`BlockGasUsed` fields to `Context, to support tx parallel execution.
* (baseapp) [#205](https://github.com/crypto-org-chain/cosmos-sdk/pull/205) Support mount object store in baseapp, add `ObjectStore` api in context..
* (baseapp) [#206](https://github.com/crypto-org-chain/cosmos-sdk/pull/206) Support mount object store in baseapp, add `ObjectStore` api in context..
* (bank) [#237](https://github.com/crypto-org-chain/cosmos-sdk/pull/237) Support virtual accounts in sending coins.

## [Unreleased-Upstream]

Expand Down
3 changes: 3 additions & 0 deletions baseapp/baseapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,9 @@ func (app *BaseApp) MountStores(keys ...storetypes.StoreKey) {
case *storetypes.MemoryStoreKey:
app.MountStore(key, storetypes.StoreTypeMemory)

case *storetypes.ObjectStoreKey:
app.MountStore(key, storetypes.StoreTypeObject)

default:
panic(fmt.Sprintf("Unrecognized store key type :%T", key))
}
Expand Down
7 changes: 7 additions & 0 deletions runtime/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ func init() {
ProvideKVStoreKey,
ProvideTransientStoreKey,
ProvideMemoryStoreKey,
ProvideObjectStoreKey,
ProvideGenesisTxHandler,
ProvideKVStoreService,
ProvideMemoryStoreService,
Expand Down Expand Up @@ -222,6 +223,12 @@ func ProvideMemoryStoreKey(key depinject.ModuleKey, app *AppBuilder) *storetypes
return storeKey
}

func ProvideObjectStoreKey(key depinject.ModuleKey, app *AppBuilder) *storetypes.ObjectStoreKey {
storeKey := storetypes.NewObjectStoreKey(fmt.Sprintf("object:%s", key.Name()))
registerStoreKey(app, storeKey)
return storeKey
}

func ProvideGenesisTxHandler(appBuilder *AppBuilder) genesis.TxHandler {
return appBuilder.app
}
Expand Down
6 changes: 6 additions & 0 deletions simapp/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ type SimApp struct {
// keys to access the substores
keys map[string]*storetypes.KVStoreKey
tkeys map[string]*storetypes.TransientStoreKey
okeys map[string]*storetypes.ObjectStoreKey

// keepers
AccountKeeper authkeeper.AccountKeeper
Expand Down Expand Up @@ -266,6 +267,7 @@ func NewSimApp(
}

tkeys := storetypes.NewTransientStoreKeys(paramstypes.TStoreKey)
okeys := storetypes.NewObjectStoreKeys(banktypes.ObjectStoreKey)
app := &SimApp{
BaseApp: bApp,
legacyAmino: legacyAmino,
Expand All @@ -274,6 +276,7 @@ func NewSimApp(
interfaceRegistry: interfaceRegistry,
keys: keys,
tkeys: tkeys,
okeys: okeys,
}

app.ParamsKeeper = initParamsKeeper(appCodec, legacyAmino, keys[paramstypes.StoreKey], tkeys[paramstypes.TStoreKey])
Expand All @@ -288,6 +291,7 @@ func NewSimApp(
app.BankKeeper = bankkeeper.NewBaseKeeper(
appCodec,
runtime.NewKVStoreService(keys[banktypes.StoreKey]),
okeys[banktypes.ObjectStoreKey],
app.AccountKeeper,
BlockedAddresses(),
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
Expand Down Expand Up @@ -456,6 +460,7 @@ func NewSimApp(
authz.ModuleName,
)
app.ModuleManager.SetOrderEndBlockers(
banktypes.ModuleName,
crisistypes.ModuleName,
govtypes.ModuleName,
stakingtypes.ModuleName,
Expand Down Expand Up @@ -516,6 +521,7 @@ func NewSimApp(
// initialize stores
app.MountKVStores(keys)
app.MountTransientStores(tkeys)
app.MountObjectStores(okeys)

// initialize BaseApp
app.SetInitChainer(app.InitChainer)
Expand Down
1 change: 1 addition & 0 deletions simapp/app_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ var (
authz.ModuleName,
},
EndBlockers: []string{
banktypes.ModuleName,
crisistypes.ModuleName,
govtypes.ModuleName,
stakingtypes.ModuleName,
Expand Down
4 changes: 3 additions & 1 deletion tests/integration/bank/keeper/deterministic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,11 @@ type deterministicFixture struct {

func initDeterministicFixture(t *testing.T) *deterministicFixture {
keys := storetypes.NewKVStoreKeys(authtypes.StoreKey, banktypes.StoreKey)
okeys := storetypes.NewObjectStoreKeys(banktypes.ObjectStoreKey)
cdc := moduletestutil.MakeTestEncodingConfig(auth.AppModuleBasic{}, bank.AppModuleBasic{}).Codec

logger := log.NewTestLogger(t)
cms := integration.CreateMultiStore(keys, logger)
cms := integration.CreateMultiStore(keys, okeys, logger)

newCtx := sdk.NewContext(cms, cmtproto.Header{}, true, logger)

Expand All @@ -93,6 +94,7 @@ func initDeterministicFixture(t *testing.T) *deterministicFixture {
bankKeeper := keeper.NewBaseKeeper(
cdc,
runtime.NewKVStoreService(keys[banktypes.StoreKey]),
okeys[banktypes.ObjectStoreKey],
accountKeeper,
blockedAddresses,
authority.String(),
Expand Down
6 changes: 5 additions & 1 deletion tests/integration/distribution/keeper/msg_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,13 @@ func initFixture(t testing.TB) *fixture {
keys := storetypes.NewKVStoreKeys(
authtypes.StoreKey, banktypes.StoreKey, distrtypes.StoreKey, stakingtypes.StoreKey,
)
okeys := storetypes.NewObjectStoreKeys(
banktypes.ObjectStoreKey,
)
cdc := moduletestutil.MakeTestEncodingConfig(auth.AppModuleBasic{}, distribution.AppModuleBasic{}).Codec

logger := log.NewTestLogger(t)
cms := integration.CreateMultiStore(keys, logger)
cms := integration.CreateMultiStore(keys, okeys, logger)

newCtx := sdk.NewContext(cms, types.Header{}, true, logger)

Expand Down Expand Up @@ -92,6 +95,7 @@ func initFixture(t testing.TB) *fixture {
bankKeeper := bankkeeper.NewBaseKeeper(
cdc,
runtime.NewKVStoreService(keys[banktypes.StoreKey]),
okeys[banktypes.ObjectStoreKey],
accountKeeper,
blockedAddresses,
authority.String(),
Expand Down
6 changes: 5 additions & 1 deletion tests/integration/evidence/keeper/infraction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,13 @@ func initFixture(t testing.TB) *fixture {
keys := storetypes.NewKVStoreKeys(
authtypes.StoreKey, banktypes.StoreKey, paramtypes.StoreKey, consensusparamtypes.StoreKey, evidencetypes.StoreKey, stakingtypes.StoreKey, slashingtypes.StoreKey,
)
okeys := storetypes.NewObjectStoreKeys(
banktypes.ObjectStoreKey,
)
cdc := moduletestutil.MakeTestEncodingConfig(auth.AppModuleBasic{}, evidence.AppModuleBasic{}).Codec

logger := log.NewTestLogger(t)
cms := integration.CreateMultiStore(keys, logger)
cms := integration.CreateMultiStore(keys, okeys, logger)

newCtx := sdk.NewContext(cms, cmtproto.Header{}, true, logger)

Expand Down Expand Up @@ -114,6 +117,7 @@ func initFixture(t testing.TB) *fixture {
bankKeeper := bankkeeper.NewBaseKeeper(
cdc,
runtime.NewKVStoreService(keys[banktypes.StoreKey]),
okeys[banktypes.ObjectStoreKey],
accountKeeper,
blockedAddresses,
authority.String(),
Expand Down
6 changes: 5 additions & 1 deletion tests/integration/gov/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,13 @@ func initFixture(t testing.TB) *fixture {
keys := storetypes.NewKVStoreKeys(
authtypes.StoreKey, banktypes.StoreKey, distrtypes.StoreKey, stakingtypes.StoreKey, types.StoreKey,
)
okeys := storetypes.NewObjectStoreKeys(
banktypes.ObjectStoreKey,
)
cdc := moduletestutil.MakeTestEncodingConfig(auth.AppModuleBasic{}, bank.AppModuleBasic{}, gov.AppModuleBasic{}).Codec

logger := log.NewTestLogger(t)
cms := integration.CreateMultiStore(keys, logger)
cms := integration.CreateMultiStore(keys, okeys, logger)

newCtx := sdk.NewContext(cms, cmtproto.Header{}, true, logger)

Expand Down Expand Up @@ -85,6 +88,7 @@ func initFixture(t testing.TB) *fixture {
bankKeeper := bankkeeper.NewBaseKeeper(
cdc,
runtime.NewKVStoreService(keys[banktypes.StoreKey]),
okeys[banktypes.ObjectStoreKey],
accountKeeper,
blockedAddresses,
authority.String(),
Expand Down
4 changes: 3 additions & 1 deletion tests/integration/slashing/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,11 @@ func initFixture(t testing.TB) *fixture {
keys := storetypes.NewKVStoreKeys(
authtypes.StoreKey, banktypes.StoreKey, slashingtypes.StoreKey, stakingtypes.StoreKey,
)
okeys := storetypes.NewObjectStoreKeys(banktypes.ObjectStoreKey)
cdc := moduletestutil.MakeTestEncodingConfig(auth.AppModuleBasic{}).Codec

logger := log.NewTestLogger(t)
cms := integration.CreateMultiStore(keys, logger)
cms := integration.CreateMultiStore(keys, okeys, logger)

newCtx := sdk.NewContext(cms, cmtproto.Header{}, true, logger)

Expand Down Expand Up @@ -85,6 +86,7 @@ func initFixture(t testing.TB) *fixture {
bankKeeper := bankkeeper.NewBaseKeeper(
cdc,
runtime.NewKVStoreService(keys[banktypes.StoreKey]),
okeys[banktypes.ObjectStoreKey],
accountKeeper,
blockedAddresses,
authority.String(),
Expand Down
6 changes: 5 additions & 1 deletion tests/integration/staking/keeper/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,13 @@ func initFixture(t testing.TB) *fixture {
keys := storetypes.NewKVStoreKeys(
authtypes.StoreKey, banktypes.StoreKey, types.StoreKey,
)
okeys := storetypes.NewObjectStoreKeys(
banktypes.ObjectStoreKey,
)
cdc := moduletestutil.MakeTestEncodingConfig(auth.AppModuleBasic{}, staking.AppModuleBasic{}).Codec

logger := log.NewTestLogger(t)
cms := integration.CreateMultiStore(keys, logger)
cms := integration.CreateMultiStore(keys, okeys, logger)

newCtx := sdk.NewContext(cms, cmtprototypes.Header{}, true, logger)

Expand Down Expand Up @@ -127,6 +130,7 @@ func initFixture(t testing.TB) *fixture {
bankKeeper := bankkeeper.NewBaseKeeper(
cdc,
runtime.NewKVStoreService(keys[banktypes.StoreKey]),
okeys[banktypes.ObjectStoreKey],
accountKeeper,
blockedAddresses,
authority.String(),
Expand Down
4 changes: 3 additions & 1 deletion tests/integration/staking/keeper/determinstic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,11 @@ func initDeterministicFixture(t *testing.T) *deterministicFixture {
keys := storetypes.NewKVStoreKeys(
authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey,
)
okeys := storetypes.NewObjectStoreKeys(banktypes.ObjectStoreKey)
cdc := moduletestutil.MakeTestEncodingConfig(auth.AppModuleBasic{}, distribution.AppModuleBasic{}).Codec

logger := log.NewTestLogger(t)
cms := integration.CreateMultiStore(keys, logger)
cms := integration.CreateMultiStore(keys, okeys, logger)

newCtx := sdk.NewContext(cms, cmtproto.Header{}, true, logger)

Expand Down Expand Up @@ -100,6 +101,7 @@ func initDeterministicFixture(t *testing.T) *deterministicFixture {
bankKeeper := bankkeeper.NewBaseKeeper(
cdc,
runtime.NewKVStoreService(keys[banktypes.StoreKey]),
okeys[banktypes.ObjectStoreKey],
accountKeeper,
blockedAddresses,
authority.String(),
Expand Down
14 changes: 14 additions & 0 deletions testutil/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,17 @@ func DefaultContextWithDB(t testing.TB, key, tkey storetypes.StoreKey) TestConte

return TestContext{ctx, db, cms}
}

func DefaultContextWithObjectStore(t testing.TB, key, tkey, okey storetypes.StoreKey) TestContext {
db := dbm.NewMemDB()
cms := store.NewCommitMultiStore(db, log.NewNopLogger(), metrics.NewNoOpMetrics())
cms.MountStoreWithDB(key, storetypes.StoreTypeIAVL, db)
cms.MountStoreWithDB(tkey, storetypes.StoreTypeTransient, nil)
cms.MountStoreWithDB(okey, storetypes.StoreTypeObject, nil)
err := cms.LoadLatestVersion()
assert.NoError(t, err)

ctx := sdk.NewContext(cms, cmtproto.Header{Time: time.Now()}, false, log.NewNopLogger())

return TestContext{ctx, db, cms}
}
4 changes: 2 additions & 2 deletions testutil/integration/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func Example() {
// replace the logger by testing values in a real test case (e.g. log.NewTestLogger(t))
logger := log.NewNopLogger()

cms := integration.CreateMultiStore(keys, logger)
cms := integration.CreateMultiStore(keys, nil, logger)
newCtx := sdk.NewContext(cms, cmtproto.Header{}, true, logger)

accountKeeper := authkeeper.NewAccountKeeper(
Expand Down Expand Up @@ -126,7 +126,7 @@ func Example_oneModule() {
// replace the logger by testing values in a real test case (e.g. log.NewTestLogger(t))
logger := log.NewLogger(io.Discard)

cms := integration.CreateMultiStore(keys, logger)
cms := integration.CreateMultiStore(keys, nil, logger)
newCtx := sdk.NewContext(cms, cmtproto.Header{}, true, logger)

accountKeeper := authkeeper.NewAccountKeeper(
Expand Down
6 changes: 5 additions & 1 deletion testutil/integration/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,14 +177,18 @@ func (app *App) QueryHelper() *baseapp.QueryServiceTestHelper {
}

// CreateMultiStore is a helper for setting up multiple stores for provided modules.
func CreateMultiStore(keys map[string]*storetypes.KVStoreKey, logger log.Logger) storetypes.CommitMultiStore {
func CreateMultiStore(keys map[string]*storetypes.KVStoreKey, okeys map[string]*storetypes.ObjectStoreKey, logger log.Logger) storetypes.CommitMultiStore {
db := dbm.NewMemDB()
cms := store.NewCommitMultiStore(db, logger, metrics.NewNoOpMetrics())

for key := range keys {
cms.MountStoreWithDB(keys[key], storetypes.StoreTypeIAVL, db)
}

for key := range okeys {
cms.MountStoreWithDB(okeys[key], storetypes.StoreTypeObject, nil)
}

_ = cms.LoadLatestVersion()
return cms
}
4 changes: 3 additions & 1 deletion x/bank/keeper/collections_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ import (

func TestBankStateCompatibility(t *testing.T) {
key := storetypes.NewKVStoreKey(banktypes.StoreKey)
testCtx := testutil.DefaultContextWithDB(t, key, storetypes.NewTransientStoreKey("transient_test"))
okey := storetypes.NewObjectStoreKey(banktypes.ObjectStoreKey)
testCtx := testutil.DefaultContextWithObjectStore(t, key, storetypes.NewTransientStoreKey("transient_test"), okey)
ctx := testCtx.Ctx.WithBlockHeader(cmtproto.Header{Time: cmttime.Now()})
encCfg := moduletestutil.MakeTestEncodingConfig()

Expand All @@ -40,6 +41,7 @@ func TestBankStateCompatibility(t *testing.T) {
k := keeper.NewBaseKeeper(
encCfg.Codec,
storeService,
okey,
authKeeper,
map[string]bool{accAddrs[4].String(): true},
authtypes.NewModuleAddress("gov").String(),
Expand Down
9 changes: 8 additions & 1 deletion x/bank/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
errorsmod "cosmossdk.io/errors"
"cosmossdk.io/log"
"cosmossdk.io/math"
storetypes "cosmossdk.io/store/types"

"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -46,9 +47,14 @@ type Keeper interface {
MintCoins(ctx context.Context, moduleName string, amt sdk.Coins) error
BurnCoins(ctx context.Context, moduleName string, amt sdk.Coins) error

SendCoinsFromAccountToModuleVirtual(ctx context.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error
SendCoinsFromModuleToAccountVirtual(ctx context.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error

DelegateCoins(ctx context.Context, delegatorAddr, moduleAccAddr sdk.AccAddress, amt sdk.Coins) error
UndelegateCoins(ctx context.Context, moduleAccAddr, delegatorAddr sdk.AccAddress, amt sdk.Coins) error

CreditVirtualAccounts(ctx context.Context) error

types.QueryServer
}

Expand Down Expand Up @@ -84,6 +90,7 @@ func (k BaseKeeper) GetPaginatedTotalSupply(ctx context.Context, pagination *que
func NewBaseKeeper(
cdc codec.BinaryCodec,
storeService store.KVStoreService,
objStoreKey storetypes.StoreKey,
ak types.AccountKeeper,
blockedAddrs map[string]bool,
authority string,
Expand All @@ -97,7 +104,7 @@ func NewBaseKeeper(
logger = logger.With(log.ModuleKey, "x/"+types.ModuleName)

return BaseKeeper{
BaseSendKeeper: NewBaseSendKeeper(cdc, storeService, ak, blockedAddrs, authority, logger),
BaseSendKeeper: NewBaseSendKeeper(cdc, storeService, objStoreKey, ak, blockedAddrs, authority, logger),
ak: ak,
cdc: cdc,
storeService: storeService,
Expand Down
Loading

0 comments on commit 9ef65ec

Please sign in to comment.