From b214e3378cac2e0633491c25ea47949df85c652a Mon Sep 17 00:00:00 2001 From: Uday Patil Date: Tue, 13 Jun 2023 21:59:34 -0500 Subject: [PATCH 1/4] refactor deferred balance to use memkv --- baseapp/baseapp.go | 2 +- proto/cosmos/accesscontrol/constants.proto | 3 + simapp/app.go | 6 +- types/accesscontrol/comparator.go | 3 + types/accesscontrol/constants.pb.go | 189 +++++++++++---------- types/accesscontrol/resource.go | 9 +- types/context.go | 11 ++ types/context_cache.go | 2 + types/handler.go | 28 +-- x/accesscontrol/keeper/keeper.go | 7 +- x/accesscontrol/testutil/accesscontrol.go | 4 + x/accesscontrol/types/graph.go | 4 +- x/auth/ante/basic.go | 4 +- x/auth/ante/fee.go | 24 ++- x/auth/ante/fee_test.go | 24 ++- x/auth/ante/sigverify.go | 4 +- x/auth/ante/testutil_test.go | 2 +- x/bank/keeper/deferred_cache.go | 126 ++++++++++++++ x/bank/keeper/keeper.go | 146 +++++++++------- x/bank/keeper/keeper_test.go | 16 +- x/bank/types/key.go | 32 ++++ 21 files changed, 449 insertions(+), 197 deletions(-) create mode 100644 x/bank/keeper/deferred_cache.go diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 2ac324916..7ff85770f 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -970,7 +970,7 @@ func (app *BaseApp) runTx(ctx sdk.Context, mode runTxMode, txBytes []byte) (gInf // Dont need to validate in checkTx mode if ctx.MsgValidator() != nil && mode == runTxModeDeliver { storeAccessOpEvents := msCache.GetEvents() - accessOps, _ := app.anteDepGenerator([]acltypes.AccessOperation{}, tx) + accessOps := ctx.TxMsgAccessOps()[acltypes.ANTE_MSG_INDEX] missingAccessOps := ctx.MsgValidator().ValidateAccessOperations(accessOps, storeAccessOpEvents) if len(missingAccessOps) != 0 { diff --git a/proto/cosmos/accesscontrol/constants.proto b/proto/cosmos/accesscontrol/constants.proto index 489be8b58..a8820fb48 100644 --- a/proto/cosmos/accesscontrol/constants.proto +++ b/proto/cosmos/accesscontrol/constants.proto @@ -128,6 +128,9 @@ enum ResourceType { KV_DEX_CONTRACT = 90; // child of KV_DEX KV_DEX_LONG_ORDER_COUNT = 91; // child of KV_DEX KV_DEX_SHORT_ORDER_COUNT = 92; // child of KV_DEX + + KV_BANK_DEFERRED = 93; // child of KV + KV_BANK_DEFERRED_MODULE_TX_INDEX = 95; // child of KV_BANK_DEFERRED } enum WasmMessageSubtype { diff --git a/simapp/app.go b/simapp/app.go index b9a60c797..4c0af924c 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -225,7 +225,7 @@ func NewSimApp( tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey) // NOTE: The testingkey is just mounted for testing purposes. Actual applications should // not include this key. - memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey, "testingkey") + memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey, "testingkey", banktypes.DeferredCacheStoreKey) // configure state listening capabilities using AppOptions // we are doing nothing with the returned streamingServices and waitGroup in this case @@ -259,8 +259,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 = bankkeeper.NewBaseKeeperWithDeferredCache( + appCodec, keys[banktypes.StoreKey], app.AccountKeeper, app.GetSubspace(banktypes.ModuleName), app.ModuleAccountAddrs(), memKeys[banktypes.DeferredCacheStoreKey], ) stakingKeeper := stakingkeeper.NewKeeper( appCodec, keys[stakingtypes.StoreKey], app.AccountKeeper, app.BankKeeper, app.GetSubspace(stakingtypes.ModuleName), diff --git a/types/accesscontrol/comparator.go b/types/accesscontrol/comparator.go index b0c86c663..d615caf49 100644 --- a/types/accesscontrol/comparator.go +++ b/types/accesscontrol/comparator.go @@ -21,6 +21,9 @@ var ( } ) +// use -1 to indicate that it is prior to msgs in the tx +const ANTE_MSG_INDEX = int(-1) + type Comparator struct { AccessType AccessType Identifier string diff --git a/types/accesscontrol/constants.pb.go b/types/accesscontrol/constants.pb.go index 03c0bdbce..1625561ed 100644 --- a/types/accesscontrol/constants.pb.go +++ b/types/accesscontrol/constants.pb.go @@ -193,6 +193,8 @@ const ( ResourceType_KV_DEX_CONTRACT ResourceType = 90 ResourceType_KV_DEX_LONG_ORDER_COUNT ResourceType = 91 ResourceType_KV_DEX_SHORT_ORDER_COUNT ResourceType = 92 + ResourceType_KV_BANK_DEFERRED ResourceType = 93 + ResourceType_KV_BANK_DEFERRED_MODULE_TX_INDEX ResourceType = 95 ) var ResourceType_name = map[int32]string{ @@ -286,6 +288,8 @@ var ResourceType_name = map[int32]string{ 90: "KV_DEX_CONTRACT", 91: "KV_DEX_LONG_ORDER_COUNT", 92: "KV_DEX_SHORT_ORDER_COUNT", + 93: "KV_BANK_DEFERRED", + 95: "KV_BANK_DEFERRED_MODULE_TX_INDEX", } var ResourceType_value = map[string]int32{ @@ -379,6 +383,8 @@ var ResourceType_value = map[string]int32{ "KV_DEX_CONTRACT": 90, "KV_DEX_LONG_ORDER_COUNT": 91, "KV_DEX_SHORT_ORDER_COUNT": 92, + "KV_BANK_DEFERRED": 93, + "KV_BANK_DEFERRED_MODULE_TX_INDEX": 95, } func (x ResourceType) String() string { @@ -426,95 +432,96 @@ func init() { } var fileDescriptor_36568f7561081112 = []byte{ - // 1425 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x56, 0xd9, 0x72, 0x13, 0x47, - 0x17, 0xf6, 0xbe, 0xb4, 0x0d, 0x1c, 0xda, 0xec, 0x36, 0x02, 0x0c, 0x3f, 0xf0, 0x1b, 0xb0, 0x59, - 0xfe, 0x3f, 0x0b, 0x24, 0x21, 0xad, 0x99, 0x23, 0x69, 0x3c, 0x33, 0xdd, 0xa3, 0xee, 0x1e, 0x2d, - 0x24, 0x55, 0x5d, 0xb6, 0xa2, 0x22, 0x54, 0xb0, 0x45, 0x59, 0x22, 0x95, 0x3c, 0x43, 0x6e, 0xf2, - 0x10, 0x79, 0x98, 0x5c, 0x72, 0x99, 0xcb, 0x14, 0xbc, 0x48, 0xaa, 0x67, 0x5a, 0x62, 0x24, 0x4c, - 0xb8, 0xb2, 0x75, 0xbe, 0xaf, 0xcf, 0xf4, 0xf9, 0xce, 0xd6, 0xe4, 0x46, 0xa7, 0xd7, 0x3f, 0xe8, - 0xf5, 0x77, 0xf6, 0x3a, 0x9d, 0x6e, 0xbf, 0xdf, 0xe9, 0x1d, 0x0e, 0x8e, 0x7a, 0x2f, 0x77, 0x3a, - 0xbd, 0xc3, 0xfe, 0x60, 0xef, 0x70, 0xd0, 0xdf, 0x7e, 0x75, 0xd4, 0x1b, 0xf4, 0xe8, 0x46, 0xce, - 0xda, 0x1e, 0x63, 0x6d, 0xff, 0xfc, 0x60, 0xbf, 0x3b, 0xd8, 0x7b, 0xb0, 0xf5, 0x98, 0x10, 0x96, - 0x01, 0xfa, 0xd7, 0x57, 0x5d, 0xba, 0x42, 0x16, 0x53, 0x1e, 0x72, 0xd1, 0xe4, 0x30, 0x45, 0x97, - 0xc8, 0x9c, 0x44, 0xe6, 0xc3, 0x34, 0x5d, 0x26, 0xf3, 0x4d, 0x19, 0x68, 0x84, 0x19, 0x4a, 0xc8, - 0x82, 0x27, 0xe2, 0x38, 0xd0, 0x30, 0xbb, 0xf5, 0xdb, 0x0c, 0x59, 0xcf, 0x0f, 0x8b, 0x57, 0xdd, - 0xa3, 0xbd, 0xc1, 0x8b, 0xde, 0xa1, 0xea, 0xbe, 0xec, 0x76, 0x06, 0xbd, 0xa3, 0xcc, 0xdb, 0x12, - 0x99, 0xe3, 0x82, 0x23, 0x4c, 0xd1, 0x05, 0x32, 0xb3, 0x5b, 0x87, 0x69, 0x7a, 0x96, 0x9c, 0xde, - 0xad, 0x9b, 0x32, 0x7a, 0xb5, 0x47, 0x0f, 0x0d, 0xf3, 0x7d, 0x89, 0x4a, 0xc1, 0x0c, 0x2d, 0x91, - 0x4b, 0xbb, 0x75, 0x13, 0x21, 0xaf, 0xea, 0x9a, 0x49, 0x24, 0x56, 0x82, 0x16, 0xfa, 0x23, 0x7c, - 0x96, 0x5e, 0x24, 0x67, 0x15, 0x72, 0x1f, 0xe5, 0xe4, 0xd1, 0x39, 0xba, 0x49, 0x4a, 0x0e, 0xfa, - 0xd8, 0xf1, 0x79, 0x7a, 0x86, 0x80, 0x27, 0xb8, 0x96, 0xcc, 0xd3, 0x23, 0xeb, 0x02, 0xbd, 0x44, - 0xce, 0xed, 0xd6, 0x4d, 0x8c, 0x4a, 0xb1, 0x2a, 0x1a, 0x4f, 0x70, 0x3f, 0xd0, 0x81, 0xe0, 0x2c, - 0x82, 0x45, 0x8b, 0x79, 0x82, 0x2b, 0xcd, 0xb8, 0x36, 0x4a, 0xcb, 0x80, 0x57, 0x8d, 0x16, 0xa6, - 0x86, 0x2d, 0x58, 0xa2, 0xe7, 0x08, 0x1d, 0x79, 0x93, 0x58, 0x41, 0x89, 0xdc, 0x43, 0x58, 0xde, - 0xfa, 0x63, 0x8d, 0xac, 0xca, 0x6e, 0xbf, 0xf7, 0xfa, 0xa8, 0xd3, 0xcd, 0xc2, 0x5f, 0x24, 0xb3, - 0x8c, 0xb7, 0xf3, 0xe8, 0xc3, 0x06, 0x4c, 0x5b, 0x43, 0xdc, 0x3d, 0xc8, 0x45, 0xf4, 0xbb, 0xbf, - 0xd8, 0xff, 0x67, 0xad, 0xe4, 0x61, 0xc3, 0x94, 0x19, 0x0f, 0x61, 0x8e, 0x9e, 0x24, 0x24, 0x6c, - 0x18, 0xa5, 0x59, 0x18, 0xf0, 0x2a, 0xcc, 0x3b, 0xb0, 0xc9, 0x54, 0x0c, 0x0b, 0xf4, 0x04, 0x59, - 0x0e, 0x1b, 0x46, 0x48, 0xe6, 0x45, 0x08, 0x8b, 0xd6, 0x49, 0xd8, 0x30, 0x7e, 0x76, 0xa7, 0x55, - 0xb2, 0x14, 0x36, 0x0c, 0x26, 0xc2, 0xab, 0xc1, 0x32, 0x5d, 0x23, 0xa7, 0xc2, 0x86, 0xd1, 0x22, - 0x44, 0x5e, 0x61, 0x9e, 0x16, 0xb2, 0x0d, 0xc4, 0x86, 0x34, 0x3a, 0x6d, 0x1a, 0x42, 0xa3, 0xd1, - 0x4c, 0x56, 0x51, 0x2b, 0x58, 0xa1, 0x97, 0xc9, 0xc5, 0xf7, 0x18, 0xab, 0x56, 0x25, 0x56, 0x99, - 0xce, 0x59, 0x0a, 0x56, 0x6d, 0xd6, 0xde, 0xc3, 0x15, 0x44, 0x1f, 0xa5, 0x82, 0x13, 0x36, 0x2b, - 0xef, 0x2f, 0x6b, 0x7c, 0x8c, 0xec, 0xa9, 0x40, 0x70, 0x38, 0x49, 0x2f, 0x90, 0x33, 0x05, 0xa8, - 0xc1, 0xa2, 0xc0, 0x67, 0x5a, 0x48, 0x38, 0xe5, 0x22, 0x62, 0xa9, 0xae, 0x01, 0x38, 0x0f, 0xf6, - 0xc7, 0x30, 0x2f, 0x46, 0x69, 0x21, 0x11, 0x4e, 0x53, 0x4a, 0x4e, 0x3a, 0x59, 0x8c, 0x4a, 0x93, - 0x24, 0x6a, 0x03, 0xa5, 0xa7, 0xc9, 0x89, 0xa1, 0xcd, 0x47, 0x2e, 0x62, 0x58, 0xb3, 0xa9, 0x1d, - 0x9a, 0xca, 0x2c, 0x62, 0xdc, 0x43, 0x05, 0x67, 0x9c, 0xdf, 0xa2, 0x00, 0xee, 0xc0, 0x59, 0xba, - 0x41, 0x2e, 0x4c, 0x42, 0x31, 0x6a, 0xe6, 0x33, 0xcd, 0xe0, 0xdc, 0x71, 0x07, 0x99, 0x1f, 0x07, - 0x1c, 0xce, 0xd3, 0x75, 0x72, 0x7e, 0x12, 0xf2, 0x24, 0x66, 0x51, 0x5d, 0x70, 0xa0, 0x53, 0x08, - 0x5b, 0x5e, 0x8d, 0xf1, 0x2a, 0x1a, 0xc9, 0x34, 0xc2, 0x45, 0x5b, 0xa2, 0x13, 0xca, 0x27, 0xc8, - 0x59, 0xa4, 0xdb, 0xc6, 0x13, 0x29, 0xd7, 0x28, 0xe1, 0x92, 0xbb, 0x96, 0xe3, 0x24, 0x32, 0xf0, - 0xd0, 0x28, 0xce, 0x12, 0x55, 0x13, 0x1a, 0xd6, 0xe9, 0x15, 0xb2, 0xfe, 0xa1, 0x9c, 0x81, 0xe0, - 0x26, 0x11, 0x4d, 0x94, 0xb0, 0xe1, 0x92, 0x3b, 0x24, 0x68, 0xa1, 0x59, 0xe4, 0xb0, 0xcb, 0xee, - 0xf3, 0x1f, 0xe4, 0x42, 0xd9, 0x92, 0xcf, 0x64, 0x87, 0x12, 0xbd, 0x4e, 0xae, 0x14, 0x38, 0x29, - 0x2f, 0xdb, 0x6e, 0x18, 0x4f, 0xea, 0x15, 0x7a, 0x8b, 0x5c, 0xff, 0x04, 0xc9, 0x7a, 0x87, 0xab, - 0x4e, 0x8d, 0x21, 0x51, 0x62, 0xc1, 0xcb, 0xb5, 0x89, 0x4f, 0x15, 0x41, 0x7b, 0xda, 0x28, 0xe9, - 0xc1, 0xe6, 0xa7, 0x48, 0xbe, 0xd2, 0x70, 0x9d, 0x5e, 0x23, 0x97, 0x3f, 0x46, 0xaa, 0xa7, 0x98, - 0x22, 0xdc, 0xb0, 0x83, 0xe5, 0xb8, 0xd8, 0x1d, 0xfe, 0x9f, 0x09, 0xbc, 0x16, 0xd8, 0xea, 0x0b, - 0x3c, 0x16, 0x99, 0x80, 0x57, 0x04, 0xdc, 0x9c, 0xa8, 0xe3, 0x51, 0xc8, 0x70, 0xeb, 0xe3, 0xaa, - 0x96, 0xdb, 0x4e, 0xf9, 0xff, 0xba, 0x3e, 0xf4, 0x03, 0x3b, 0x41, 0xca, 0x69, 0x16, 0xff, 0x6d, - 0x97, 0xe9, 0xa2, 0xd1, 0xb6, 0x94, 0x49, 0x84, 0x88, 0x60, 0x8b, 0x5e, 0x25, 0x1b, 0x93, 0x68, - 0x22, 0x45, 0x22, 0x14, 0x4a, 0x13, 0x62, 0x1b, 0xee, 0xb8, 0x2c, 0x8c, 0x31, 0x44, 0xaa, 0xed, - 0xa8, 0xf2, 0x73, 0x19, 0x9a, 0x4c, 0xfa, 0x0a, 0xee, 0xd2, 0x3b, 0xe4, 0xd6, 0x24, 0xd1, 0x29, - 0x24, 0xa4, 0x69, 0x06, 0xba, 0xe6, 0x4b, 0xd6, 0xcc, 0x0b, 0xe0, 0xde, 0xbf, 0x93, 0x95, 0x66, - 0x52, 0x5b, 0xe7, 0x99, 0x2a, 0xdb, 0x74, 0x8b, 0xdc, 0x9c, 0x24, 0xdb, 0xac, 0x14, 0xe4, 0x1b, - 0xde, 0x62, 0xe7, 0xb8, 0xeb, 0x5a, 0xae, 0x97, 0x4a, 0x89, 0x5c, 0x8f, 0x88, 0xf7, 0xe9, 0x6d, - 0x72, 0xe3, 0x38, 0x22, 0xf3, 0xbc, 0x34, 0x36, 0xd9, 0xca, 0x51, 0xca, 0x2a, 0xf8, 0xc0, 0x75, - 0xc3, 0x18, 0x53, 0x45, 0x4c, 0xd5, 0x0c, 0x36, 0x90, 0x6b, 0x78, 0x38, 0x94, 0x18, 0x5b, 0x66, - 0x34, 0xa8, 0x23, 0xc1, 0xab, 0x65, 0x21, 0x42, 0x78, 0xe4, 0x86, 0xdd, 0x18, 0xaa, 0x6a, 0x42, - 0xea, 0x0c, 0xfe, 0x9f, 0x1b, 0x76, 0x16, 0x56, 0xa8, 0x75, 0x84, 0xb1, 0xf5, 0xf9, 0x7f, 0x3b, - 0xf5, 0x9d, 0x39, 0x61, 0x81, 0x74, 0x5b, 0x06, 0x3e, 0xa3, 0xa7, 0xc8, 0x8a, 0xb3, 0xeb, 0x26, - 0x4b, 0xe0, 0x73, 0x0a, 0x64, 0x75, 0x48, 0xb4, 0x6d, 0x0c, 0x5f, 0xb8, 0x76, 0x18, 0xf7, 0x68, - 0x90, 0x6b, 0xd9, 0x86, 0x2f, 0x5d, 0xe7, 0x5a, 0x50, 0x62, 0x35, 0x50, 0x1a, 0x25, 0xfa, 0xd9, - 0x27, 0xe0, 0x71, 0xc1, 0x95, 0x90, 0x3e, 0x4a, 0xf8, 0xca, 0x4d, 0xc0, 0xec, 0xee, 0x76, 0xd6, - 0x45, 0xf0, 0xf5, 0xb0, 0x62, 0xb0, 0x65, 0xa5, 0xb2, 0xf3, 0xc4, 0x30, 0x4f, 0x07, 0x0d, 0xcc, - 0xcf, 0x28, 0xf8, 0xa6, 0x10, 0x11, 0x53, 0x0a, 0xb5, 0x89, 0x02, 0xa5, 0xe1, 0x5b, 0x57, 0xdb, - 0xd6, 0xcc, 0xb1, 0xa5, 0x73, 0xba, 0x09, 0x7c, 0x60, 0x05, 0x85, 0x32, 0xa4, 0x70, 0xeb, 0xc0, - 0x87, 0x32, 0x3d, 0x4f, 0xd6, 0x1c, 0x1c, 0x33, 0xed, 0xd5, 0x8c, 0x44, 0x95, 0x46, 0x1a, 0x3c, - 0xd7, 0x4d, 0x13, 0x81, 0x8e, 0xfc, 0xfa, 0x85, 0x8b, 0xe4, 0xc6, 0x4c, 0x71, 0x74, 0x33, 0x9c, - 0x79, 0x1e, 0x2a, 0x95, 0xa5, 0x44, 0x44, 0x50, 0xa5, 0x77, 0xc9, 0xed, 0x49, 0x6b, 0xb6, 0x08, - 0x8d, 0x8f, 0x89, 0x5d, 0xf8, 0xdc, 0x6b, 0x9b, 0x98, 0x25, 0x89, 0x6d, 0xc7, 0x9a, 0x93, 0x2a, - 0xc3, 0x3d, 0xe1, 0x23, 0x04, 0xae, 0x08, 0x9c, 0x65, 0x62, 0xf9, 0xef, 0x3a, 0xd9, 0xc7, 0xd1, - 0x7c, 0xf5, 0x84, 0x4e, 0x98, 0x0c, 0x53, 0x58, 0x4f, 0xed, 0x7a, 0xcf, 0x7a, 0x2f, 0x72, 0x13, - 0x67, 0xfc, 0x94, 0xfd, 0x9c, 0x2b, 0xfd, 0x36, 0xc4, 0xae, 0x38, 0xc7, 0x29, 0xe5, 0x76, 0xce, - 0x0a, 0x7c, 0xe0, 0x4e, 0xdc, 0x8c, 0x90, 0x04, 0x9c, 0xa3, 0xef, 0x30, 0x6e, 0x37, 0xb9, 0x70, - 0x9f, 0xc8, 0x56, 0x62, 0x35, 0x12, 0xe5, 0xbc, 0x03, 0xb2, 0xb4, 0xf2, 0x34, 0x2e, 0xa3, 0x84, - 0xc4, 0x2d, 0x7b, 0x4b, 0x79, 0x06, 0x75, 0x57, 0x80, 0x15, 0xc4, 0xaa, 0x64, 0x5c, 0x83, 0x74, - 0x3b, 0x6c, 0x68, 0x30, 0x2c, 0x8a, 0x44, 0xd3, 0x16, 0x0b, 0x28, 0xc7, 0xcd, 0x9a, 0xc5, 0xca, - 0xa6, 0x5d, 0xf1, 0x0c, 0x0d, 0xf9, 0x00, 0x0e, 0xaa, 0x7c, 0xd4, 0xeb, 0xa9, 0x6b, 0xcb, 0x11, - 0xc3, 0x2a, 0x68, 0x92, 0xb4, 0x1c, 0x62, 0xdb, 0x48, 0x8c, 0xf2, 0x69, 0x6b, 0xc5, 0x69, 0xb8, - 0x34, 0x66, 0x65, 0x81, 0xb1, 0xab, 0xd8, 0x66, 0x21, 0xe7, 0xd6, 0xea, 0xaa, 0xb6, 0x55, 0x68, - 0x27, 0x6b, 0xf6, 0x31, 0x11, 0x2a, 0xd0, 0xd0, 0x1e, 0x8e, 0xcc, 0x42, 0x73, 0xc2, 0xb3, 0x42, - 0x03, 0xd9, 0x36, 0x76, 0xc5, 0x93, 0x89, 0x02, 0xdf, 0x15, 0x9a, 0x3d, 0xeb, 0xe2, 0x31, 0xf4, - 0xfb, 0xcd, 0xb9, 0xa5, 0x27, 0xf0, 0x64, 0x73, 0x6e, 0xe9, 0x29, 0x3c, 0xdd, 0x9c, 0x5b, 0xaa, - 0x40, 0x65, 0xeb, 0x2e, 0xa1, 0xcd, 0xbd, 0xfe, 0x41, 0xdc, 0xed, 0xf7, 0xf7, 0x9e, 0x77, 0xd5, - 0xeb, 0xfd, 0x81, 0x7d, 0xab, 0x2d, 0x93, 0xf9, 0x7a, 0x8a, 0xd2, 0xbe, 0xd6, 0x56, 0xc8, 0x22, - 0xb6, 0xd0, 0x4b, 0x35, 0xc2, 0x74, 0x79, 0xf7, 0xcf, 0xb7, 0xa5, 0xe9, 0x37, 0x6f, 0x4b, 0xd3, - 0x7f, 0xbf, 0x2d, 0x4d, 0xff, 0xfe, 0xae, 0x34, 0xf5, 0xe6, 0x5d, 0x69, 0xea, 0xaf, 0x77, 0xa5, - 0xa9, 0x67, 0xf7, 0x9f, 0xbf, 0x18, 0xfc, 0xf8, 0x7a, 0x7f, 0xbb, 0xd3, 0x3b, 0xd8, 0x71, 0xef, - 0xf0, 0xfc, 0xcf, 0xbd, 0xfe, 0x0f, 0x3f, 0xed, 0x58, 0xa7, 0x13, 0x0f, 0xf3, 0xfd, 0x85, 0xec, - 0x3d, 0xfe, 0xe8, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x83, 0xc2, 0xe2, 0x27, 0xb7, 0x0b, 0x00, - 0x00, + // 1445 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x56, 0x5b, 0x73, 0x13, 0xbf, + 0x15, 0xcf, 0xfd, 0xa2, 0x04, 0x38, 0x28, 0xdc, 0x13, 0x0c, 0x84, 0x14, 0x68, 0x80, 0x84, 0x4b, + 0xaf, 0xd0, 0x96, 0xca, 0xab, 0x63, 0x7b, 0xe3, 0x5d, 0x69, 0x2d, 0x69, 0x7d, 0xa1, 0xed, 0x68, + 0x12, 0xd7, 0x43, 0x99, 0x92, 0x98, 0x89, 0x4d, 0xa7, 0xfd, 0x0c, 0x7d, 0xe9, 0xc7, 0xea, 0x23, + 0x8f, 0x7d, 0x64, 0xe0, 0x8b, 0x74, 0xb4, 0x2b, 0x9b, 0xb5, 0x09, 0x7f, 0x9e, 0x12, 0x9f, 0xdf, + 0x4f, 0x67, 0x75, 0x7e, 0xe7, 0x26, 0xb2, 0xd3, 0xed, 0x0f, 0x8e, 0xfb, 0x83, 0xfd, 0xc3, 0x6e, + 0xb7, 0x37, 0x18, 0x74, 0xfb, 0x27, 0xc3, 0xd3, 0xfe, 0xbb, 0xfd, 0x6e, 0xff, 0x64, 0x30, 0x3c, + 0x3c, 0x19, 0x0e, 0xf6, 0xde, 0x9f, 0xf6, 0x87, 0x7d, 0xba, 0x95, 0xb3, 0xf6, 0x26, 0x58, 0x7b, + 0xff, 0x78, 0x7a, 0xd4, 0x1b, 0x1e, 0x3e, 0xdd, 0x7d, 0x41, 0x08, 0xcb, 0x00, 0xf3, 0xaf, 0xf7, + 0x3d, 0xba, 0x46, 0x96, 0x53, 0x51, 0x17, 0xb2, 0x25, 0x60, 0x86, 0xae, 0x90, 0x05, 0x85, 0x8c, + 0xc3, 0x2c, 0x5d, 0x25, 0x8b, 0x2d, 0x15, 0x1a, 0x84, 0x39, 0x4a, 0xc8, 0x52, 0x20, 0xe3, 0x38, + 0x34, 0x30, 0xbf, 0xfb, 0xef, 0x39, 0xb2, 0x99, 0x1f, 0x96, 0xef, 0x7b, 0xa7, 0x87, 0xc3, 0xb7, + 0xfd, 0x13, 0xdd, 0x7b, 0xd7, 0xeb, 0x0e, 0xfb, 0xa7, 0x99, 0xb7, 0x15, 0xb2, 0x20, 0xa4, 0x40, + 0x98, 0xa1, 0x4b, 0x64, 0xee, 0xa0, 0x01, 0xb3, 0xf4, 0x32, 0xb9, 0x78, 0xd0, 0xb0, 0x65, 0x0c, + 0x6a, 0xcf, 0x9f, 0x59, 0xc6, 0xb9, 0x42, 0xad, 0x61, 0x8e, 0x96, 0xc8, 0x8d, 0x83, 0x86, 0x8d, + 0x50, 0x54, 0x4d, 0xcd, 0x26, 0x0a, 0x2b, 0x61, 0x1b, 0xf9, 0x18, 0x9f, 0xa7, 0xd7, 0xc9, 0x65, + 0x8d, 0x82, 0xa3, 0x9a, 0x3e, 0xba, 0x40, 0xb7, 0x49, 0xc9, 0x43, 0xdf, 0x3b, 0xbe, 0x48, 0x2f, + 0x11, 0x08, 0xa4, 0x30, 0x8a, 0x05, 0x66, 0x6c, 0x5d, 0xa2, 0x37, 0xc8, 0x95, 0x83, 0x86, 0x8d, + 0x51, 0x6b, 0x56, 0x45, 0x1b, 0x48, 0xc1, 0x43, 0x13, 0x4a, 0xc1, 0x22, 0x58, 0x76, 0x58, 0x20, + 0x85, 0x36, 0x4c, 0x18, 0xab, 0x8d, 0x0a, 0x45, 0xd5, 0x1a, 0x69, 0x6b, 0xd8, 0x86, 0x15, 0x7a, + 0x85, 0xd0, 0xb1, 0x37, 0x85, 0x15, 0x54, 0x28, 0x02, 0x84, 0xd5, 0xdd, 0x4f, 0x1b, 0x64, 0x5d, + 0xf5, 0x06, 0xfd, 0x0f, 0xa7, 0xdd, 0x5e, 0x16, 0xfe, 0x32, 0x99, 0x67, 0xa2, 0x93, 0x47, 0x5f, + 0x6f, 0xc2, 0xac, 0x33, 0xc4, 0xbd, 0xe3, 0x5c, 0x44, 0xde, 0xfb, 0xa7, 0xfb, 0x7f, 0xde, 0x49, + 0x5e, 0x6f, 0xda, 0x32, 0x13, 0x75, 0x58, 0xa0, 0xe7, 0x09, 0xa9, 0x37, 0xad, 0x36, 0xac, 0x1e, + 0x8a, 0x2a, 0x2c, 0x7a, 0xb0, 0xc5, 0x74, 0x0c, 0x4b, 0xf4, 0x1c, 0x59, 0xad, 0x37, 0xad, 0x54, + 0x2c, 0x88, 0x10, 0x96, 0x9d, 0x93, 0x7a, 0xd3, 0xf2, 0xec, 0x4e, 0xeb, 0x64, 0xa5, 0xde, 0xb4, + 0x98, 0xc8, 0xa0, 0x06, 0xab, 0x74, 0x83, 0x5c, 0xa8, 0x37, 0xad, 0x91, 0x75, 0x14, 0x15, 0x16, + 0x18, 0xa9, 0x3a, 0x40, 0x5c, 0x48, 0xe3, 0xd3, 0xb6, 0x29, 0x0d, 0x5a, 0xc3, 0x54, 0x15, 0x8d, + 0x86, 0x35, 0x7a, 0x93, 0x5c, 0xff, 0x8a, 0xb1, 0x6a, 0x55, 0x61, 0x95, 0x99, 0x9c, 0xa5, 0x61, + 0xdd, 0x65, 0xed, 0x2b, 0x5c, 0x41, 0xe4, 0xa8, 0x34, 0x9c, 0x73, 0x59, 0xf9, 0x7a, 0x59, 0xcb, + 0x31, 0x72, 0xa7, 0x42, 0x29, 0xe0, 0x3c, 0xbd, 0x46, 0x2e, 0x15, 0xa0, 0x26, 0x8b, 0x42, 0xce, + 0x8c, 0x54, 0x70, 0xc1, 0x47, 0xc4, 0x52, 0x53, 0x03, 0xf0, 0x1e, 0xdc, 0x8f, 0x51, 0x5e, 0xac, + 0x36, 0x52, 0x21, 0x5c, 0xa4, 0x94, 0x9c, 0xf7, 0xb2, 0x58, 0x9d, 0x26, 0x49, 0xd4, 0x01, 0x4a, + 0x2f, 0x92, 0x73, 0x23, 0x1b, 0x47, 0x21, 0x63, 0xd8, 0x70, 0xa9, 0x1d, 0x99, 0xca, 0x2c, 0x62, + 0x22, 0x40, 0x0d, 0x97, 0xbc, 0xdf, 0xa2, 0x00, 0xfe, 0xc0, 0x65, 0xba, 0x45, 0xae, 0x4d, 0x43, + 0x31, 0x1a, 0xc6, 0x99, 0x61, 0x70, 0xe5, 0xac, 0x83, 0x8c, 0xc7, 0xa1, 0x80, 0xab, 0x74, 0x93, + 0x5c, 0x9d, 0x86, 0x02, 0x85, 0x59, 0x54, 0xd7, 0x3c, 0xe8, 0x15, 0xc2, 0x76, 0x50, 0x63, 0xa2, + 0x8a, 0x56, 0x31, 0x83, 0x70, 0xdd, 0x95, 0xe8, 0x94, 0xf2, 0x09, 0x0a, 0x16, 0x99, 0x8e, 0x0d, + 0x64, 0x2a, 0x0c, 0x2a, 0xb8, 0xe1, 0xaf, 0xe5, 0x39, 0x89, 0x0a, 0x03, 0xb4, 0x5a, 0xb0, 0x44, + 0xd7, 0xa4, 0x81, 0x4d, 0x7a, 0x8b, 0x6c, 0x7e, 0x2b, 0x67, 0x28, 0x85, 0x4d, 0x64, 0x0b, 0x15, + 0x6c, 0xf9, 0xe4, 0x8e, 0x08, 0x46, 0x1a, 0x16, 0x79, 0xec, 0xa6, 0xff, 0xfc, 0x37, 0xb9, 0xd0, + 0xae, 0xe4, 0x33, 0xd9, 0xa1, 0x44, 0xef, 0x92, 0x5b, 0x05, 0x4e, 0x2a, 0xca, 0xae, 0x1b, 0x26, + 0x93, 0x7a, 0x8b, 0xde, 0x27, 0x77, 0x7f, 0x40, 0x72, 0xde, 0xe1, 0xb6, 0x57, 0x63, 0x44, 0x54, + 0x58, 0xf0, 0x72, 0x67, 0xea, 0x53, 0x45, 0xd0, 0x9d, 0xb6, 0x5a, 0x05, 0xb0, 0xfd, 0x23, 0x12, + 0xd7, 0x06, 0xee, 0xd2, 0x3b, 0xe4, 0xe6, 0xf7, 0x48, 0x8d, 0x14, 0x53, 0x84, 0x1d, 0x37, 0x58, + 0xce, 0x8a, 0xdd, 0xe3, 0x3f, 0x9b, 0xc2, 0x6b, 0xa1, 0xab, 0xbe, 0x30, 0x60, 0x91, 0x0d, 0x45, + 0x45, 0xc2, 0xbd, 0xa9, 0x3a, 0x1e, 0x87, 0x0c, 0xf7, 0xbf, 0xaf, 0x6a, 0xb9, 0xe3, 0x95, 0xff, + 0xb9, 0xef, 0x43, 0x1e, 0xba, 0x09, 0x52, 0x4e, 0xb3, 0xf8, 0x1f, 0xf8, 0x4c, 0x17, 0x8d, 0xae, + 0xa5, 0x6c, 0x22, 0x65, 0x04, 0xbb, 0xf4, 0x36, 0xd9, 0x9a, 0x46, 0x13, 0x25, 0x13, 0xa9, 0x51, + 0xd9, 0x3a, 0x76, 0xe0, 0xa1, 0xcf, 0xc2, 0x04, 0x43, 0xa6, 0xc6, 0x8d, 0x2a, 0x9e, 0xcb, 0xd0, + 0x62, 0x8a, 0x6b, 0x78, 0x44, 0x1f, 0x92, 0xfb, 0xd3, 0x44, 0xaf, 0x90, 0x54, 0xb6, 0x15, 0x9a, + 0x1a, 0x57, 0xac, 0x95, 0x17, 0xc0, 0xe3, 0x9f, 0x26, 0x6b, 0xc3, 0x94, 0x71, 0xce, 0x33, 0x55, + 0xf6, 0xe8, 0x2e, 0xb9, 0x37, 0x4d, 0x76, 0x59, 0x29, 0xc8, 0x37, 0xba, 0xc5, 0xfe, 0x59, 0xd7, + 0x75, 0xdc, 0x20, 0x55, 0x0a, 0x85, 0x19, 0x13, 0x9f, 0xd0, 0x07, 0x64, 0xe7, 0x2c, 0x22, 0x0b, + 0x82, 0x34, 0xb6, 0xd9, 0xca, 0xd1, 0xda, 0x29, 0xf8, 0xd4, 0x77, 0xc3, 0x04, 0x53, 0x47, 0x4c, + 0xd7, 0x2c, 0x36, 0x51, 0x18, 0x78, 0x36, 0x92, 0x18, 0xdb, 0x76, 0x3c, 0xa8, 0x23, 0x29, 0xaa, + 0x65, 0x29, 0xeb, 0xf0, 0xdc, 0x0f, 0xbb, 0x09, 0x54, 0xd7, 0xa4, 0x32, 0x19, 0xfc, 0x0b, 0x3f, + 0xec, 0x1c, 0xac, 0xd1, 0x98, 0x08, 0x63, 0xe7, 0xf3, 0x97, 0x6e, 0xea, 0x7b, 0x73, 0xc2, 0x42, + 0xe5, 0xb7, 0x0c, 0xfc, 0x8a, 0x5e, 0x20, 0x6b, 0xde, 0x6e, 0x5a, 0x2c, 0x81, 0x5f, 0x53, 0x20, + 0xeb, 0x23, 0xa2, 0x6b, 0x63, 0xf8, 0x8d, 0x6f, 0x87, 0x49, 0x8f, 0x16, 0x85, 0x51, 0x1d, 0xf8, + 0xad, 0xef, 0x5c, 0x07, 0x2a, 0xac, 0x86, 0xda, 0xa0, 0x42, 0x9e, 0x7d, 0x02, 0x5e, 0x14, 0x5c, + 0x49, 0xc5, 0x51, 0xc1, 0xef, 0xfc, 0x04, 0xcc, 0xee, 0xee, 0x66, 0x5d, 0x04, 0xbf, 0x1f, 0x55, + 0x0c, 0xb6, 0x9d, 0x54, 0x6e, 0x9e, 0x58, 0x16, 0x98, 0xb0, 0x89, 0xf9, 0x19, 0x0d, 0x7f, 0x28, + 0x44, 0xc4, 0xb4, 0x46, 0x63, 0xa3, 0x50, 0x1b, 0xf8, 0xa3, 0xaf, 0x6d, 0x67, 0x16, 0xd8, 0x36, + 0x39, 0xdd, 0x86, 0x1c, 0x58, 0x41, 0xa1, 0x0c, 0x29, 0xdc, 0x3a, 0xe4, 0x50, 0xa6, 0x57, 0xc9, + 0x86, 0x87, 0x63, 0x66, 0x82, 0x9a, 0x55, 0xa8, 0xd3, 0xc8, 0x40, 0xe0, 0xbb, 0x69, 0x2a, 0xd0, + 0xb1, 0x5f, 0x5e, 0xb8, 0x48, 0x6e, 0xcc, 0x14, 0x47, 0x3f, 0xc3, 0x59, 0x10, 0xa0, 0xd6, 0x59, + 0x4a, 0x64, 0x04, 0x55, 0xfa, 0x88, 0x3c, 0x98, 0xb6, 0x66, 0x8b, 0xd0, 0x72, 0x4c, 0xdc, 0xc2, + 0x17, 0x41, 0xc7, 0xc6, 0x2c, 0x49, 0x5c, 0x3b, 0xd6, 0xbc, 0x54, 0x19, 0x1e, 0x48, 0x8e, 0x10, + 0xfa, 0x22, 0xf0, 0x96, 0xa9, 0xe5, 0x7f, 0xe0, 0x65, 0x9f, 0x44, 0xf3, 0xd5, 0x53, 0xf7, 0xc2, + 0x64, 0x98, 0xc6, 0x46, 0xea, 0xd6, 0x7b, 0xd6, 0x7b, 0x91, 0x9f, 0x38, 0x93, 0xa7, 0xdc, 0xe7, + 0x7c, 0xe9, 0x77, 0x20, 0xf6, 0xc5, 0x39, 0x49, 0x29, 0x77, 0x72, 0x56, 0xc8, 0x41, 0x78, 0x71, + 0x33, 0x42, 0x12, 0x0a, 0x81, 0xdc, 0x63, 0xc2, 0x6d, 0x72, 0xe9, 0x3f, 0x91, 0xad, 0xc4, 0x6a, + 0x24, 0xcb, 0x79, 0x07, 0x64, 0x69, 0x15, 0x69, 0x5c, 0x46, 0x05, 0x89, 0x5f, 0xf6, 0x8e, 0xf2, + 0x1a, 0x1a, 0xbe, 0x00, 0x2b, 0x88, 0x55, 0xc5, 0x84, 0x01, 0xe5, 0x77, 0xd8, 0xc8, 0x60, 0x59, + 0x14, 0xc9, 0x96, 0x2b, 0x16, 0xd0, 0x9e, 0x9b, 0x35, 0x8b, 0x93, 0xcd, 0xf8, 0xe2, 0x19, 0x19, + 0xf2, 0x01, 0x1c, 0x56, 0xc5, 0xb8, 0xd7, 0x53, 0xdf, 0x96, 0x63, 0x86, 0x53, 0xd0, 0x26, 0x69, + 0xb9, 0x8e, 0x1d, 0xab, 0x30, 0xca, 0xa7, 0xad, 0x13, 0xa7, 0xe9, 0xd3, 0x98, 0x95, 0x05, 0xc6, + 0xbe, 0x62, 0x5b, 0x85, 0x9c, 0x3b, 0xab, 0xaf, 0xda, 0x76, 0xa1, 0x9d, 0x9c, 0x99, 0x63, 0x22, + 0x75, 0x68, 0xa0, 0x33, 0x1a, 0x99, 0x85, 0xe6, 0x84, 0xd7, 0x85, 0x06, 0x72, 0x6d, 0xec, 0x8b, + 0x27, 0x13, 0x05, 0xfe, 0x54, 0x68, 0xf6, 0xac, 0x8b, 0x27, 0xd0, 0x3f, 0x17, 0xdf, 0x07, 0xdc, + 0xbd, 0xd5, 0x14, 0x72, 0xf8, 0x0b, 0xdd, 0x21, 0xb7, 0xa7, 0xad, 0x36, 0x96, 0x3c, 0x8d, 0xd0, + 0x9a, 0xb6, 0x4f, 0x85, 0xdd, 0x5e, 0x58, 0x79, 0x09, 0x2f, 0xb7, 0x17, 0x56, 0x5e, 0xc1, 0xab, + 0xed, 0x85, 0x95, 0x0a, 0x54, 0x76, 0x1f, 0x11, 0xda, 0x3a, 0x1c, 0x1c, 0xc7, 0xbd, 0xc1, 0xe0, + 0xf0, 0x4d, 0x4f, 0x7f, 0x38, 0x1a, 0xba, 0x77, 0xde, 0x2a, 0x59, 0x6c, 0xa4, 0xa8, 0xdc, 0x4b, + 0x6f, 0x8d, 0x2c, 0x63, 0x1b, 0x83, 0xd4, 0x20, 0xcc, 0x96, 0x0f, 0xfe, 0xfb, 0xb9, 0x34, 0xfb, + 0xf1, 0x73, 0x69, 0xf6, 0xd3, 0xe7, 0xd2, 0xec, 0x7f, 0xbe, 0x94, 0x66, 0x3e, 0x7e, 0x29, 0xcd, + 0xfc, 0xef, 0x4b, 0x69, 0xe6, 0xf5, 0x93, 0x37, 0x6f, 0x87, 0x7f, 0xfb, 0x70, 0xb4, 0xd7, 0xed, + 0x1f, 0xef, 0xfb, 0x37, 0x7c, 0xfe, 0xe7, 0xf1, 0xe0, 0xaf, 0x7f, 0xdf, 0x77, 0x4e, 0xa7, 0x1e, + 0xf5, 0x47, 0x4b, 0xd9, 0x5b, 0xfe, 0xf9, 0xff, 0x03, 0x00, 0x00, 0xff, 0xff, 0x19, 0x02, 0xe2, + 0x5e, 0xf3, 0x0b, 0x00, 0x00, } diff --git a/types/accesscontrol/resource.go b/types/accesscontrol/resource.go index feb1d99a4..a43867612 100644 --- a/types/accesscontrol/resource.go +++ b/types/accesscontrol/resource.go @@ -21,6 +21,7 @@ var ResourceTree = map[ResourceType]TreeNode{ ResourceType_KV_AUTHZ, ResourceType_KV_FEEGRANT, ResourceType_KV_SLASHING, + ResourceType_KV_BANK_DEFERRED, }}, ResourceType_Mem: {ResourceType_ANY, []ResourceType{ ResourceType_DexMem, @@ -31,9 +32,11 @@ var ResourceTree = map[ResourceType]TreeNode{ ResourceType_KV_BANK_DENOM, ResourceType_KV_BANK_BALANCES, }}, - ResourceType_KV_BANK_SUPPLY: {ResourceType_KV_BANK, []ResourceType{}}, - ResourceType_KV_BANK_DENOM: {ResourceType_KV_BANK, []ResourceType{}}, - ResourceType_KV_BANK_BALANCES: {ResourceType_KV_BANK, []ResourceType{}}, + ResourceType_KV_BANK_SUPPLY: {ResourceType_KV_BANK, []ResourceType{}}, + ResourceType_KV_BANK_DENOM: {ResourceType_KV_BANK, []ResourceType{}}, + ResourceType_KV_BANK_BALANCES: {ResourceType_KV_BANK, []ResourceType{}}, + ResourceType_KV_BANK_DEFERRED: {ResourceType_KV, []ResourceType{ResourceType_KV_BANK_DEFERRED_MODULE_TX_INDEX}}, + ResourceType_KV_BANK_DEFERRED_MODULE_TX_INDEX: {ResourceType_KV, []ResourceType{}}, ResourceType_KV_STAKING: {ResourceType_KV, []ResourceType{ ResourceType_KV_STAKING_DELEGATION, ResourceType_KV_STAKING_VALIDATOR, diff --git a/types/context.go b/types/context.go index a261aa2d8..25e4584a9 100644 --- a/types/context.go +++ b/types/context.go @@ -47,6 +47,7 @@ type Context struct { msgValidator *acltypes.MsgValidator messageIndex int // Used to track current message being processed + txIndex int contextMemCache *ContextMemCache @@ -133,6 +134,10 @@ func (c Context) MessageIndex() int { return c.messageIndex } +func (c Context) TxIndex() int { + return c.txIndex +} + func (c Context) MsgValidator() *acltypes.MsgValidator { return c.msgValidator } @@ -335,6 +340,12 @@ func (c Context) WithMessageIndex(messageIndex int) Context { return c } +// WithTxIndex returns a Context with the current transaction index that's being processed +func (c Context) WithTxIndex(txIndex int) Context { + c.txIndex = txIndex + return c +} + func (c Context) WithMsgValidator(msgValidator *acltypes.MsgValidator) Context { c.msgValidator = msgValidator return c diff --git a/types/context_cache.go b/types/context_cache.go index d3ebbf0e2..9173775c6 100644 --- a/types/context_cache.go +++ b/types/context_cache.go @@ -7,6 +7,8 @@ import ( ) type ContextMemCache struct { + storeKey StoreKey + deferredBankOpsLock *sync.Mutex deferredSends *DeferredBankOperationMapping } diff --git a/types/handler.go b/types/handler.go index c50815650..b2fd28725 100644 --- a/types/handler.go +++ b/types/handler.go @@ -10,7 +10,7 @@ type Handler func(ctx Context, msg Msg) (*Result, error) // AnteHandler authenticates transactions, before their internal messages are handled. // If newCtx.IsZero(), ctx is used instead. type AnteHandler func(ctx Context, tx Tx, simulate bool) (newCtx Context, err error) -type AnteDepGenerator func(txDeps []sdkacltypes.AccessOperation, tx Tx) (newTxDeps []sdkacltypes.AccessOperation, err error) +type AnteDepGenerator func(txDeps []sdkacltypes.AccessOperation, tx Tx, txIndex int) (newTxDeps []sdkacltypes.AccessOperation, err error) // AnteDecorator wraps the next AnteHandler to perform custom pre- and post-processing. type AnteDecorator interface { @@ -18,27 +18,27 @@ type AnteDecorator interface { } type AnteDepDecorator interface { - AnteDeps(txDeps []sdkacltypes.AccessOperation, tx Tx, next AnteDepGenerator) (newTxDeps []sdkacltypes.AccessOperation, err error) + AnteDeps(txDeps []sdkacltypes.AccessOperation, tx Tx, txIndex int, next AnteDepGenerator) (newTxDeps []sdkacltypes.AccessOperation, err error) } type DefaultDepDecorator struct{} // Defeault AnteDeps returned -func (d DefaultDepDecorator) AnteDeps(txDeps []sdkacltypes.AccessOperation, tx Tx, next AnteDepGenerator) (newTxDeps []sdkacltypes.AccessOperation, err error) { +func (d DefaultDepDecorator) AnteDeps(txDeps []sdkacltypes.AccessOperation, tx Tx, txIndex int, next AnteDepGenerator) (newTxDeps []sdkacltypes.AccessOperation, err error) { defaultDeps := []sdkacltypes.AccessOperation{ { - ResourceType: sdkacltypes.ResourceType_ANY, - AccessType: sdkacltypes.AccessType_UNKNOWN, + ResourceType: sdkacltypes.ResourceType_ANY, + AccessType: sdkacltypes.AccessType_UNKNOWN, IdentifierTemplate: "*", }, } - return next(append(txDeps, defaultDeps...), tx) + return next(append(txDeps, defaultDeps...), tx, txIndex) } type NoDepDecorator struct{} -func (d NoDepDecorator) AnteDeps(txDeps []sdkacltypes.AccessOperation, tx Tx, next AnteDepGenerator) (newTxDeps []sdkacltypes.AccessOperation, err error) { - return next(txDeps, tx) +func (d NoDepDecorator) AnteDeps(txDeps []sdkacltypes.AccessOperation, tx Tx, txIndex int, next AnteDepGenerator) (newTxDeps []sdkacltypes.AccessOperation, err error) { + return next(txDeps, tx, txIndex) } type AnteFullDecorator interface { @@ -92,8 +92,8 @@ func chainAnteDecoratorDepGenerators(chain ...AnteFullDecorator) AnteDepGenerato chain = append(chain, Terminator{}) } - return func(txDeps []sdkacltypes.AccessOperation, tx Tx) ([]sdkacltypes.AccessOperation, error) { - return chain[0].AnteDeps(txDeps, tx, chainAnteDecoratorDepGenerators(chain[1:]...)) + return func(txDeps []sdkacltypes.AccessOperation, tx Tx, txIndex int) ([]sdkacltypes.AccessOperation, error) { + return chain[0].AnteDeps(txDeps, tx, txIndex, chainAnteDecoratorDepGenerators(chain[1:]...)) } } @@ -111,7 +111,7 @@ func CustomDepWrappedAnteDecorator(decorator AnteDecorator, depDecorator AnteDep func DefaultWrappedAnteDecorator(decorator AnteDecorator) WrappedAnteDecorator { return WrappedAnteDecorator{ - Decorator: decorator, + Decorator: decorator, // TODO:: Use DefaultDepDecorator when each decorator defines their own // See NewConsumeGasForTxSizeDecorator for an example of how to implement a decorator DepDecorator: NoDepDecorator{}, @@ -122,8 +122,8 @@ func (wad WrappedAnteDecorator) AnteHandle(ctx Context, tx Tx, simulate bool, ne return wad.Decorator.AnteHandle(ctx, tx, simulate, next) } -func (wad WrappedAnteDecorator) AnteDeps(txDeps []sdkacltypes.AccessOperation, tx Tx, next AnteDepGenerator) (newTxDeps []sdkacltypes.AccessOperation, err error) { - return wad.DepDecorator.AnteDeps(txDeps, tx, next) +func (wad WrappedAnteDecorator) AnteDeps(txDeps []sdkacltypes.AccessOperation, tx Tx, txIndex int, next AnteDepGenerator) (newTxDeps []sdkacltypes.AccessOperation, err error) { + return wad.DepDecorator.AnteDeps(txDeps, tx, txIndex, next) } // Terminator AnteDecorator will get added to the chain to simplify decorator code @@ -152,6 +152,6 @@ func (t Terminator) AnteHandle(ctx Context, _ Tx, _ bool, _ AnteHandler) (Contex } // Simply return provided txDeps and nil error -func (t Terminator) AnteDeps(txDeps []sdkacltypes.AccessOperation, _ Tx, _ AnteDepGenerator) ([]sdkacltypes.AccessOperation, error) { +func (t Terminator) AnteDeps(txDeps []sdkacltypes.AccessOperation, _ Tx, _ int, _ AnteDepGenerator) ([]sdkacltypes.AccessOperation, error) { return txDeps, nil } diff --git a/x/accesscontrol/keeper/keeper.go b/x/accesscontrol/keeper/keeper.go index eb44ace29..6f41f2317 100644 --- a/x/accesscontrol/keeper/keeper.go +++ b/x/accesscontrol/keeper/keeper.go @@ -493,9 +493,6 @@ func (k Keeper) IterateWasmDependencies(ctx sdk.Context, handler func(wasmDepend } } -// use -1 to indicate that it is prior to msgs in the tx -const ANTE_MSG_INDEX = int(-1) - func (k Keeper) BuildDependencyDag(ctx sdk.Context, txDecoder sdk.TxDecoder, anteDepGen sdk.AnteDepGenerator, txs [][]byte) (*types.Dag, error) { defer MeasureBuildDagDuration(time.Now(), "BuildDependencyDag") // contains the latest msg index for a specific Access Operation @@ -506,7 +503,7 @@ func (k Keeper) BuildDependencyDag(ctx sdk.Context, txDecoder sdk.TxDecoder, ant return nil, err } // get the ante dependencies and add them to the dag - anteDeps, err := anteDepGen([]acltypes.AccessOperation{}, tx) + anteDeps, err := anteDepGen([]acltypes.AccessOperation{}, tx, txIndex) if err != nil { return nil, err } @@ -522,7 +519,7 @@ func (k Keeper) BuildDependencyDag(ctx sdk.Context, txDecoder sdk.TxDecoder, ant if err != nil { return nil, err } - dependencyDag.AddNodeBuildDependency(ANTE_MSG_INDEX, txIndex, accessOp) + dependencyDag.AddNodeBuildDependency(acltypes.ANTE_MSG_INDEX, txIndex, accessOp) } msgs := tx.GetMsgs() diff --git a/x/accesscontrol/testutil/accesscontrol.go b/x/accesscontrol/testutil/accesscontrol.go index 5de8f1771..29e25e867 100644 --- a/x/accesscontrol/testutil/accesscontrol.go +++ b/x/accesscontrol/testutil/accesscontrol.go @@ -28,6 +28,10 @@ var TestingStoreKeyToResourceTypePrefixMap = acltypes.StoreKeyToResourceTypePref acltypes.ResourceType_KV_BANK_SUPPLY: banktypes.SupplyKey, acltypes.ResourceType_KV_BANK_DENOM: banktypes.DenomMetadataPrefix, }, + banktypes.DeferredCacheStoreKey: { + acltypes.ResourceType_KV_BANK_DEFERRED: acltypes.EmptyPrefix, + acltypes.ResourceType_KV_BANK_DEFERRED_MODULE_TX_INDEX: banktypes.DeferredCachePrefix, + }, authtypes.StoreKey: { acltypes.ResourceType_KV_AUTH: acltypes.EmptyPrefix, acltypes.ResourceType_KV_AUTH_ADDRESS_STORE: authtypes.AddressStoreKeyPrefix, diff --git a/x/accesscontrol/types/graph.go b/x/accesscontrol/types/graph.go index e93d791e7..95113d79f 100644 --- a/x/accesscontrol/types/graph.go +++ b/x/accesscontrol/types/graph.go @@ -41,7 +41,7 @@ type Dag struct { NextID DagNodeID CompletionSignalingMap map[int]MessageCompletionSignalMapping // keys on tx index BlockingSignalsMap map[int]MessageCompletionSignalMapping // keys on tx index - TxMsgAccessOpMapping map[int]MsgIndexToAccessOpMapping // Mapping of Tx Index -> Msg Index -> All access ops + TxMsgAccessOpMapping map[int]MsgIndexToAccessOpMapping // Mapping of Tx Index -> Msg Index -> All access ops } // Alias for mapping MessageIndexId -> AccessOperations -> CompletionSignals @@ -115,7 +115,6 @@ func GetResourceAccess(accessOp acltypes.AccessOperation) ResourceAccess { } } - func (dag *Dag) AddAccessOpsForMsg(messageIndex int, txIndex int, accessOps []acltypes.AccessOperation) { if _, ok := dag.TxMsgAccessOpMapping[txIndex]; !ok { dag.TxMsgAccessOpMapping[txIndex] = make(MsgIndexToAccessOpMapping) @@ -124,7 +123,6 @@ func (dag *Dag) AddAccessOpsForMsg(messageIndex int, txIndex int, accessOps []ac dag.TxMsgAccessOpMapping[txIndex][messageIndex] = accessOps } - func (dag *Dag) AddNode(messageIndex int, txIndex int, accessOp acltypes.AccessOperation) DagNode { dagNode := DagNode{ NodeID: dag.NextID, diff --git a/x/auth/ante/basic.go b/x/auth/ante/basic.go index 6a716739c..3449d40df 100644 --- a/x/auth/ante/basic.go +++ b/x/auth/ante/basic.go @@ -83,7 +83,7 @@ type ConsumeTxSizeGasDecorator struct { ak AccountKeeper } -func (d ConsumeTxSizeGasDecorator) AnteDeps(txDeps []sdkacltypes.AccessOperation, tx sdk.Tx, next sdk.AnteDepGenerator) (newTxDeps []sdkacltypes.AccessOperation, err error) { +func (d ConsumeTxSizeGasDecorator) AnteDeps(txDeps []sdkacltypes.AccessOperation, tx sdk.Tx, txIndex int, next sdk.AnteDepGenerator) (newTxDeps []sdkacltypes.AccessOperation, err error) { sigTx, _ := tx.(authsigning.SigVerifiableTx) deps := []sdkacltypes.AccessOperation{} for _, signer := range sigTx.GetSigners() { @@ -99,7 +99,7 @@ func (d ConsumeTxSizeGasDecorator) AnteDeps(txDeps []sdkacltypes.AccessOperation ) } - return next(append(txDeps, deps...), tx) + return next(append(txDeps, deps...), tx, txIndex) } func NewConsumeGasForTxSizeDecorator(ak AccountKeeper) ConsumeTxSizeGasDecorator { diff --git a/x/auth/ante/fee.go b/x/auth/ante/fee.go index 8f9a3dc24..83b56a580 100644 --- a/x/auth/ante/fee.go +++ b/x/auth/ante/fee.go @@ -50,10 +50,30 @@ func NewDeductFeeDecorator( } } -func (d DeductFeeDecorator) AnteDeps(txDeps []sdkacltypes.AccessOperation, tx sdk.Tx, next sdk.AnteDepGenerator) (newTxDeps []sdkacltypes.AccessOperation, err error) { +func (d DeductFeeDecorator) AnteDeps(txDeps []sdkacltypes.AccessOperation, tx sdk.Tx, txIndex int, next sdk.AnteDepGenerator) (newTxDeps []sdkacltypes.AccessOperation, err error) { feeTx, _ := tx.(sdk.FeeTx) deps := []sdkacltypes.AccessOperation{} + moduleAdr := d.accountKeeper.GetModuleAddress(types.FeeCollectorName) + + deps = append(deps, []sdkacltypes.AccessOperation{ + { + AccessType: sdkacltypes.AccessType_READ, + ResourceType: sdkacltypes.ResourceType_KV_AUTH_ADDRESS_STORE, + IdentifierTemplate: hex.EncodeToString(authtypes.AddressStoreKey(moduleAdr)), + }, + { + AccessType: sdkacltypes.AccessType_READ, + ResourceType: sdkacltypes.ResourceType_KV_BANK_DEFERRED_MODULE_TX_INDEX, + IdentifierTemplate: hex.EncodeToString(banktypes.CreateDeferredCacheModuleTxIndexedPrefix(moduleAdr, uint64(txIndex))), + }, + { + AccessType: sdkacltypes.AccessType_WRITE, + ResourceType: sdkacltypes.ResourceType_KV_BANK_DEFERRED_MODULE_TX_INDEX, + IdentifierTemplate: hex.EncodeToString(banktypes.CreateDeferredCacheModuleTxIndexedPrefix(moduleAdr, uint64(txIndex))), + }, + }...) + if feeTx.FeePayer() != nil { deps = append(deps, []sdkacltypes.AccessOperation{ @@ -108,7 +128,7 @@ func (d DeductFeeDecorator) AnteDeps(txDeps []sdkacltypes.AccessOperation, tx sd } } - return next(append(txDeps, deps...), tx) + return next(append(txDeps, deps...), tx, txIndex) } func (dfd DeductFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { diff --git a/x/auth/ante/fee_test.go b/x/auth/ante/fee_test.go index c5951e323..06228dc15 100644 --- a/x/auth/ante/fee_test.go +++ b/x/auth/ante/fee_test.go @@ -1,10 +1,13 @@ package ante_test import ( + "fmt" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/simapp" "github.com/cosmos/cosmos-sdk/testutil/testdata" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/accesscontrol" sdkacltypes "github.com/cosmos/cosmos-sdk/types/accesscontrol" acltestutil "github.com/cosmos/cosmos-sdk/x/accesscontrol/testutil" "github.com/cosmos/cosmos-sdk/x/auth/ante" @@ -13,6 +16,16 @@ import ( paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" ) +type BadAnteDecoratorOne struct{} + +func (ad BadAnteDecoratorOne) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { + return ctx, fmt.Errorf("some error") +} + +func (ad BadAnteDecoratorOne) AnteDeps(txDeps []accesscontrol.AccessOperation, tx sdk.Tx, txIndex int, next sdk.AnteDepGenerator) (newTxDeps []accesscontrol.AccessOperation, err error) { + return next(txDeps, tx, txIndex) +} + func (suite *AnteTestSuite) TestEnsureMempoolFees() { suite.SetupTest(true) // setup suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder() @@ -122,7 +135,7 @@ func (suite *AnteTestSuite) TestDeductFees() { suite.Require().Nil(err, "Tx errored after account has been set with sufficient funds") } -func (suite *AnteTestSuite) TestLazySendToModuleAccoutn() { +func (suite *AnteTestSuite) TestLazySendToModuleAccount() { suite.SetupTest(false) // setup suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder() @@ -144,14 +157,14 @@ func (suite *AnteTestSuite) TestLazySendToModuleAccoutn() { // Set account with insufficient funds acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr1) suite.app.AccountKeeper.SetAccount(suite.ctx, acc) - err = simapp.FundAccount(suite.app.BankKeeper, suite.ctx, addr1, sdk.NewCoins(sdk.NewCoin("atom", sdk.NewInt(300)))) + err = simapp.FundAccount(suite.app.BankKeeper, suite.ctx, addr1, sdk.NewCoins(sdk.NewCoin("atom", sdk.NewInt(900)))) suite.Require().NoError(err) feeCollectorAcc := suite.app.AccountKeeper.GetModuleAccount(suite.ctx, types.FeeCollectorName) expectedFeeCollectorBalance := suite.app.BankKeeper.GetBalance(suite.ctx, feeCollectorAcc.GetAddress(), "atom") dfd := ante.NewDeductFeeDecorator(suite.app.AccountKeeper, suite.app.BankKeeper, nil, suite.app.ParamsKeeper, nil) - antehandler, _ := sdk.ChainAnteDecorators(sdk.DefaultWrappedAnteDecorator(dfd)) + antehandler, _ := sdk.ChainAnteDecorators(dfd) // Set account with sufficient funds antehandler(suite.ctx, tx, false) @@ -167,7 +180,7 @@ func (suite *AnteTestSuite) TestLazySendToModuleAccoutn() { ) // Fee Collector actual account balance deposit coins into the fee collector account - suite.app.BankKeeper.WriteDeferredDepositsToModuleAccounts(suite.ctx) + suite.app.BankKeeper.WriteDeferredBalances(suite.ctx) depositFeeCollectorBalance := suite.app.BankKeeper.GetBalance(suite.ctx, feeCollectorAcc.GetAddress(), "atom") @@ -313,6 +326,7 @@ func (suite *AnteTestSuite) TestDeductFeeDependency() { msgValidator := sdkacltypes.NewMsgValidator(acltestutil.TestingStoreKeyToResourceTypePrefixMap) suite.ctx = suite.ctx.WithMsgValidator(msgValidator) + suite.ctx = suite.ctx.WithTxIndex(1) ms := suite.ctx.MultiStore() msCache := ms.CacheMultiStore() suite.ctx = suite.ctx.WithMultiStore(msCache) @@ -320,7 +334,7 @@ func (suite *AnteTestSuite) TestDeductFeeDependency() { _, err = antehandler(suite.ctx, tx, false) suite.Require().Nil(err, "Tx errored after account has been set with sufficient funds") - newDeps, err := decorator([]sdkacltypes.AccessOperation{}, tx) + newDeps, err := decorator([]sdkacltypes.AccessOperation{}, tx, 1) suite.Require().NoError(err) storeAccessOpEvents := msCache.GetEvents() diff --git a/x/auth/ante/sigverify.go b/x/auth/ante/sigverify.go index 672a09545..8b11d5150 100644 --- a/x/auth/ante/sigverify.go +++ b/x/auth/ante/sigverify.go @@ -327,7 +327,7 @@ func NewIncrementSequenceDecorator(ak AccountKeeper) IncrementSequenceDecorator } } -func (isd IncrementSequenceDecorator) AnteDeps(txDeps []sdkacltypes.AccessOperation, tx sdk.Tx, next sdk.AnteDepGenerator) (newTxDeps []sdkacltypes.AccessOperation, err error) { +func (isd IncrementSequenceDecorator) AnteDeps(txDeps []sdkacltypes.AccessOperation, tx sdk.Tx, txIndex int, next sdk.AnteDepGenerator) (newTxDeps []sdkacltypes.AccessOperation, err error) { sigTx, _ := tx.(authsigning.SigVerifiableTx) deps := []sdkacltypes.AccessOperation{} @@ -343,7 +343,7 @@ func (isd IncrementSequenceDecorator) AnteDeps(txDeps []sdkacltypes.AccessOperat }) } - return next(append(txDeps, deps...), tx) + return next(append(txDeps, deps...), tx, txIndex) } func (isd IncrementSequenceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { diff --git a/x/auth/ante/testutil_test.go b/x/auth/ante/testutil_test.go index 8adbdc99a..30a6918af 100644 --- a/x/auth/ante/testutil_test.go +++ b/x/auth/ante/testutil_test.go @@ -173,7 +173,7 @@ func (suite *AnteTestSuite) RunTestCase(privs []cryptotypes.PrivKey, msgs []sdk. newCtx, anteErr := suite.anteHandler(suite.ctx, tx, tc.simulate) // Fee Collector actual account balance deposit coins into the fee collector account - suite.app.BankKeeper.WriteDeferredDepositsToModuleAccounts(suite.ctx) + suite.app.BankKeeper.WriteDeferredBalances(suite.ctx) if tc.expPass { suite.Require().NoError(txErr) diff --git a/x/bank/keeper/deferred_cache.go b/x/bank/keeper/deferred_cache.go new file mode 100644 index 000000000..3a6c649f7 --- /dev/null +++ b/x/bank/keeper/deferred_cache.go @@ -0,0 +1,126 @@ +package keeper + +import ( + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +type DeferredCache struct { + storeKey sdk.StoreKey + cdc codec.BinaryCodec +} + +func NewDeferredCache(cdc codec.BinaryCodec, storeKey sdk.StoreKey) *DeferredCache { + return &DeferredCache{ + cdc: cdc, + storeKey: storeKey, + } +} + +func (d *DeferredCache) getModuleTxIndexedStore(ctx sdk.Context, moduleAddr sdk.AccAddress, txIndex uint64) prefix.Store { + store := ctx.KVStore(d.storeKey) + + return prefix.NewStore(store, types.CreateDeferredCacheModuleTxIndexedPrefix(moduleAddr, txIndex)) +} + +// GetBalance returns the balance of a specific denomination for a given module address and transaction index +func (d *DeferredCache) GetBalance(ctx sdk.Context, moduleAddr sdk.AccAddress, txIndex uint64, denom string) sdk.Coin { + deferredStore := d.getModuleTxIndexedStore(ctx, moduleAddr, txIndex) + + bz := deferredStore.Get([]byte(denom)) + if bz == nil { + return sdk.NewCoin(denom, sdk.ZeroInt()) + } + + var balance sdk.Coin + d.cdc.MustUnmarshal(bz, &balance) + + return balance +} + +// setBalance sets the coin balance for a module and tx Index. +func (d *DeferredCache) setBalance(ctx sdk.Context, moduleAddr sdk.AccAddress, txIndex uint64, balance sdk.Coin) error { + if !balance.IsValid() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, balance.String()) + } + + deferredStore := d.getModuleTxIndexedStore(ctx, moduleAddr, txIndex) + // Bank invariants require to not store zero balances, so we follow the same pattern in deferred cache. + if balance.IsZero() { + deferredStore.Delete([]byte(balance.Denom)) + } else { + bz := d.cdc.MustMarshal(&balance) + deferredStore.Set([]byte(balance.Denom), bz) + } + return nil +} + +// upsertBalance updates or sets the coin balance for a module and tx combination keyed on balance denom. +func (d *DeferredCache) upsertBalance(ctx sdk.Context, moduleAddr sdk.AccAddress, txIndex uint64, balance sdk.Coin) error { + if !balance.IsValid() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, balance.String()) + } + + currBalance := d.GetBalance(ctx, moduleAddr, txIndex, balance.Denom) + newBalance := currBalance.Add(balance) + + return d.setBalance(ctx, moduleAddr, txIndex, newBalance) +} + +// UpsertBalances updates or sets the coin balances for a module and tx combination with the given coins. +func (d *DeferredCache) UpsertBalances(ctx sdk.Context, moduleAddr sdk.AccAddress, txIndex uint64, balances sdk.Coins) error { + if !balances.IsValid() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, balances.String()) + } + + // iterate through coins and upsert + for _, coin := range balances { + err := d.upsertBalance(ctx, moduleAddr, txIndex, coin) + if err != nil { + return err + } + } + return nil +} + +// IterateAccountBalances iterates over the balances of a single module for all tx indices and +// provides the token balance to a callback. +// Note that because there can be multiple tx indices per module, +// there can be multiple occurrences of the same denom in `balance`. +// If true is returned from the +// callback, iteration is halted. +func (d *DeferredCache) IterateDeferredBalances(ctx sdk.Context, cb func(moduleAddr sdk.AccAddress, balance sdk.Coin) bool) { + deferredStore := prefix.NewStore(ctx.KVStore(d.storeKey), types.DeferredCachePrefix) + + iterator := deferredStore.Iterator(nil, nil) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + var balance sdk.Coin + d.cdc.MustUnmarshal(iterator.Value(), &balance) + moduleAddr, err := types.AddressFromDeferredCacheStore(iterator.Key()) + if err != nil { + ctx.Logger().With("key", iterator.Key(), "err", err).Error("failed to get address from deferred cache store") + panic(err) + } + + if cb(moduleAddr, balance) { + break + } + } +} + +// Clear deletes all of the keys in the deferred cache +func (d *DeferredCache) Clear(ctx sdk.Context) { + store := prefix.NewStore(ctx.KVStore(d.storeKey), types.DeferredCachePrefix) + + iterator := store.Iterator(nil, nil) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + store.Delete(iterator.Key()) + } +} diff --git a/x/bank/keeper/keeper.go b/x/bank/keeper/keeper.go index 2cbe4715d..038d9708e 100644 --- a/x/bank/keeper/keeper.go +++ b/x/bank/keeper/keeper.go @@ -3,7 +3,7 @@ package keeper import ( "errors" "fmt" - "log" + "sort" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/prefix" @@ -45,8 +45,7 @@ type Keeper interface { BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error DeferredSendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error - WriteDeferredDepositsToModuleAccounts(ctx sdk.Context) []abci.Event - WriteDeferredOperations(ctx sdk.Context) []abci.Event + WriteDeferredBalances(ctx sdk.Context) []abci.Event DelegateCoins(ctx sdk.Context, delegatorAddr, moduleAccAddr sdk.AccAddress, amt sdk.Coins) error UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegatorAddr sdk.AccAddress, amt sdk.Coins) error @@ -59,6 +58,7 @@ type BaseKeeper struct { BaseSendKeeper ak types.AccountKeeper + deferredCache *DeferredCache cdc codec.BinaryCodec storeKey sdk.StoreKey paramSpace paramtypes.Subspace @@ -125,6 +125,31 @@ func NewBaseKeeper( } } +func NewBaseKeeperWithDeferredCache( + cdc codec.BinaryCodec, + storeKey sdk.StoreKey, + ak types.AccountKeeper, + paramSpace paramtypes.Subspace, + blockedAddrs map[string]bool, + deferredCacheStoreKey sdk.StoreKey, +) BaseKeeper { + + // set KeyTable if it has not already been set + if !paramSpace.HasKeyTable() { + paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) + } + + return BaseKeeper{ + BaseSendKeeper: NewBaseSendKeeper(cdc, storeKey, ak, paramSpace, blockedAddrs), + ak: ak, + deferredCache: NewDeferredCache(cdc, deferredCacheStoreKey), + cdc: cdc, + storeKey: storeKey, + paramSpace: paramSpace, + mintCoinsRestrictionFn: func(ctx sdk.Context, coins sdk.Coins) error { return nil }, + } +} + // WithMintCoinsRestriction restricts the bank Keeper used within a specific module to // have restricted permissions on minting via function passed in parameter. // Previous restriction functions can be nested as such: @@ -330,22 +355,7 @@ func (k BaseKeeper) SendCoinsFromModuleToAccount( if k.BlockedAddr(recipientAddr) { return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "%s is not allowed to receive funds", recipientAddr) } - addCoinsAmount := amt - // if we dont call the remainder, the total amount was processed against deferrred sends, so we can "addCoins" the full amount - err := ctx.ContextMemCache().AtomicSpilloverSubDeferredSends(senderModule, amt, func(amount sdk.Coins) error { - // modify the `addCoins` amount to represent the amount subtracted from deferred sends - addCoinsAmount = addCoinsAmount.Sub(amount) - // sendCoins the remainder - return k.SendCoins(ctx, senderAddr, recipientAddr, amount) - }) - if err != nil { - return err - } - if !addCoinsAmount.IsZero() { - // if we have some amount that was processed against the deferred balance, we need to send them - return k.addCoins(ctx, recipientAddr, addCoinsAmount) - } - return nil + return k.SendCoins(ctx, senderAddr, recipientAddr, amt) } // SendCoinsFromModuleToModule transfers coins from a ModuleAccount to another. @@ -370,18 +380,7 @@ func (k BaseKeeper) SendCoinsFromModuleToModule( k.Logger(ctx).Debug("Sending coins from module to module", "sender", senderModule, "sender_address", senderAddr.String(), "recipient", recipientModule, "recipient_address", recipientAcc.GetAddress().String(), "amount", amt.String()) - addCoinsAmount := amt - // if we dont call the remainder, the total amount was processed against deferrred sends, so we can "addCoins" the full amount - err := ctx.ContextMemCache().AtomicSpilloverSubDeferredSends(senderModule, amt, func(amount sdk.Coins) error { - // modify the `addCoins` amount to represent the amount subtracted from deferred sends - addCoinsAmount = addCoinsAmount.Sub(amount) - // sendCoins the remainder - return k.SendCoins(ctx, senderAddr, recipientAcc.GetAddress(), amount) - }) - if err != nil { - return err - } - return k.addCoins(ctx, recipientAcc.GetAddress(), addCoinsAmount) + return k.SendCoins(ctx, senderAddr, recipientAcc.GetAddress(), amt) } // SendCoinsFromAccountToModule transfers coins from an AccAddress to a ModuleAccount. @@ -404,13 +403,22 @@ func (k BaseKeeper) SendCoinsFromAccountToModule( func (k BaseKeeper) DeferredSendCoinsFromAccountToModule( ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amount sdk.Coins, ) error { + if k.deferredCache == nil { + panic("bank keeper created without deferred cache") + } // Deducts Fees from the Sender Account err := k.subUnlockedCoins(ctx, senderAddr, amount) if err != nil { return err } - - err = ctx.ContextMemCache().UpsertDeferredSends(recipientModule, amount) + // get recipient module address + moduleAcc := k.ak.GetModuleAccount(ctx, recipientModule) + if moduleAcc == nil { + panic(sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", recipientModule)) + } + // get txIndex + txIndex := ctx.TxIndex() + err = k.deferredCache.UpsertBalances(ctx, moduleAcc.GetAddress(), uint64(txIndex), amount) if err != nil { return err } @@ -418,26 +426,54 @@ func (k BaseKeeper) DeferredSendCoinsFromAccountToModule( return nil } -func (k BaseKeeper) WriteDeferredOperations(ctx sdk.Context) []abci.Event { - return k.WriteDeferredDepositsToModuleAccounts(ctx) -} - // WriteDeferredDepositsToModuleAccounts Iterates on all the lazy deposits and deposit them into the store -func (k BaseKeeper) WriteDeferredDepositsToModuleAccounts(ctx sdk.Context) []abci.Event { +func (k BaseKeeper) WriteDeferredBalances(ctx sdk.Context) []abci.Event { + if k.deferredCache == nil { + panic("bank keeper created without deferred cache") + } ctx = ctx.WithEventManager(sdk.NewEventManager()) - ctx.ContextMemCache().RangeOnDeferredSendsAndDelete( - func(recipient string, amount sdk.Coins) { - recipientAcc := k.ak.GetModuleAccount(ctx, recipient) - if recipientAcc == nil { - panic(sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", recipient)) - } - log.Printf("Adding coin=%s to module=%s address=%s", amount, recipient, recipientAcc.GetAddress()) - err := k.addCoins(ctx, recipientAcc.GetAddress(), amount) - if err != nil { - ctx.Logger().Error(fmt.Sprintf("Failed to add coin=%s to module=%s address=%s, error is: %s", amount, recipient, recipientAcc.GetAddress(), err)) - } - }, - ) + + // maps between bech32 stringified module account address and balance + moduleAddrBalanceMap := make(map[string]sdk.Coins) + // slice of modules to be sorted for consistent write order later + moduleList := []string{} + + // iterate over deferred cache and accumulate totals per module + k.deferredCache.IterateDeferredBalances(ctx, func(moduleAddr sdk.AccAddress, amount sdk.Coin) bool { + currCoins, ok := moduleAddrBalanceMap[moduleAddr.String()] + if !ok { + // add to list of modules + moduleList = append(moduleList, moduleAddr.String()) + // set the map value + moduleAddrBalanceMap[moduleAddr.String()] = sdk.NewCoins(amount) + return false + } + // add to currCoins + newCoins := currCoins.Add(amount) + // update map + moduleAddrBalanceMap[moduleAddr.String()] = newCoins + return false + }) + // sort module list + sort.Strings(moduleList) + + // iterate through module list and add the balance to module bank balances in sorted order + for _, moduleBech32Addr := range moduleList { + amount, ok := moduleAddrBalanceMap[moduleBech32Addr] + if !ok { + err := fmt.Errorf("Failed to get module balance for writing deferred balances for address=%s", moduleBech32Addr) + ctx.Logger().Error(err.Error()) + panic(err) + } + err := k.addCoins(ctx, sdk.MustAccAddressFromBech32(moduleBech32Addr), amount) + if err != nil { + ctx.Logger().Error(fmt.Sprintf("Failed to add coin=%s to module address=%s, error is: %s", amount, moduleBech32Addr, err)) + panic(err) + } + } + + // clear deferred cache + k.deferredCache.Clear(ctx) return ctx.EventManager().ABCIEvents() } @@ -568,12 +604,8 @@ func (k BaseKeeper) destroyCoins(ctx sdk.Context, moduleName string, amounts sdk // It will panic if the module account does not exist or is unauthorized. func (k BaseKeeper) BurnCoins(ctx sdk.Context, moduleName string, amounts sdk.Coins) error { subFn := func(ctx sdk.Context, moduleName string, amounts sdk.Coins) error { - // first subtract from deferred sends - return ctx.ContextMemCache().AtomicSpilloverSubDeferredSends(moduleName, amounts, func(remainder sdk.Coins) error { - acc := k.ak.GetModuleAccount(ctx, moduleName) - // then sub Unlocked coins on the remainder, if there is an error here, contextMemcache will rollback AND subFn will error - return k.subUnlockedCoins(ctx, acc.GetAddress(), remainder) - }) + acc := k.ak.GetModuleAccount(ctx, moduleName) + return k.subUnlockedCoins(ctx, acc.GetAddress(), amounts) } err := k.destroyCoins(ctx, moduleName, amounts, subFn) diff --git a/x/bank/keeper/keeper_test.go b/x/bank/keeper/keeper_test.go index 20c3dea0b..67da81254 100644 --- a/x/bank/keeper/keeper_test.go +++ b/x/bank/keeper/keeper_test.go @@ -84,9 +84,9 @@ func (suite *IntegrationTestSuite) initKeepersWithmAccPerms(blockedAddrs map[str appCodec, app.GetKey(types.StoreKey), app.GetSubspace(types.ModuleName), authtypes.ProtoBaseAccount, maccPerms, ) - keeper := keeper.NewBaseKeeper( + keeper := keeper.NewBaseKeeperWithDeferredCache( appCodec, app.GetKey(types.StoreKey), authKeeper, - app.GetSubspace(types.ModuleName), blockedAddrs, + app.GetSubspace(types.ModuleName), blockedAddrs, app.GetMemKey(types.DeferredCacheStoreKey), ) return authKeeper, keeper @@ -702,14 +702,14 @@ func (suite *IntegrationTestSuite) TestWriteDeferredOperations() { suite.Require().Equal(bankBalances, app.BankKeeper.GetAllBalances(ctx, multiPermAcc.GetAddress())) // write deferred balances - app.BankKeeper.WriteDeferredOperations(ctx) + app.BankKeeper.WriteDeferredBalances(ctx) // verify total balance in module bank balances suite.Require().Equal(sdk.NewCoins(newFooCoin(30), newBarCoin(80)), app.BankKeeper.GetAllBalances(ctx, multiPermAcc.GetAddress())) // test error ctx.ContextMemCache().GetDeferredSends().Set("asd", deferredBalances) - suite.Require().Panics(func() { app.BankKeeper.WriteDeferredOperations(ctx) }) + suite.Require().Panics(func() { app.BankKeeper.WriteDeferredBalances(ctx) }) } @@ -1337,8 +1337,8 @@ func (suite *IntegrationTestSuite) TestBalanceTrackingEvents() { authtypes.ProtoBaseAccount, maccPerms, ) - suite.app.BankKeeper = keeper.NewBaseKeeper(suite.app.AppCodec(), suite.app.GetKey(types.StoreKey), - suite.app.AccountKeeper, suite.app.GetSubspace(types.ModuleName), nil) + suite.app.BankKeeper = keeper.NewBaseKeeperWithDeferredCache(suite.app.AppCodec(), suite.app.GetKey(types.StoreKey), + suite.app.AccountKeeper, suite.app.GetSubspace(types.ModuleName), nil, suite.app.GetKey(types.DeferredCacheStoreKey)) // set account with multiple permissions suite.app.AccountKeeper.SetModuleAccount(suite.ctx, multiPermAcc) @@ -1497,8 +1497,8 @@ func (suite *IntegrationTestSuite) TestMintCoinRestrictions() { } for _, test := range tests { - suite.app.BankKeeper = keeper.NewBaseKeeper(suite.app.AppCodec(), suite.app.GetKey(types.StoreKey), - suite.app.AccountKeeper, suite.app.GetSubspace(types.ModuleName), nil).WithMintCoinsRestriction(keeper.MintingRestrictionFn(test.restrictionFn)) + suite.app.BankKeeper = keeper.NewBaseKeeperWithDeferredCache(suite.app.AppCodec(), suite.app.GetKey(types.StoreKey), + suite.app.AccountKeeper, suite.app.GetSubspace(types.ModuleName), nil, suite.app.GetKey(types.DeferredCacheStoreKey)).WithMintCoinsRestriction(keeper.MintingRestrictionFn(test.restrictionFn)) for _, testCase := range test.testCases { if testCase.expectPass { suite.Require().NoError( diff --git a/x/bank/types/key.go b/x/bank/types/key.go index 77338a3bd..8b8c25a2d 100644 --- a/x/bank/types/key.go +++ b/x/bank/types/key.go @@ -13,6 +13,9 @@ const ( // StoreKey defines the primary module store key StoreKey = ModuleName + // DeferredCacheStoreKey defines the store key for the deferred cache + DeferredCacheStoreKey = "deferredcache" + // RouterKey defines the module's message routing key RouterKey = ModuleName @@ -24,6 +27,7 @@ const ( var ( // BalancesPrefix is the prefix for the account balances store. We use a byte // (instead of `[]byte("balances")` to save some disk space). + DeferredCachePrefix = []byte{0x03} BalancesPrefix = []byte{0x02} SupplyKey = []byte{0x00} DenomMetadataPrefix = []byte{0x1} @@ -69,3 +73,31 @@ func CreateAccountBalancesPrefixFromBech32(addr string) []byte { func CreatePrefixedAccountStoreKey(addr []byte, denom []byte) []byte { return append(CreateAccountBalancesPrefix(addr), denom...) } + +// This creates the prefix for use for the mem KV store used to track deferred balances by module name +func CreateDeferredCacheModulePrefix(moduleAddr []byte) []byte { + return append(DeferredCachePrefix, address.MustLengthPrefix(moduleAddr)...) +} + +// This creates the prefix for use for the mem KV store used to track deferred balances by module and txIndex to appropriately partition reads and writes to and from module balances +func CreateDeferredCacheModuleTxIndexedPrefix(moduleAddr []byte, index uint64) []byte { + return append(CreateDeferredCacheModulePrefix(moduleAddr), sdk.Uint64ToBigEndian(index)...) +} + +// AddressFromDeferredCacheStore returns an account address from a deferred Cache prefix +// store. The key must not contain the prefix DeferredCachePrefix as the prefix store +// iterator discards the actual prefix. +// +// If invalid key is passed, AddressFromBalancesStore returns ErrInvalidKey. +func AddressFromDeferredCacheStore(key []byte) (sdk.AccAddress, error) { + if len(key) == 0 { + return nil, ErrInvalidKey + } + kv.AssertKeyAtLeastLength(key, 1) + addrLen := key[0] + bound := int(addrLen) + if len(key)-1 < bound { + return nil, ErrInvalidKey + } + return key[1 : bound+1], nil +} From 28f13104fcf5d804d580549b0e34ea8e29aaa52c Mon Sep 17 00:00:00 2001 From: Uday Patil Date: Tue, 13 Jun 2023 22:37:27 -0500 Subject: [PATCH 2/4] fix tests --- baseapp/block_gas_test.go | 2 +- types/accesscontrol/resource.go | 2 +- x/accesscontrol/keeper/keeper_test.go | 8 +- x/bank/keeper/keeper_test.go | 105 ++++---------------------- 4 files changed, 19 insertions(+), 98 deletions(-) diff --git a/baseapp/block_gas_test.go b/baseapp/block_gas_test.go index f636afb8a..7d9e02c7b 100644 --- a/baseapp/block_gas_test.go +++ b/baseapp/block_gas_test.go @@ -125,7 +125,7 @@ func TestBaseApp_BlockGas(t *testing.T) { } // check block gas is always consumed - this value may change if we update the logic for // how gas is consumed - baseGas := uint64(52585) // baseGas is the gas consumed before tx msg + baseGas := uint64(58406) // baseGas is the gas consumed before tx msg expGasConsumed := addUint64Saturating(tc.gasToConsume, baseGas) if expGasConsumed > txtypes.MaxGasWanted { // capped by gasLimit diff --git a/types/accesscontrol/resource.go b/types/accesscontrol/resource.go index a43867612..a1c4c7190 100644 --- a/types/accesscontrol/resource.go +++ b/types/accesscontrol/resource.go @@ -36,7 +36,7 @@ var ResourceTree = map[ResourceType]TreeNode{ ResourceType_KV_BANK_DENOM: {ResourceType_KV_BANK, []ResourceType{}}, ResourceType_KV_BANK_BALANCES: {ResourceType_KV_BANK, []ResourceType{}}, ResourceType_KV_BANK_DEFERRED: {ResourceType_KV, []ResourceType{ResourceType_KV_BANK_DEFERRED_MODULE_TX_INDEX}}, - ResourceType_KV_BANK_DEFERRED_MODULE_TX_INDEX: {ResourceType_KV, []ResourceType{}}, + ResourceType_KV_BANK_DEFERRED_MODULE_TX_INDEX: {ResourceType_KV_BANK_DEFERRED, []ResourceType{}}, ResourceType_KV_STAKING: {ResourceType_KV, []ResourceType{ ResourceType_KV_STAKING_DELEGATION, ResourceType_KV_STAKING_VALIDATOR, diff --git a/x/accesscontrol/keeper/keeper_test.go b/x/accesscontrol/keeper/keeper_test.go index 421985808..f08cd1ade 100644 --- a/x/accesscontrol/keeper/keeper_test.go +++ b/x/accesscontrol/keeper/keeper_test.go @@ -2114,7 +2114,7 @@ func TestBuildDependencyDag_MultipleTransactions(t *testing.T) { _, err = app.AccessControlKeeper.BuildDependencyDag(ctx, simapp.MakeTestEncodingConfig().TxConfig.TxDecoder(), app.GetAnteDepGenerator(), txs) require.NoError(t, err) - mockAnteDepGenerator := func(_ []acltypes.AccessOperation, _ sdk.Tx) ([]acltypes.AccessOperation, error) { + mockAnteDepGenerator := func(_ []acltypes.AccessOperation, _ sdk.Tx, _ int) ([]acltypes.AccessOperation, error) { return nil, errors.New("Mocked error") } _, err = app.AccessControlKeeper.BuildDependencyDag(ctx, simapp.MakeTestEncodingConfig().TxConfig.TxDecoder(), mockAnteDepGenerator, txs) @@ -2182,7 +2182,7 @@ func BencharkAccessOpsBuildDependencyDag(b *testing.B) { bz2, } - mockAnteDepGenerator := func(_ []acltypes.AccessOperation, _ sdk.Tx) ([]acltypes.AccessOperation, error) { + mockAnteDepGenerator := func(_ []acltypes.AccessOperation, _ sdk.Tx, _ int) ([]acltypes.AccessOperation, error) { return []acltypes.AccessOperation{ { ResourceType: acltypes.ResourceType_KV_AUTH_GLOBAL_ACCOUNT_NUMBER, @@ -2273,7 +2273,7 @@ func TestInvalidAccessOpsBuildDependencyDag(t *testing.T) { bz2, } - mockAnteDepGenerator := func(_ []acltypes.AccessOperation, _ sdk.Tx) ([]acltypes.AccessOperation, error) { + mockAnteDepGenerator := func(_ []acltypes.AccessOperation, _ sdk.Tx, _ int) ([]acltypes.AccessOperation, error) { return []acltypes.AccessOperation{ { ResourceType: acltypes.ResourceType_KV, @@ -2288,7 +2288,7 @@ func TestInvalidAccessOpsBuildDependencyDag(t *testing.T) { ctx, simapp.MakeTestEncodingConfig().TxConfig.TxDecoder(), mockAnteDepGenerator, txs) require.Error(t, err) - mockAnteDepGenerator = func(_ []acltypes.AccessOperation, _ sdk.Tx) ([]acltypes.AccessOperation, error) { + mockAnteDepGenerator = func(_ []acltypes.AccessOperation, _ sdk.Tx, _ int) ([]acltypes.AccessOperation, error) { return []acltypes.AccessOperation{ { ResourceType: acltypes.ResourceType_KV_AUTH_GLOBAL_ACCOUNT_NUMBER, diff --git a/x/bank/keeper/keeper_test.go b/x/bank/keeper/keeper_test.go index 67da81254..8514677a3 100644 --- a/x/bank/keeper/keeper_test.go +++ b/x/bank/keeper/keeper_test.go @@ -478,10 +478,9 @@ func (suite *IntegrationTestSuite) TestSendCoins() { suite.Require().Equal(newBarCoin(25), coins[0], "expected only bar coins in the account balance, got: %v", coins) } -func (suite *IntegrationTestSuite) TestSendCoinsModuleToAccountWithDeferredBalance() { +func (suite *IntegrationTestSuite) TestSendCoinsModuleToAccount() { // add module accounts to supply keeper ctx := suite.ctx - ctx = ctx.WithContextMemCache(sdk.NewContextMemCache()) authKeeper, keeper := suite.initKeepersWithmAccPerms(make(map[string]bool)) authKeeper.SetModuleAccount(ctx, multiPermAcc) app := suite.app @@ -491,10 +490,7 @@ func (suite *IntegrationTestSuite) TestSendCoinsModuleToAccountWithDeferredBalan acc1 := authKeeper.NewAccountWithAddress(ctx, addr1) authKeeper.SetAccount(ctx, acc1) - deferredBalances := sdk.NewCoins(newFooCoin(10), newBarCoin(50)) bankBalances := sdk.NewCoins(newFooCoin(20), newBarCoin(30)) - // setup deferred balances - ctx.ContextMemCache().UpsertDeferredSends(multiPerm, deferredBalances) // set up bank balances suite.Require().NoError(simapp.FundAccount(app.BankKeeper, ctx, multiPermAcc.GetAddress(), bankBalances)) @@ -502,12 +498,8 @@ func (suite *IntegrationTestSuite) TestSendCoinsModuleToAccountWithDeferredBalan sendCoins := sdk.NewCoins(newFooCoin(20), newBarCoin(20)) // perform send from module to account suite.Require().NoError(app.BankKeeper.SendCoinsFromModuleToAccount(ctx, multiPerm, addr1, sendCoins)) - expectedDeferredBalances := sdk.NewCoins(newBarCoin(30)) - expectedBankBalances := sdk.NewCoins(newFooCoin(10), newBarCoin(30)) + expectedBankBalances := sdk.NewCoins(newBarCoin(10)) // assert module balances correct - deferredBals, ok := ctx.ContextMemCache().GetDeferredSends().Get(multiPerm) - suite.Require().True(ok) - suite.Require().Equal(expectedDeferredBalances, deferredBals) bals := app.BankKeeper.GetAllBalances(ctx, multiPermAcc.GetAddress()) suite.Require().Equal(expectedBankBalances, bals) // assert receiver balances correct @@ -516,48 +508,25 @@ func (suite *IntegrationTestSuite) TestSendCoinsModuleToAccountWithDeferredBalan // perform same send from module to account - should fail this time - all vals should remain same suite.Require().Error(app.BankKeeper.SendCoinsFromModuleToAccount(ctx, multiPerm, addr1, sendCoins)) - expectedDeferredBalances = sdk.NewCoins(newBarCoin(30)) - expectedBankBalances = sdk.NewCoins(newFooCoin(10), newBarCoin(30)) + expectedBankBalances = sdk.NewCoins(newBarCoin(10)) // assert module balances correct - deferredBals, ok = ctx.ContextMemCache().GetDeferredSends().Get(multiPerm) - suite.Require().True(ok) - suite.Require().Equal(expectedDeferredBalances, deferredBals) bals = app.BankKeeper.GetAllBalances(ctx, multiPermAcc.GetAddress()) suite.Require().Equal(expectedBankBalances, bals) // assert receiver balances correct userBals = app.BankKeeper.GetAllBalances(ctx, addr1) suite.Require().Equal(sendCoins, userBals) - - // perform send 2 that only processes against deferred balances - sendCoins2 := sdk.NewCoins(newBarCoin(20)) - suite.Require().NoError(app.BankKeeper.SendCoinsFromModuleToAccount(ctx, multiPerm, addr1, sendCoins2)) - expectedDeferredBalances = sdk.NewCoins(newBarCoin(10)) - expectedBankBalances = sdk.NewCoins(newFooCoin(10), newBarCoin(30)) - // assert module balances correct - deferredBals, ok = ctx.ContextMemCache().GetDeferredSends().Get(multiPerm) - suite.Require().True(ok) - suite.Require().Equal(expectedDeferredBalances, deferredBals) - bals = app.BankKeeper.GetAllBalances(ctx, multiPermAcc.GetAddress()) - suite.Require().Equal(expectedBankBalances, bals) - // assert receiver balances correct - userBals = app.BankKeeper.GetAllBalances(ctx, addr1) - suite.Require().Equal(sendCoins.Add(sendCoins2...), userBals) } -func (suite *IntegrationTestSuite) TestSendCoinsModuleToModuleWithDeferredBalance() { +func (suite *IntegrationTestSuite) TestSendCoinsModuleToModule() { // add module accounts to supply keeper ctx := suite.ctx - ctx = ctx.WithContextMemCache(sdk.NewContextMemCache()) authKeeper, keeper := suite.initKeepersWithmAccPerms(make(map[string]bool)) authKeeper.SetModuleAccount(ctx, multiPermAcc) authKeeper.SetModuleAccount(ctx, randomPermAcc) app := suite.app app.BankKeeper = keeper - deferredBalances := sdk.NewCoins(newFooCoin(10), newBarCoin(50)) bankBalances := sdk.NewCoins(newFooCoin(20), newBarCoin(30)) - // setup deferred balances - ctx.ContextMemCache().UpsertDeferredSends(multiPerm, deferredBalances) // set up bank balances suite.Require().NoError(simapp.FundAccount(app.BankKeeper, ctx, multiPermAcc.GetAddress(), bankBalances)) @@ -565,12 +534,8 @@ func (suite *IntegrationTestSuite) TestSendCoinsModuleToModuleWithDeferredBalanc sendCoins := sdk.NewCoins(newFooCoin(20), newBarCoin(20)) // perform send from module to module suite.Require().NoError(app.BankKeeper.SendCoinsFromModuleToModule(ctx, multiPerm, randomPerm, sendCoins)) - expectedDeferredBalances := sdk.NewCoins(newBarCoin(30)) - expectedBankBalances := sdk.NewCoins(newFooCoin(10), newBarCoin(30)) + expectedBankBalances := sdk.NewCoins(newBarCoin(10)) // assert module balances correct - deferredBals, ok := ctx.ContextMemCache().GetDeferredSends().Get(multiPerm) - suite.Require().True(ok) - suite.Require().Equal(expectedDeferredBalances, deferredBals) bals := app.BankKeeper.GetAllBalances(ctx, multiPermAcc.GetAddress()) suite.Require().Equal(expectedBankBalances, bals) // assert receiver balances correct @@ -579,38 +544,18 @@ func (suite *IntegrationTestSuite) TestSendCoinsModuleToModuleWithDeferredBalanc // perform same send from module to module - should fail this time - all vals should remain same suite.Require().Error(app.BankKeeper.SendCoinsFromModuleToModule(ctx, multiPerm, randomPerm, sendCoins)) - expectedDeferredBalances = sdk.NewCoins(newBarCoin(30)) - expectedBankBalances = sdk.NewCoins(newFooCoin(10), newBarCoin(30)) + expectedBankBalances = sdk.NewCoins(newBarCoin(10)) // assert module balances correct - deferredBals, ok = ctx.ContextMemCache().GetDeferredSends().Get(multiPerm) - suite.Require().True(ok) - suite.Require().Equal(expectedDeferredBalances, deferredBals) bals = app.BankKeeper.GetAllBalances(ctx, multiPermAcc.GetAddress()) suite.Require().Equal(expectedBankBalances, bals) // assert receiver balances correct userBals = app.BankKeeper.GetAllBalances(ctx, randomPermAcc.GetAddress()) suite.Require().Equal(sendCoins, userBals) - - // perform send 2 that only processes against deferred balances - sendCoins2 := sdk.NewCoins(newBarCoin(20)) - suite.Require().NoError(app.BankKeeper.SendCoinsFromModuleToModule(ctx, multiPerm, randomPerm, sendCoins2)) - expectedDeferredBalances = sdk.NewCoins(newBarCoin(10)) - expectedBankBalances = sdk.NewCoins(newFooCoin(10), newBarCoin(30)) - // assert module balances correct - deferredBals, ok = ctx.ContextMemCache().GetDeferredSends().Get(multiPerm) - suite.Require().True(ok) - suite.Require().Equal(expectedDeferredBalances, deferredBals) - bals = app.BankKeeper.GetAllBalances(ctx, multiPermAcc.GetAddress()) - suite.Require().Equal(expectedBankBalances, bals) - // assert receiver balances correct - userBals = app.BankKeeper.GetAllBalances(ctx, randomPermAcc.GetAddress()) - suite.Require().Equal(sendCoins.Add(sendCoins2...), userBals) } -func (suite *IntegrationTestSuite) TestBurnCoinsWithDeferredBalance() { +func (suite *IntegrationTestSuite) TestBurnCoins() { // add module accounts to supply keeper ctx := suite.ctx - ctx = ctx.WithContextMemCache(sdk.NewContextMemCache()) authKeeper, keeper := suite.initKeepersWithmAccPerms(make(map[string]bool)) authKeeper.SetModuleAccount(ctx, multiPermAcc) app := suite.app @@ -625,9 +570,9 @@ func (suite *IntegrationTestSuite) TestBurnCoinsWithDeferredBalance() { suite.Require().NoError(simapp.FundAccount(app.BankKeeper, ctx, addr2, deferredBalances)) suite.Require().NoError(app.BankKeeper.DeferredSendCoinsFromAccountToModule(ctx, addr2, multiPerm, deferredBalances)) + app.BankKeeper.WriteDeferredBalances(ctx) + bankBalances := sdk.NewCoins(newFooCoin(20), newBarCoin(30)) - // setup deferred balances - // ctx.ContextMemCache().UpsertDeferredSends(multiPerm, deferredBalances) // set up bank balances suite.Require().NoError(simapp.FundAccount(app.BankKeeper, ctx, multiPermAcc.GetAddress(), bankBalances)) @@ -635,39 +580,18 @@ func (suite *IntegrationTestSuite) TestBurnCoinsWithDeferredBalance() { sendCoins := sdk.NewCoins(newFooCoin(20), newBarCoin(20)) // perform burn suite.Require().NoError(app.BankKeeper.BurnCoins(ctx, multiPerm, sendCoins)) - expectedDeferredBalances := sdk.NewCoins(newBarCoin(30)) - expectedBankBalances := sdk.NewCoins(newFooCoin(10), newBarCoin(30)) + expectedBankBalances := sdk.NewCoins(newFooCoin(10), newBarCoin(60)) // assert module balances correct - deferredBals, ok := ctx.ContextMemCache().GetDeferredSends().Get(multiPerm) - suite.Require().True(ok) - suite.Require().Equal(expectedDeferredBalances, deferredBals) bals := app.BankKeeper.GetAllBalances(ctx, multiPermAcc.GetAddress()) suite.Require().Equal(expectedBankBalances, bals) suite.Require().Equal(newFooCoin(10), app.BankKeeper.GetSupply(ctx, "foo")) suite.Require().Equal(newBarCoin(60), app.BankKeeper.GetSupply(ctx, "bar")) - // perform same burn - should fail this time - all vals should remain same - suite.Require().Error(app.BankKeeper.BurnCoins(ctx, multiPerm, sendCoins)) - expectedDeferredBalances = sdk.NewCoins(newBarCoin(30)) - expectedBankBalances = sdk.NewCoins(newFooCoin(10), newBarCoin(30)) - // assert module balances correct - deferredBals, ok = ctx.ContextMemCache().GetDeferredSends().Get(multiPerm) - suite.Require().True(ok) - suite.Require().Equal(expectedDeferredBalances, deferredBals) - bals = app.BankKeeper.GetAllBalances(ctx, multiPermAcc.GetAddress()) - suite.Require().Equal(expectedBankBalances, bals) - suite.Require().Equal(newFooCoin(10), app.BankKeeper.GetSupply(ctx, "foo")) - suite.Require().Equal(newBarCoin(60), app.BankKeeper.GetSupply(ctx, "bar")) - - // perform burn 2 that only processes against deferred balances + // perform burn 2 sendCoins2 := sdk.NewCoins(newBarCoin(20)) + expectedBankBalances = sdk.NewCoins(newFooCoin(10), newBarCoin(40)) suite.Require().NoError(app.BankKeeper.BurnCoins(ctx, multiPerm, sendCoins2)) - expectedDeferredBalances = sdk.NewCoins(newBarCoin(10)) - expectedBankBalances = sdk.NewCoins(newFooCoin(10), newBarCoin(30)) // assert module balances correct - deferredBals, ok = ctx.ContextMemCache().GetDeferredSends().Get(multiPerm) - suite.Require().True(ok) - suite.Require().Equal(expectedDeferredBalances, deferredBals) bals = app.BankKeeper.GetAllBalances(ctx, multiPermAcc.GetAddress()) suite.Require().Equal(expectedBankBalances, bals) suite.Require().Equal(newFooCoin(10), app.BankKeeper.GetSupply(ctx, "foo")) @@ -677,7 +601,6 @@ func (suite *IntegrationTestSuite) TestBurnCoinsWithDeferredBalance() { func (suite *IntegrationTestSuite) TestWriteDeferredOperations() { // add module accounts to supply keeper ctx := suite.ctx - ctx = ctx.WithContextMemCache(sdk.NewContextMemCache()) authKeeper, keeper := suite.initKeepersWithmAccPerms(make(map[string]bool)) authKeeper.SetModuleAccount(ctx, multiPermAcc) app := suite.app @@ -708,9 +631,7 @@ func (suite *IntegrationTestSuite) TestWriteDeferredOperations() { suite.Require().Equal(sdk.NewCoins(newFooCoin(30), newBarCoin(80)), app.BankKeeper.GetAllBalances(ctx, multiPermAcc.GetAddress())) // test error - ctx.ContextMemCache().GetDeferredSends().Set("asd", deferredBalances) - suite.Require().Panics(func() { app.BankKeeper.WriteDeferredBalances(ctx) }) - + suite.Require().Error(app.BankKeeper.DeferredSendCoinsFromAccountToModule(ctx, addr2, "asdas", deferredBalances)) } func (suite *IntegrationTestSuite) TestValidateBalance() { From 36d9bb68a843047086bfd51eaa71180349fa7f8c Mon Sep 17 00:00:00 2001 From: Uday Patil Date: Wed, 14 Jun 2023 09:58:13 -0500 Subject: [PATCH 3/4] remove context cache and add deferred cache tests --- types/context.go | 31 +-- types/context_cache.go | 89 --------- types/context_cache_test.go | 279 --------------------------- types/deferred_bank_operations.go | 117 ----------- x/bank/keeper/deferred_cache_test.go | 85 ++++++++ x/bank/keeper/keeper_test.go | 2 - 6 files changed, 94 insertions(+), 509 deletions(-) delete mode 100644 types/context_cache.go delete mode 100644 types/context_cache_test.go delete mode 100644 types/deferred_bank_operations.go create mode 100644 x/bank/keeper/deferred_cache_test.go diff --git a/types/context.go b/types/context.go index 25e4584a9..ef847d3a3 100644 --- a/types/context.go +++ b/types/context.go @@ -49,8 +49,6 @@ type Context struct { messageIndex int // Used to track current message being processed txIndex int - contextMemCache *ContextMemCache - traceSpanContext context.Context } @@ -142,10 +140,6 @@ func (c Context) MsgValidator() *acltypes.MsgValidator { return c.msgValidator } -func (c Context) ContextMemCache() *ContextMemCache { - return c.contextMemCache -} - // clone the header before returning func (c Context) BlockHeader() tmproto.Header { msg := proto.Clone(&c.header).(*tmproto.Header) @@ -178,16 +172,15 @@ func NewContext(ms MultiStore, header tmproto.Header, isCheckTx bool, logger log // https://github.com/gogo/protobuf/issues/519 header.Time = header.Time.UTC() return Context{ - ctx: context.Background(), - ms: ms, - header: header, - chainID: header.ChainID, - checkTx: isCheckTx, - logger: logger, - gasMeter: stypes.NewInfiniteGasMeter(), - minGasPrice: DecCoins{}, - eventManager: NewEventManager(), - contextMemCache: NewContextMemCache(), + ctx: context.Background(), + ms: ms, + header: header, + chainID: header.ChainID, + checkTx: isCheckTx, + logger: logger, + gasMeter: stypes.NewInfiniteGasMeter(), + minGasPrice: DecCoins{}, + eventManager: NewEventManager(), txBlockingChannels: make(acltypes.MessageAccessOpsChannelMapping), txCompletionChannels: make(acltypes.MessageAccessOpsChannelMapping), @@ -351,12 +344,6 @@ func (c Context) WithMsgValidator(msgValidator *acltypes.MsgValidator) Context { return c } -// WithContextMemCache returns a Context with a new context mem cache -func (c Context) WithContextMemCache(contextMemCache *ContextMemCache) Context { - c.contextMemCache = contextMemCache - return c -} - func (c Context) WithTraceSpanContext(ctx context.Context) Context { c.traceSpanContext = ctx return c diff --git a/types/context_cache.go b/types/context_cache.go deleted file mode 100644 index 9173775c6..000000000 --- a/types/context_cache.go +++ /dev/null @@ -1,89 +0,0 @@ -package types - -import ( - "sync" - - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" -) - -type ContextMemCache struct { - storeKey StoreKey - - deferredBankOpsLock *sync.Mutex - deferredSends *DeferredBankOperationMapping -} - -func NewContextMemCache() *ContextMemCache { - return &ContextMemCache{ - deferredBankOpsLock: &sync.Mutex{}, - deferredSends: NewDeferredBankOperationMap(), - } -} - -func (c *ContextMemCache) GetDeferredSends() *DeferredBankOperationMapping { - return c.deferredSends -} - -func (c *ContextMemCache) UpsertDeferredSends(moduleAccount string, amount Coins) error { - if !amount.IsValid() { - return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, amount.String()) - } - - // Separate locks needed for all mappings - atomic transaction needed - c.deferredBankOpsLock.Lock() - defer c.deferredBankOpsLock.Unlock() - - c.deferredSends.UpsertMapping(moduleAccount, amount) - return nil -} - -// This will perform a saturating sub against the deferred module balance atomically. This means that it will subtract any balances that it is able to, and then call the passed in `remainder handler` to ensure the remaining balance can be safely subtracted as well. If this remainderHandler returns an error, we will revert the saturating sub to ensure atomicity of the subtraction across the multiple balances -func (c *ContextMemCache) AtomicSpilloverSubDeferredSends(moduleAccount string, amount Coins, remainderHandler func(amount Coins) error) error { - if !amount.IsValid() { - panic(sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, amount.String())) - } - c.deferredBankOpsLock.Lock() - defer c.deferredBankOpsLock.Unlock() - - originalBalance, ok := c.deferredSends.Get(moduleAccount) - if !ok { - // run the remainder handler on the full amount - err := remainderHandler(amount) - // no need for revert because we dont even attempt a saturating sub, bubble up error if applicable - return err - } - // found a balance, try to perform the logic - remainder := c.deferredSends.SaturatingSub(moduleAccount, amount) - if remainder.IsZero() { - // no remainder, return now - return nil - } - err := remainderHandler(remainder) - if err != nil { - // revert the map subtraction and the bubble up error - c.deferredSends.Set(moduleAccount, originalBalance) - } - return err -} - -func (c *ContextMemCache) SafeSubDeferredSends(moduleAccount string, amount Coins) bool { - if !amount.IsValid() { - panic(sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, amount.String())) - } - c.deferredBankOpsLock.Lock() - defer c.deferredBankOpsLock.Unlock() - - return c.deferredSends.SafeSub(moduleAccount, amount) -} - -func (c *ContextMemCache) RangeOnDeferredSendsAndDelete(apply func(recipient string, amount Coins)) { - c.deferredBankOpsLock.Lock() - defer c.deferredBankOpsLock.Unlock() - c.deferredSends.RangeAndRemove(apply) -} - -func (c *ContextMemCache) Clear() { - c.deferredBankOpsLock.Lock() - defer c.deferredBankOpsLock.Unlock() - c.deferredSends = NewDeferredBankOperationMap() -} diff --git a/types/context_cache_test.go b/types/context_cache_test.go deleted file mode 100644 index 2f662f26a..000000000 --- a/types/context_cache_test.go +++ /dev/null @@ -1,279 +0,0 @@ -package types_test - -import ( - fmt "fmt" - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/stretchr/testify/suite" -) - -type contextCacheTestSuite struct { - suite.Suite - contextCache sdk.ContextMemCache -} - -func TestContextCacheTestSuite(t *testing.T) { - suite.Run(t, new(contextCacheTestSuite)) -} - -func (s *contextCacheTestSuite) SetupSuite() { - s.T().Parallel() - s.contextCache = *sdk.NewContextMemCache() -} - -func (s *contextCacheTestSuite) TestDeferredSendUpserts() { - s.contextCache.UpsertDeferredSends("module1", sdk.NewCoins( - sdk.NewInt64Coin("denom1", 100), - sdk.NewInt64Coin("denom2", 20), - )) - - s.contextCache.UpsertDeferredSends("module1", sdk.NewCoins( - sdk.NewInt64Coin("denom3", 50), - sdk.NewInt64Coin("denom2", 10), - )) - - s.contextCache.UpsertDeferredSends("module2", sdk.NewCoins( - sdk.NewInt64Coin("denom3", 50), - sdk.NewInt64Coin("denom4", 40), - )) - - expectedDeferredBalances := map[string]sdk.Coins{ - "module1": sdk.NewCoins( - sdk.NewInt64Coin("denom1", 100), - sdk.NewInt64Coin("denom2", 30), - sdk.NewInt64Coin("denom3", 50), - ), - "module2": sdk.NewCoins( - sdk.NewInt64Coin("denom3", 50), - sdk.NewInt64Coin("denom4", 40), - ), - } - entries := 0 - s.contextCache.RangeOnDeferredSendsAndDelete(func(recipient string, amount sdk.Coins) { - s.Require().Equal(expectedDeferredBalances[recipient], amount, fmt.Sprint("unexpected deferred balances", recipient, amount)) - entries++ - }) - s.Require().Equal(len(expectedDeferredBalances), entries) - entries = 0 - // assert empty after range and delete - s.contextCache.RangeOnDeferredSendsAndDelete(func(recipient string, amount sdk.Coins) { - entries++ - }) - s.Require().Zero(entries) -} - -func (s *contextCacheTestSuite) TestDeferredSendSafeSub() { - // set up some balances - s.contextCache.UpsertDeferredSends("module1", sdk.NewCoins( - sdk.NewInt64Coin("denom1", 100), - sdk.NewInt64Coin("denom2", 20), - )) - s.contextCache.UpsertDeferredSends("module1", sdk.NewCoins( - sdk.NewInt64Coin("denom3", 50), - sdk.NewInt64Coin("denom2", 10), - )) - s.contextCache.UpsertDeferredSends("module2", sdk.NewCoins( - sdk.NewInt64Coin("denom3", 50), - sdk.NewInt64Coin("denom4", 40), - )) - s.contextCache.UpsertDeferredSends("module3", sdk.NewCoins( - sdk.NewInt64Coin("denom1", 10), - )) - - // valid safesub - should succeed - subtracted := s.contextCache.SafeSubDeferredSends("module1", sdk.NewCoins( - sdk.NewInt64Coin("denom3", 25), - )) - s.Require().True(subtracted) - - // safesub with nonexisting denom and valid one - should fail - subtracted = s.contextCache.SafeSubDeferredSends("module1", sdk.NewCoins( - sdk.NewInt64Coin("denom1", 20), - sdk.NewInt64Coin("denom4", 20), - )) - s.Require().False(subtracted) - - // safesub with other module multiple denoms - should succeed - subtracted = s.contextCache.SafeSubDeferredSends("module2", sdk.NewCoins( - sdk.NewInt64Coin("denom3", 20), - sdk.NewInt64Coin("denom4", 20), - )) - s.Require().True(subtracted) - - // safesub with nonexisting denom and valid one - should fail - subtracted = s.contextCache.SafeSubDeferredSends("module4", sdk.NewCoins( - sdk.NewInt64Coin("denom1", 20), - sdk.NewInt64Coin("denom4", 20), - )) - s.Require().False(subtracted) - - // safesub full balance for a module - should succeed - subtracted = s.contextCache.SafeSubDeferredSends("module3", sdk.NewCoins( - sdk.NewInt64Coin("denom1", 10), - )) - s.Require().True(subtracted) - - expectedDeferredBalances := map[string]sdk.Coins{ - "module1": sdk.NewCoins( - sdk.NewInt64Coin("denom1", 100), - sdk.NewInt64Coin("denom2", 30), - sdk.NewInt64Coin("denom3", 25), - ), - "module2": sdk.NewCoins( - sdk.NewInt64Coin("denom3", 30), - sdk.NewInt64Coin("denom4", 20), - ), - // is empty because was fully subbed - "module3": sdk.Coins(nil), - } - - entries := 0 - s.contextCache.RangeOnDeferredSendsAndDelete(func(recipient string, amount sdk.Coins) { - s.Require().Equal(expectedDeferredBalances[recipient], amount, fmt.Sprint("unexpected deferred balances", recipient, amount)) - entries++ - }) - s.Require().Equal(len(expectedDeferredBalances), entries) -} - -func (s *contextCacheTestSuite) TestDeferredSendSaturatingSub() { - // set up some balances - s.contextCache.UpsertDeferredSends("module1", sdk.NewCoins( - sdk.NewInt64Coin("denom1", 100), - sdk.NewInt64Coin("denom2", 20), - )) - s.contextCache.UpsertDeferredSends("module1", sdk.NewCoins( - sdk.NewInt64Coin("denom3", 50), - sdk.NewInt64Coin("denom2", 10), - )) - s.contextCache.UpsertDeferredSends("module2", sdk.NewCoins( - sdk.NewInt64Coin("denom3", 50), - sdk.NewInt64Coin("denom4", 40), - )) - s.contextCache.UpsertDeferredSends("module3", sdk.NewCoins( - sdk.NewInt64Coin("denom1", 10), - )) - - // valid saturating sub - should succeed - err := s.contextCache.AtomicSpilloverSubDeferredSends( - "module1", - sdk.NewCoins( - sdk.NewInt64Coin("denom3", 25), - ), - func(amount sdk.Coins) error { - // we shouldnt even touch this - panic("Shouldn't be called") - }, - ) - s.Require().NoError(err) - - // saturating sub with nonexisting denom and valid one - should fail - called := false - err = s.contextCache.AtomicSpilloverSubDeferredSends( - "module1", - sdk.NewCoins( - sdk.NewInt64Coin("denom1", 20), - sdk.NewInt64Coin("denom4", 20), - ), - func(amount sdk.Coins) error { - // should be called with 20denom4 - s.Require().Equal(sdk.NewCoins(sdk.NewInt64Coin("denom4", 20)), amount) - called = true - // simulate error - return fmt.Errorf("insufficient balance") - }, - ) - s.Require().True(called) - s.Require().Error(err) - - // different saturaing sub but this time the balance *is* present in underlying store - called = false - err = s.contextCache.AtomicSpilloverSubDeferredSends( - "module1", - sdk.NewCoins( - sdk.NewInt64Coin("denom1", 5), - sdk.NewInt64Coin("denom5", 20), - ), - func(amount sdk.Coins) error { - s.Require().Equal(sdk.NewCoins(sdk.NewInt64Coin("denom5", 20)), amount) - // simulate success querying underlying store - called = true - return nil - }, - ) - s.Require().True(called) - s.Require().NoError(err) - - // test failed subtraction from underlying store - called = false - err = s.contextCache.AtomicSpilloverSubDeferredSends( - "module2", - sdk.NewCoins( - sdk.NewInt64Coin("denom3", 50), - sdk.NewInt64Coin("denom4", 55), - ), - func(amount sdk.Coins) error { - s.Require().Equal(sdk.NewCoins(sdk.NewInt64Coin("denom4", 15)), amount) - // simulate success querying underlying store - called = true - return fmt.Errorf("failed underlying subtract") - }, - ) - s.Require().True(called) - s.Require().Error(err) - - // saturating sub that uses all the balance of a denom and spills over into underlying store - called = false - err = s.contextCache.AtomicSpilloverSubDeferredSends( - "module3", - sdk.NewCoins( - sdk.NewInt64Coin("denom1", 75), - ), - func(amount sdk.Coins) error { - s.Require().Equal(sdk.NewCoins(sdk.NewInt64Coin("denom1", 65)), amount) - // simulate success querying underlying store - called = true - return nil - }, - ) - s.Require().True(called) - s.Require().NoError(err) - - // saturating sub for a module that doesnt exist in the map - called = false - err = s.contextCache.AtomicSpilloverSubDeferredSends( - "module4", - sdk.NewCoins( - sdk.NewInt64Coin("denom2", 30), - ), - func(amount sdk.Coins) error { - s.Require().Equal(sdk.NewCoins(sdk.NewInt64Coin("denom2", 30)), amount) - // simulate success querying underlying store - called = true - return nil - }, - ) - s.Require().True(called) - s.Require().NoError(err) - - expectedDeferredBalances := map[string]sdk.Coins{ - "module1": sdk.NewCoins( - sdk.NewInt64Coin("denom1", 95), - sdk.NewInt64Coin("denom2", 30), - sdk.NewInt64Coin("denom3", 25), - ), - "module2": sdk.NewCoins( - sdk.NewInt64Coin("denom3", 50), - sdk.NewInt64Coin("denom4", 40), - ), - // is empty because was fully subbed - "module3": sdk.Coins(nil), - } - - entries := 0 - s.contextCache.RangeOnDeferredSendsAndDelete(func(recipient string, amount sdk.Coins) { - s.Require().Equal(expectedDeferredBalances[recipient], amount, fmt.Sprint("unexpected deferred balances", recipient, amount)) - entries++ - }) - s.Require().Equal(len(expectedDeferredBalances), entries) -} diff --git a/types/deferred_bank_operations.go b/types/deferred_bank_operations.go deleted file mode 100644 index 87024add1..000000000 --- a/types/deferred_bank_operations.go +++ /dev/null @@ -1,117 +0,0 @@ -package types - -import ( - "sort" - "sync" -) - -type DeferredBankOperationMapping struct { - deferredOperations map[string]Coins - mappingLock *sync.Mutex -} - -func NewDeferredBankOperationMap() *DeferredBankOperationMapping { - return &DeferredBankOperationMapping{ - deferredOperations: make(map[string]Coins), - mappingLock: &sync.Mutex{}, - } -} - -// Get returns the current deferred balances for the passed in module account as well as a `found` bool. -// This is threadsafe since it acquires a lock on the mutex. -func (m *DeferredBankOperationMapping) Get(moduleAccount string) (Coins, bool) { - m.mappingLock.Lock() - defer m.mappingLock.Unlock() - - deferredAmount, ok := m.deferredOperations[moduleAccount] - return deferredAmount, ok -} - -// Get returns the current deferred balances for the passed in module account as well as a `found` bool. -// This is threadsafe since it acquires a lock on the mutex. -func (m *DeferredBankOperationMapping) Set(moduleAccount string, amount Coins) { - m.mappingLock.Lock() - defer m.mappingLock.Unlock() - - m.deferredOperations[moduleAccount] = amount -} - -// SaturatingSub will subtract the given amount from the module account as long as the resulting balance is positive or zero. -// If there would be a remainder (eg. negative balance after subtraction), then it would subtract the full balance in the map -// and then return the remainder that was unable to be subtracted. -func (m *DeferredBankOperationMapping) SaturatingSub(moduleAccount string, amount Coins) Coins { - m.mappingLock.Lock() - defer m.mappingLock.Unlock() - - if deferredAmount, ok := m.deferredOperations[moduleAccount]; ok { - newAmount, isNegative := deferredAmount.SafeSub(amount) - if !isNegative { - // this means that the subtraction FULLY succeeded, no remainders - m.deferredOperations[moduleAccount] = newAmount - // return empty remainder - return Coins{} - } else { - // else there were some negative, we need to partition the results, and return the negative balances as positive instead as the remainder - pos, neg := newAmount.PartitionSigned() - // assign positives to map (anything that wasnt touched or had sufficient balance to process the subtraction fully) - m.deferredOperations[moduleAccount] = pos - // convert the negatives to positives to represent the remainder - return neg.negative() - } - } - // no entry, so we return the full amount as the remainder - return amount -} - -// If there's already a pending opposite operation then subtract it from that amount first -// returns true if amount was subtracted -func (m *DeferredBankOperationMapping) SafeSub(moduleAccount string, amount Coins) bool { - m.mappingLock.Lock() - defer m.mappingLock.Unlock() - - if deferredAmount, ok := m.deferredOperations[moduleAccount]; ok { - newAmount, isNegative := deferredAmount.SafeSub(amount) - if !isNegative { - m.deferredOperations[moduleAccount] = newAmount - return true - } - } - return false -} - -func (m *DeferredBankOperationMapping) UpsertMapping(moduleAccount string, amount Coins) { - m.mappingLock.Lock() - defer m.mappingLock.Unlock() - - newAmount := amount - if v, ok := m.deferredOperations[moduleAccount]; ok { - newAmount = v.Add(amount...) - } - m.deferredOperations[moduleAccount] = newAmount -} - -func (m *DeferredBankOperationMapping) GetSortedKeys() []string { - - // Need to sort keys for deterministic iterating - keys := make([]string, 0, len(m.deferredOperations)) - for key := range m.deferredOperations { - keys = append(keys, key) - } - sort.Strings(keys) - return keys -} - -func (m *DeferredBankOperationMapping) RangeAndRemove(apply func(recipient string, amount Coins)) { - m.mappingLock.Lock() - defer m.mappingLock.Unlock() - - keys := m.GetSortedKeys() - - for _, moduleAccount := range keys { - apply(moduleAccount, m.deferredOperations[moduleAccount]) - } - - for _, moduleAccount := range keys { - delete(m.deferredOperations, moduleAccount) - } -} diff --git a/x/bank/keeper/deferred_cache_test.go b/x/bank/keeper/deferred_cache_test.go new file mode 100644 index 000000000..21355d8c2 --- /dev/null +++ b/x/bank/keeper/deferred_cache_test.go @@ -0,0 +1,85 @@ +package keeper_test + +import ( + "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +func (suite *IntegrationTestSuite) TestDeferredCacheUpsertBalances() { + // add module accounts to supply keeper + ctx := suite.ctx + authKeeper, keeper := suite.initKeepersWithmAccPerms(make(map[string]bool)) + authKeeper.SetModuleAccount(ctx, multiPermAcc) + app := suite.app + app.BankKeeper = keeper + + addr1 := sdk.AccAddress("addr1_______________") + acc1 := authKeeper.NewAccountWithAddress(ctx, addr1) + authKeeper.SetAccount(ctx, acc1) + + bankBalances := sdk.NewCoins(newFooCoin(20), newBarCoin(30)) + // set up bank balances + suite.Require().NoError(simapp.FundAccount(app.BankKeeper, ctx, addr1, bankBalances)) + suite.Require().NoError(simapp.FundAccount(app.BankKeeper, ctx, multiPermAcc.GetAddress(), bankBalances)) + // we initialize a deferrred cache to test functions directly as opposed to via bankkeeper functionality + deferredCache := bankkeeper.NewDeferredCache(app.AppCodec(), app.GetMemKey(types.DeferredCacheStoreKey)) + + // get deferred balance for a denom - should be zero + coin := deferredCache.GetBalance(ctx, multiPermAcc.GetAddress(), 2, fooDenom) + suite.Require().Equal(sdk.NewCoin(fooDenom, sdk.ZeroInt()), coin) + // perform upsert - should have a balance now of 10foo + err := deferredCache.UpsertBalances(ctx, multiPermAcc.GetAddress(), 2, sdk.NewCoins(newFooCoin(10))) + suite.Require().NoError(err) + suite.Require().Equal(newFooCoin(10), deferredCache.GetBalance(ctx, multiPermAcc.GetAddress(), 2, fooDenom)) + // Add foo coin on a different tx index - should have same balance of 10 for old tx index AND an entry for new tx index + err = deferredCache.UpsertBalances(ctx, multiPermAcc.GetAddress(), 1, sdk.NewCoins(newFooCoin(15))) + suite.Require().NoError(err) + suite.Require().Equal(newFooCoin(10), deferredCache.GetBalance(ctx, multiPermAcc.GetAddress(), 2, fooDenom)) + suite.Require().Equal(newFooCoin(15), deferredCache.GetBalance(ctx, multiPermAcc.GetAddress(), 1, fooDenom)) + // upsert on an existing index with multiple coins-> should increment the value + err = deferredCache.UpsertBalances(ctx, multiPermAcc.GetAddress(), 2, sdk.NewCoins(newFooCoin(10), newBarCoin(5))) + suite.Require().NoError(err) + suite.Require().Equal(newFooCoin(20), deferredCache.GetBalance(ctx, multiPermAcc.GetAddress(), 2, fooDenom)) + suite.Require().Equal(newBarCoin(5), deferredCache.GetBalance(ctx, multiPermAcc.GetAddress(), 2, barDenom)) + suite.Require().Equal(newFooCoin(15), deferredCache.GetBalance(ctx, multiPermAcc.GetAddress(), 1, fooDenom)) + + // upsert on a different module acc + err = deferredCache.UpsertBalances(ctx, randomPermAcc.GetAddress(), 2, sdk.NewCoins(newFooCoin(7))) + suite.Require().NoError(err) + suite.Require().Equal(newFooCoin(20), deferredCache.GetBalance(ctx, multiPermAcc.GetAddress(), 2, fooDenom)) + suite.Require().Equal(newFooCoin(7), deferredCache.GetBalance(ctx, randomPermAcc.GetAddress(), 2, fooDenom)) + + // upsert with invalid balance should fail + suite.Require().Error(deferredCache.UpsertBalances(ctx, randomPermAcc.GetAddress(), 2, []sdk.Coin{{Denom: fooDenom, Amount: sdk.NewInt(-5)}})) + + count := 0 + // iterate and count entries + deferredCache.IterateDeferredBalances(ctx, func(moduleAddr sdk.AccAddress, balance sdk.Coin) bool { + count += 1 + return false + }) + suite.Require().Equal(4, count) + + // write deferred balances should increase foo by 25 for multiPermAcc + app.BankKeeper.WriteDeferredBalances(ctx) + + count = 0 + // iterate and count should have no entries after writing balances (since it clears) + deferredCache.IterateDeferredBalances(ctx, func(moduleAddr sdk.AccAddress, balance sdk.Coin) bool { + count += 1 + return false + }) + suite.Require().Equal(0, count) + + // assert module balances correct + expectedBankBalances := sdk.NewCoins(newFooCoin(55), newBarCoin(35)) + bals := app.BankKeeper.GetAllBalances(ctx, multiPermAcc.GetAddress()) + suite.Require().Equal(expectedBankBalances, bals) + + // assert module balances correct for other module acc + expectedBankBalances = sdk.NewCoins(newFooCoin(7)) + bals = app.BankKeeper.GetAllBalances(ctx, randomPermAcc.GetAddress()) + suite.Require().Equal(expectedBankBalances, bals) +} diff --git a/x/bank/keeper/keeper_test.go b/x/bank/keeper/keeper_test.go index 8514677a3..660adc0fc 100644 --- a/x/bank/keeper/keeper_test.go +++ b/x/bank/keeper/keeper_test.go @@ -616,8 +616,6 @@ func (suite *IntegrationTestSuite) TestWriteDeferredOperations() { suite.Require().NoError(app.BankKeeper.DeferredSendCoinsFromAccountToModule(ctx, addr2, multiPerm, deferredBalances)) bankBalances := sdk.NewCoins(newFooCoin(20), newBarCoin(30)) - // setup deferred balances - // ctx.ContextMemCache().UpsertDeferredSends(multiPerm, deferredBalances) // set up bank balances suite.Require().NoError(simapp.FundAccount(app.BankKeeper, ctx, multiPermAcc.GetAddress(), bankBalances)) From 85b0d5f9be0ee6e46f0c5a36d2e7bb1dbba100af Mon Sep 17 00:00:00 2001 From: Uday Patil Date: Wed, 14 Jun 2023 10:39:38 -0500 Subject: [PATCH 4/4] update comment --- types/accesscontrol/comparator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/accesscontrol/comparator.go b/types/accesscontrol/comparator.go index d615caf49..a1276f8d9 100644 --- a/types/accesscontrol/comparator.go +++ b/types/accesscontrol/comparator.go @@ -21,7 +21,7 @@ var ( } ) -// use -1 to indicate that it is prior to msgs in the tx +// We generate dependencies on a per message basis for a trnasaction, but antehandlers also use resources. As a result we use -1 for the ante handler index (used as map key) to indicate that it is prior to msgs in the tx const ANTE_MSG_INDEX = int(-1) type Comparator struct {