Treat call service result de errors as local service errors (#134)

This commit is contained in:
Mike Voronov 2021-09-02 18:01:21 +03:00 committed by GitHub
parent 1502cd6f45
commit 7762e4a599
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 72 additions and 51 deletions

20
Cargo.lock generated
View File

@ -33,6 +33,8 @@ dependencies = [
"pretty_assertions", "pretty_assertions",
"serde", "serde",
"serde_json", "serde_json",
"strum",
"strum_macros",
"thiserror", "thiserror",
"wasm-bindgen", "wasm-bindgen",
] ]
@ -1818,6 +1820,24 @@ dependencies = [
"precomputed-hash", "precomputed-hash",
] ]
[[package]]
name = "strum"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aaf86bbcfd1fa9670b7a129f64fc0c9fcbbfe4f1bc4210e9e98fe71ffc12cde2"
[[package]]
name = "strum_macros"
version = "0.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d06aaeeee809dbc59eb4556183dd927df67db1540de5be8d3ec0b6636358a5ec"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "subtle" name = "subtle"
version = "2.4.1" version = "2.4.1"

View File

@ -25,6 +25,8 @@ jsonpath_lib-fl = "=0.3.7"
boolinator = "2.4.0" boolinator = "2.4.0"
log = "0.4.11" log = "0.4.11"
thiserror = "1.0.23" thiserror = "1.0.23"
strum = "0.21"
strum_macros = "0.21"
# Keep 0.2.65 until this is resolved https://github.com/rustwasm/wasm-pack/issues/886 # Keep 0.2.65 until this is resolved https://github.com/rustwasm/wasm-pack/issues/886
wasm-bindgen = "=0.2.65" wasm-bindgen = "=0.2.65"

View File

@ -103,16 +103,12 @@ impl<'i> ResolvedCall<'i> {
exec_ctx: &mut ExecutionCtx<'i>, exec_ctx: &mut ExecutionCtx<'i>,
trace_ctx: &mut TraceHandler, trace_ctx: &mut TraceHandler,
) -> ExecutionResult<()> { ) -> ExecutionResult<()> {
use ExecutionError::CallServiceResultDeError as DeError;
// check that service call succeeded // check that service call succeeded
let service_result = handle_service_error(service_result, trace_ctx)?; let call_service_result = handle_service_error(service_result, trace_ctx)?;
// try to get service result from call service result
let result: JValue = serde_json::from_str(&service_result.result).map_err(|e| DeError(service_result, e))?; let result = try_to_service_result(call_service_result, trace_ctx)?;
let result = Rc::new(result);
let trace_pos = trace_ctx.trace_pos(); let trace_pos = trace_ctx.trace_pos();
let executed_result = ResolvedCallResult::new(result, self.tetraplet.clone(), trace_pos); let executed_result = ResolvedCallResult::new(result, self.tetraplet.clone(), trace_pos);
let new_call_result = set_local_result(executed_result, &self.output, exec_ctx)?; let new_call_result = set_local_result(executed_result, &self.output, exec_ctx)?;
trace_ctx.meet_call_end(new_call_result); trace_ctx.meet_call_end(new_call_result);
@ -191,3 +187,26 @@ fn handle_service_error(
Err(error) Err(error)
} }
fn try_to_service_result(
service_result: CallServiceResult,
trace_ctx: &mut TraceHandler,
) -> ExecutionResult<Rc<JValue>> {
use CallResult::CallServiceFailed;
match serde_json::from_str(&service_result.result) {
Ok(result) => Ok(Rc::new(result)),
Err(e) => {
let error_msg = format!(
"call_service result '{0}' can't be serialized or deserialized with an error: {1}",
service_result.result, e
);
let error_msg = Rc::new(error_msg);
let error = CallServiceFailed(i32::MAX, error_msg.clone());
trace_ctx.meet_call_end(error);
Err(Rc::new(ExecutionError::LocalServiceError(i32::MAX, error_msg.clone())))
}
}
}

