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

New implementation for addr_canonicalize and addr_humanize functions #1873

Closed
DariuszDepta opened this issue Sep 15, 2023 · 5 comments · Fixed by #1914
Closed

New implementation for addr_canonicalize and addr_humanize functions #1873

DariuszDepta opened this issue Sep 15, 2023 · 5 comments · Fixed by #1914
Assignees
Labels
std cosmwasm-std crate
Milestone

Comments

@DariuszDepta
Copy link
Member

DariuszDepta commented Sep 15, 2023

This issue and the corresponding PR is a proposal of using new algorithms in functions:

  • Api::addr_canonicalize, and
  • Api::addr_humanize

implemented in cosmwasm_std::testing::MockApi.

The new implementation is based on Bech32 encoding format (as idescribed in BIP-0173 and Bech32m encoding format described in BIP-0350) and uses the implementation provided by crate bech32.

Proposed solution supports all currently implemented functionality, like the possibility of using short custom addresses like foobar that are not bech32 encoded. Additionaly, new functions allow users to generate humanized addresses just like real-life blockchain in bech32 format with user-defined prefix like juno, osmosis etc. Finally, this solution solves the issue #1648 and unlocks implementation of the issue #39.

Proposed solution

This solution is based on Bech32 encoding format with default or user-defined bech32 prefix. User can define Bech32 prefix during MockApi instantiation.

All input addresses represented directly as a string or wrapped with Addr are treated either as Bech32 encoded or as a plain text. The simplest usage scenario is following: a user provides a simple plain-text address which is then canonicalized and humanized, e.g.:

// create mock with default bech32 prefix
let api: MockApi = MockApi::default();
// address is NOT in bech32 encoding
let addr: &str = "creator";
let canonical: CanonicalAddr = api.addr_canonicalize(addr)?;
let humanized: Addr = api.addr_humanize(canonical)?;
assert_eq!("creator", humanized);

When a user provides a long address, similar as in Juno chain, then the previous example would look like this:

// create mock with bech32 prefix equal to "juno"
let api: MockApi = MockApi::new_with_bech32_prefix("juno");
// address is in bech32 encoding format
let addr: &str = "juno1v82su97skv6ucfqvuvswe0t5fph7pfsrtraxf0x33d8ylj5qnrysdvkc95";
let canonical: CanonicalAddr = api.addr_canonicalize(addr)?;
let humanized: Addr = api.addr_humanize(canonical)?;
assert_eq!("juno1v82su97skv6ucfqvuvswe0t5fph7pfsrtraxf0x33d8ylj5qnrysdvkc95", humanized);

When a user wants to generate and humanize a predictable contract address using a function instantiate2_address while testing contracts in Juno chain test cases, then it could be done as follows:

let api: MockApi = MockApi::new_with_bech32_prefix("juno");
let address = api.addr_humanize(&instantiate2_address(&checksum, &creator, &salt)?)?;
// the humanized address will be in bech32 format with prefix
assert_eq!("juno1t6r960j945lfv8mhl4mage2rg97w63xeynwrupum2s2l7em4lprs9ce5hk", address);

Proposed algorithm

It is assumed, that MockApi has configured Bech32 prefix during instantiation for example: juno. The reversed version of this prefix (rev_prefix) is used internally as desribed below.

addr_canonicalize

  • If input is in Bech32 format with prefix then unpack the content and return as canonical form.
  • If input is in Bech32 format with rev_prefix then leave it as it is, and treat the binary form as canonical.
  • If input is not in Bech32 format, then generate Bech32 address with rev_prefix and treat the binary form as canonical.

addr_humanize

  • If input is in Bech32 format with prefix then leave it as it is.
  • If input is in Bech32 format with rev_prefix then unpack it, and return the content as an address.
  • If input is not in Bech32 format, then generate Bech32 address with prefix.
@DariuszDepta DariuszDepta added the std cosmwasm-std crate label Sep 15, 2023
@DariuszDepta DariuszDepta self-assigned this Sep 15, 2023
@DariuszDepta
Copy link
Member Author

After brainstorming about this change with @webmaster128 and @chipshort we agreed,
that the simplest, safest and the closest to real-life blockchain way of handling addresses
in tests will be using Bech32 encoding. It means, that all user addresses and contract
addresses will be either in canonical form or Bech32 encoded.

Planned changes

Implementation of the trait cosmwasm_std::Api for cosmwasm_std::testing::MockApi will be
adjusted in the extent described below.

Function addr_validate

This function will probably stay untouched. The validation process checks if the input address
can be canonicalized and then humanized, and the result is compared with the input.

It means, that when the user passes valid Bech32 or Bech32m address
with predefined prefix (see Bech32 prefix section below) to this function,
it will be properly canonicalized. Canonical address can be always humanized,
so the whole validation process will always success.

In case the user passes an invalid address (not Bech32 encoded), the canonicalization
will reject it with an error, and then the whole validation fails.

Function addr_canonicalize

Canonicalization will use Bech32 decoder with predefined prefix. If decoding fails,
it means that the provided address is invalid and an error will be returned.
After change, this function will accept only addresses in Bech32 or Bech32m encoding
having predefined prefix (see Bech32 prefix section below).

Function addr_humanize

This function will use Bech32 encoder to generate humanized address
with predefined prefix (see Bech32 prefix section below).

Bech32 prefix

cosmwasm_std::testing::MockApi during instantiation will have a predefined prefix set.
The default prefix used in Bech32 encoding/decoding will be cosmwasm, but it can be set
to any reasonable value. So the user may create addresses like these in real blockchain,
e.g. juno1v82su97skv6ucfqvuvswe0t5fph7pfsrtraxf0x33d8ylj5qnrysdvkc95

Addr struct

We will provide utility function named hashed, to be used only for testing purposes
(just like unchecked) for creating Bech32 addresses from any provided input.
The unchecked function will be deprecated, so the proper ways of creating Addr will be:

  • using let checked: Addr = Addr::hashed(input),
  • using let checked: Addr = deps.api.addr_validate(input)?, or
  • using let checked: Addr = deps.api.addr_humanize(canonical_addr)?.

@DariuszDepta
Copy link
Member Author

Implementation plan

Adding function Addr::hashed is non-breaking change, under condition, that bech32 crate compiles to wasm32
(can be implemented immediately).

Changing the behaviour of functions addr_canonicalize and addr_humanize is a breaking change.
These changes have to be postponed to version 2.0. All test cases im cosmwasm and tests for contracts (cw-plus)
have to be reviewed and adjusted.

Adding Bech32 prefix to MockApi seems to be a non-breaking change and can be implemented immediately.

@webmaster128
Copy link
Member

I agree with the above except for one thing: Addr::hashed("cosmwasm", "foobar") requires you to always put the prefix there and means it's easy to use the wrong prefix. Is there something wrong with adding the address maker as MockApi::addr_make(&self, input: &str) -> StdResult<Addr>? Then you can use Addr::unchecked internally.

I think it would be good to keep Addr encoding agnostic.

@DariuszDepta
Copy link
Member Author

I like the idea. Let's keep Addr encoding agnostic and move the address builder to MockApi.

@webmaster128
Copy link
Member

I pulled out #1887 as a preparation that allows users to use it instead of Addr::unchecked. This I think should go in 1.5. The rest if this ticket we can do later.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
std cosmwasm-std crate
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants