Skip to content
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

Abstracting API out of tests internals so it is clearly owned by App #368

Merged
merged 2 commits into from
Aug 3, 2021

Conversation

hashedone
Copy link
Contributor

closes #353

The reason behind whole change is that Router (or WasmKeeper) is no longer the only user of Api.

The easy way is to keep Api in Rc, and besides my worries about that, I tried this solution. Unfortunately BankKeeper which is eager to use Api is passed to App after it is configured, so it would require exposing information that things are Rc internally to the world, which I don't like, as it allows creator of App to keep his copy of App, and I don't like idea that App is nevermore owner of Api. I would probably go this way if only I would be able to keep App::new just taking Api with ownership - I even found a way, but it overcomplicates internals.

Another shot is instead of keeping Api internal for App, just take it there as a borrow, and deal this borrow to another users. Unfortunately it doesn't have too much upsides - app still is nevermore clean owner of Api, and lifetimes bounds everywhere makes thinks slightly less clean, which is not needed to happen in tests.

Also it is possible to just clone Api around, as it is pretty much trivial, but it would make it less flexible to extend it in future.

I took a way, where Api is just passed to relevant calls, just like Storage and other utilities. This isolates everything nicely, doesn't affect usage, and is very consistent with other interfaces.

Copy link
Contributor

@maurolacy maurolacy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm.

.unwrap();

// shows up in cache
let cached_rcpt = query_router(&app.router, &cache, &rcpt);
let cached_rcpt = query_router(&app.router, app.api.as_ref(), &cache, &rcpt);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let cached_rcpt = query_router(&app.router, app.api.as_ref(), &cache, &rcpt);
let cached_rcpt = query_router(&app.router, &*app.api, &cache, &rcpt);

here and elsewhere?

Copy link
Contributor Author

@hashedone hashedone Aug 2, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly I personally find as_ref() more explicit, and what is more important - wider used also in this project. That is why I would keep it here for consistency. I don't have strong preference, and also I see you safe couple signs, and if you really want I would change it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's OK. It just seems nice to me to have all parameters referenced in more or less the same way (with &). But it's the same.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then I will change it, I somehow agree with you. Today I was working on other think at afternoon, but I will do it as first thing at the morning an merge this (as you approved I assume there are no other issues).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either way. I'll defer to both your judgement for handling boxes (feel free to update other usages if desired... maybe as a separate PR)

let bank_storage = prefixed_read(storage, NAMESPACE_BANK);
match request {
BankQuery::AllBalances { address } => {
// TODO: shall we pass in Api to make this safer?
let amount = self.get_balance(&bank_storage, &Addr::unchecked(address))?;
let address = api.addr_validate(&address).map_err(|err| err.to_string())?;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice.

Copy link
Member

@ethanfrey ethanfrey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice

@@ -189,29 +197,31 @@ where
/// QuerierWrapper to interact with
pub fn query(
&self,
api: &dyn Api,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great solution to this problem... pass it in!

@@ -62,14 +63,15 @@ where
C: Clone + fmt::Debug + PartialEq + JsonSchema + 'static,
{
pub fn new(
api: Box<dyn Api>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice to remove Box from the public API. Better this way.

(And on reflection from you, I think maybe generics for eg. Bank implementation makes sense.. but that is a different refactor).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would actually prefer to be generic over all those things (like Api and Storage), as internal optimizer tells me there is additional overhead of v-call here, but... come on, those are tests. This makes usage easier, as additional type hints are never an issue. I would not do that unless there is an actual need (I found sometimes dyn traits doesn't play well with typesystem, but I don't think here is a case).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you look at Deps and DepsMut we use dyn for Storage, Api and Querier. That change was made in 0.10 or 0.11. This made writing contracts much, much easier, especially for Rust newcomers.

I am very happy with that and would avoid re-introducing generics there. But for all other types, I am open. I just got in the habit after seeing how much that simplified the code.

.unwrap();

// shows up in cache
let cached_rcpt = query_router(&app.router, &cache, &rcpt);
let cached_rcpt = query_router(&app.router, app.api.as_ref(), &cache, &rcpt);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either way. I'll defer to both your judgement for handling boxes (feel free to update other usages if desired... maybe as a separate PR)

@hashedone hashedone merged commit 2156012 into main Aug 3, 2021
@hashedone hashedone deleted the bank-keeper-api branch August 3, 2021 07:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

multi-test: Pass in API access to BankKeeper
3 participants