-
Notifications
You must be signed in to change notification settings - Fork 35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: concurrency issues between simulation, grpc queries and ABCI commit flow #213
Conversation
5d920ae
to
6fd8642
Compare
baseapp/abci.go
Outdated
@@ -603,15 +603,19 @@ func (app *BaseApp) createQueryContext(height int64, prove bool) (sdk.Context, e | |||
) | |||
} | |||
|
|||
cacheMS, err := app.cms.CacheMultiStoreWithVersion(height) | |||
if err != nil { | |||
if height > app.LastBlockHeight() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should store app.LastBlockHeight()
in a variable since we use it twice :)
client/grpc_query.go
Outdated
|
||
// selectHeight returns the height chosen from client context and grpc context. | ||
// If exists, height extracted from grpcCtx takes precedence. | ||
func selectHeight(clientContext Context, grpcCtx gocontext.Context) (height int64, err error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we avoid named return vars?
Co-authored-by: Aleksandr Bezobchuk <[email protected]>
…mit flow (#213) * fix: simulation and grpc query concurrency with ABCI * table tests for selectHeight * add table-driven GRPC query tests and fix non-existent heights * clean up * clean up grpc query tests * Apply suggestions from code review * Update testutil/network/network.go * fix typo in abci.go * Update baseapp/abci.go Co-authored-by: Aleksandr Bezobchuk <[email protected]> * store last block height in a var * avoid returning named parameters Co-authored-by: Aleksandr Bezobchuk <[email protected]> (cherry picked from commit 18b0d2d)
// selectHeight returns the height chosen from client context and grpc context. | ||
// If exists, height extracted from grpcCtx takes precedence. | ||
func selectHeight(clientContext Context, grpcCtx gocontext.Context) (int64, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we choosing 0 when neither is set? If so maybe lets set this more explicitly?
Should we be having input validation for heights > latest block height?
// selectHeight returns the height chosen from client context and grpc context. | ||
// If exists, height extracted from grpcCtx takes precedence. | ||
func selectHeight(clientContext Context, grpcCtx gocontext.Context) (int64, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we choosing 0 when neither is set? If so maybe lets set this more explicitly?
Should we be having input validation for heights > latest block height?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Zero is guaranteed to be returned in that case by var height int64
which is being initialized to 0. There is a test to cover this case as well. How are you suggesting making this more explicit? With height := int64(0)
or adding a relevant comment to the spec? Just making sure I understand what you mean
The validation for heights > latest block height
is done at the server layer. It would be challenging to have that information here in client.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need for height := int64(0)
IMO.
Description
Fixes the problem in: osmosis-labs/osmosis#1356
Previously, queries were always directed to ABCI, getting eventually synchronized with the commit flow. In #137 , we allowed GRPC queries to be concurrent with the ABCI commit flow. However, integration tests were not configured correctly to test that update. Specifically, the GRPC client was never set up in the integration suite. As a result, the flow with concurrent GRPC queries was never tested.
Upon setting up the GRPC client correctly
in testutil/network/util.go
, 2 problems were exposed:grpc context
orclient context
. Currently, if the caller provided height throughgrpc context
, that would work. However, it wouldn't if they attempted to supply it via theclient context
, similar to how integration tests currently do. As a result, I added a function to choose the right height (the priority is described in the spec) and correctly pass it to either GRPC or ABCI query.Also, I realized that a number of queries must never be concurrent with ABCI. Specifically, tendermint and simulation. Therefore, those are now always directed to the ABCI flow to avoid data races. This change should directly address the reported problem in osmosis-labs/osmosis#1356
I proceeded by writing table-driven tests for
TestGRPCQuery
in client and discovered that if a user request a height that does not exist, an error is returned. This is stemming from the fact that IAVL tree never returns an error fromGetImmutable(< height >)
when a non-existent height is requested. Instead it returns an empty tree with nil. This is contrary to what is stated in the following comment. This problem should be investigated further in a separate issue and potentially fixed. For now, I added an additional safeguard against non-existent heights hereTask Log
selectHeight
method