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

Migrate to v0.11 #104

Merged
merged 20 commits into from
Oct 5, 2020
Merged

Migrate to v0.11 #104

merged 20 commits into from
Oct 5, 2020

Conversation

maurolacy
Copy link
Contributor

WIP for #96.

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 work, and quite a bit of cleanup here.

I like your usage of very clear error cases in subkeys. It is quite good in atomic swap as well, but I think there are still too many user-facing strings being created in the code, not in the error type.

I think it is best practice to only return data related to the error inside the ContractError type, and all formatting to make it reasonable (making use of the metadata) is done in the #[error] text. This also gives a very clear overview for anyone trying to adjust the messages (or trace a bug)

contracts/cw1-subkeys/src/contract.rs Outdated Show resolved Hide resolved
contracts/cw1-subkeys/src/contract.rs Show resolved Hide resolved
);

// And then cannot (not enough funds anymore)
let res = handle(&mut deps, env, handle_msg.clone());
match res.unwrap_err() {
StdError::Underflow { .. } => {}
ContractError::Std(StdError::Underflow { .. }) => {}
Copy link
Member

Choose a reason for hiding this comment

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

Good example to show how this is compatible with StdErrors

Copy link
Member

Choose a reason for hiding this comment

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

But since we are are creating custom errors everywhere, maybe we want to map this.
Either where it is generated like .map_err(|e| ...). Or do something like:

impl From<cw1_whitelist::ContractError> for ContractError
    fn from(err: cw1_whitelist::ContractError) -> Self {
        match err {
            cw1_whitelist::ContractError::Std(error) => ContractError::Std(error),
            cw1_whitelist::ContractError::Unauthorized {} => ContractError::Unauthorized {},
        }
    }
}

But mapping StdError::Underflow{} => ContractError::InsufficientAllowance{}?

Copy link
Member

Choose a reason for hiding this comment

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

Although the underflow message does show you the amounts, which is nice and shouldn't be lost.

This is an idea, take it or leave it.

Copy link
Contributor Author

@maurolacy maurolacy Oct 4, 2020

Choose a reason for hiding this comment

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

I would leave it as it is. Besides the extra boilerplate, it's pretty clear what's being done.

