WIP soft limits triggering is signalled via AVMOutcome

This commit is contained in:
Roman Nozdrin
2024-02-07 17:19:24 +00:00
parent 81019e6633
commit 62ff7ebba7
15 changed files with 238 additions and 64 deletions

View File

@ -25,6 +25,7 @@ use crate::INTERPRETER_SUCCESS;
use air_interpreter_data::InterpreterDataEnvelope; use air_interpreter_data::InterpreterDataEnvelope;
use air_interpreter_interface::CallRequests; use air_interpreter_interface::CallRequests;
use air_interpreter_interface::CallRequestsRepr; use air_interpreter_interface::CallRequestsRepr;
use air_interpreter_interface::SoftLimitsTriggering;
use air_interpreter_sede::ToSerialized; use air_interpreter_sede::ToSerialized;
use air_interpreter_signatures::KeyPair; use air_interpreter_signatures::KeyPair;
use air_utils::measure; use air_utils::measure;
@ -41,6 +42,7 @@ pub(crate) fn from_success_result(
exec_ctx: ExecutionCtx<'_>, exec_ctx: ExecutionCtx<'_>,
trace_handler: TraceHandler, trace_handler: TraceHandler,
keypair: &KeyPair, keypair: &KeyPair,
soft_limits_triggering: SoftLimitsTriggering,
) -> Result<InterpreterOutcome, InterpreterOutcome> { ) -> Result<InterpreterOutcome, InterpreterOutcome> {
let (ret_code, error_message) = if exec_ctx.call_results.is_empty() { let (ret_code, error_message) = if exec_ctx.call_results.is_empty() {
(INTERPRETER_SUCCESS, String::new()) (INTERPRETER_SUCCESS, String::new())
@ -49,7 +51,14 @@ pub(crate) fn from_success_result(
(farewell_error.to_error_code(), farewell_error.to_string()) (farewell_error.to_error_code(), farewell_error.to_string())
}; };
let outcome = populate_outcome_from_contexts(exec_ctx, trace_handler, ret_code, error_message, keypair); let outcome = populate_outcome_from_contexts(
exec_ctx,
trace_handler,
ret_code,
error_message,
keypair,
soft_limits_triggering,
);
Ok(outcome) Ok(outcome)
} }
@ -59,6 +68,7 @@ pub(crate) fn from_success_result(
pub(crate) fn from_uncatchable_error( pub(crate) fn from_uncatchable_error(
data: impl Into<Vec<u8>> + Debug, data: impl Into<Vec<u8>> + Debug,
error: impl ToErrorCode + ToString + Debug, error: impl ToErrorCode + ToString + Debug,
soft_limits_triggering: SoftLimitsTriggering,
) -> InterpreterOutcome { ) -> InterpreterOutcome {
let ret_code = error.to_error_code(); let ret_code = error.to_error_code();
let data = data.into(); let data = data.into();
@ -66,7 +76,14 @@ pub(crate) fn from_uncatchable_error(
.serialize(&CallRequests::new()) .serialize(&CallRequests::new())
.expect("default serializer shouldn't fail"); .expect("default serializer shouldn't fail");
InterpreterOutcome::new(ret_code, error.to_string(), data, vec![], call_requests) InterpreterOutcome::new(
ret_code,
error.to_string(),
data,
vec![],
call_requests,
soft_limits_triggering,
)
} }
/// Create InterpreterOutcome from supplied execution context, trace handler, and error, /// Create InterpreterOutcome from supplied execution context, trace handler, and error,
@ -77,6 +94,7 @@ pub(crate) fn from_execution_error(
trace_handler: TraceHandler, trace_handler: TraceHandler,
error: impl ToErrorCode + ToString + Debug, error: impl ToErrorCode + ToString + Debug,
keypair: &KeyPair, keypair: &KeyPair,
soft_limits_triggering: SoftLimitsTriggering,
) -> InterpreterOutcome { ) -> InterpreterOutcome {
populate_outcome_from_contexts( populate_outcome_from_contexts(
exec_ctx, exec_ctx,
@ -84,6 +102,7 @@ pub(crate) fn from_execution_error(
error.to_error_code(), error.to_error_code(),
error.to_string(), error.to_string(),
keypair, keypair,
soft_limits_triggering,
) )
} }
@ -94,13 +113,14 @@ fn populate_outcome_from_contexts(
ret_code: i64, ret_code: i64,
error_message: String, error_message: String,
keypair: &KeyPair, keypair: &KeyPair,
soft_limits_triggering: SoftLimitsTriggering,
) -> InterpreterOutcome { ) -> InterpreterOutcome {
match compactify_streams(&mut exec_ctx, &mut trace_handler) { match compactify_streams(&mut exec_ctx, &mut trace_handler, soft_limits_triggering) {
Ok(()) => {} Ok(()) => {}
Err(outcome) => return outcome, Err(outcome) => return outcome,
}; };
match sign_result(&mut exec_ctx, keypair) { match sign_result(&mut exec_ctx, keypair, soft_limits_triggering) {
Ok(()) => {} Ok(()) => {}
Err(outcome) => return outcome, Err(outcome) => return outcome,
}; };
@ -126,22 +146,37 @@ fn populate_outcome_from_contexts(
tracing::Level::INFO, tracing::Level::INFO,
"CallRequestsRepr.serialize", "CallRequestsRepr.serialize",
); );
InterpreterOutcome::new(ret_code, error_message, data, next_peer_pks, call_requests) InterpreterOutcome::new(
ret_code,
error_message,
data,
next_peer_pks,
call_requests,
soft_limits_triggering,
)
} }
fn compactify_streams(exec_ctx: &mut ExecutionCtx<'_>, trace_ctx: &mut TraceHandler) -> Result<(), InterpreterOutcome> { fn compactify_streams(
exec_ctx: &mut ExecutionCtx<'_>,
trace_ctx: &mut TraceHandler,
soft_limits_triggering: SoftLimitsTriggering,
) -> Result<(), InterpreterOutcome> {
exec_ctx exec_ctx
.streams .streams
.compactify(trace_ctx) .compactify(trace_ctx)
.and_then(|_| exec_ctx.stream_maps.compactify(trace_ctx)) .and_then(|_| exec_ctx.stream_maps.compactify(trace_ctx))
.map_err(execution_error_into_outcome) .map_err(|err| execution_error_into_outcome(err, soft_limits_triggering))
} }
fn sign_result(exec_ctx: &mut ExecutionCtx<'_>, keypair: &KeyPair) -> Result<(), InterpreterOutcome> { fn sign_result(
exec_ctx: &mut ExecutionCtx<'_>,
keypair: &KeyPair,
soft_limits_triggering: SoftLimitsTriggering,
) -> Result<(), InterpreterOutcome> {
let current_signature = exec_ctx let current_signature = exec_ctx
.peer_cid_tracker .peer_cid_tracker
.gen_signature(&exec_ctx.run_parameters.salt, keypair) .gen_signature(&exec_ctx.run_parameters.salt, keypair)
.map_err(signing_error_into_outcome)?; .map_err(|err| signing_error_into_outcome(err, soft_limits_triggering))?;
let current_pubkey = keypair.public(); let current_pubkey = keypair.public();
exec_ctx.signature_store.put(current_pubkey, current_signature); exec_ctx.signature_store.put(current_pubkey, current_signature);
@ -151,12 +186,29 @@ fn sign_result(exec_ctx: &mut ExecutionCtx<'_>, keypair: &KeyPair) -> Result<(),
// these methods are called only if there is an internal error in the interpreter and // these methods are called only if there is an internal error in the interpreter and
// new execution trace was corrupted // new execution trace was corrupted
fn execution_error_into_outcome(error: ExecutionError) -> InterpreterOutcome { fn execution_error_into_outcome(
InterpreterOutcome::new(error.to_error_code(), error.to_string(), vec![], vec![], <_>::default()) error: ExecutionError,
soft_limits_triggering: SoftLimitsTriggering,
) -> InterpreterOutcome {
InterpreterOutcome::new(
error.to_error_code(),
error.to_string(),
vec![],
vec![],
<_>::default(),
soft_limits_triggering,
)
} }
fn signing_error_into_outcome(error: SigningError) -> InterpreterOutcome { fn signing_error_into_outcome(error: SigningError, soft_limits_triggering: SoftLimitsTriggering) -> InterpreterOutcome {
InterpreterOutcome::new(error.to_error_code(), error.to_string(), vec![], vec![], <_>::default()) InterpreterOutcome::new(
error.to_error_code(),
error.to_string(),
vec![],
vec![],
<_>::default(),
soft_limits_triggering,
)
} }
/// Deduplicate values in a supplied vector. /// Deduplicate values in a supplied vector.

View File

@ -128,7 +128,7 @@ impl PreparationError {
} }
pub fn air_size_limit(actual_size: usize, limit: u64) -> Self { pub fn air_size_limit(actual_size: usize, limit: u64) -> Self {
Self::SizeLimitsExceded(SizeLimitsExceded::AIR(actual_size, limit)) Self::SizeLimitsExceded(SizeLimitsExceded::Air(actual_size, limit))
} }
pub fn particle_size_limit(actual_size: usize, limit: u64) -> Self { pub fn particle_size_limit(actual_size: usize, limit: u64) -> Self {
@ -144,7 +144,7 @@ impl PreparationError {
pub enum SizeLimitsExceded { pub enum SizeLimitsExceded {
/// AIR script size is bigger than the allowed limit. /// AIR script size is bigger than the allowed limit.
#[error("air size: {0} bytes is bigger than the limit allowed: {1} bytes")] #[error("air size: {0} bytes is bigger than the limit allowed: {1} bytes")]
AIR(usize, u64), Air(usize, u64),
/// Current_data particle size is bigger than the allowed limit. /// Current_data particle size is bigger than the allowed limit.
#[error("Current_data particle size: {0} bytes is bigger than the limit allowed: {1} bytes")] #[error("Current_data particle size: {0} bytes is bigger than the limit allowed: {1} bytes")]

View File

@ -26,6 +26,7 @@ use air_interpreter_data::Versions;
use air_interpreter_interface::CallResultsRepr; use air_interpreter_interface::CallResultsRepr;
use air_interpreter_interface::RunParameters; use air_interpreter_interface::RunParameters;
use air_interpreter_interface::SerializedCallResults; use air_interpreter_interface::SerializedCallResults;
use air_interpreter_interface::SoftLimitsTriggering;
use air_interpreter_sede::FromSerialized; use air_interpreter_sede::FromSerialized;
use air_interpreter_signatures::KeyError; use air_interpreter_signatures::KeyError;
use air_interpreter_signatures::KeyPair; use air_interpreter_signatures::KeyPair;
@ -75,6 +76,7 @@ pub(crate) fn prepare<'i>(
call_results: &SerializedCallResults, call_results: &SerializedCallResults,
run_parameters: RunParameters, run_parameters: RunParameters,
signature_store: SignatureStore, signature_store: SignatureStore,
soft_limits_triggering: &mut SoftLimitsTriggering,
) -> PreparationResult<PreparationDescriptor<'static, 'i>> { ) -> PreparationResult<PreparationDescriptor<'static, 'i>> {
let air: Instruction<'i> = air_parser::parse(raw_air).map_err(PreparationError::AIRParseError)?; let air: Instruction<'i> = air_parser::parse(raw_air).map_err(PreparationError::AIRParseError)?;
@ -94,6 +96,7 @@ pub(crate) fn prepare<'i>(
call_results, call_results,
signature_store, signature_store,
&run_parameters, &run_parameters,
soft_limits_triggering,
)?; )?;
let trace_handler = TraceHandler::from_trace(prev_data.trace, current_data.trace); let trace_handler = TraceHandler::from_trace(prev_data.trace, current_data.trace);
@ -143,6 +146,7 @@ fn make_exec_ctx(
call_results: &SerializedCallResults, call_results: &SerializedCallResults,
signature_store: SignatureStore, signature_store: SignatureStore,
run_parameters: &RunParameters, run_parameters: &RunParameters,
soft_limits_triggering: &mut SoftLimitsTriggering,
) -> PreparationResult<ExecutionCtx<'static>> { ) -> PreparationResult<ExecutionCtx<'static>> {
use crate::preparation_step::sizes_limits_check::limit_behavior; use crate::preparation_step::sizes_limits_check::limit_behavior;
@ -159,8 +163,12 @@ fn make_exec_ctx(
.values() .values()
.any(|call_result| call_result.result.len() > run_parameters.call_result_size_limit as usize) .any(|call_result| call_result.result.len() > run_parameters.call_result_size_limit as usize)
{ {
let error = PreparationError::call_result_size_limit(run_parameters.call_result_size_limit); let error: PreparationError = PreparationError::call_result_size_limit(run_parameters.call_result_size_limit);
limit_behavior(run_parameters, error)?; limit_behavior(
run_parameters,
error,
&mut soft_limits_triggering.particle_size_limit_exceeded,
)?;
} }
let ctx = ExecutionCtx::new( let ctx = ExecutionCtx::new(

View File

@ -17,12 +17,17 @@
use super::preparation::PreparationResult; use super::preparation::PreparationResult;
use crate::PreparationError; use crate::PreparationError;
use air_interpreter_interface::RunParameters; use air_interpreter_interface::{RunParameters, SoftLimitsTriggering};
pub(crate) fn limit_behavior(run_parameters: &RunParameters, error: PreparationError) -> PreparationResult<()> { pub(crate) fn limit_behavior(
run_parameters: &RunParameters,
error: PreparationError,
soft_limit_flag: &mut bool,
) -> PreparationResult<()> {
if run_parameters.hard_limit_enabled { if run_parameters.hard_limit_enabled {
Err(error) Err(error)
} else { } else {
*soft_limit_flag = true;
Ok(()) Ok(())
} }
} }
@ -31,16 +36,26 @@ pub(crate) fn check_against_size_limits(
run_parameters: &RunParameters, run_parameters: &RunParameters,
air: &str, air: &str,
raw_current_data: &[u8], raw_current_data: &[u8],
) -> PreparationResult<()> { ) -> PreparationResult<SoftLimitsTriggering> {
let mut soft_limits_triggering = SoftLimitsTriggering::default();
if air.len() as u64 > run_parameters.air_size_limit { if air.len() as u64 > run_parameters.air_size_limit {
let error = PreparationError::air_size_limit(air.len(), run_parameters.air_size_limit); let error = PreparationError::air_size_limit(air.len(), run_parameters.air_size_limit);
limit_behavior(run_parameters, error)?; limit_behavior(
run_parameters,
error,
&mut soft_limits_triggering.air_size_limit_exceeded,
)?;
} }
if raw_current_data.len() as u64 > run_parameters.particle_size_limit { if raw_current_data.len() as u64 > run_parameters.particle_size_limit {
let error = PreparationError::particle_size_limit(raw_current_data.len(), run_parameters.particle_size_limit); let error = PreparationError::particle_size_limit(raw_current_data.len(), run_parameters.particle_size_limit);
limit_behavior(run_parameters, error)?; limit_behavior(
run_parameters,
error,
&mut soft_limits_triggering.particle_size_limit_exceeded,
)?;
} }
Ok(()) Ok(soft_limits_triggering)
} }

View File

@ -63,20 +63,34 @@ fn execute_air_impl(
) -> Result<InterpreterOutcome, InterpreterOutcome> { ) -> Result<InterpreterOutcome, InterpreterOutcome> {
use crate::preparation_step::check_against_size_limits; use crate::preparation_step::check_against_size_limits;
farewell_if_fail!( let mut soft_limits_triggering = farewell_if_fail!(
check_against_size_limits(&params, &air, &raw_current_data), check_against_size_limits(&params, &air, &raw_current_data),
raw_prev_data raw_prev_data
); );
farewell_if_fail!(
check_against_size_limits(&params, &air, &raw_current_data),
raw_prev_data,
soft_limits_triggering
);
let ParsedDataPair { let ParsedDataPair {
prev_data, prev_data,
current_data, current_data,
} = farewell_if_fail!(parse_data(&raw_prev_data, &raw_current_data), raw_prev_data); } = farewell_if_fail!(
parse_data(&raw_prev_data, &raw_current_data),
raw_prev_data,
soft_limits_triggering
);
// TODO currently we use particle ID, but it should be changed to signature, // TODO currently we use particle ID, but it should be changed to signature,
// as partical ID can be equally replayed // as partical ID can be equally replayed
let salt = params.particle_id.clone(); let salt = params.particle_id.clone();
let signature_store = farewell_if_fail!(verify(&prev_data, &current_data, &salt), raw_prev_data); let signature_store = farewell_if_fail!(
verify(&prev_data, &current_data, &salt),
raw_prev_data,
soft_limits_triggering
);
let PreparationDescriptor { let PreparationDescriptor {
mut exec_ctx, mut exec_ctx,
@ -84,8 +98,17 @@ fn execute_air_impl(
air, air,
keypair, keypair,
} = farewell_if_fail!( } = farewell_if_fail!(
prepare(prev_data, current_data, &air, &call_results, params, signature_store,), prepare(
raw_prev_data prev_data,
current_data,
&air,
&call_results,
params,
signature_store,
&mut soft_limits_triggering
),
raw_prev_data,
soft_limits_triggering
); );
// 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
@ -103,18 +126,29 @@ fn execute_air_impl(
&salt, &salt,
&keypair, &keypair,
), ),
raw_prev_data raw_prev_data,
soft_limits_triggering
); );
measure!( measure!(
match exec_result { match exec_result {
Ok(_) => farewell::from_success_result(exec_ctx, trace_handler, &keypair), Ok(_) => farewell::from_success_result(exec_ctx, trace_handler, &keypair, soft_limits_triggering),
// return new collected trace in case of errors // return new collected trace in case of errors
Err(error) if error.is_catchable() => { Err(error) if error.is_catchable() => {
Err(farewell::from_execution_error(exec_ctx, trace_handler, error, &keypair)) Err(farewell::from_execution_error(
exec_ctx,
trace_handler,
error,
&keypair,
soft_limits_triggering,
))
} }
// return the prev data in case of any trace errors // return the prev data in case of any trace errors
Err(error) => Err(farewell::from_uncatchable_error(raw_prev_data, error)), Err(error) => Err(farewell::from_uncatchable_error(
raw_prev_data,
error,
soft_limits_triggering
)),
}, },
tracing::Level::INFO, tracing::Level::INFO,
"farewell", "farewell",

View File

@ -17,6 +17,7 @@
use super::CallRequests; use super::CallRequests;
use crate::raw_outcome::RawAVMOutcome; use crate::raw_outcome::RawAVMOutcome;
use air_interpreter_interface::SoftLimitsTriggering;
use serde::Deserialize; use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
@ -40,6 +41,8 @@ pub struct AVMOutcome {
/// Time of a particle execution /// Time of a particle execution
/// (it counts only execution time without operations with DataStore and so on) /// (it counts only execution time without operations with DataStore and so on)
pub execution_time: Duration, pub execution_time: Duration,
soft_limits_triggering: SoftLimitsTriggering, // WIP
} }
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
@ -56,6 +59,7 @@ impl AVMOutcome {
next_peer_pks: Vec<String>, next_peer_pks: Vec<String>,
memory_delta: usize, memory_delta: usize,
execution_time: Duration, execution_time: Duration,
soft_limits_triggering: SoftLimitsTriggering,
) -> Self { ) -> Self {
Self { Self {
data, data,
@ -63,6 +67,7 @@ impl AVMOutcome {
next_peer_pks, next_peer_pks,
memory_delta, memory_delta,
execution_time, execution_time,
soft_limits_triggering,
} }
} }
@ -80,6 +85,7 @@ impl AVMOutcome {
data, data,
call_requests, call_requests,
next_peer_pks, next_peer_pks,
soft_limits_triggering,
} = raw_outcome; } = raw_outcome;
let avm_outcome = AVMOutcome::new( let avm_outcome = AVMOutcome::new(
@ -88,6 +94,7 @@ impl AVMOutcome {
next_peer_pks, next_peer_pks,
memory_delta, memory_delta,
execution_time, execution_time,
soft_limits_triggering,
); );
if ret_code == INTERPRETER_SUCCESS { if ret_code == INTERPRETER_SUCCESS {

View File

@ -20,6 +20,7 @@ use super::CallRequests;
use air_interpreter_interface::InterpreterOutcome; use air_interpreter_interface::InterpreterOutcome;
use air_interpreter_interface::SoftLimitsTriggering;
use serde::Deserialize; use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
@ -31,6 +32,7 @@ pub struct RawAVMOutcome {
pub data: Vec<u8>, pub data: Vec<u8>,
pub call_requests: CallRequests, pub call_requests: CallRequests,
pub next_peer_pks: Vec<String>, pub next_peer_pks: Vec<String>,
pub soft_limits_triggering: SoftLimitsTriggering,
} }
impl RawAVMOutcome { impl RawAVMOutcome {
@ -41,9 +43,17 @@ impl RawAVMOutcome {
data, data,
call_requests, call_requests,
next_peer_pks, next_peer_pks,
air_size_limit_exceeded,
particle_size_limit_exceeded,
call_result_size_limit_exceeded,
} = outcome; } = outcome;
let call_requests = crate::from_raw_call_requests(call_requests.into())?; let call_requests = crate::from_raw_call_requests(call_requests.into())?;
let soft_limits_triggering = SoftLimitsTriggering::new(
air_size_limit_exceeded,
particle_size_limit_exceeded,
call_result_size_limit_exceeded,
);
let raw_avm_outcome = Self { let raw_avm_outcome = Self {
ret_code, ret_code,
@ -51,6 +61,7 @@ impl RawAVMOutcome {
data, data,
call_requests, call_requests,
next_peer_pks, next_peer_pks,
soft_limits_triggering,
}; };
Ok(raw_avm_outcome) Ok(raw_avm_outcome)

View File

@ -43,6 +43,7 @@ pub struct AVMRuntimeLimits {
pub hard_limit_enabled: bool, pub hard_limit_enabled: bool,
} }
#[derive(Default)]
pub struct RuntimeLimits { pub struct RuntimeLimits {
// The AIR script size limit. // The AIR script size limit.
pub air_size_limit: Option<u64>, pub air_size_limit: Option<u64>,
@ -392,17 +393,6 @@ impl RuntimeLimits {
} }
} }
impl Default for RuntimeLimits {
fn default() -> Self {
Self {
air_size_limit: None,
particle_size_limit: None,
call_result_size_limit: None,
hard_limit_enabled: false,
}
}
}
impl From<RuntimeLimits> for AVMRuntimeLimits { impl From<RuntimeLimits> for AVMRuntimeLimits {
fn from(value: RuntimeLimits) -> Self { fn from(value: RuntimeLimits) -> Self {
use air_interpreter_interface::MAX_AIR_SIZE; use air_interpreter_interface::MAX_AIR_SIZE;

View File

@ -25,6 +25,7 @@ pub struct AVMRuntimeLimits {
pub hard_limit_enabled: bool, pub hard_limit_enabled: bool,
} }
#[derive(Default)]
pub struct RuntimeLimits { pub struct RuntimeLimits {
pub air_size_limit: Option<u64>, pub air_size_limit: Option<u64>,
pub particle_size_limit: Option<u64>, pub particle_size_limit: Option<u64>,
@ -48,17 +49,6 @@ impl AVMRuntimeLimits {
} }
} }
impl Default for RuntimeLimits {
fn default() -> Self {
Self {
air_size_limit: None,
particle_size_limit: None,
call_result_size_limit: None,
hard_limit_enabled: false,
}
}
}
impl From<RuntimeLimits> for AVMRuntimeLimits { impl From<RuntimeLimits> for AVMRuntimeLimits {
fn from(value: RuntimeLimits) -> Self { fn from(value: RuntimeLimits) -> Self {
use air_interpreter_interface::MAX_AIR_SIZE; use air_interpreter_interface::MAX_AIR_SIZE;

View File

@ -24,6 +24,13 @@ use serde::Serialize;
pub const INTERPRETER_SUCCESS: i64 = 0; pub const INTERPRETER_SUCCESS: i64 = 0;
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SoftLimitsTriggering {
pub air_size_limit_exceeded: bool,
pub particle_size_limit_exceeded: bool,
pub call_result_size_limit_exceeded: bool,
}
/// Describes a result returned at the end of the interpreter execution_step. /// Describes a result returned at the end of the interpreter execution_step.
#[cfg_attr(feature = "marine", marine)] #[cfg_attr(feature = "marine", marine)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
@ -43,6 +50,25 @@ pub struct InterpreterOutcome {
/// Collected parameters of all met call instructions that could be executed on a current peer. /// Collected parameters of all met call instructions that could be executed on a current peer.
pub call_requests: Vec<u8>, pub call_requests: Vec<u8>,
/// WIP
pub air_size_limit_exceeded: bool,
pub particle_size_limit_exceeded: bool,
pub call_result_size_limit_exceeded: bool,
}
impl SoftLimitsTriggering {
pub fn new(
air_size_limit_exceeded: bool,
particle_size_limit_exceeded: bool,
call_result_size_limit_exceeded: bool,
) -> Self {
Self {
air_size_limit_exceeded,
particle_size_limit_exceeded,
call_result_size_limit_exceeded,
}
}
} }
impl InterpreterOutcome { impl InterpreterOutcome {
@ -52,6 +78,7 @@ impl InterpreterOutcome {
data: Vec<u8>, data: Vec<u8>,
next_peer_pks: Vec<String>, next_peer_pks: Vec<String>,
call_requests: SerializedCallRequests, call_requests: SerializedCallRequests,
soft_limits_triggering: SoftLimitsTriggering,
) -> Self { ) -> Self {
let call_requests = call_requests.into(); let call_requests = call_requests.into();
Self { Self {
@ -60,6 +87,9 @@ impl InterpreterOutcome {
data, data,
next_peer_pks, next_peer_pks,
call_requests, call_requests,
air_size_limit_exceeded: soft_limits_triggering.air_size_limit_exceeded,
particle_size_limit_exceeded: soft_limits_triggering.particle_size_limit_exceeded,
call_result_size_limit_exceeded: soft_limits_triggering.call_result_size_limit_exceeded,
} }
} }
} }
@ -67,7 +97,7 @@ impl InterpreterOutcome {
#[cfg(feature = "marine")] #[cfg(feature = "marine")]
impl InterpreterOutcome { impl InterpreterOutcome {
pub fn from_ivalue(ivalue: IValue) -> Result<Self, String> { pub fn from_ivalue(ivalue: IValue) -> Result<Self, String> {
const OUTCOME_FIELDS_COUNT: usize = 5; const OUTCOME_FIELDS_COUNT: usize = 8;
let mut record_values = try_as_record(ivalue)?.into_vec(); let mut record_values = try_as_record(ivalue)?.into_vec();
if record_values.len() != OUTCOME_FIELDS_COUNT { if record_values.len() != OUTCOME_FIELDS_COUNT {
@ -76,11 +106,24 @@ impl InterpreterOutcome {
)); ));
} }
let air_size_limit_exceeded =
try_as_boolean(record_values.pop().unwrap(), "air_size_limit_exceeded")?;
let particle_size_limit_exceeded =
try_as_boolean(record_values.pop().unwrap(), "particle_size_limit_exceeded")?;
let call_result_size_limit_exceeded = try_as_boolean(
record_values.pop().unwrap(),
"call_result_size_limit_exceeded",
)?;
let call_requests = try_as_byte_vec(record_values.pop().unwrap(), "call_requests")?; let call_requests = try_as_byte_vec(record_values.pop().unwrap(), "call_requests")?;
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_i64(record_values.pop().unwrap(), "ret_code")?; let ret_code = try_as_i64(record_values.pop().unwrap(), "ret_code")?;
let soft_limits_triggering = SoftLimitsTriggering::new(
air_size_limit_exceeded,
particle_size_limit_exceeded,
call_result_size_limit_exceeded,
);
let outcome = Self::new( let outcome = Self::new(
ret_code, ret_code,
@ -88,6 +131,7 @@ impl InterpreterOutcome {
data, data,
next_peer_pks, next_peer_pks,
call_requests.into(), call_requests.into(),
soft_limits_triggering,
); );
Ok(outcome) Ok(outcome)
@ -160,3 +204,11 @@ fn try_as_string_vec(ivalue: IValue, field_name: &str) -> Result<Vec<String>, St
v => Err(format!("expected an array for {field_name}, got {v:?}")), v => Err(format!("expected an array for {field_name}, got {v:?}")),
} }
} }
#[cfg(feature = "marine")]
fn try_as_boolean(ivalue: IValue, field_name: &str) -> Result<bool, String> {
match ivalue {
IValue::Boolean(value) => Ok(value),
v => Err(format!("expected a bool for {field_name}, got {v:?}")),
}
}

View File

@ -57,7 +57,7 @@ impl AirRunner for WasmAirRunner {
) )
}); });
let runner = pool.pull(|| make_pooled_avm_runner(test_init_parameters.clone())); let runner = pool.pull(|| make_pooled_avm_runner(test_init_parameters));
Self { Self {
current_peer_id: current_peer_id.into(), current_peer_id: current_peer_id.into(),

View File

@ -51,11 +51,26 @@ macro_rules! auto_checked_add {
#[macro_export] #[macro_export]
macro_rules! farewell_if_fail { macro_rules! farewell_if_fail {
($cmd:expr, $raw_prev_data:expr, $soft_limits_triggering:expr) => {
match $cmd {
Ok(result) => result,
// return the prev data in case of errors
Err(error) => {
return Err(farewell::from_uncatchable_error(
$raw_prev_data,
error,
$soft_limits_triggering,
))
}
};
};
($cmd:expr, $raw_prev_data:expr) => { ($cmd:expr, $raw_prev_data:expr) => {
match $cmd { match $cmd {
Ok(result) => result, Ok(result) => result,
// return the prev data in case of errors // return the prev data in case of errors
Err(error) => return Err(farewell::from_uncatchable_error($raw_prev_data, error)), Err(error) => {
farewell_if_fail!($cmd, $raw_prev_data, <_>::default())
}
}; };
}; };
} }

View File

@ -164,7 +164,7 @@ impl<R: AirRunner> Network<R> {
resolver: Default::default(), resolver: Default::default(),
}); });
for peer_name in named_peers { for peer_name in named_peers {
network.ensure_named_peer(peer_name, test_init_params.clone()); network.ensure_named_peer(peer_name, test_init_params);
} }
network network
} }

View File

@ -100,7 +100,7 @@ impl<R: AirRunner> AirScriptExecutor<R> {
annotated_air_script: &str, annotated_air_script: &str,
) -> Result<Self, String> { ) -> Result<Self, String> {
let transformed = let transformed =
TransformedAirScript::new(annotated_air_script, network, test_init_parameters.clone())?; TransformedAirScript::new(annotated_air_script, network, test_init_parameters)?;
Self::from_transformed_air_script(test_parameters, test_init_parameters, transformed) Self::from_transformed_air_script(test_parameters, test_init_parameters, transformed)
} }
@ -115,10 +115,10 @@ impl<R: AirRunner> AirScriptExecutor<R> {
let network = Network::new( let network = Network::new(
extra_peers.into_iter(), extra_peers.into_iter(),
common_services, common_services,
test_init_parameters.clone(), test_init_parameters,
); );
let transformed = let transformed =
TransformedAirScript::new(annotated_air_script, network, test_init_parameters.clone())?; TransformedAirScript::new(annotated_air_script, network, test_init_parameters)?;
Self::from_transformed_air_script(test_parameters, test_init_parameters, transformed) Self::from_transformed_air_script(test_parameters, test_init_parameters, transformed)
} }

View File

@ -83,11 +83,11 @@ struct Transformer<'net, R> {
impl<R: AirRunner> Transformer<'_, R> { impl<R: AirRunner> Transformer<'_, R> {
pub(crate) fn transform(&self, sexp: &mut Sexp, test_init_parameters: TestInitParameters) { pub(crate) fn transform(&self, sexp: &mut Sexp, test_init_parameters: TestInitParameters) {
match sexp { match sexp {
Sexp::Call(call) => self.handle_call(call, test_init_parameters.clone()), Sexp::Call(call) => self.handle_call(call, test_init_parameters),
Sexp::Canon(canon) => self.handle_canon(canon, test_init_parameters.clone()), Sexp::Canon(canon) => self.handle_canon(canon, test_init_parameters),
Sexp::List(children) => { Sexp::List(children) => {
for child in children.iter_mut().skip(1) { for child in children.iter_mut().skip(1) {
self.transform(child, test_init_parameters.clone()); self.transform(child, test_init_parameters);
} }
} }
Sexp::Symbol(_) | Sexp::String(_) => {} Sexp::Symbol(_) | Sexp::String(_) => {}