@@ -480,6 +480,7 @@ pub fn call_function<'a, 'b, 'c>(
480
480
sponsor : Option < PrincipalData > ,
481
481
) -> Result < Value , Error > {
482
482
let epoch = global_context. epoch_id ;
483
+ let clarity_version = * contract_context. get_clarity_version ( ) ;
483
484
let context = ClarityWasmContext :: new_run (
484
485
global_context,
485
486
contract_context,
@@ -564,7 +565,9 @@ pub fn call_function<'a, 'b, 'c>(
564
565
565
566
// Call the function
566
567
func. call ( & mut store, & wasm_args, & mut results)
567
- . map_err ( |e| error_mapping:: resolve_error ( e, instance, & mut store) ) ?;
568
+ . map_err ( |e| {
569
+ error_mapping:: resolve_error ( e, instance, & mut store, & epoch, & clarity_version)
570
+ } ) ?;
568
571
569
572
// If the function returns a value, translate it into a Clarity `Value`
570
573
wasm_to_clarity_value ( & return_type, 0 , & results, memory, & mut & mut store, epoch)
@@ -7663,12 +7666,13 @@ mod tests {
7663
7666
}
7664
7667
7665
7668
mod error_mapping {
7669
+ use stacks_common:: types:: StacksEpochId ;
7666
7670
use wasmtime:: { AsContextMut , Instance , Trap } ;
7667
7671
7668
- use super :: read_identifier_from_wasm;
7672
+ use super :: { read_from_wasm_indirect , read_identifier_from_wasm, signature_from_string } ;
7669
7673
use crate :: vm:: errors:: { CheckErrors , Error , RuntimeErrorType , ShortReturnType , WasmError } ;
7670
- use crate :: vm:: types:: ResponseData ;
7671
- use crate :: vm:: Value ;
7674
+ use crate :: vm:: types:: { OptionalData , ResponseData } ;
7675
+ use crate :: vm:: { ClarityVersion , Value } ;
7672
7676
7673
7677
const LOG2_ERROR_MESSAGE : & str = "log2 must be passed a positive integer" ;
7674
7678
const SQRTI_ERROR_MESSAGE : & str = "sqrti must be passed a positive integer" ;
@@ -7719,6 +7723,18 @@ mod error_mapping {
7719
7723
/// Indicates an attempt to use a name that is already in use, possibly for a variable or function.
7720
7724
NameAlreadyUsed = 9 ,
7721
7725
7726
+ /// Represents a short-return error for an expected value that wraps a Response type.
7727
+ /// Usually triggered by `(try!...)`.
7728
+ ShortReturnExpectedValueResponse = 10 ,
7729
+
7730
+ /// Represents a short-return error for an expected value that wraps an Optional type.
7731
+ /// Usually triggered by `(try!...)`.
7732
+ ShortReturnExpectedValueOptional = 11 ,
7733
+
7734
+ /// Represents a short-return error for an expected value.
7735
+ /// usually triggered by `(unwrap!...)` and `(unwrap-err!...)`.
7736
+ ShortReturnExpectedValue = 12 ,
7737
+
7722
7738
/// A catch-all for errors that are not mapped to specific error codes.
7723
7739
/// This might be used for unexpected or unclassified errors.
7724
7740
NotMapped = 99 ,
@@ -7738,15 +7754,20 @@ mod error_mapping {
7738
7754
7 => ErrorMap :: ShortReturnAssertionFailure ,
7739
7755
8 => ErrorMap :: ArithmeticPowError ,
7740
7756
9 => ErrorMap :: NameAlreadyUsed ,
7757
+ 10 => ErrorMap :: ShortReturnExpectedValueResponse ,
7758
+ 11 => ErrorMap :: ShortReturnExpectedValueOptional ,
7759
+ 12 => ErrorMap :: ShortReturnExpectedValue ,
7741
7760
_ => ErrorMap :: NotMapped ,
7742
7761
}
7743
7762
}
7744
7763
}
7745
7764
7746
- pub fn resolve_error (
7765
+ pub ( crate ) fn resolve_error (
7747
7766
e : wasmtime:: Error ,
7748
7767
instance : Instance ,
7749
7768
mut store : impl AsContextMut ,
7769
+ epoch_id : & StacksEpochId ,
7770
+ clarity_version : & ClarityVersion ,
7750
7771
) -> Error {
7751
7772
if let Some ( vm_error) = e. root_cause ( ) . downcast_ref :: < Error > ( ) {
7752
7773
// SAFETY:
@@ -7804,23 +7825,32 @@ mod error_mapping {
7804
7825
// In this case, runtime errors are handled
7805
7826
// by being mapped to the corresponding ClarityWasm Errors.
7806
7827
if let Some ( Trap :: UnreachableCodeReached ) = e. root_cause ( ) . downcast_ref :: < Trap > ( ) {
7807
- return from_runtime_error_code ( instance, & mut store, e) ;
7828
+ return from_runtime_error_code ( instance, & mut store, e, epoch_id , clarity_version ) ;
7808
7829
}
7809
7830
7810
7831
// All other errors are treated as general runtime errors.
7811
7832
Error :: Wasm ( WasmError :: Runtime ( e) )
7812
7833
}
7813
7834
7835
+ /// Converts a WebAssembly runtime error code into a Clarity `Error`.
7836
+ ///
7837
+ /// This function interprets an error code from a WebAssembly runtime execution and
7838
+ /// translates it into an appropriate Clarity error type. It handles various categories
7839
+ /// of errors including arithmetic errors, short returns, and other runtime issues.
7840
+ ///
7841
+ /// # Returns
7842
+ ///
7843
+ /// Returns a Clarity `Error` that corresponds to the runtime error encountered during
7844
+ /// WebAssembly execution.
7845
+ ///
7814
7846
fn from_runtime_error_code (
7815
7847
instance : Instance ,
7816
7848
mut store : impl AsContextMut ,
7817
7849
e : wasmtime:: Error ,
7850
+ epoch_id : & StacksEpochId ,
7851
+ clarity_version : & ClarityVersion ,
7818
7852
) -> 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" ) ) ;
7853
+ let runtime_error_code = get_global_i32 ( & instance, & mut store, "runtime-error-code" ) ;
7824
7854
7825
7855
match ErrorMap :: from ( runtime_error_code) {
7826
7856
ErrorMap :: NotClarityError => Error :: Wasm ( WasmError :: Runtime ( e) ) ,
@@ -7849,33 +7879,20 @@ mod error_mapping {
7849
7879
// This RuntimeErrorType::UnwrapFailure need to have a proper context.
7850
7880
Error :: Runtime ( RuntimeErrorType :: UnwrapFailure , Some ( Vec :: new ( ) ) )
7851
7881
}
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
- ) ,
7882
+ ErrorMap :: ShortReturnAssertionFailure => {
7883
+ let clarity_val =
7884
+ short_return_value ( & instance, & mut store, epoch_id, clarity_version) ;
7885
+ Error :: ShortReturn ( ShortReturnType :: AssertionFailed ( clarity_val) )
7886
+ }
7861
7887
ErrorMap :: ArithmeticPowError => Error :: Runtime (
7862
7888
RuntimeErrorType :: Arithmetic ( POW_ERROR_MESSAGE . into ( ) ) ,
7863
7889
Some ( Vec :: new ( ) ) ,
7864
7890
) ,
7865
7891
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
- } ) ;
7892
+ let runtime_error_arg_offset =
7893
+ get_global_i32 ( & instance, & mut store, "runtime-error-arg-offset" ) ;
7894
+ let runtime_error_arg_len =
7895
+ get_global_i32 ( & instance, & mut store, "runtime-error-arg-len" ) ;
7879
7896
7880
7897
let memory = instance
7881
7898
. get_memory ( & mut store, "memory" )
@@ -7890,7 +7907,76 @@ mod error_mapping {
7890
7907
7891
7908
Error :: Unchecked ( CheckErrors :: NameAlreadyUsed ( arg_name) )
7892
7909
}
7910
+ ErrorMap :: ShortReturnExpectedValueResponse => {
7911
+ let clarity_val =
7912
+ short_return_value ( & instance, & mut store, epoch_id, clarity_version) ;
7913
+ Error :: ShortReturn ( ShortReturnType :: ExpectedValue ( Value :: Response (
7914
+ ResponseData {
7915
+ committed : false ,
7916
+ data : Box :: new ( clarity_val) ,
7917
+ } ,
7918
+ ) ) )
7919
+ }
7920
+ ErrorMap :: ShortReturnExpectedValueOptional => Error :: ShortReturn (
7921
+ ShortReturnType :: ExpectedValue ( Value :: Optional ( OptionalData { data : None } ) ) ,
7922
+ ) ,
7923
+ ErrorMap :: ShortReturnExpectedValue => {
7924
+ let clarity_val =
7925
+ short_return_value ( & instance, & mut store, epoch_id, clarity_version) ;
7926
+ Error :: ShortReturn ( ShortReturnType :: ExpectedValue ( clarity_val) )
7927
+ }
7893
7928
_ => panic ! ( "Runtime error code {} not supported" , runtime_error_code) ,
7894
7929
}
7895
7930
}
7931
+
7932
+ /// Retrieves the value of a 32-bit integer global variable from a WebAssembly instance.
7933
+ ///
7934
+ /// This function attempts to fetch a global variable by name from the provided WebAssembly
7935
+ /// instance and return its value as an `i32`. It's designed to simplify the process of
7936
+ /// reading global variables in WebAssembly modules.
7937
+ ///
7938
+ /// # Returns
7939
+ ///
7940
+ /// Returns the value of the global variable as an `i32`.
7941
+ ///
7942
+ fn get_global_i32 ( instance : & Instance , store : & mut impl AsContextMut , name : & str ) -> i32 {
7943
+ instance
7944
+ . get_global ( & mut * store, name)
7945
+ . and_then ( |glob| glob. get ( store) . i32 ( ) )
7946
+ . unwrap_or_else ( || panic ! ( "Could not find ${} global with i32 value" , name) )
7947
+ }
7948
+
7949
+ /// Retrieves and deserializes a Clarity value from WebAssembly memory in the context of a short return.
7950
+ ///
7951
+ /// This function is used to extract a Clarity value that has been stored in WebAssembly memory
7952
+ /// as part of a short return operation. It reads necessary metadata from global variables,
7953
+ /// deserializes the type information, and then reads and deserializes the actual value.
7954
+ ///
7955
+ /// # Returns
7956
+ ///
7957
+ /// Returns a deserialized Clarity `Value` representing the short return value.
7958
+ ///
7959
+ fn short_return_value (
7960
+ instance : & Instance ,
7961
+ store : & mut impl AsContextMut ,
7962
+ epoch_id : & StacksEpochId ,
7963
+ clarity_version : & ClarityVersion ,
7964
+ ) -> Value {
7965
+ let val_offset = get_global_i32 ( instance, store, "runtime-error-value-offset" ) ;
7966
+ let type_ser_offset = get_global_i32 ( instance, store, "runtime-error-type-ser-offset" ) ;
7967
+ let type_ser_len = get_global_i32 ( instance, store, "runtime-error-type-ser-len" ) ;
7968
+
7969
+ let memory = instance
7970
+ . get_memory ( & mut * store, "memory" )
7971
+ . unwrap_or_else ( || panic ! ( "Could not find wasm instance memory" ) ) ;
7972
+
7973
+ let type_ser_str = read_identifier_from_wasm ( memory, store, type_ser_offset, type_ser_len)
7974
+ . unwrap_or_else ( |e| panic ! ( "Could not recover stringified type: {}" , e) ) ;
7975
+
7976
+ let value_ty = signature_from_string ( & type_ser_str, * clarity_version, * epoch_id)
7977
+ . unwrap_or_else ( |e| panic ! ( "Could not recover thrown value: {}" , e) ) ;
7978
+
7979
+ read_from_wasm_indirect ( memory, store, & value_ty, val_offset, * epoch_id)
7980
+ . unwrap_or_else ( |e| panic ! ( "Could not read thrown value from memory: {}" , e) )
7981
+ }
7896
7982
}
0 commit comments