contracts/cw1-subkeys/src/error.rs Show resolved Hide resolved
contracts/cw1-subkeys/src/state.rs Show resolved Hide resolved
contracts/cw20-atomic-swap/src/contract.rs Outdated Show resolved Hide resolved
contracts/cw20-atomic-swap/src/contract.rs Outdated Show resolved Hide resolved
contracts/cw20-atomic-swap/src/contract.rs Outdated Show resolved Hide resolved
@@ -192,17 +192,17 @@ pub fn try_refund<S: Storage, A: Api, Q: Querier>(
Err(StdError::unauthorized())
} else {
// we delete the escrow (TODO: expose this in Bucket for simpler API)
prefixed(PREFIX_ESCROW, &mut deps.storage).remove(id.as_bytes());
prefixed(&mut deps.storage, PREFIX_ESCROW).remove(id.as_bytes());
Copy link
Member

Choose a reason for hiding this comment

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

Note, this is now in Bucket.remove you can use that now.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will change those in another branch / PR.

@@ -161,17 +161,17 @@ pub fn try_approve<S: Storage, A: Api, Q: Querier>(
Err(StdError::generic_err("escrow expired"))
} else {
// we delete the escrow (TODO: expose this in Bucket for simpler API)
prefixed(PREFIX_ESCROW, &mut deps.storage).remove(id.as_bytes());
prefixed(&mut deps.storage, PREFIX_ESCROW).remove(id.as_bytes());
Copy link
Member

Choose a reason for hiding this comment

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

And here... time to update

@maurolacy
Copy link
Contributor Author

maurolacy commented Oct 4, 2020

It is quite good in atomic swap as well, but I think there are still too many user-facing strings being created in the code, not in the error type.

You're right, I see you point: The very idea of custom errors is to move the messages to the error definition; and in any case just pass parameters. And that, only if justified.

@ethanfrey
Copy link
Member

ethanfrey commented Oct 4, 2020

I think there is a lot of work migrating to proper custom errors, and a lot of this can be done in parallel to other 0.11 upgrade stuff. I am preparing some larger changes to bucket (and adding an indexed bucket) for 0.11-alpha4.

Now that you have fully migrated the error messages in a few contracts, and we can get some clarity there on what makes sense to us both, it would be great if you could finish up the other contracts with minimal changes. Either somehow asking clippy to ignore the deprecation warning for a minute, or just using a StdError + Unauthorized minimal wrapper, like in cw1-whitelist, to the other contracts you have not yet ported.

Oh, and rebasing/merging on master to resolve all conflicts (I think mainly with the 0.2.2 release and version changes?)

Then please take out of draft mode, so we can merge this in, and you can keep updating the error codes on one branch, while I can update the Bucket refactor on another branch. I hope to do the Bucket refactor monday or tuesday

@maurolacy
Copy link
Contributor Author

maurolacy commented Oct 4, 2020

Now that you have fully migrated the error messages in a few contracts, and we can get some clarity there on what makes sense to us both, it would be great if you could finish up the other contracts with minimal changes. Either somehow asking clippy to ignore the deprecation warning for a minute, or just using a StdError + Unauthorized minimal wrapper, like in cw1-whitelist, to the other contracts you have not yet ported.

Turns out is not so easy to do that, because once I change to ContractError, that forces me to change all the branches of the match in handle(), and so on.

What I can do is leave the warnings (or revert to using v0.10.1 in the remaining contracts) for now, and focus on the rebase from master and other small changes, in order to remove Draft mode. So we can merge the work so far.

Update: Tried to revert remaining contract (staking) to 0.10.1, but that's not possible due to "library"-type dependencies. So I guess forward is the simple path. I'll try to finish migration tomorrow, to a point that it can be merged without errors / warnings.

@maurolacy
Copy link
Contributor Author

maurolacy commented Oct 4, 2020

OK, migrated all but the two new contracts (cw3-fixed-multisig and cw721-nft).

Also rebased from master. Will remove Draft, so you can review and merge this if you want. And, I can migrate the other two contracts in a different branch / PR.

@maurolacy maurolacy marked this pull request as ready for review October 4, 2020 21:43
@maurolacy
Copy link
Contributor Author

maurolacy commented Oct 4, 2020

It's probably a good idea to increase the version of the packages to 0.2.3, before publishing.

@ethanfrey
Copy link
Member

It's probably a good idea to increase the version of the packages to 0.2.3, before publishing.

Good point, but I don't intend to publish anything until 0.3.0, with 0.11 support. As 0.10 -> 0.11 is breaking.

Thank you for finishing this up to a usable point. I will review and merge and we can both work on this as needed (I would just mess with the bucket and query stuff from my open PRs on cosmwasm with the next 0.11-alpha, and leave all the error work to you to ensure we don't step on toes)

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.

Good stuff here, and thanks for getting it stable.

I will merge this in. Left a few comments along the way that may be useful for the next segment of your error-refactoring PR.

contracts/cw20-escrow/src/error.rs Show resolved Hide resolved
contracts/cw20-staking/src/contract.rs Show resolved Hide resolved
contracts/cw20-staking/src/contract.rs Show resolved Hide resolved
}

impl From<cw20_base::ContractError> for ContractError {
fn from(err: cw20_base::ContractError) -> Self {
Copy link
Member

Choose a reason for hiding this comment

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

Nice extension.

I did try to figure out how to "extend" enums in rust and it is not possible.
I wonder if we could simplify this one day with codegen? But I guess it is only a few minutes to write such code now.

Copy link
Contributor Author

@maurolacy maurolacy Oct 5, 2020

Choose a reason for hiding this comment

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

Yeah, these cases made me search for "rust inheritance" and the like... Traits are fine and dandy, but for real abstraction there's nothing like subtypes (interface inheritance) IMO.

Copy link
Contributor Author

@maurolacy maurolacy Oct 5, 2020

Choose a reason for hiding this comment

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

Come to think of it, this is probably more a case requiring or benefiting from "plain old" (implementation) inheritance, rather than interface inheritance.

NotInValidatorSet(String),

#[error("Different denominations in bonds: '{0}' vs. '{1}'")]
DifferentBondDenom(String, String),
Copy link
Member

Choose a reason for hiding this comment

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

Question: would it make sense to have these named (struct) variants rather than tuple variants, where there is more than one argument?

I think the generated code is the same, you just then use DifferentBondDenom{contract: String, message: String} or something like that to make it clear which side is which.

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 think it makes sense, yes. I'll change it for clarity.

cw0 = { path = "../../packages/cw0", version = "0.2.2" }
cw2 = { path = "../../packages/cw2", version = "0.2.2" }
cw3 = { path = "../../packages/cw3", version = "0.2.2" }
cw0 = { version = "0.2.2" }
Copy link
Member

Choose a reason for hiding this comment

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

Ah, interesting way to do this... as long as no one else imports this, we can hold it back to the older package versions. Nice idea!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, that took a while... :-) happy that I made it compile (and then mergeable).

@ethanfrey ethanfrey merged commit 17b5781 into master Oct 5, 2020
@ethanfrey ethanfrey deleted the migrate-to-v0.11 branch October 5, 2020 09:36
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.

2 participants