From ae8e001b2eb6bd1a45d2815a7aaab16b86c18217 Mon Sep 17 00:00:00 2001 From: Roshan Date: Sat, 8 Jul 2023 10:30:04 +0800 Subject: [PATCH] add mutex for different state --- baseapp/abci.go | 35 ++++++++++++++++++++++++----------- baseapp/baseapp.go | 42 +++++++++++++++++++++++++++++++++++++++++- go.mod | 2 +- go.sum | 4 ++-- 4 files changed, 68 insertions(+), 15 deletions(-) diff --git a/baseapp/abci.go b/baseapp/abci.go index 7ec14cd951..e40129fb0a 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -73,6 +73,7 @@ func (app *BaseApp) InitChain(req abci.RequestInitChain) (res abci.ResponseInitC } // initialize states with a correct header + app.setQueryState(initHeader) app.setState(runTxModeDeliver, initHeader) app.setState(runTxModeCheck, initHeader) @@ -194,6 +195,16 @@ func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeg WithBlockHeight(req.Header.Height) } + if app.queryState == nil { + app.setQueryState(req.Header) + } else { + // In the first block, app.queryState.ctx will already be initialized + // by InitChain. Context is now updated with Header information. + app.queryState.ctx = app.queryState.ctx. + WithBlockHeader(req.Header). + WithBlockHeight(req.Header.Height) + } + gasMeter := app.getBlockGasMeter(app.deliverState.ctx) app.deliverState.ctx = app.deliverState.ctx. @@ -736,11 +747,12 @@ func (app *BaseApp) handleQueryGRPC(handler GRPCQueryHandler, req abci.RequestQu } func (app *BaseApp) handleEthQuery(handler EthQueryHandler, req cmtrpctypes.RPCRequest) abci.ResponseEthQuery { - // use custom query multistore if provided - qms := app.qms - if qms == nil { - qms = app.cms.(storetypes.MultiStore) + // use custom query state if provided + qs := app.getQueryState() + if qs == nil { + return sdkerrors.EthQueryResult(fmt.Errorf("queryState is nil"), app.trace) } + qms := qs.ms.(sdk.MultiStore) height := qms.LatestVersion() if height == 0 { @@ -758,7 +770,7 @@ func (app *BaseApp) handleEthQuery(handler EthQueryHandler, req cmtrpctypes.RPCR } // branch the commit-multistore for safety - ctx := sdk.NewContext(cacheMS, app.checkState.ctx.BlockHeader(), true, app.upgradeChecker, app.logger). + ctx := sdk.NewContext(cacheMS, qs.ctx.BlockHeader(), true, app.upgradeChecker, app.logger). WithBlockHeight(height) res, err := handler(ctx, req) @@ -808,11 +820,12 @@ func (app *BaseApp) CreateQueryContext(height int64, prove bool, path ...string) return sdk.Context{}, err } - // use custom query multistore if provided - qms := app.qms - if qms == nil { - qms = app.cms.(sdk.MultiStore) + // use custom query state if provided + qs := app.getQueryState() + if qs == nil { + return sdk.Context{}, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "queryState is nil") } + qms := app.getQueryState().ms.(sdk.MultiStore) lastBlockHeight := qms.LatestVersion() if lastBlockHeight == 0 { @@ -845,7 +858,7 @@ func (app *BaseApp) CreateQueryContext(height int64, prove bool, path ...string) if len(path) == 1 && path[0] == "/cosmos.auth.v1beta1.Query/Account" { // use checkState for account queries // we could get the newest account info to send multi txs in one block - cacheMS, err = app.checkState.ms.(sdk.MultiStore).CacheMultiStoreWithVersion(height) + cacheMS, err = app.getState(runTxModeCheck).ms.(sdk.MultiStore).CacheMultiStoreWithVersion(height) } else { cacheMS, err = qms.CacheMultiStoreWithVersion(height) } @@ -858,7 +871,7 @@ func (app *BaseApp) CreateQueryContext(height int64, prove bool, path ...string) } // branch the commit-multistore for safety - ctx := sdk.NewContext(cacheMS, app.checkState.ctx.BlockHeader(), true, app.upgradeChecker, app.logger). + ctx := sdk.NewContext(cacheMS, qs.ctx.BlockHeader(), true, app.upgradeChecker, app.logger). WithMinGasPrices(app.minGasPrices). WithBlockHeight(height) diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 06067e92ba..808dc355d1 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -5,6 +5,7 @@ import ( "fmt" "sort" "strings" + "sync" dbm "github.com/cometbft/cometbft-db" abci "github.com/cometbft/cometbft/abci/types" @@ -52,7 +53,6 @@ type BaseApp struct { // nolint: maligned name string // application name from abci.Info db dbm.DB // common DB backend cms sdk.CommitMultiStore // Main (uncached) state - qms sdk.MultiStore // Optional alternative multistore for querying only. storeLoader StoreLoader // function to handle store loading, may be overridden with SetStoreLoader() grpcQueryRouter *GRPCQueryRouter // router for redirecting gRPC query calls ethQueryRouter *EthQueryRouter // router for redirecting eth query calls @@ -80,11 +80,16 @@ type BaseApp struct { // nolint: maligned // // checkState is set on InitChain and reset on Commit // deliverState is set on InitChain and BeginBlock and set to nil on Commit + // queryState is set on InitChain and BeginBlock + queryState *state // optional alternative multistore for querying only. checkState *state // for CheckTx deliverState *state // for DeliverTx processProposalState *state // for ProcessProposal prepareProposalState *state // for PrepareProposal + queryStateMtx *sync.RWMutex // mutex for queryState + checkStateMtx *sync.RWMutex // mutex for checkState + // an inter-block write-through cache provided to the context during deliverState interBlockCache sdk.MultiStorePersistentCache @@ -179,6 +184,16 @@ func NewBaseApp( app.SetMempool(mempool.NoOpMempool{}) } + if app.queryStateMtx == nil { + mtx := new(sync.RWMutex) + app.queryStateMtx = mtx + } + + if app.checkStateMtx == nil { + mtx := new(sync.RWMutex) + app.checkStateMtx = mtx + } + abciProposalHandler := NewDefaultProposalHandler(app.mempool, app) if app.prepareProposal == nil { @@ -441,6 +456,8 @@ func (app *BaseApp) setState(mode runTxMode, header tmproto.Header) { switch mode { case runTxModeCheck: + app.checkStateMtx.Lock() + defer app.checkStateMtx.Unlock() // Minimum gas prices are also set. It is set on InitChain and reset on Commit. baseState.ctx = baseState.ctx.WithIsCheckTx(true).WithMinGasPrices(app.minGasPrices) app.checkState = baseState @@ -458,6 +475,19 @@ func (app *BaseApp) setState(mode runTxMode, header tmproto.Header) { } } +func (app *BaseApp) setQueryState(header tmproto.Header) { + app.queryStateMtx.Lock() + defer app.queryStateMtx.Unlock() + + ms := app.cms.CacheMultiStore() + baseState := &state{ + ms: ms, + ctx: sdk.NewContext(ms, header, false, app.upgradeChecker, app.logger), + } + + app.queryState = baseState +} + // GetConsensusParams returns the current consensus parameters from the BaseApp's // ParamStore. If the BaseApp has no ParamStore defined, nil is returned. func (app *BaseApp) GetConsensusParams(ctx sdk.Context) *tmproto.ConsensusParams { @@ -578,10 +608,20 @@ func (app *BaseApp) getState(mode runTxMode) *state { return app.processProposalState default: + app.queryStateMtx.RLock() + defer app.queryStateMtx.RUnlock() + return app.checkState } } +func (app *BaseApp) getQueryState() *state { + app.queryStateMtx.RLock() + defer app.queryStateMtx.RUnlock() + + return app.queryState +} + func (app *BaseApp) getBlockGasMeter(ctx sdk.Context) storetypes.GasMeter { if maxGas := app.GetMaximumBlockGas(ctx); maxGas > 0 { return storetypes.NewGasMeter(maxGas) diff --git a/go.mod b/go.mod index fc384962c9..4f227a2277 100644 --- a/go.mod +++ b/go.mod @@ -171,7 +171,7 @@ replace ( // use cosmos fork of keyring github.com/99designs/keyring => github.com/cosmos/keyring v1.2.0 github.com/btcsuite/btcd => github.com/btcsuite/btcd v0.23.0 - github.com/cometbft/cometbft => github.com/Pythonberg1997/greenfield-cometbft v0.0.0-20230707013815-11540a027260 + github.com/cometbft/cometbft => github.com/Pythonberg1997/greenfield-cometbft v0.0.0-20230708021401-da08119f78a0 // Downgraded to avoid bugs in following commits which caused simulations to fail. // dgrijalva/jwt-go is deprecated and doesn't receive security updates. // TODO: remove it: https://github.com/cosmos/cosmos-sdk/issues/13134 diff --git a/go.sum b/go.sum index a5ddb9c047..92581159c8 100644 --- a/go.sum +++ b/go.sum @@ -143,8 +143,8 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE github.com/OpenPeeDeeP/depguard v1.1.0/go.mod h1:JtAMzWkmFEzDPyAd+W0NHl1lvpQKTvT9jnRVsohBKpc= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/Pythonberg1997/greenfield-cometbft v0.0.0-20230707013815-11540a027260 h1:MpCoAIomvZ//W9W9QDtW++nxyEgGVfuMlxZgGzj8XXY= -github.com/Pythonberg1997/greenfield-cometbft v0.0.0-20230707013815-11540a027260/go.mod h1:9q11eHNRY9FDwFH+4pompzPNGv//Z3VcfvkELaHJPMs= +github.com/Pythonberg1997/greenfield-cometbft v0.0.0-20230708021401-da08119f78a0 h1:/Uxruh7STp2BMry76vVkSnN7RghlyAC37uucEcNI+zU= +github.com/Pythonberg1997/greenfield-cometbft v0.0.0-20230708021401-da08119f78a0/go.mod h1:9q11eHNRY9FDwFH+4pompzPNGv//Z3VcfvkELaHJPMs= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/sarama v1.26.1/go.mod h1:NbSGBSSndYaIhRcBtY9V0U7AyH+x71bG668AuWys/yU= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=