mirror of
https://github.com/fluencelabs/aquavm
synced 2024-12-04 15:20:16 +00:00
introduce farewell step; reafactoring
This commit is contained in:
parent
8dbae91bda
commit
54e383cdaf
13
Cargo.lock
generated
13
Cargo.lock
generated
@ -25,6 +25,7 @@ dependencies = [
|
|||||||
"air-test-utils",
|
"air-test-utils",
|
||||||
"air-trace-handler",
|
"air-trace-handler",
|
||||||
"boolinator",
|
"boolinator",
|
||||||
|
"concat-idents",
|
||||||
"criterion",
|
"criterion",
|
||||||
"csv",
|
"csv",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
@ -73,7 +74,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "air-interpreter-interface"
|
name = "air-interpreter-interface"
|
||||||
version = "0.7.0"
|
version = "0.8.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fluence-it-types",
|
"fluence-it-types",
|
||||||
"marine-rs-sdk",
|
"marine-rs-sdk",
|
||||||
@ -408,6 +409,16 @@ dependencies = [
|
|||||||
"unicode-width",
|
"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]]
|
[[package]]
|
||||||
name = "constant_time_eq"
|
name = "constant_time_eq"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
|
@ -30,6 +30,7 @@ serde = { version = "1.0.118", features = [ "derive", "rc" ] }
|
|||||||
serde_json = "1.0.61"
|
serde_json = "1.0.61"
|
||||||
|
|
||||||
boolinator = "2.4.0"
|
boolinator = "2.4.0"
|
||||||
|
concat-idents = "1.1.3"
|
||||||
maplit = "1.0.2"
|
maplit = "1.0.2"
|
||||||
log = "0.4.11"
|
log = "0.4.11"
|
||||||
thiserror = "1.0.23"
|
thiserror = "1.0.23"
|
||||||
|
@ -22,7 +22,7 @@ use super::ExecutionResult;
|
|||||||
use super::TraceHandler;
|
use super::TraceHandler;
|
||||||
use crate::execution_step::air::ValueAggregate;
|
use crate::execution_step::air::ValueAggregate;
|
||||||
use crate::execution_step::boxed_value::Variable;
|
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::trace_to_exec_err;
|
||||||
use crate::JValue;
|
use crate::JValue;
|
||||||
use crate::SecurityTetraplet;
|
use crate::SecurityTetraplet;
|
||||||
|
@ -52,7 +52,7 @@ fn apply_last_error(
|
|||||||
exec_ctx: &ExecutionCtx<'_>,
|
exec_ctx: &ExecutionCtx<'_>,
|
||||||
trace_ctx: &TraceHandler,
|
trace_ctx: &TraceHandler,
|
||||||
) -> ExecutionResult<ValueAggregate> {
|
) -> ExecutionResult<ValueAggregate> {
|
||||||
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);
|
let value = Rc::new(value);
|
||||||
// removing is safe because prepare_last_error always returns a vec with one element.
|
// removing is safe because prepare_last_error always returns a vec with one element.
|
||||||
let tetraplet = tetraplets.remove(0);
|
let tetraplet = tetraplets.remove(0);
|
||||||
|
@ -149,7 +149,7 @@ impl<'i> ResolvedCall<'i> {
|
|||||||
|
|
||||||
/// Prepare arguments of this call instruction by resolving and preparing their security tetraplets.
|
/// Prepare arguments of this call instruction by resolving and preparing their security tetraplets.
|
||||||
fn resolve_args(&self, exec_ctx: &ExecutionCtx<'i>) -> ExecutionResult<ResolvedArguments> {
|
fn resolve_args(&self, exec_ctx: &ExecutionCtx<'i>) -> ExecutionResult<ResolvedArguments> {
|
||||||
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 function_args = self.function_arg_paths.iter();
|
||||||
let mut call_arguments = Vec::new();
|
let mut call_arguments = Vec::new();
|
||||||
|
@ -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.
|
/// Resolve value to string by either resolving variable from `ExecutionCtx`, taking literal value, or etc.
|
||||||
// TODO: return Rc<String> to avoid excess cloning
|
// TODO: return Rc<String> to avoid excess cloning
|
||||||
fn resolve_to_string<'i>(value: &ast::CallInstrValue<'i>, ctx: &ExecutionCtx<'i>) -> ExecutionResult<String> {
|
fn resolve_to_string<'i>(value: &ast::CallInstrValue<'i>, ctx: &ExecutionCtx<'i>) -> ExecutionResult<String> {
|
||||||
use crate::execution_step::utils::resolve_ast_variable_wl;
|
use crate::execution_step::resolver::resolve_ast_variable_wl;
|
||||||
use ast::CallInstrValue::*;
|
use ast::CallInstrValue::*;
|
||||||
|
|
||||||
let resolved = match value {
|
let resolved = match value {
|
||||||
|
@ -16,8 +16,8 @@
|
|||||||
|
|
||||||
use crate::execution_step::air::ExecutionResult;
|
use crate::execution_step::air::ExecutionResult;
|
||||||
use crate::execution_step::execution_context::ExecutionCtx;
|
use crate::execution_step::execution_context::ExecutionCtx;
|
||||||
use crate::execution_step::utils::prepare_last_error;
|
use crate::execution_step::resolver::prepare_last_error;
|
||||||
use crate::execution_step::utils::resolve_ast_variable_wl;
|
use crate::execution_step::resolver::resolve_ast_variable_wl;
|
||||||
use crate::JValue;
|
use crate::JValue;
|
||||||
|
|
||||||
use air_parser::ast;
|
use air_parser::ast;
|
||||||
|
@ -14,10 +14,11 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use super::ExecutionError;
|
use super::ExecutionError::LambdaApplierError;
|
||||||
use super::ExecutionResult;
|
use super::ExecutionResult;
|
||||||
use super::JValuable;
|
use super::JValuable;
|
||||||
use super::LambdaAST;
|
use super::LambdaAST;
|
||||||
|
use super::LambdaError::EmptyStream;
|
||||||
use crate::exec_err;
|
use crate::exec_err;
|
||||||
use crate::execution_step::ExecutionCtx;
|
use crate::execution_step::ExecutionCtx;
|
||||||
use crate::execution_step::RSecurityTetraplet;
|
use crate::execution_step::RSecurityTetraplet;
|
||||||
@ -29,7 +30,7 @@ use std::borrow::Cow;
|
|||||||
impl JValuable for () {
|
impl JValuable for () {
|
||||||
fn apply_lambda<'i>(&self, _lambda: &LambdaAST<'_>, _exec_ctx: &ExecutionCtx<'i>) -> ExecutionResult<&JValue> {
|
fn apply_lambda<'i>(&self, _lambda: &LambdaAST<'_>, _exec_ctx: &ExecutionCtx<'i>) -> ExecutionResult<&JValue> {
|
||||||
// applying lambda to an empty stream will produce a join behaviour
|
// 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>(
|
fn apply_lambda_with_tetraplets<'i>(
|
||||||
@ -38,7 +39,7 @@ impl JValuable for () {
|
|||||||
_exec_ctx: &ExecutionCtx<'i>,
|
_exec_ctx: &ExecutionCtx<'i>,
|
||||||
) -> ExecutionResult<(&JValue, RSecurityTetraplet)> {
|
) -> ExecutionResult<(&JValue, RSecurityTetraplet)> {
|
||||||
// applying lambda to an empty stream will produce a join behaviour
|
// 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> {
|
fn as_jvalue(&self) -> Cow<'_, JValue> {
|
||||||
|
@ -23,8 +23,8 @@ pub(crate) use joinable::Joinable;
|
|||||||
use super::Stream;
|
use super::Stream;
|
||||||
use crate::execution_step::lambda_applier::LambdaError;
|
use crate::execution_step::lambda_applier::LambdaError;
|
||||||
use crate::JValue;
|
use crate::JValue;
|
||||||
|
use crate::ToErrorCode;
|
||||||
|
|
||||||
use air_interpreter_interface::CallResults;
|
|
||||||
use air_trace_handler::MergerApResult;
|
use air_trace_handler::MergerApResult;
|
||||||
use air_trace_handler::TraceHandlerError;
|
use air_trace_handler::TraceHandlerError;
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
@ -54,10 +54,6 @@ pub(crate) enum ExecutionError {
|
|||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
LambdaApplierError(#[from] LambdaError),
|
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.
|
/// Provided JValue has incompatible type with a requested one.
|
||||||
#[error(
|
#[error(
|
||||||
"expected JValue type '{expected_value_type}' for the variable `{variable_name}`, but got '{actual_value}'"
|
"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.
|
/// 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")]
|
#[error("ap result {0:?} doesn't match corresponding instruction")]
|
||||||
ApResultNotCorrespondToInstr(MergerApResult),
|
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<LambdaError> for Rc<ExecutionError> {
|
impl From<LambdaError> for Rc<ExecutionError> {
|
||||||
@ -131,15 +121,31 @@ macro_rules! trace_to_exec_err {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExecutionError {
|
/*
|
||||||
pub(crate) fn to_error_code(&self) -> u32 {
|
impl ToErrorCode for ExecutionError {
|
||||||
const EXECUTION_ERRORS_START_ID: u32 = 1000;
|
fn to_error_code(&self) -> i64 {
|
||||||
|
const EXECUTION_ERRORS_START_ID: i64 = 1000;
|
||||||
|
|
||||||
let mut errors = ExecutionErrorDiscriminants::iter();
|
let mut errors = ExecutionErrorDiscriminants::iter();
|
||||||
let actual_error_type = ExecutionErrorDiscriminants::from(self);
|
let actual_error_type = ExecutionErrorDiscriminants::from(self);
|
||||||
|
|
||||||
// unwrap is safe here because errors are guaranteed to contain all errors variants
|
// 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<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.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
|
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);
|
log_join!(" waiting for an argument with idx '{}' on stream with size '{}'", idx, stream_size);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
EmptyStreamLambdaError => {
|
LambdaApplierError(LambdaError::EmptyStream) => {
|
||||||
log_join!(" waiting on empty stream for path ");
|
log_join!(" waiting on empty stream for path ");
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,10 @@ pub(crate) enum LambdaError {
|
|||||||
#[error("lambda is applied to a stream that have only '{stream_size}' elements, but '{idx}' requested")]
|
#[error("lambda is applied to a stream that have only '{stream_size}' elements, but '{idx}' requested")]
|
||||||
StreamNotHaveEnoughValues { stream_size: usize, idx: u32 },
|
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")]
|
#[error("field accessor (with field name = '{field_name}') can't be applied to a stream")]
|
||||||
FieldAccessorAppliedToStream { field_name: String },
|
FieldAccessorAppliedToStream { field_name: String },
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ mod boxed_value;
|
|||||||
mod errors;
|
mod errors;
|
||||||
pub(crate) mod execution_context;
|
pub(crate) mod execution_context;
|
||||||
mod lambda_applier;
|
mod lambda_applier;
|
||||||
mod utils;
|
mod resolver;
|
||||||
|
|
||||||
pub(super) use self::air::ExecutableInstruction;
|
pub(super) use self::air::ExecutableInstruction;
|
||||||
pub(super) use self::air::FoldState;
|
pub(super) use self::air::FoldState;
|
||||||
|
47
air/src/farewell_step/errors.rs
Normal file
47
air/src/farewell_step/errors.rs
Normal file
@ -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
|
||||||
|
}
|
||||||
|
}
|
23
air/src/farewell_step/mod.rs
Normal file
23
air/src/farewell_step/mod.rs
Normal file
@ -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;
|
@ -14,11 +14,11 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use super::FarewellError;
|
||||||
use crate::execution_step::ExecutionCtx;
|
use crate::execution_step::ExecutionCtx;
|
||||||
use crate::execution_step::ExecutionError;
|
|
||||||
use crate::execution_step::TraceHandler;
|
use crate::execution_step::TraceHandler;
|
||||||
use crate::preparation_step::PreparationError;
|
|
||||||
use crate::InterpreterOutcome;
|
use crate::InterpreterOutcome;
|
||||||
|
use crate::ToErrorCode;
|
||||||
use crate::INTERPRETER_SUCCESS;
|
use crate::INTERPRETER_SUCCESS;
|
||||||
|
|
||||||
use air_interpreter_data::InterpreterData;
|
use air_interpreter_data::InterpreterData;
|
||||||
@ -29,53 +29,34 @@ use std::rc::Rc;
|
|||||||
|
|
||||||
/// Create InterpreterOutcome from supplied execution context and trace handler,
|
/// Create InterpreterOutcome from supplied execution context and trace handler,
|
||||||
/// set ret_code to INTERPRETER_SUCCESS.
|
/// set ret_code to INTERPRETER_SUCCESS.
|
||||||
pub(crate) fn from_success_result(exec_ctx: ExecutionCtx<'_>, trace_handler: TraceHandler) -> InterpreterOutcome {
|
pub(crate) fn from_success_result(
|
||||||
let (global_streams, restricted_streams) = exec_ctx.streams.into_streams_data();
|
exec_ctx: ExecutionCtx<'_>,
|
||||||
let data = InterpreterData::from_execution_result(
|
trace_handler: TraceHandler,
|
||||||
trace_handler.into_result_trace(),
|
) -> Result<InterpreterOutcome, InterpreterOutcome> {
|
||||||
global_streams,
|
let (ret_code, error_message) = if exec_ctx.call_results.is_empty() {
|
||||||
restricted_streams,
|
(INTERPRETER_SUCCESS, String::new())
|
||||||
exec_ctx.last_call_request_id,
|
} else {
|
||||||
);
|
let farewell_error = Rc::new(FarewellError::CallResultsNotEmpty(exec_ctx.call_results.clone()));
|
||||||
let data = serde_json::to_vec(&data).expect("default serializer shouldn't fail");
|
(farewell_error.to_error_code(), farewell_error.to_string())
|
||||||
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");
|
|
||||||
|
|
||||||
InterpreterOutcome {
|
let outcome = populate_outcome_from_contexts(exec_ctx, trace_handler, ret_code, error_message);
|
||||||
ret_code: INTERPRETER_SUCCESS,
|
Ok(outcome)
|
||||||
error_message: String::new(),
|
|
||||||
data,
|
|
||||||
next_peer_pks,
|
|
||||||
call_requests,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create InterpreterOutcome from supplied data and error,
|
/// Create InterpreterOutcome from supplied data and error,
|
||||||
/// set ret_code based on the error.
|
/// set ret_code based on the error.
|
||||||
pub(crate) fn from_preparation_error(data: impl Into<Vec<u8>>, err: PreparationError) -> InterpreterOutcome {
|
pub(crate) fn from_uncatchable_error(
|
||||||
let ret_code = err.to_error_code() as i32;
|
data: impl Into<Vec<u8>>,
|
||||||
|
error: impl ToErrorCode + ToString,
|
||||||
|
) -> InterpreterOutcome {
|
||||||
|
let ret_code = error.to_error_code();
|
||||||
let data = data.into();
|
let data = data.into();
|
||||||
let call_requests = serde_json::to_vec(&CallRequests::new()).expect("default serializer shouldn't fail");
|
let call_requests = serde_json::to_vec(&CallRequests::new()).expect("default serializer shouldn't fail");
|
||||||
|
|
||||||
InterpreterOutcome {
|
InterpreterOutcome {
|
||||||
ret_code,
|
ret_code,
|
||||||
error_message: format!("{}", err),
|
error_message: error.to_string(),
|
||||||
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<Vec<u8>>, err: Rc<ExecutionError>) -> 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),
|
|
||||||
data,
|
data,
|
||||||
next_peer_pks: vec![],
|
next_peer_pks: vec![],
|
||||||
call_requests,
|
call_requests,
|
||||||
@ -87,10 +68,17 @@ pub(crate) fn from_trace_error(data: impl Into<Vec<u8>>, err: Rc<ExecutionError>
|
|||||||
pub(crate) fn from_execution_error(
|
pub(crate) fn from_execution_error(
|
||||||
exec_ctx: ExecutionCtx<'_>,
|
exec_ctx: ExecutionCtx<'_>,
|
||||||
trace_handler: TraceHandler,
|
trace_handler: TraceHandler,
|
||||||
err: Rc<ExecutionError>,
|
error: impl ToErrorCode + ToString,
|
||||||
) -> InterpreterOutcome {
|
) -> 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 (global_streams, restricted_streams) = exec_ctx.streams.into_streams_data();
|
||||||
let data = InterpreterData::from_execution_result(
|
let data = InterpreterData::from_execution_result(
|
||||||
trace_handler.into_result_trace(),
|
trace_handler.into_result_trace(),
|
||||||
@ -104,7 +92,7 @@ pub(crate) fn from_execution_error(
|
|||||||
|
|
||||||
InterpreterOutcome {
|
InterpreterOutcome {
|
||||||
ret_code,
|
ret_code,
|
||||||
error_message: format!("{}", err),
|
error_message,
|
||||||
data,
|
data,
|
||||||
next_peer_pks,
|
next_peer_pks,
|
||||||
call_requests,
|
call_requests,
|
@ -27,8 +27,10 @@
|
|||||||
)]
|
)]
|
||||||
|
|
||||||
mod execution_step;
|
mod execution_step;
|
||||||
|
mod farewell_step;
|
||||||
mod preparation_step;
|
mod preparation_step;
|
||||||
mod runner;
|
mod runner;
|
||||||
|
mod utils;
|
||||||
|
|
||||||
pub use air_interpreter_interface::InterpreterOutcome;
|
pub use air_interpreter_interface::InterpreterOutcome;
|
||||||
pub use air_interpreter_interface::RunParameters;
|
pub use air_interpreter_interface::RunParameters;
|
||||||
@ -53,4 +55,6 @@ pub mod parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) type JValue = serde_json::Value;
|
pub(crate) type JValue = serde_json::Value;
|
||||||
|
pub(crate) use utils::ToErrorCode;
|
||||||
|
|
||||||
use air_lambda_parser::LambdaAST;
|
use air_lambda_parser::LambdaAST;
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use crate::ToErrorCode;
|
||||||
use air_interpreter_data::DATA_FORMAT_VERSION;
|
use air_interpreter_data::DATA_FORMAT_VERSION;
|
||||||
|
|
||||||
use serde_json::Error as SerdeJsonError;
|
use serde_json::Error as SerdeJsonError;
|
||||||
@ -22,7 +23,7 @@ use strum_macros::EnumDiscriminants;
|
|||||||
use strum_macros::EnumIter;
|
use strum_macros::EnumIter;
|
||||||
use thiserror::Error as ThisError;
|
use thiserror::Error as ThisError;
|
||||||
|
|
||||||
/// Errors happened during the interpreter preparation_step step.
|
/// Errors happened during the interpreter preparation step.
|
||||||
#[derive(Debug, EnumDiscriminants, ThisError)]
|
#[derive(Debug, EnumDiscriminants, ThisError)]
|
||||||
#[strum_discriminants(derive(EnumIter))]
|
#[strum_discriminants(derive(EnumIter))]
|
||||||
pub enum PreparationError {
|
pub enum PreparationError {
|
||||||
@ -40,15 +41,15 @@ pub enum PreparationError {
|
|||||||
CallResultsDeFailed(SerdeJsonError, Vec<u8>),
|
CallResultsDeFailed(SerdeJsonError, Vec<u8>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PreparationError {
|
impl ToErrorCode for PreparationError {
|
||||||
pub(crate) fn to_error_code(&self) -> u32 {
|
fn to_error_code(&self) -> i64 {
|
||||||
const PREPARATION_ERRORS_START_ID: u32 = 1;
|
const PREPARATION_ERRORS_START_ID: i64 = 1;
|
||||||
|
|
||||||
let mut errors = PreparationErrorDiscriminants::iter();
|
let mut errors = PreparationErrorDiscriminants::iter();
|
||||||
let actual_error_type = PreparationErrorDiscriminants::from(self);
|
let actual_error_type = PreparationErrorDiscriminants::from(self);
|
||||||
|
|
||||||
// unwrap is safe here because errors are guaranteed to contain all errors variants
|
// 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
|
PREPARATION_ERRORS_START_ID + enum_variant_position
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,13 +14,9 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
mod outcome;
|
|
||||||
|
|
||||||
use crate::execution_step::Catchable;
|
use crate::execution_step::Catchable;
|
||||||
use crate::execution_step::ExecutableInstruction;
|
use crate::execution_step::ExecutableInstruction;
|
||||||
use crate::execution_step::ExecutionCtx;
|
use crate::farewell_step as farewell;
|
||||||
use crate::execution_step::ExecutionError;
|
|
||||||
use crate::execution_step::TraceHandler;
|
|
||||||
use crate::preparation_step::prepare;
|
use crate::preparation_step::prepare;
|
||||||
use crate::preparation_step::PreparationDescriptor;
|
use crate::preparation_step::PreparationDescriptor;
|
||||||
|
|
||||||
@ -28,8 +24,6 @@ use air_interpreter_interface::InterpreterOutcome;
|
|||||||
use air_interpreter_interface::RunParameters;
|
use air_interpreter_interface::RunParameters;
|
||||||
use air_log_targets::RUN_PARAMS;
|
use air_log_targets::RUN_PARAMS;
|
||||||
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
pub fn execute_air(
|
pub fn execute_air(
|
||||||
air: String,
|
air: String,
|
||||||
prev_data: Vec<u8>,
|
prev_data: Vec<u8>,
|
||||||
@ -66,30 +60,16 @@ fn execute_air_impl(
|
|||||||
} = match prepare(&prev_data, &data, air.as_str(), &call_results, params) {
|
} = match prepare(&prev_data, &data, air.as_str(), &call_results, params) {
|
||||||
Ok(desc) => desc,
|
Ok(desc) => desc,
|
||||||
// return the initial data in case of errors
|
// 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
|
// 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
|
// they are exclusive and would treat exec_ctx and trace_handler as moved
|
||||||
match air.execute(&mut exec_ctx, &mut trace_handler) {
|
match air.execute(&mut exec_ctx, &mut trace_handler) {
|
||||||
Ok(_) => try_make_outcome(exec_ctx, trace_handler),
|
Ok(_) => farewell::from_success_result(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)),
|
|
||||||
// return new collected trace in case of errors
|
// 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<InterpreterOutcome, InterpreterOutcome> {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
19
air/src/utils/mod.rs
Normal file
19
air/src/utils/mod.rs
Normal file
@ -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;
|
37
air/src/utils/to_error_code.rs
Normal file
37
air/src/utils/to_error_code.rs
Normal file
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
@ -16,7 +16,7 @@ name = "avm_server"
|
|||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
|
|
||||||
[dependencies]
|
[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" }
|
avm-data-store = { version = "0.1.0", path = "../../crates/data-store" }
|
||||||
fluence-faas = "0.10.0"
|
fluence-faas = "0.10.0"
|
||||||
polyplets = { version = "0.2.0", path = "../../crates/air-lib/polyplets" }
|
polyplets = { version = "0.2.0", path = "../../crates/air-lib/polyplets" }
|
||||||
|
@ -37,7 +37,7 @@ pub struct AVMOutcome {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct ErrorAVMOutcome {
|
pub struct ErrorAVMOutcome {
|
||||||
pub error_code: i32,
|
pub error_code: i64,
|
||||||
pub error_message: String,
|
pub error_message: String,
|
||||||
pub outcome: AVMOutcome,
|
pub outcome: AVMOutcome,
|
||||||
}
|
}
|
||||||
@ -78,7 +78,7 @@ impl AVMOutcome {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ErrorAVMOutcome {
|
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 {
|
Self {
|
||||||
error_code,
|
error_code,
|
||||||
error_message: error_msg,
|
error_message: error_msg,
|
||||||
|
@ -25,7 +25,7 @@ use serde::Serialize;
|
|||||||
/// This struct is very similar to AVMOutcome, but keeps error_code and error_msg for test purposes.
|
/// This struct is very similar to AVMOutcome, but keeps error_code and error_msg for test purposes.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct RawAVMOutcome {
|
pub struct RawAVMOutcome {
|
||||||
pub ret_code: i32,
|
pub ret_code: i64,
|
||||||
pub error_message: String,
|
pub error_message: String,
|
||||||
pub data: Vec<u8>,
|
pub data: Vec<u8>,
|
||||||
pub call_requests: CallRequests,
|
pub call_requests: CallRequests,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "air-interpreter-interface"
|
name = "air-interpreter-interface"
|
||||||
description = "Interface of the AIR interpreter"
|
description = "Interface of the AIR interpreter"
|
||||||
version = "0.7.0"
|
version = "0.8.0"
|
||||||
authors = ["Fluence Labs"]
|
authors = ["Fluence Labs"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
|
@ -20,14 +20,14 @@ use fluence_it_types::IValue;
|
|||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde::Serialize;
|
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.
|
/// Describes a result returned at the end of the interpreter execution_step.
|
||||||
#[marine]
|
#[marine]
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct InterpreterOutcome {
|
pub struct InterpreterOutcome {
|
||||||
/// A return code, where INTERPRETER_SUCCESS means success.
|
/// A return code, where INTERPRETER_SUCCESS means success.
|
||||||
pub ret_code: i32,
|
pub ret_code: i64,
|
||||||
|
|
||||||
/// Contains error message if ret_code != INTERPRETER_SUCCESS.
|
/// Contains error message if ret_code != INTERPRETER_SUCCESS.
|
||||||
pub error_message: String,
|
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 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 data = try_as_byte_vec(record_values.pop().unwrap(), "data")?;
|
||||||
let error_message = try_as_string(record_values.pop().unwrap(), "error_message")?;
|
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 {
|
let outcome = Self {
|
||||||
ret_code,
|
ret_code,
|
||||||
@ -87,10 +87,10 @@ fn try_as_record(ivalue: IValue) -> Result<NEVec<IValue>, String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_as_i32(ivalue: IValue, field_name: &str) -> Result<i32, String> {
|
fn try_as_i64(ivalue: IValue, field_name: &str) -> Result<i64, String> {
|
||||||
match ivalue {
|
match ivalue {
|
||||||
IValue::S32(value) => Ok(value),
|
IValue::S64(value) => Ok(value),
|
||||||
v => return Err(format!("expected an i32 for {}, got {:?}", field_name, v)),
|
v => return Err(format!("expected an i64 for {}, got {:?}", field_name, v)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user