-
Notifications
You must be signed in to change notification settings - Fork 3.6k
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
EPIC: make guarantees around query responses #13041
Comments
I believe there should be some annotation in the .proto files to indicate which queries are deterministic and can be used inside the state machine. There may always be some cases where people want to use queries in some non-deterministic or very inefficient way. Those queries shouldn't be exposed to the state machine and modules like cosmwasm. Probably by default we should assume all queries are unsafe, and one by one start marking the safe ones (which have proper regression tests, gas consumption, etc.) with an annotation. |
It's also probably safer to disable all historical queries, since they depend on each node's pruning settings. |
could you elaborate |
If your state machine code makes a historical query for height say N-1000, then:
causing a consensus error. My safe solution above is to only allow state machine queries to query the latest state. |
I'm not sure I understand @AmauryM. AFAIK, CW would not make any historical queries, but rather assumes the latest/current state. I like @aaronc's proposal of a Proto annotation. This way devs/clients can inspect docs and know what queries are safe to use. So I say we:
|
I creatd a first PR to make sure we agree on the proto annotation, and which queries will have the guarantees on determinism. #13174 |
How about using property-based testing with // Check GetBalance determinism
rapid.Check(func(t *testing.T) {
addr := AddressGenerator().Draw(t) // where AddressGenerator returns a rapid.Generator[sdk.AccAddress]
amt := rapid.Uint64().Draw(t)
bankKeeper.SetBalance(ctx, addr, sdk.NewCoin(amt, "stake"))
for i := 0; i < 1000; i++ {
// make sure bankKeeper.GetBalance always returns the same response
}
}) So there are 1000*N iterations, where N = our rapid's configuration. This way we don't hardcode the response. Do we also agree these tests belong inside |
I've never seen or used Rapid, but the approach seems reasonable to me. |
with rapid how do you verify that the response didnt change in minor releases? |
Good point. So maybe we do one or three hardcoded responses (to check backwards-determinism) plus rapid (to check the property "query is deterministic"). I feel both are useful here since they test different things. |
FYI, the way we currently test determinism/regression across minor releases is weak. We basically test queries against hardcoded values. E.g. if we fund With the above method, we might catch changes in the query response. But we wouldn't catch stuff like:
These are not trivial to catch though. Are people fine, for this epic, to do the following:
Also happy to hear other ideas on how to test state-machine breaking changes in queries. |
@AmauryM I'm a bit lost as to how your points relate to non-determinism re queries:
How is validation breaking determinism? If some query previous didn't error on input but with a new change now does, is this what you mean? If so, tests should easily catch this (e.g.
Why is this difficult? Can't we read the gas consumed off of the context? |
Yes. Imagine you (or any module developer in the future) create a PR on a deterministic query which:
Then our existing deterministic tests won't fail. Even though this is a state-machine breaking change. We would need to write new tests.
So you're proposing to hardcode the gas consumed by each query inside the test itself? Not sure how flakey this would be with our test setup, but we can try. |
Yeah, makes sense. I suppose there isn't much we can do -- we just have to ensure we right good tests for new fields.
Yes, exactly! With queries, the gas should not be flakey since we're not simulating any state! In fact, we can improve these tests by also ensuring the gas consumed never changes per iteration. |
This Epic is complete 🎉. As a summary, we added the |
amazing, thank you!!! Nice job!! Should we open a new epic to slowly migrate other modules as well? |
Not sure about all modules, there are still caveats like #13041 (comment), so a consensus error probability is never 0. Are there queries/modules that people particularly want? Let's do those first. |
@ValarDragon @ethanfrey @assafmo do you have queries you need to be deterministic from the core sdk modules |
Bank, Staking and Auth is a huge step forward 💪 I don't have any more pressing needs. I think gov would be interesting to some users, but I think it is also in a process of change and not in a place to produce such guarantees. Maybe adding such deterministic query checks for NB: We just merged support to let chains configure their own such whitelist. Will play together well with this work CosmWasm/wasmd#1069 |
We went over all of these queries and found them to be deterministic: https://github.com/scrtlabs/SecretNetwork/blob/4397f93b2/x/compute/internal/keeper/query_plugins.go#L163-L199 Actually we didn't find a query in the standard modules that isn't deterministic, but we excluded the ones with iterations (E.g. |
Thanks for the list! @assafmo How did you check they were deterministic? |
By eye, I went over the code and made sure there's just storage access and no maps serializations |
Summary
As mentioned in the issue from cosmwasm there is a need to have data response guarantees around queries and messages. This issue focuses on the former, queries.
Problem Definition
Within minor releases responses of queries could change, potentially causing issues to downstream users.
Proposal
module_query_safe
for x/auth's bech32 grpc queries #13625ModuleAccountByName
query #13704The text was updated successfully, but these errors were encountered: