Skip to content

Commit 6c7ddc5

Browse files
committed
chore: sync with clarity-wasm repo
1 parent dfdf66a commit 6c7ddc5

File tree

1 file changed

+111
-30
lines changed

1 file changed

+111
-30
lines changed

clarity/src/vm/clarity_wasm.rs

Lines changed: 111 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,7 @@ pub fn call_function<'a, 'b, 'c>(
564564

565565
// Call the function
566566
func.call(&mut store, &wasm_args, &mut results)
567-
.map_err(|e| error_mapping::resolve_error(e, instance, &mut store))?;
567+
.map_err(|e| error_mapping::resolve_error(e, instance, &mut store, &epoch, &clarity_version))?;
568568

569569
// If the function returns a value, translate it into a Clarity `Value`
570570
wasm_to_clarity_value(&return_type, 0, &results, memory, &mut &mut store, epoch)
@@ -7719,6 +7719,18 @@ mod error_mapping {
77197719
/// Indicates an attempt to use a name that is already in use, possibly for a variable or function.
77207720
NameAlreadyUsed = 9,
77217721

7722+
/// Represents a short-return error for an expected value that wraps a Response type.
7723+
/// Usually triggered by `(try!...)`.
7724+
ShortReturnExpectedValueResponse = 10,
7725+
7726+
/// Represents a short-return error for an expected value that wraps an Optional type.
7727+
/// Usually triggered by `(try!...)`.
7728+
ShortReturnExpectedValueOptional = 11,
7729+
7730+
/// Represents a short-return error for an expected value.
7731+
/// usually triggered by `(unwrap!...)` and `(unwrap-err!...)`.
7732+
ShortReturnExpectedValue = 12,
7733+
77227734
/// A catch-all for errors that are not mapped to specific error codes.
77237735
/// This might be used for unexpected or unclassified errors.
77247736
NotMapped = 99,
@@ -7738,15 +7750,20 @@ mod error_mapping {
77387750
7 => ErrorMap::ShortReturnAssertionFailure,
77397751
8 => ErrorMap::ArithmeticPowError,
77407752
9 => ErrorMap::NameAlreadyUsed,
7753+
10 => ErrorMap::ShortReturnExpectedValueResponse,
7754+
11 => ErrorMap::ShortReturnExpectedValueOptional,
7755+
12 => ErrorMap::ShortReturnExpectedValue,
77417756
_ => ErrorMap::NotMapped,
77427757
}
77437758
}
77447759
}
77457760

