From 54e383cdaf4defde684509212c6f754d14a9f7cd Mon Sep 17 00:00:00 2001 From: vms Date: Fri, 17 Dec 2021 22:02:16 +0300 Subject: [PATCH] introduce farewell step; reafactoring --- Cargo.lock | 13 +++- air/Cargo.toml | 1 + air/src/execution_step/air/ap.rs | 2 +- .../air/ap/apply_to_arguments.rs | 2 +- .../execution_step/air/call/resolved_call.rs | 2 +- air/src/execution_step/air/call/triplet.rs | 2 +- .../air/compare_matchable/comparator.rs | 4 +- .../boxed_value/jvaluable/empty_stream.rs | 7 +- air/src/execution_step/errors.rs | 38 +++++----- .../execution_step/lambda_applier/errors.rs | 4 ++ air/src/execution_step/mod.rs | 2 +- .../execution_step/{utils => resolver}/mod.rs | 0 .../{utils => resolver}/resolve.rs | 0 air/src/farewell_step/errors.rs | 47 ++++++++++++ air/src/farewell_step/mod.rs | 23 ++++++ air/src/{runner => farewell_step}/outcome.rs | 72 ++++++++----------- air/src/lib.rs | 4 ++ air/src/preparation_step/errors.rs | 11 +-- air/src/runner.rs | 32 ++------- air/src/utils/mod.rs | 19 +++++ air/src/utils/to_error_code.rs | 37 ++++++++++ avm/server/Cargo.toml | 2 +- avm/server/src/interface/outcome.rs | 4 +- avm/server/src/interface/raw_outcome.rs | 2 +- .../air-lib/interpreter-interface/Cargo.toml | 2 +- .../src/interpreter_outcome.rs | 12 ++-- 26 files changed, 233 insertions(+), 111 deletions(-) rename air/src/execution_step/{utils => resolver}/mod.rs (100%) rename air/src/execution_step/{utils => resolver}/resolve.rs (100%) create mode 100644 air/src/farewell_step/errors.rs create mode 100644 air/src/farewell_step/mod.rs rename air/src/{runner => farewell_step}/outcome.rs (58%) create mode 100644 air/src/utils/mod.rs create mode 100644 air/src/utils/to_error_code.rs diff --git a/Cargo.lock b/Cargo.lock index 1949f64c..6a75d3fb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -25,6 +25,7 @@ dependencies = [ "air-test-utils", "air-trace-handler", "boolinator", + "concat-idents", "criterion", "csv", "env_logger", @@ -73,7 +74,7 @@ dependencies = [ [[package]] name = "air-interpreter-interface" -version = "0.7.0" +version = "0.8.0" dependencies = [ "fluence-it-types", "marine-rs-sdk", @@ -408,6 +409,16 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "concat-idents" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b6f90860248d75014b7b103db8fee4f291c07bfb41306cdf77a0a5ab7a10d2f" +dependencies = [ + "quote", + "syn", +] + [[package]] name = "constant_time_eq" version = "0.1.5" diff --git a/air/Cargo.toml b/air/Cargo.toml index 378fbf96..bb7155a4 100644 --- a/air/Cargo.toml +++ b/air/Cargo.toml @@ -30,6 +30,7 @@ serde = { version = "1.0.118", features = [ "derive", "rc" ] } serde_json = "1.0.61" boolinator = "2.4.0" +concat-idents = "1.1.3" maplit = "1.0.2" log = "0.4.11" thiserror = "1.0.23" diff --git a/air/src/execution_step/air/ap.rs b/air/src/execution_step/air/ap.rs index 463f0da9..a4080908 100644 --- a/air/src/execution_step/air/ap.rs +++ b/air/src/execution_step/air/ap.rs @@ -22,7 +22,7 @@ use super::ExecutionResult; use super::TraceHandler; use crate::execution_step::air::ValueAggregate; use crate::execution_step::boxed_value::Variable; -use crate::execution_step::utils::apply_lambda; +use crate::execution_step::resolver::apply_lambda; use crate::trace_to_exec_err; use crate::JValue; use crate::SecurityTetraplet; diff --git a/air/src/execution_step/air/ap/apply_to_arguments.rs b/air/src/execution_step/air/ap/apply_to_arguments.rs index 13c0ed7c..8a0de25c 100644 --- a/air/src/execution_step/air/ap/apply_to_arguments.rs +++ b/air/src/execution_step/air/ap/apply_to_arguments.rs @@ -52,7 +52,7 @@ fn apply_last_error( exec_ctx: &ExecutionCtx<'_>, trace_ctx: &TraceHandler, ) -> ExecutionResult { - let (value, mut tetraplets) = crate::execution_step::utils::prepare_last_error(error_path, exec_ctx)?; + let (value, mut tetraplets) = crate::execution_step::resolver::prepare_last_error(error_path, exec_ctx)?; let value = Rc::new(value); // removing is safe because prepare_last_error always returns a vec with one element. let tetraplet = tetraplets.remove(0); diff --git a/air/src/execution_step/air/call/resolved_call.rs b/air/src/execution_step/air/call/resolved_call.rs index 9578fa3a..c5ee26b7 100644 --- a/air/src/execution_step/air/call/resolved_call.rs +++ b/air/src/execution_step/air/call/resolved_call.rs @@ -149,7 +149,7 @@ impl<'i> ResolvedCall<'i> { /// Prepare arguments of this call instruction by resolving and preparing their security tetraplets. fn resolve_args(&self, exec_ctx: &ExecutionCtx<'i>) -> ExecutionResult { - use crate::execution_step::utils::resolve_to_args; + use crate::execution_step::resolver::resolve_to_args; let function_args = self.function_arg_paths.iter(); let mut call_arguments = Vec::new(); diff --git a/air/src/execution_step/air/call/triplet.rs b/air/src/execution_step/air/call/triplet.rs index 8dde9ff5..996c44f7 100644 --- a/air/src/execution_step/air/call/triplet.rs +++ b/air/src/execution_step/air/call/triplet.rs @@ -45,7 +45,7 @@ pub(crate) fn resolve<'i>(triplet: &ast::Triplet<'i>, ctx: &ExecutionCtx<'i>) -> /// Resolve value to string by either resolving variable from `ExecutionCtx`, taking literal value, or etc. // TODO: return Rc to avoid excess cloning fn resolve_to_string<'i>(value: &ast::CallInstrValue<'i>, ctx: &ExecutionCtx<'i>) -> ExecutionResult { - use crate::execution_step::utils::resolve_ast_variable_wl; + use crate::execution_step::resolver::resolve_ast_variable_wl; use ast::CallInstrValue::*; let resolved = match value { diff --git a/air/src/execution_step/air/compare_matchable/comparator.rs b/air/src/execution_step/air/compare_matchable/comparator.rs index ae6d4989..f4049fac 100644 --- a/air/src/execution_step/air/compare_matchable/comparator.rs +++ b/air/src/execution_step/air/compare_matchable/comparator.rs @@ -16,8 +16,8 @@ use crate::execution_step::air::ExecutionResult; use crate::execution_step::execution_context::ExecutionCtx; -use crate::execution_step::utils::prepare_last_error; -use crate::execution_step::utils::resolve_ast_variable_wl; +use crate::execution_step::resolver::prepare_last_error; +use crate::execution_step::resolver::resolve_ast_variable_wl; use crate::JValue; use air_parser::ast; diff --git a/air/src/execution_step/boxed_value/jvaluable/empty_stream.rs b/air/src/execution_step/boxed_value/jvaluable/empty_stream.rs index c2f82a26..76271c8f 100644 --- a/air/src/execution_step/boxed_value/jvaluable/empty_stream.rs +++ b/air/src/execution_step/boxed_value/jvaluable/empty_stream.rs @@ -14,10 +14,11 @@ * limitations under the License. */ -use super::ExecutionError; +use super::ExecutionError::LambdaApplierError; use super::ExecutionResult; use super::JValuable; use super::LambdaAST; +use super::LambdaError::EmptyStream; use crate::exec_err; use crate::execution_step::ExecutionCtx; use crate::execution_step::RSecurityTetraplet; @@ -29,7 +30,7 @@ use std::borrow::Cow; impl JValuable for () { fn apply_lambda<'i>(&self, _lambda: &LambdaAST<'_>, _exec_ctx: &ExecutionCtx<'i>) -> ExecutionResult<&JValue> { // applying lambda to an empty stream will produce a join behaviour - exec_err!(ExecutionError::EmptyStreamLambdaError) + exec_err!(LambdaApplierError(EmptyStream)) } fn apply_lambda_with_tetraplets<'i>( @@ -38,7 +39,7 @@ impl JValuable for () { _exec_ctx: &ExecutionCtx<'i>, ) -> ExecutionResult<(&JValue, RSecurityTetraplet)> { // applying lambda to an empty stream will produce a join behaviour - exec_err!(ExecutionError::EmptyStreamLambdaError) + exec_err!(LambdaApplierError(EmptyStream)) } fn as_jvalue(&self) -> Cow<'_, JValue> { diff --git a/air/src/execution_step/errors.rs b/air/src/execution_step/errors.rs index f3984bb1..4fe0e72e 100644 --- a/air/src/execution_step/errors.rs +++ b/air/src/execution_step/errors.rs @@ -23,8 +23,8 @@ pub(crate) use joinable::Joinable; use super::Stream; use crate::execution_step::lambda_applier::LambdaError; use crate::JValue; +use crate::ToErrorCode; -use air_interpreter_interface::CallResults; use air_trace_handler::MergerApResult; use air_trace_handler::TraceHandlerError; use strum::IntoEnumIterator; @@ -54,10 +54,6 @@ pub(crate) enum ExecutionError { #[error(transparent)] LambdaApplierError(#[from] LambdaError), - /// An error occurred while trying to apply lambda to an empty stream. - #[error("lambda is applied to an empty stream")] - EmptyStreamLambdaError, - /// Provided JValue has incompatible type with a requested one. #[error( "expected JValue type '{expected_value_type}' for the variable `{variable_name}`, but got '{actual_value}'" @@ -108,12 +104,6 @@ pub(crate) enum ExecutionError { /// could be applied to a stream, but result doesn't contain generation in a source position. #[error("ap result {0:?} doesn't match corresponding instruction")] ApResultNotCorrespondToInstr(MergerApResult), - - /// Call results should be empty at the end of execution thanks to a execution invariant. - #[error( - "after finishing execution of supplied AIR, call results aren't empty: `{0:?}`, probably wrong call_id used" - )] - CallResultsNotEmpty(CallResults), } impl From for Rc { @@ -131,15 +121,31 @@ macro_rules! trace_to_exec_err { }; } -impl ExecutionError { - pub(crate) fn to_error_code(&self) -> u32 { - const EXECUTION_ERRORS_START_ID: u32 = 1000; +/* +impl ToErrorCode for ExecutionError { + fn to_error_code(&self) -> i64 { + const EXECUTION_ERRORS_START_ID: i64 = 1000; let mut errors = ExecutionErrorDiscriminants::iter(); let actual_error_type = ExecutionErrorDiscriminants::from(self); // unwrap is safe here because errors are guaranteed to contain all errors variants - let enum_variant_position = errors.position(|et| et == actual_error_type).unwrap() as u32; + let enum_variant_position = errors.position(|et| et == actual_error_type).unwrap() as i64; + EXECUTION_ERRORS_START_ID + enum_variant_position + } +} + + */ + +impl ToErrorCode for Rc { + fn to_error_code(&self) -> i64 { + const EXECUTION_ERRORS_START_ID: i64 = 1000; + + let mut errors = ExecutionErrorDiscriminants::iter(); + let actual_error_type = ExecutionErrorDiscriminants::from(self.as_ref()); + + // unwrap is safe here because errors are guaranteed to contain all errors variants + let enum_variant_position = errors.position(|et| et == actual_error_type).unwrap() as i64; EXECUTION_ERRORS_START_ID + enum_variant_position } } @@ -166,7 +172,7 @@ impl Joinable for ExecutionError { log_join!(" waiting for an argument with idx '{}' on stream with size '{}'", idx, stream_size); true } - EmptyStreamLambdaError => { + LambdaApplierError(LambdaError::EmptyStream) => { log_join!(" waiting on empty stream for path "); true } diff --git a/air/src/execution_step/lambda_applier/errors.rs b/air/src/execution_step/lambda_applier/errors.rs index ab54de2f..62842494 100644 --- a/air/src/execution_step/lambda_applier/errors.rs +++ b/air/src/execution_step/lambda_applier/errors.rs @@ -23,6 +23,10 @@ pub(crate) enum LambdaError { #[error("lambda is applied to a stream that have only '{stream_size}' elements, but '{idx}' requested")] StreamNotHaveEnoughValues { stream_size: usize, idx: u32 }, + /// An error occurred while trying to apply lambda to an empty stream. + #[error("lambda is applied to an empty stream")] + EmptyStream, + #[error("field accessor (with field name = '{field_name}') can't be applied to a stream")] FieldAccessorAppliedToStream { field_name: String }, diff --git a/air/src/execution_step/mod.rs b/air/src/execution_step/mod.rs index 51772fce..21df2f83 100644 --- a/air/src/execution_step/mod.rs +++ b/air/src/execution_step/mod.rs @@ -19,7 +19,7 @@ mod boxed_value; mod errors; pub(crate) mod execution_context; mod lambda_applier; -mod utils; +mod resolver; pub(super) use self::air::ExecutableInstruction; pub(super) use self::air::FoldState; diff --git a/air/src/execution_step/utils/mod.rs b/air/src/execution_step/resolver/mod.rs similarity index 100% rename from air/src/execution_step/utils/mod.rs rename to air/src/execution_step/resolver/mod.rs diff --git a/air/src/execution_step/utils/resolve.rs b/air/src/execution_step/resolver/resolve.rs similarity index 100% rename from air/src/execution_step/utils/resolve.rs rename to air/src/execution_step/resolver/resolve.rs diff --git a/air/src/farewell_step/errors.rs b/air/src/farewell_step/errors.rs new file mode 100644 index 00000000..cc034d75 --- /dev/null +++ b/air/src/farewell_step/errors.rs @@ -0,0 +1,47 @@ +/* + * Copyright 2021 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::ToErrorCode; +use air_interpreter_interface::CallResults; + +use strum::IntoEnumIterator; +use strum_macros::EnumDiscriminants; +use strum_macros::EnumIter; +use thiserror::Error as ThisError; + +/// Errors happened during the interpreter farewell step. +#[derive(Debug, EnumDiscriminants, ThisError)] +#[strum_discriminants(derive(EnumIter))] +pub enum FarewellError { + /// Call results should be empty at the end of execution thanks to a execution invariant. + #[error( + "after finishing execution of supplied AIR, call results aren't empty: `{0:?}`, probably wrong call_id used" + )] + CallResultsNotEmpty(CallResults), +} + +impl ToErrorCode for FarewellError { + fn to_error_code(&self) -> i64 { + const FAREWELL_ERRORS_START_ID: i64 = 20000; + + let mut errors = FarewellErrorDiscriminants::iter(); + let actual_error_type = FarewellErrorDiscriminants::from(self); + + // unwrap is safe here because errors are guaranteed to contain all errors variants + let enum_variant_position = errors.position(|et| et == actual_error_type).unwrap() as i64; + FAREWELL_ERRORS_START_ID + enum_variant_position + } +} diff --git a/air/src/farewell_step/mod.rs b/air/src/farewell_step/mod.rs new file mode 100644 index 00000000..10fef167 --- /dev/null +++ b/air/src/farewell_step/mod.rs @@ -0,0 +1,23 @@ +/* + * Copyright 2021 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +mod errors; +mod outcome; + +pub(crate) use errors::FarewellError; +pub(crate) use outcome::from_execution_error; +pub(crate) use outcome::from_success_result; +pub(crate) use outcome::from_uncatchable_error; diff --git a/air/src/runner/outcome.rs b/air/src/farewell_step/outcome.rs similarity index 58% rename from air/src/runner/outcome.rs rename to air/src/farewell_step/outcome.rs index c0d111b5..e94c439b 100644 --- a/air/src/runner/outcome.rs +++ b/air/src/farewell_step/outcome.rs @@ -14,11 +14,11 @@ * limitations under the License. */ +use super::FarewellError; use crate::execution_step::ExecutionCtx; -use crate::execution_step::ExecutionError; use crate::execution_step::TraceHandler; -use crate::preparation_step::PreparationError; use crate::InterpreterOutcome; +use crate::ToErrorCode; use crate::INTERPRETER_SUCCESS; use air_interpreter_data::InterpreterData; @@ -29,53 +29,34 @@ use std::rc::Rc; /// Create InterpreterOutcome from supplied execution context and trace handler, /// set ret_code to INTERPRETER_SUCCESS. -pub(crate) fn from_success_result(exec_ctx: ExecutionCtx<'_>, trace_handler: TraceHandler) -> InterpreterOutcome { - let (global_streams, restricted_streams) = exec_ctx.streams.into_streams_data(); - let data = InterpreterData::from_execution_result( - trace_handler.into_result_trace(), - global_streams, - restricted_streams, - exec_ctx.last_call_request_id, - ); - let data = serde_json::to_vec(&data).expect("default serializer shouldn't fail"); - let next_peer_pks = dedup(exec_ctx.next_peer_pks); - let call_requests = serde_json::to_vec(&exec_ctx.call_requests).expect("default serializer shouldn't fail"); +pub(crate) fn from_success_result( + exec_ctx: ExecutionCtx<'_>, + trace_handler: TraceHandler, +) -> Result { + let (ret_code, error_message) = if exec_ctx.call_results.is_empty() { + (INTERPRETER_SUCCESS, String::new()) + } else { + let farewell_error = Rc::new(FarewellError::CallResultsNotEmpty(exec_ctx.call_results.clone())); + (farewell_error.to_error_code(), farewell_error.to_string()) + }; - InterpreterOutcome { - ret_code: INTERPRETER_SUCCESS, - error_message: String::new(), - data, - next_peer_pks, - call_requests, - } + let outcome = populate_outcome_from_contexts(exec_ctx, trace_handler, ret_code, error_message); + Ok(outcome) } /// Create InterpreterOutcome from supplied data and error, /// set ret_code based on the error. -pub(crate) fn from_preparation_error(data: impl Into>, err: PreparationError) -> InterpreterOutcome { - let ret_code = err.to_error_code() as i32; +pub(crate) fn from_uncatchable_error( + data: impl Into>, + error: impl ToErrorCode + ToString, +) -> InterpreterOutcome { + let ret_code = error.to_error_code(); let data = data.into(); let call_requests = serde_json::to_vec(&CallRequests::new()).expect("default serializer shouldn't fail"); InterpreterOutcome { ret_code, - error_message: format!("{}", err), - data, - next_peer_pks: vec![], - call_requests, - } -} - -/// Create InterpreterOutcome from supplied data and error, -/// set ret_code based on the error. -pub(crate) fn from_trace_error(data: impl Into>, err: Rc) -> InterpreterOutcome { - let ret_code = err.to_error_code() as i32; - let data = data.into(); - let call_requests = serde_json::to_vec(&CallRequests::new()).expect("default serializer shouldn't fail"); - - InterpreterOutcome { - ret_code, - error_message: format!("{}", err), + error_message: error.to_string(), data, next_peer_pks: vec![], call_requests, @@ -87,10 +68,17 @@ pub(crate) fn from_trace_error(data: impl Into>, err: Rc pub(crate) fn from_execution_error( exec_ctx: ExecutionCtx<'_>, trace_handler: TraceHandler, - err: Rc, + error: impl ToErrorCode + ToString, ) -> InterpreterOutcome { - let ret_code = err.to_error_code() as i32; + populate_outcome_from_contexts(exec_ctx, trace_handler, error.to_error_code(), error.to_string()) +} +fn populate_outcome_from_contexts( + exec_ctx: ExecutionCtx<'_>, + trace_handler: TraceHandler, + ret_code: i64, + error_message: String, +) -> InterpreterOutcome { let (global_streams, restricted_streams) = exec_ctx.streams.into_streams_data(); let data = InterpreterData::from_execution_result( trace_handler.into_result_trace(), @@ -104,7 +92,7 @@ pub(crate) fn from_execution_error( InterpreterOutcome { ret_code, - error_message: format!("{}", err), + error_message, data, next_peer_pks, call_requests, diff --git a/air/src/lib.rs b/air/src/lib.rs index ca0d179e..5a56499d 100644 --- a/air/src/lib.rs +++ b/air/src/lib.rs @@ -27,8 +27,10 @@ )] mod execution_step; +mod farewell_step; mod preparation_step; mod runner; +mod utils; pub use air_interpreter_interface::InterpreterOutcome; pub use air_interpreter_interface::RunParameters; @@ -53,4 +55,6 @@ pub mod parser { } pub(crate) type JValue = serde_json::Value; +pub(crate) use utils::ToErrorCode; + use air_lambda_parser::LambdaAST; diff --git a/air/src/preparation_step/errors.rs b/air/src/preparation_step/errors.rs index becc9eb9..36e13ccd 100644 --- a/air/src/preparation_step/errors.rs +++ b/air/src/preparation_step/errors.rs @@ -14,6 +14,7 @@ * limitations under the License. */ +use crate::ToErrorCode; use air_interpreter_data::DATA_FORMAT_VERSION; use serde_json::Error as SerdeJsonError; @@ -22,7 +23,7 @@ use strum_macros::EnumDiscriminants; use strum_macros::EnumIter; use thiserror::Error as ThisError; -/// Errors happened during the interpreter preparation_step step. +/// Errors happened during the interpreter preparation step. #[derive(Debug, EnumDiscriminants, ThisError)] #[strum_discriminants(derive(EnumIter))] pub enum PreparationError { @@ -40,15 +41,15 @@ pub enum PreparationError { CallResultsDeFailed(SerdeJsonError, Vec), } -impl PreparationError { - pub(crate) fn to_error_code(&self) -> u32 { - const PREPARATION_ERRORS_START_ID: u32 = 1; +impl ToErrorCode for PreparationError { + fn to_error_code(&self) -> i64 { + const PREPARATION_ERRORS_START_ID: i64 = 1; let mut errors = PreparationErrorDiscriminants::iter(); let actual_error_type = PreparationErrorDiscriminants::from(self); // unwrap is safe here because errors are guaranteed to contain all errors variants - let enum_variant_position = errors.position(|et| et == actual_error_type).unwrap() as u32; + let enum_variant_position = errors.position(|et| et == actual_error_type).unwrap() as i64; PREPARATION_ERRORS_START_ID + enum_variant_position } } diff --git a/air/src/runner.rs b/air/src/runner.rs index 3daec9eb..b97749e3 100644 --- a/air/src/runner.rs +++ b/air/src/runner.rs @@ -14,13 +14,9 @@ * limitations under the License. */ -mod outcome; - use crate::execution_step::Catchable; use crate::execution_step::ExecutableInstruction; -use crate::execution_step::ExecutionCtx; -use crate::execution_step::ExecutionError; -use crate::execution_step::TraceHandler; +use crate::farewell_step as farewell; use crate::preparation_step::prepare; use crate::preparation_step::PreparationDescriptor; @@ -28,8 +24,6 @@ use air_interpreter_interface::InterpreterOutcome; use air_interpreter_interface::RunParameters; use air_log_targets::RUN_PARAMS; -use std::rc::Rc; - pub fn execute_air( air: String, prev_data: Vec, @@ -66,30 +60,16 @@ fn execute_air_impl( } = match prepare(&prev_data, &data, air.as_str(), &call_results, params) { Ok(desc) => desc, // return the initial data in case of errors - Err(error) => return Err(outcome::from_preparation_error(prev_data, error)), + Err(error) => return Err(farewell::from_uncatchable_error(prev_data, error)), }; // match here is used instead of map_err, because the compiler can't determine that // they are exclusive and would treat exec_ctx and trace_handler as moved match air.execute(&mut exec_ctx, &mut trace_handler) { - Ok(_) => try_make_outcome(exec_ctx, trace_handler), - // return the old data in case of any trace errors - Err(e) if !e.is_catchable() => Err(outcome::from_trace_error(prev_data, e)), + Ok(_) => farewell::from_success_result(exec_ctx, trace_handler), // return new collected trace in case of errors - Err(e) => Err(outcome::from_execution_error(exec_ctx, trace_handler, e)), + Err(error) if error.is_catchable() => Err(farewell::from_execution_error(exec_ctx, trace_handler, error)), + // return the old data in case of any trace errors + Err(error) => Err(farewell::from_uncatchable_error(prev_data, error)), } } - -fn try_make_outcome( - exec_ctx: ExecutionCtx<'_>, - trace_handler: TraceHandler, -) -> Result { - if exec_ctx.call_results.is_empty() { - let outcome = outcome::from_success_result(exec_ctx, trace_handler); - return Ok(outcome); - } - - let exec_error = Rc::new(ExecutionError::CallResultsNotEmpty(exec_ctx.call_results.clone())); - let outcome = outcome::from_execution_error(exec_ctx, trace_handler, exec_error); - Err(outcome) -} diff --git a/air/src/utils/mod.rs b/air/src/utils/mod.rs new file mode 100644 index 00000000..af80c745 --- /dev/null +++ b/air/src/utils/mod.rs @@ -0,0 +1,19 @@ +/* + * Copyright 2021 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +mod to_error_code; + +pub(crate) use to_error_code::ToErrorCode; diff --git a/air/src/utils/to_error_code.rs b/air/src/utils/to_error_code.rs new file mode 100644 index 00000000..3f02c146 --- /dev/null +++ b/air/src/utils/to_error_code.rs @@ -0,0 +1,37 @@ +/* + * Copyright 2021 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +pub(crate) trait ToErrorCode { + fn to_error_code(&self) -> i64; +} + +/* +use concat_idents::concat_idents; + +#[macro_export] +macro_rules! generate_to_error_code { + ($error_type:ident, $start_id: ident) => { + const PREPARATION_ERRORS_START_ID: u32 = $start_id; + + let mut errors = PreparationErrorDiscriminants::iter(); + let actual_error_type = PreparationErrorDiscriminants::from(self); + + // unwrap is safe here because errors are guaranteed to contain all errors variants + let enum_variant_position = errors.position(|et| et == actual_error_type).unwrap() as i64; + PREPARATION_ERRORS_START_ID + enum_variant_position + } +} + */ diff --git a/avm/server/Cargo.toml b/avm/server/Cargo.toml index 6a5aadbf..33033309 100644 --- a/avm/server/Cargo.toml +++ b/avm/server/Cargo.toml @@ -16,7 +16,7 @@ name = "avm_server" path = "src/lib.rs" [dependencies] -air-interpreter-interface = { version = "0.7.0", path = "../../crates/air-lib/interpreter-interface" } +air-interpreter-interface = { version = "0.8.0", path = "../../crates/air-lib/interpreter-interface" } avm-data-store = { version = "0.1.0", path = "../../crates/data-store" } fluence-faas = "0.10.0" polyplets = { version = "0.2.0", path = "../../crates/air-lib/polyplets" } diff --git a/avm/server/src/interface/outcome.rs b/avm/server/src/interface/outcome.rs index 8b608164..981f80fa 100644 --- a/avm/server/src/interface/outcome.rs +++ b/avm/server/src/interface/outcome.rs @@ -37,7 +37,7 @@ pub struct AVMOutcome { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct ErrorAVMOutcome { - pub error_code: i32, + pub error_code: i64, pub error_message: String, pub outcome: AVMOutcome, } @@ -78,7 +78,7 @@ impl AVMOutcome { } impl ErrorAVMOutcome { - pub(self) fn new(error_code: i32, error_msg: String, outcome: AVMOutcome) -> Self { + pub(self) fn new(error_code: i64, error_msg: String, outcome: AVMOutcome) -> Self { Self { error_code, error_message: error_msg, diff --git a/avm/server/src/interface/raw_outcome.rs b/avm/server/src/interface/raw_outcome.rs index bdafdb65..23ad625d 100644 --- a/avm/server/src/interface/raw_outcome.rs +++ b/avm/server/src/interface/raw_outcome.rs @@ -25,7 +25,7 @@ use serde::Serialize; /// This struct is very similar to AVMOutcome, but keeps error_code and error_msg for test purposes. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct RawAVMOutcome { - pub ret_code: i32, + pub ret_code: i64, pub error_message: String, pub data: Vec, pub call_requests: CallRequests, diff --git a/crates/air-lib/interpreter-interface/Cargo.toml b/crates/air-lib/interpreter-interface/Cargo.toml index fe3245c4..6bb4200e 100644 --- a/crates/air-lib/interpreter-interface/Cargo.toml +++ b/crates/air-lib/interpreter-interface/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "air-interpreter-interface" description = "Interface of the AIR interpreter" -version = "0.7.0" +version = "0.8.0" authors = ["Fluence Labs"] edition = "2018" license = "Apache-2.0" diff --git a/crates/air-lib/interpreter-interface/src/interpreter_outcome.rs b/crates/air-lib/interpreter-interface/src/interpreter_outcome.rs index 727a4b14..51d54b61 100644 --- a/crates/air-lib/interpreter-interface/src/interpreter_outcome.rs +++ b/crates/air-lib/interpreter-interface/src/interpreter_outcome.rs @@ -20,14 +20,14 @@ use fluence_it_types::IValue; use serde::Deserialize; use serde::Serialize; -pub const INTERPRETER_SUCCESS: i32 = 0; +pub const INTERPRETER_SUCCESS: i64 = 0; /// Describes a result returned at the end of the interpreter execution_step. #[marine] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct InterpreterOutcome { /// A return code, where INTERPRETER_SUCCESS means success. - pub ret_code: i32, + pub ret_code: i64, /// Contains error message if ret_code != INTERPRETER_SUCCESS. pub error_message: String, @@ -59,7 +59,7 @@ impl InterpreterOutcome { let next_peer_pks = try_as_string_vec(record_values.pop().unwrap(), "next_peer_pks")?; let data = try_as_byte_vec(record_values.pop().unwrap(), "data")?; let error_message = try_as_string(record_values.pop().unwrap(), "error_message")?; - let ret_code = try_as_i32(record_values.pop().unwrap(), "ret_code")?; + let ret_code = try_as_i64(record_values.pop().unwrap(), "ret_code")?; let outcome = Self { ret_code, @@ -87,10 +87,10 @@ fn try_as_record(ivalue: IValue) -> Result, String> { } } -fn try_as_i32(ivalue: IValue, field_name: &str) -> Result { +fn try_as_i64(ivalue: IValue, field_name: &str) -> Result { match ivalue { - IValue::S32(value) => Ok(value), - v => return Err(format!("expected an i32 for {}, got {:?}", field_name, v)), + IValue::S64(value) => Ok(value), + v => return Err(format!("expected an i64 for {}, got {:?}", field_name, v)), } }