View File

@ -24,22 +24,20 @@ use super::trace_handler::MergerApResult;
use super::trace_handler::TraceHandlerError; use super::trace_handler::TraceHandlerError;
use super::ResolvedCallResult; use super::ResolvedCallResult;
use super::Stream; use super::Stream;
use crate::build_targets::CallServiceResult;
use crate::JValue; use crate::JValue;
use jsonpath_lib::JsonPathError; use jsonpath_lib::JsonPathError;
use serde_json::Error as SerdeJsonError; use strum::IntoEnumIterator;
use strum_macros::EnumDiscriminants;
use strum_macros::EnumIter;
use thiserror::Error as ThisError; use thiserror::Error as ThisError;
use std::rc::Rc; use std::rc::Rc;
/// Errors arised while executing AIR script. /// Errors arised while executing AIR script.
#[derive(ThisError, Debug)] #[derive(ThisError, EnumDiscriminants, Debug)]
#[strum_discriminants(derive(EnumIter))]
pub(crate) enum ExecutionError { pub(crate) enum ExecutionError {
/// Errors occurred while parsing returned by call_service value.
#[error("call_service result '{0}' can't be serialized or deserialized with an error: {1}")]
CallServiceResultDeError(CallServiceResult, SerdeJsonError),
/// Semantic errors in a call instructions. /// Semantic errors in a call instructions.
#[error("call should have service id specified by peer part or function part")] #[error("call should have service id specified by peer part or function part")]
IncorrectCallTriplet, IncorrectCallTriplet,
@ -137,32 +135,11 @@ impl From<TraceHandlerError> for Rc<ExecutionError> {
impl ExecutionError { impl ExecutionError {
pub(crate) fn to_error_code(&self) -> u32 { pub(crate) fn to_error_code(&self) -> u32 {
use ExecutionError::*; let mut errors = ExecutionErrorDiscriminants::iter();
let actual_error_type = ExecutionErrorDiscriminants::from(self);
match self { // unwrap is safe here because errors are guaranteed to contain all errors variants
CallServiceResultDeError(..) => 1, errors.position(|et| et == actual_error_type).unwrap() as _
IncorrectCallTriplet => 2,
LocalServiceError(..) => 3,
VariableNotFound(_) => 4,
MultipleVariablesFound(_) => 5,
JValueJsonPathError(..) => 6,
GenerationStreamJsonPathError(..) => 7,
IncompatibleJValueType(..) => 8,
IncompatibleAValueType(..) => 9,
MultipleValuesInJsonPath(_) => 10,
FoldStateNotFound(_) => 11,
MultipleFoldStates(_) => 12,
IterableShadowing(_) => 13,
MatchWithoutXorError => 14,
MismatchWithoutXorError => 15,
FlatteningError(_) => 16,
JsonPathVariableTypeError(_) => 17,
StreamJsonPathError(..) => 18,
StreamDontHaveSuchGeneration(..) => 19,
ApResultNotCorrespondToInstr(_) => 20,
EmptyStreamJsonPathError(_) => 21,
TraceError(_) => 22,
}
} }
} }

View File

@ -14,14 +14,19 @@
* limitations under the License. * limitations under the License.
*/ */
use air_interpreter_data::DATA_FORMAT_VERSION;
use serde_json::Error as SerdeJsonError; use serde_json::Error as SerdeJsonError;
use strum::IntoEnumIterator;
use strum_macros::EnumDiscriminants;
use strum_macros::EnumIter;
use thiserror::Error as ThisError; use thiserror::Error as ThisError;
use air_interpreter_data::DATA_FORMAT_VERSION;
use std::env::VarError; use std::env::VarError;
/// Errors happened during the interpreter preparation_step step. /// Errors happened during the interpreter preparation_step step.
#[derive(Debug, ThisError)] #[derive(Debug, EnumDiscriminants, ThisError)]
#[strum_discriminants(derive(EnumIter))]
pub enum PreparationError { pub enum PreparationError {
/// Error occurred while parsing AIR script /// Error occurred while parsing AIR script
#[error("air can't be parsed:\n{0}")] #[error("air can't be parsed:\n{0}")]
@ -39,12 +44,10 @@ pub enum PreparationError {
impl PreparationError { impl PreparationError {
pub(crate) fn to_error_code(&self) -> u32 { pub(crate) fn to_error_code(&self) -> u32 {
use PreparationError::*; let mut errors = PreparationErrorDiscriminants::iter();
let actual_error_type = PreparationErrorDiscriminants::from(self);
match self { // unwrap is safe here because errors are guaranteed to contain all errors variants
AIRParseError(_) => 1, errors.position(|et| et == actual_error_type).unwrap() as _
DataDeFailed(..) => 2,
CurrentPeerIdEnvError(_) => 3,
}
} }
} }

View File

@ -120,7 +120,7 @@ fn duplicate_variables() {
let result = call_vm!(vm, "asd", script, "", ""); let result = call_vm!(vm, "asd", script, "", "");
assert_eq!(result.ret_code, 1005); assert_eq!(result.ret_code, 1003);
assert!(result.next_peer_pks.is_empty()); assert!(result.next_peer_pks.is_empty());
} }

View File

@ -176,7 +176,7 @@ fn dont_wait_on_json_path_on_scalars() {
let init_peer_id = "asd"; let init_peer_id = "asd";
let result = call_vm!(set_variable_vm, init_peer_id, &script, "", ""); let result = call_vm!(set_variable_vm, init_peer_id, &script, "", "");
let array_result = call_vm!(array_consumer, init_peer_id, &script, "", result.data.clone()); let array_result = call_vm!(array_consumer, init_peer_id, &script, "", result.data.clone());
assert_eq!(array_result.ret_code, 1006); assert_eq!(array_result.ret_code, 1004);
assert_eq!( assert_eq!(
array_result.error_message, array_result.error_message,
r#"variable with path '$.[5]' not found in '[1,2,3,4,5]' with an error: 'json value not set'"# r#"variable with path '$.[5]' not found in '[1,2,3,4,5]' with an error: 'json value not set'"#
@ -195,7 +195,7 @@ fn dont_wait_on_json_path_on_scalars() {
let init_peer_id = "asd"; let init_peer_id = "asd";
let result = call_vm!(set_variable_vm, init_peer_id, &script, "", ""); let result = call_vm!(set_variable_vm, init_peer_id, &script, "", "");
let object_result = call_vm!(object_consumer, init_peer_id, script, "", result.data); let object_result = call_vm!(object_consumer, init_peer_id, script, "", result.data);
assert_eq!(object_result.ret_code, 1006); assert_eq!(object_result.ret_code, 1004);
assert_eq!( assert_eq!(
object_result.error_message, object_result.error_message,
r#"variable with path '$.non_exist_path' not found in '{"err_msg":"","is_authenticated":1,"ret_code":0}' with an error: 'json value not set'"# r#"variable with path '$.non_exist_path' not found in '{"err_msg":"","is_authenticated":1,"ret_code":0}' with an error: 'json value not set'"#

View File

@ -104,7 +104,7 @@ fn par_early_exit() {
]; ];
let setter_3_malicious_data = raw_data_from_trace(setter_3_malicious_trace); let setter_3_malicious_data = raw_data_from_trace(setter_3_malicious_trace);
let init_result_5 = call_vm!(init, "", &script, init_result_3.data.clone(), setter_3_malicious_data); let init_result_5 = call_vm!(init, "", &script, init_result_3.data.clone(), setter_3_malicious_data);
assert_eq!(init_result_5.ret_code, 1022); assert_eq!(init_result_5.ret_code, 1018);
let actual_trace = trace_from_result(&init_result_5); let actual_trace = trace_from_result(&init_result_5);
let expected_trace = trace_from_result(&init_result_3); let expected_trace = trace_from_result(&init_result_3);