7746-
pub fn resolve_error(
7761+
pub(crate) fn resolve_error(
77477762
e: wasmtime::Error,
77487763
instance: Instance,
77497764
mut store: impl AsContextMut,
7765+
epoch_id: &StacksEpochId,
7766+
clarity_version: &ClarityVersion,
77507767
) -> Error {
77517768
if let Some(vm_error) = e.root_cause().downcast_ref::<Error>() {
77527769
// SAFETY:
@@ -7804,23 +7821,32 @@ mod error_mapping {
78047821
// In this case, runtime errors are handled
78057822
// by being mapped to the corresponding ClarityWasm Errors.
78067823
if let Some(Trap::UnreachableCodeReached) = e.root_cause().downcast_ref::<Trap>() {
7807-
return from_runtime_error_code(instance, &mut store, e);
7824+
return from_runtime_error_code(instance, &mut store, e, epoch_id, clarity_version);
78087825
}
78097826

78107827
// All other errors are treated as general runtime errors.
78117828
Error::Wasm(WasmError::Runtime(e))
78127829
}
78137830

7831+
/// Converts a WebAssembly runtime error code into a Clarity `Error`.
7832+
///
7833+
/// This function interprets an error code from a WebAssembly runtime execution and
7834+
/// translates it into an appropriate Clarity error type. It handles various categories
7835+
/// of errors including arithmetic errors, short returns, and other runtime issues.
7836+
///
7837+
/// # Returns
7838+
///
7839+
/// Returns a Clarity `Error` that corresponds to the runtime error encountered during
7840+
/// WebAssembly execution.
7841+
///
78147842
fn from_runtime_error_code(
78157843
instance: Instance,
78167844
mut store: impl AsContextMut,
78177845
e: wasmtime::Error,
7846+
epoch_id: &StacksEpochId,
7847+
clarity_version: &ClarityVersion,
78187848
) -> Error {
7819-
let global = "runtime-error-code";
7820-
let runtime_error_code = instance
7821-
.get_global(&mut store, global)
7822-
.and_then(|glob| glob.get(&mut store).i32())
7823-
.unwrap_or_else(|| panic!("Could not find {global} global with i32 value"));
7849+
let runtime_error_code = get_global_i32(&instance, &mut store, "runtime-error-code");
78247850

78257851
match ErrorMap::from(runtime_error_code) {
78267852
ErrorMap::NotClarityError => Error::Wasm(WasmError::Runtime(e)),
@@ -7849,33 +7875,19 @@ mod error_mapping {
78497875
// This RuntimeErrorType::UnwrapFailure need to have a proper context.
78507876
Error::Runtime(RuntimeErrorType::UnwrapFailure, Some(Vec::new()))
78517877
}
7852-
// TODO: UInt(42) value below is just a placeholder.
7853-
// It should be replaced by the current "thrown-value" when clarity-wasm issue #385 is resolved.
7854-
// Tests that reach this code are currently ignored.
7855-
ErrorMap::ShortReturnAssertionFailure => Error::ShortReturn(
7856-
ShortReturnType::AssertionFailed(Value::Response(ResponseData {
7857-
committed: false,
7858-
data: Box::new(Value::UInt(42)),
7859-
})),
7860-
),
7878+
ErrorMap::ShortReturnAssertionFailure => {
7879+
let clarity_val = short_return_value(&instance, &mut store, epoch_id, clarity_version);
7880+
Error::ShortReturn(ShortReturnType::AssertionFailed(clarity_val))
7881+
}
78617882
ErrorMap::ArithmeticPowError => Error::Runtime(
78627883
RuntimeErrorType::Arithmetic(POW_ERROR_MESSAGE.into()),
78637884
Some(Vec::new()),
78647885
),
78657886
ErrorMap::NameAlreadyUsed => {
7866-
let runtime_error_arg_offset = instance
7867-
.get_global(&mut store, "runtime-error-arg-offset")
7868-
.and_then(|glob| glob.get(&mut store).i32())
7869-
.unwrap_or_else(|| {
7870-
panic!("Could not find $runtime-error-arg-offset global with i32 value")
7871-
});
7872-
7873-
let runtime_error_arg_len = instance
7874-
.get_global(&mut store, "runtime-error-arg-len")
7875-
.and_then(|glob| glob.get(&mut store).i32())
7876-
.unwrap_or_else(|| {
7877-
panic!("Could not find $runtime-error-arg-len global with i32 value")
7878-
});
7887+
let runtime_error_arg_offset =
7888+
get_global_i32(&instance, &mut store, "runtime-error-arg-offset");
7889+
let runtime_error_arg_len =
7890+
get_global_i32(&instance, &mut store, "runtime-error-arg-len");
78797891

78807892
let memory = instance
78817893
.get_memory(&mut store, "memory")
@@ -7890,7 +7902,76 @@ mod error_mapping {
78907902

78917903
Error::Unchecked(CheckErrors::NameAlreadyUsed(arg_name))
78927904
}
7905+
ErrorMap::ShortReturnExpectedValueResponse => {
7906+
let clarity_val = short_return_value(&instance, &mut store, epoch_id, clarity_version);
7907+
Error::ShortReturn(ShortReturnType::ExpectedValue(Value::Response(
7908+
ResponseData {
7909+
committed: false,
7910+
data: Box::new(clarity_val),
7911+
},
7912+
)))
7913+
}
7914+
ErrorMap::ShortReturnExpectedValueOptional => {
7915+
Error::ShortReturn(ShortReturnType::ExpectedValue(Value::Optional(
7916+
clarity::vm::types::OptionalData { data: None },
7917+
)))
7918+
}
7919+
ErrorMap::ShortReturnExpectedValue => {
7920+
let clarity_val = short_return_value(&instance, &mut store, epoch_id, clarity_version);
7921+
Error::ShortReturn(ShortReturnType::ExpectedValue(clarity_val))
7922+
}
78937923
_ => panic!("Runtime error code {} not supported", runtime_error_code),
78947924
}
78957925
}
7926+
7927+
/// Retrieves the value of a 32-bit integer global variable from a WebAssembly instance.
7928+
///
7929+
/// This function attempts to fetch a global variable by name from the provided WebAssembly
7930+
/// instance and return its value as an `i32`. It's designed to simplify the process of
7931+
/// reading global variables in WebAssembly modules.
7932+
///
7933+
/// # Returns
7934+
///
7935+
/// Returns the value of the global variable as an `i32`.
7936+
///
7937+
fn get_global_i32(instance: &Instance, store: &mut impl AsContextMut, name: &str) -> i32 {
7938+
instance
7939+
.get_global(&mut *store, name)
7940+
.and_then(|glob| glob.get(store).i32())
7941+
.unwrap_or_else(|| panic!("Could not find ${} global with i32 value", name))
7942+
}
7943+
7944+
/// Retrieves and deserializes a Clarity value from WebAssembly memory in the context of a short return.
7945+
///
7946+
/// This function is used to extract a Clarity value that has been stored in WebAssembly memory
7947+
/// as part of a short return operation. It reads necessary metadata from global variables,
7948+
/// deserializes the type information, and then reads and deserializes the actual value.
7949+
///
7950+
/// # Returns
7951+
///
7952+
/// Returns a deserialized Clarity `Value` representing the short return value.
7953+
///
7954+
fn short_return_value(
7955+
instance: &Instance,
7956+
store: &mut impl AsContextMut,
7957+
epoch_id: &StacksEpochId,
7958+
clarity_version: &ClarityVersion,
7959+
) -> Value {
7960+
let val_offset = get_global_i32(instance, store, "runtime-error-value-offset");
7961+
let type_ser_offset = get_global_i32(instance, store, "runtime-error-type-ser-offset");
7962+
let type_ser_len = get_global_i32(instance, store, "runtime-error-type-ser-len");
7963+
7964+
let memory = instance
7965+
.get_memory(&mut *store, "memory")
7966+
.unwrap_or_else(|| panic!("Could not find wasm instance memory"));
7967+
7968+
let type_ser_str = read_identifier_from_wasm(memory, store, type_ser_offset, type_ser_len)
7969+
.unwrap_or_else(|e| panic!("Could not recover stringified type: {}", e));
7970+
7971+
let value_ty = signature_from_string(&type_ser_str, *clarity_version, *epoch_id)
7972+
.unwrap_or_else(|e| panic!("Could not recover thrown value: {}", e));
7973+
7974+
read_from_wasm_indirect(memory, store, &value_ty, val_offset, *epoch_id)
7975+
.unwrap_or_else(|e| panic!("Could not read thrown value from memory: {}", e))
7976+
}
78967977
}

0 commit comments

Comments
 (0)