Skip to content

Commit 6b177a6

Browse files
authored
Merge pull request #443 from CosmWasm/do_canonicalize_address-error
Allow canonicalize_address/humanize_address to return an error string
2 parents fcfb649 + 9a0bea4 commit 6b177a6

12 files changed

+115
-108
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@
8282
contract. A standard library should ensure this never happens by correctly
8383
encoding string input values.
8484
- Merge trait `ReadonlyStorage` into `Storage`.
85+
- The imports `canonicalize_address` and `humanize_address` now return a memory
86+
address to an error `Region`. If this address is 0, the call succeeded.
87+
- Bump `cosmwasm_vm_version_1` to `cosmwasm_vm_version_2`.
8588

8689
## 0.8.1 (2020-06-08)
8790

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,8 @@ extern "C" {
138138
#[cfg(feature = "iterator")]
139139
fn db_next(iterator_id: u32) -> u32;
140140

141-
fn canonicalize_address(source: u32, destination: u32) -> i32;
142-
fn humanize_address(source: u32, destination: u32) -> i32;
141+
fn canonicalize_address(source: u32, destination: u32) -> u32;
142+
fn humanize_address(source: u32, destination: u32) -> u32;
143143

144144
/// Executes a query on the chain (import). Not to be confused with the
145145
/// query export, which queries the state of the contract.

packages/std/src/entry_points.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ macro_rules! create_entry_points {
9696

9797
$crate::create_entry_points!(@migration; $contract, $migration);
9898

99-
// Other C externs like cosmwasm_vm_version_1, allocate, deallocate are available
99+
// Other C externs like cosmwasm_vm_version_2, allocate, deallocate are available
100100
// automatically because we `use cosmwasm_std`.
101101
}
102102
};

packages/std/src/exports.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! exports exposes the public wasm API
22
//!
3-
//! cosmwasm_vm_version_1, allocate and deallocate turn into Wasm exports
3+
//! cosmwasm_vm_version_2, allocate and deallocate turn into Wasm exports
44
//! as soon as cosmwasm_std is `use`d in the contract, even privately.
55
//!
66
//! do_init and do_wrapper should be wrapped with a extern "C" entry point
@@ -26,7 +26,7 @@ extern "C" fn requires_staking() -> () {}
2626
/// They can be checked by cosmwasm_vm.
2727
/// Update this whenever the Wasm VM interface breaks.
2828
#[no_mangle]
29-
extern "C" fn cosmwasm_vm_version_1() -> () {}
29+
extern "C" fn cosmwasm_vm_version_2() -> () {}
3030

3131
/// allocate reserves the given number of bytes in wasm memory and returns a pointer
3232
/// to a Region defining this data. This space is managed by the calling process

packages/std/src/imports.rs

+26-12
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ extern "C" {
2828
#[cfg(feature = "iterator")]
2929
fn db_next(iterator_id: u32) -> u32;
3030

31-
fn canonicalize_address(source: u32, destination: u32) -> i32;
32-
fn humanize_address(source: u32, destination: u32) -> i32;
31+
fn canonicalize_address(source: u32, destination: u32) -> u32;
32+
fn humanize_address(source: u32, destination: u32) -> u32;
3333

3434
/// Executes a query on the chain (import). Not to be confused with the
3535
/// query export, which queries the state of the contract.
@@ -157,9 +157,13 @@ impl Api for ExternalApi {
157157
let send_ptr = &*send as *const Region as u32;
158158
let canon = alloc(CANONICAL_ADDRESS_BUFFER_LENGTH);
159159

160-
let read = unsafe { canonicalize_address(send_ptr, canon as u32) };
161-
if read < 0 {
162-
return Err(StdError::generic_err("canonicalize_address returned error"));
160+
let result = unsafe { canonicalize_address(send_ptr, canon as u32) };
161+
if result != 0 {
162+
let error = unsafe { consume_string_region_written_by_vm(result as *mut Region) };
163+
return Err(StdError::generic_err(format!(
164+
"canonicalize_address errored: {}",
165+
error
166+
)));
163167
}
164168

165169
let out = unsafe { consume_region(canon) };
@@ -171,18 +175,28 @@ impl Api for ExternalApi {
171175
let send_ptr = &*send as *const Region as u32;
172176
let human = alloc(HUMAN_ADDRESS_BUFFER_LENGTH);
173177

174-
let read = unsafe { humanize_address(send_ptr, human as u32) };
175-
if read < 0 {
176-
return Err(StdError::generic_err("humanize_address returned error"));
178+
let result = unsafe { humanize_address(send_ptr, human as u32) };
179+
if result != 0 {
180+
let error = unsafe { consume_string_region_written_by_vm(result as *mut Region) };
181+
return Err(StdError::generic_err(format!(
182+
"humanize_address errored: {}",
183+
error
184+
)));
177185
}
178186

179-
let out = unsafe { consume_region(human) };
180-
// we know input was correct when created, so let's save some bytes
181-
let result = unsafe { String::from_utf8_unchecked(out) };
182-
Ok(HumanAddr(result))
187+
let address = unsafe { consume_string_region_written_by_vm(human) };
188+
Ok(address.into())
183189
}
184190
}
185191

192+
/// Takes a pointer to a Region and reads the data into a String.
193+
/// This is for trusted string sources only.
194+
unsafe fn consume_string_region_written_by_vm(from: *mut Region) -> String {
195+
let data = consume_region(from);
196+
// We trust the VM/chain to return correct UTF-8, so let's save some gas
197+
String::from_utf8_unchecked(data)
198+
}
199+
186200
/// A stateless convenience wrapper around imports provided by the VM
187201
pub struct ExternalQuerier {}
188202

packages/vm/src/compatability.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ static SUPPORTED_IMPORTS: &[&str] = &[
2525
/// Basically, anything that is used in calls.rs
2626
/// This is unlikely to change much, must be frozen at 1.0 to avoid breaking existing contracts
2727
static REQUIRED_EXPORTS: &[&str] = &[
28-
"cosmwasm_vm_version_1",
28+
"cosmwasm_vm_version_2",
2929
"query",
3030
"init",
3131
"handle",
@@ -176,15 +176,15 @@ mod test {
176176
fn test_check_wasm_old_contract() {
177177
match check_wasm(CONTRACT_0_7, &default_features()) {
178178
Err(VmError::StaticValidationErr { msg, .. }) => assert!(msg.starts_with(
179-
"Wasm contract doesn't have required export: \"cosmwasm_vm_version_1\""
179+
"Wasm contract doesn't have required export: \"cosmwasm_vm_version_2\""
180180
)),
181181
Err(e) => panic!("Unexpected error {:?}", e),
182182
Ok(_) => panic!("This must not succeeed"),
183183
};
184184

185185
match check_wasm(CONTRACT_0_6, &default_features()) {
186186
Err(VmError::StaticValidationErr { msg, .. }) => assert!(msg.starts_with(
187-
"Wasm contract doesn't have required export: \"cosmwasm_vm_version_1\""
187+
"Wasm contract doesn't have required export: \"cosmwasm_vm_version_2\""
188188
)),
189189
Err(e) => panic!("Unexpected error {:?}", e),
190190
Ok(_) => panic!("This must not succeeed"),
@@ -309,7 +309,7 @@ mod test {
309309
match check_wasm_exports(&module) {
310310
Err(VmError::StaticValidationErr { msg, .. }) => {
311311
assert!(msg.starts_with(
312-
"Wasm contract doesn't have required export: \"cosmwasm_vm_version_1\""
312+
"Wasm contract doesn't have required export: \"cosmwasm_vm_version_2\""
313313
));
314314
}
315315
Err(e) => panic!("Unexpected error {:?}", e),
@@ -323,7 +323,7 @@ mod test {
323323
match check_wasm_exports(&module) {
324324
Err(VmError::StaticValidationErr { msg, .. }) => {
325325
assert!(msg.starts_with(
326-
"Wasm contract doesn't have required export: \"cosmwasm_vm_version_1\""
326+
"Wasm contract doesn't have required export: \"cosmwasm_vm_version_2\""
327327
));
328328
}
329329
Err(e) => panic!("Unexpected error {:?}", e),

packages/vm/src/context.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -380,8 +380,8 @@ mod test {
380380
"db_scan" => Func::new(|_a: u32, _b: u32, _c: i32| -> u32 { 0 }),
381381
"db_next" => Func::new(|_a: u32| -> u32 { 0 }),
382382
"query_chain" => Func::new(|_a: u32| -> u32 { 0 }),
383-
"canonicalize_address" => Func::new(|_a: u32, _b: u32| -> i32 { 0 }),
384-
"humanize_address" => Func::new(|_a: u32, _b: u32| -> i32 { 0 }),
383+
"canonicalize_address" => Func::new(|_a: u32, _b: u32| -> u32 { 0 }),
384+
"humanize_address" => Func::new(|_a: u32, _b: u32| -> u32 { 0 }),
385385
},
386386
};
387387
let mut instance = Box::from(module.instantiate(&import_obj).unwrap());

packages/vm/src/errors.rs

+1
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ impl CommunicationError {
269269
InvalidOrder { value }.build()
270270
}
271271

272+
#[allow(dead_code)]
272273
pub(crate) fn invalid_utf8<S: ToString>(msg: S) -> Self {
273274
InvalidUtf8 {
274275
msg: msg.to_string(),

0 commit comments

Comments
 (0)