WIP new structs to hand limits over in runtime

This commit is contained in:
Roman Nozdrin 2024-02-07 10:01:34 +00:00
parent 1da02d197d
commit 81019e6633
17 changed files with 413 additions and 129 deletions

View File

@ -91,17 +91,9 @@ pub enum PreparationError {
#[error(transparent)] #[error(transparent)]
DataSignatureCheckError(#[from] DataVerifierError), DataSignatureCheckError(#[from] DataVerifierError),
/// AIR script size is bigger than the allowed limit. /// RAM limits are excedeed.
#[error("air size: {0} bytes is bigger than the limit allowed: {1} bytes")] #[error(transparent)]
AIRSizeLimitReached(usize, u64), SizeLimitsExceded(#[from] SizeLimitsExceded),
/// 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")]
ParticleSizeLimitReached(usize, u64),
/// CallResult size is bigger than the allowed limit.
#[error("Call result size is bigger than the limit allowed: {0} bytes")]
CallResultSizeLimitReached(u64),
} }
impl ToErrorCode for PreparationError { impl ToErrorCode for PreparationError {
@ -136,14 +128,29 @@ 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::AIRSizeLimitReached(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 {
Self::ParticleSizeLimitReached(actual_size, limit) Self::SizeLimitsExceded(SizeLimitsExceded::Particle(actual_size, limit))
} }
pub fn call_result_size_limit(limit: u64) -> Self { pub fn call_result_size_limit(limit: u64) -> Self {
Self::CallResultSizeLimitReached(limit) Self::SizeLimitsExceded(SizeLimitsExceded::CallResult(limit))
} }
} }
#[derive(Debug, ThisError)]
pub enum SizeLimitsExceded {
/// AIR script size is bigger than the allowed limit.
#[error("air size: {0} bytes is bigger than the limit allowed: {1} bytes")]
AIR(usize, u64),
/// 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")]
Particle(usize, u64),
/// CallResult size is bigger than the allowed limit.
#[error("Call result size is bigger than the limit allowed: {0} bytes")]
CallResult(u64),
}

View File

@ -144,6 +144,8 @@ fn make_exec_ctx(
signature_store: SignatureStore, signature_store: SignatureStore,
run_parameters: &RunParameters, run_parameters: &RunParameters,
) -> PreparationResult<ExecutionCtx<'static>> { ) -> PreparationResult<ExecutionCtx<'static>> {
use crate::preparation_step::sizes_limits_check::limit_behavior;
let call_results = measure!( let call_results = measure!(
CallResultsRepr CallResultsRepr
.deserialize(call_results) .deserialize(call_results)
@ -157,9 +159,8 @@ 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)
{ {
return Err(PreparationError::call_result_size_limit( let error = PreparationError::call_result_size_limit(run_parameters.call_result_size_limit);
run_parameters.call_result_size_limit, limit_behavior(run_parameters, error)?;
));
} }
let ctx = ExecutionCtx::new( let ctx = ExecutionCtx::new(

View File

@ -19,23 +19,27 @@ use crate::PreparationError;
use air_interpreter_interface::RunParameters; use air_interpreter_interface::RunParameters;
pub(crate) fn limit_behavior(run_parameters: &RunParameters, error: PreparationError) -> PreparationResult<()> {
if run_parameters.hard_limit_enabled {
Err(error)
} else {
Ok(())
}
}
pub(crate) fn check_against_size_limits( 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<()> {
if air.len() as u64 > run_parameters.air_size_limit { if air.len() as u64 > run_parameters.air_size_limit {
return Err(PreparationError::air_size_limit( let error = PreparationError::air_size_limit(air.len(), run_parameters.air_size_limit);
air.len(), limit_behavior(run_parameters, error)?;
run_parameters.air_size_limit,
));
} }
if raw_current_data.len() > run_parameters.particle_size_limit as usize { if raw_current_data.len() as u64 > run_parameters.particle_size_limit {
return Err(PreparationError::particle_size_limit( let error = PreparationError::particle_size_limit(raw_current_data.len(), run_parameters.particle_size_limit);
raw_current_data.len(), limit_behavior(run_parameters, error)?;
run_parameters.particle_size_limit,
));
} }
Ok(()) Ok(())

View File

@ -102,6 +102,7 @@ fn invalid_callresults() {
let air_size_limit = MAX_AIR_SIZE; let air_size_limit = MAX_AIR_SIZE;
let particle_size_limit = MAX_PARTICLE_SIZE; let particle_size_limit = MAX_PARTICLE_SIZE;
let call_result_size_limit = MAX_CALL_RESULT_SIZE; let call_result_size_limit = MAX_CALL_RESULT_SIZE;
let hard_limit_enable = false;
let run_parameters = RunParameters::new( let run_parameters = RunParameters::new(
client_peer_id.clone(), client_peer_id.clone(),
@ -114,6 +115,7 @@ fn invalid_callresults() {
air_size_limit, air_size_limit,
particle_size_limit, particle_size_limit,
call_result_size_limit, call_result_size_limit,
hard_limit_enable,
); );
let result = air::execute_air(air, prev_data, data, run_parameters, wrong_call_results.clone().into()); let result = air::execute_air(air, prev_data, data, run_parameters, wrong_call_results.clone().into());
@ -128,50 +130,111 @@ fn invalid_callresults() {
} }
#[test] #[test]
fn air_size_limit() { fn air_size_hard_limit() {
let script = "a".repeat((MAX_AIR_SIZE + 1) as usize); let script = "a".repeat((MAX_AIR_SIZE + 1) as usize);
let mut vm = create_avm(unit_call_service(), "some_peer_id");
let result = vm.call(script, "", "", <_>::default()).unwrap();
let expected_error = PreparationError::AIRSizeLimitReached((MAX_AIR_SIZE + 1) as usize, MAX_AIR_SIZE); let peer_id = "some_peer_id".to_owned();
let air_size_limit = MAX_AIR_SIZE;
let particle_size_limit = MAX_PARTICLE_SIZE;
let call_result_size_limit = MAX_CALL_RESULT_SIZE;
let hard_limit_enable = true;
let run_parameters = RunParameters::new(
peer_id.clone(),
peer_id,
0,
0,
<_>::default(),
<_>::default(),
"".to_owned(),
air_size_limit,
particle_size_limit,
call_result_size_limit,
hard_limit_enable,
);
let result = air::execute_air(script, vec![], vec![], run_parameters, <_>::default());
let result = RawAVMOutcome::from_interpreter_outcome(result).unwrap();
let expected_error = PreparationError::air_size_limit((MAX_AIR_SIZE + 1) as usize, MAX_AIR_SIZE);
assert!(check_error(&result, expected_error)); assert!(check_error(&result, expected_error));
} }
#[test] #[test]
fn particle_size_limit() { fn particle_size_hard_limit() {
let script = "(null)"; let script = "(null)".to_owned();
let mut vm = create_avm(unit_call_service(), "some_peer_id");
let cur_data = vec![0; (MAX_PARTICLE_SIZE + 1) as usize]; let cur_data = vec![0; (MAX_PARTICLE_SIZE + 1) as usize];
let result = vm.call(script, "", cur_data, <_>::default()).unwrap();
let expected_error = let peer_id = "some_peer_id".to_owned();
PreparationError::ParticleSizeLimitReached((MAX_PARTICLE_SIZE + 1) as usize, MAX_PARTICLE_SIZE); let air_size_limit = MAX_AIR_SIZE;
let particle_size_limit = MAX_PARTICLE_SIZE;
let call_result_size_limit = MAX_CALL_RESULT_SIZE;
let hard_limit_enable = true;
let run_parameters = RunParameters::new(
peer_id.clone(),
peer_id,
0,
0,
<_>::default(),
<_>::default(),
"".to_owned(),
air_size_limit,
particle_size_limit,
call_result_size_limit,
hard_limit_enable,
);
let result = air::execute_air(script, vec![], cur_data, run_parameters, <_>::default());
let result = RawAVMOutcome::from_interpreter_outcome(result).unwrap();
let expected_error = PreparationError::particle_size_limit((MAX_PARTICLE_SIZE + 1) as usize, MAX_PARTICLE_SIZE);
assert!(check_error(&result, expected_error)); assert!(check_error(&result, expected_error));
} }
#[test] #[test]
fn call_result_size_limit() { fn call_result_size_hard_limit() {
use maplit::hashmap; use maplit::hashmap;
use air::ToErrorCode; use air::ToErrorCode;
use air_interpreter_interface::MAX_CALL_RESULT_SIZE; use air_interpreter_interface::MAX_CALL_RESULT_SIZE;
use air_interpreter_sede::ToSerialized;
let peer_id = "some_peer_id"; let script = "(null)".to_owned();
let mut vm = create_avm(unit_call_service(), "some_peer_id");
let script = "(null)";
let result_1 = "a".repeat((MAX_CALL_RESULT_SIZE / 2 + 1) as usize); let result_1 = "a".repeat((MAX_CALL_RESULT_SIZE / 2 + 1) as usize);
let result_2 = "b".repeat((MAX_CALL_RESULT_SIZE + 1) as usize); let result_2 = "b".repeat((MAX_CALL_RESULT_SIZE + 1) as usize);
let call_results: CallResults = let call_results: CallResults =
hashmap! {0 => CallServiceResult::ok(result_1.into()), 1 => CallServiceResult::ok(result_2.into())}; hashmap! {0 => CallServiceResult::ok(result_1.into()), 1 => CallServiceResult::ok(result_2.into())};
let result = vm let raw_call_results = into_raw_result(call_results);
.call_single(script, "", "", peer_id, 0, 64, None, call_results, "particle_id") let raw_call_results = CallResultsRepr.serialize(&raw_call_results).unwrap();
.unwrap();
let expected_error = PreparationError::CallResultSizeLimitReached(MAX_CALL_RESULT_SIZE); let peer_id = "some_peer_id".to_owned();
let air_size_limit = MAX_AIR_SIZE;
let particle_size_limit = MAX_PARTICLE_SIZE;
let call_result_size_limit = MAX_CALL_RESULT_SIZE;
let hard_limit_enable = true;
let run_parameters = RunParameters::new(
peer_id.clone(),
peer_id,
0,
0,
<_>::default(),
<_>::default(),
"".to_owned(),
air_size_limit,
particle_size_limit,
call_result_size_limit,
hard_limit_enable,
);
let result = air::execute_air(script, vec![], vec![], run_parameters, raw_call_results);
let result = RawAVMOutcome::from_interpreter_outcome(result).unwrap();
let expected_error = PreparationError::call_result_size_limit(MAX_CALL_RESULT_SIZE);
assert_eq!(result.ret_code, expected_error.to_error_code()); assert_eq!(result.ret_code, expected_error.to_error_code());
} }

View File

@ -70,7 +70,7 @@ impl<E> AVM<E> {
data_store.initialize()?; data_store.initialize()?;
let runner = AVMRunner::new(air_wasm_path, max_heap_size, None, None, None, logging_mask) let runner = AVMRunner::new(air_wasm_path, max_heap_size, <_>::default(), logging_mask)
.map_err(AVMError::RunnerError)?; .map_err(AVMError::RunnerError)?;
let runner = SendSafeRunner(runner); let runner = SendSafeRunner(runner);
let avm = Self { runner, data_store }; let avm = Self { runner, data_store };

View File

@ -28,11 +28,14 @@ mod avm;
mod config; mod config;
mod errors; mod errors;
mod runner; mod runner;
mod runtime_limits;
pub use avm::AVM; pub use avm::AVM;
pub use config::AVMConfig; pub use config::AVMConfig;
pub use errors::AVMError; pub use errors::AVMError;
pub use runner::AVMMemoryStats; pub use runner::AVMMemoryStats;
pub use runner::AVMRuntimeLimits;
pub use runner::RuntimeLimits;
pub use avm_interface::*; pub use avm_interface::*;

View File

@ -32,18 +32,36 @@ use marine::ModuleDescriptor;
use std::path::PathBuf; use std::path::PathBuf;
#[derive(Clone, Copy, Debug)]
pub struct AVMRuntimeLimits {
pub air_size_limit: u64, // WIP remove pub?
/// The particle data size limit.
pub particle_size_limit: u64,
/// This is the limit for the size of service call result.
pub call_result_size_limit: u64,
/// This knob controls hard RAM limits behavior for AVMRunner.
pub hard_limit_enabled: bool,
}
pub struct RuntimeLimits {
// The AIR script size limit.
pub air_size_limit: Option<u64>,
/// The particle data size limit.
pub particle_size_limit: Option<u64>,
/// This is the limit for the size of service call result.
pub call_result_size_limit: Option<u64>,
/// This knob controls hard RAM limits behavior for AVMRunner.
pub hard_limit_enabled: bool,
}
pub struct AVMRunner { pub struct AVMRunner {
marine: Marine, marine: Marine,
/// file name of the AIR interpreter .wasm /// file name of the AIR interpreter .wasm
wasm_filename: String, wasm_filename: String,
/// The memory limit provided by constructor /// The memory limit provided by constructor
total_memory_limit: Option<u64>, total_memory_limit: Option<u64>,
/// The AIR script size limit. /// This struct contains runtime RAM allowance.
pub air_size_limit: u64, avm_runtime_limits: AVMRuntimeLimits,
/// The particle data size limit.
pub particle_size_limit: u64,
// This is the limit for the size of service call result.
pub call_result_size_limit: u64,
} }
/// Return statistic of AVM server Wasm module heap footprint. /// Return statistic of AVM server Wasm module heap footprint.
@ -63,32 +81,21 @@ impl AVMRunner {
pub fn new( pub fn new(
air_wasm_path: PathBuf, air_wasm_path: PathBuf,
total_memory_limit: Option<u64>, total_memory_limit: Option<u64>,
air_size_limit: Option<u64>, runtime_limits: RuntimeLimits,
particle_size_limit: Option<u64>,
call_result_size_limit: Option<u64>,
logging_mask: i32, logging_mask: i32,
) -> RunnerResult<Self> { ) -> RunnerResult<Self> {
use air_interpreter_interface::MAX_AIR_SIZE;
use air_interpreter_interface::MAX_CALL_RESULT_SIZE;
use air_interpreter_interface::MAX_PARTICLE_SIZE;
let (wasm_dir, wasm_filename) = split_dirname(air_wasm_path)?; let (wasm_dir, wasm_filename) = split_dirname(air_wasm_path)?;
let marine_config = let marine_config =
make_marine_config(wasm_dir, &wasm_filename, total_memory_limit, logging_mask); make_marine_config(wasm_dir, &wasm_filename, total_memory_limit, logging_mask);
let marine = Marine::with_raw_config(marine_config)?; let marine = Marine::with_raw_config(marine_config)?;
let avm_runtime_limits = runtime_limits.into();
let air_size_limit = air_size_limit.unwrap_or(MAX_AIR_SIZE);
let particle_size_limit = particle_size_limit.unwrap_or(MAX_PARTICLE_SIZE);
let call_result_size_limit = call_result_size_limit.unwrap_or(MAX_CALL_RESULT_SIZE);
let avm = Self { let avm = Self {
marine, marine,
wasm_filename, wasm_filename,
total_memory_limit, total_memory_limit,
air_size_limit, avm_runtime_limits,
particle_size_limit,
call_result_size_limit,
}; };
Ok(avm) Ok(avm)
@ -122,9 +129,7 @@ impl AVMRunner {
init_peer_id.into(), init_peer_id.into(),
timestamp, timestamp,
ttl, ttl,
self.air_size_limit, self.avm_runtime_limits,
self.particle_size_limit,
self.call_result_size_limit,
call_results, call_results,
key_format.into(), key_format.into(),
secret_key_bytes, secret_key_bytes,
@ -173,9 +178,7 @@ impl AVMRunner {
init_peer_id.into(), init_peer_id.into(),
timestamp, timestamp,
ttl, ttl,
self.air_size_limit, self.avm_runtime_limits,
self.particle_size_limit,
self.call_result_size_limit,
call_results, call_results,
key_format, key_format,
secret_key_bytes, secret_key_bytes,
@ -242,14 +245,19 @@ fn prepare_args(
init_peer_id: String, init_peer_id: String,
timestamp: u64, timestamp: u64,
ttl: u32, ttl: u32,
air_size_limit: u64, avm_runtime_limits: AVMRuntimeLimits,
particle_size_limit: u64,
call_result_size_limit: u64,
call_results: CallResults, call_results: CallResults,
key_format: u8, key_format: u8,
secret_key_bytes: Vec<u8>, secret_key_bytes: Vec<u8>,
particle_id: String, particle_id: String,
) -> Vec<IValue> { ) -> Vec<IValue> {
let AVMRuntimeLimits {
air_size_limit,
particle_size_limit,
call_result_size_limit,
hard_limit_enabled,
} = avm_runtime_limits;
let run_parameters = air_interpreter_interface::RunParameters::new( let run_parameters = air_interpreter_interface::RunParameters::new(
init_peer_id, init_peer_id,
current_peer_id, current_peer_id,
@ -261,6 +269,7 @@ fn prepare_args(
air_size_limit, air_size_limit,
particle_size_limit, particle_size_limit,
call_result_size_limit, call_result_size_limit,
hard_limit_enabled,
) )
.into_ivalue(); .into_ivalue();
@ -350,3 +359,61 @@ fn try_as_one_value_vec(mut ivalues: Vec<IValue>) -> RunnerResult<IValue> {
Ok(ivalues.remove(0)) Ok(ivalues.remove(0))
} }
impl AVMRuntimeLimits {
pub fn new(
air_size_limit: u64,
particle_size_limit: u64,
call_result_size_limit: u64,
hard_limit_enabled: bool,
) -> Self {
Self {
air_size_limit,
particle_size_limit,
call_result_size_limit,
hard_limit_enabled,
}
}
}
impl RuntimeLimits {
pub fn new(
air_size_limit: Option<u64>,
particle_size_limit: Option<u64>,
call_result_size_limit: Option<u64>,
hard_limit_enabled: bool,
) -> Self {
Self {
air_size_limit,
particle_size_limit,
call_result_size_limit,
hard_limit_enabled,
}
}
}
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 {
fn from(value: RuntimeLimits) -> Self {
use air_interpreter_interface::MAX_AIR_SIZE;
use air_interpreter_interface::MAX_CALL_RESULT_SIZE;
use air_interpreter_interface::MAX_PARTICLE_SIZE;
AVMRuntimeLimits::new(
value.air_size_limit.unwrap_or(MAX_AIR_SIZE),
value.particle_size_limit.unwrap_or(MAX_PARTICLE_SIZE),
value.call_result_size_limit.unwrap_or(MAX_CALL_RESULT_SIZE),
value.hard_limit_enabled,
)
}
}

View File

@ -0,0 +1,75 @@
/*
* Copyright 2024 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 struct AVMRuntimeLimits {
/// AIR script size limit.
pub air_size_limit: u64,
/// Particle data size limit.
pub particle_size_limit: u64,
/// Service call result size limit.
pub call_result_size_limit: u64,
/// Knob to enable/disable RAM consumption hard limits in AquaVM.
pub hard_limit_enabled: bool,
}
pub struct RuntimeLimits {
pub air_size_limit: Option<u64>,
pub particle_size_limit: Option<u64>,
pub call_result_size_limit: Option<u64>,
pub hard_limit_enabled: bool,
}
impl AVMRuntimeLimits {
pub fn new(
air_size_limit: u64,
particle_size_limit: u64,
call_result_size_limit: u64,
hard_limit_enabled: bool,
) -> Self {
Self {
air_size_limit,
particle_size_limit,
call_result_size_limit,
hard_limit_enabled,
}
}
}
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 {
fn from(value: RuntimeLimits) -> Self {
use air_interpreter_interface::MAX_AIR_SIZE;
use air_interpreter_interface::MAX_CALL_RESULT_SIZE;
use air_interpreter_interface::MAX_PARTICLE_SIZE;
AVMRuntimeLimits::new(
value.air_size_limit.unwrap_or(MAX_AIR_SIZE),
value.particle_size_limit.unwrap_or(MAX_PARTICLE_SIZE),
value.call_result_size_limit.unwrap_or(MAX_CALL_RESULT_SIZE),
value.hard_limit_enabled,
)
}
}

View File

@ -62,6 +62,9 @@ pub struct RunParameters {
/// This is the limit for the size of service call result. /// This is the limit for the size of service call result.
pub call_result_size_limit: u64, pub call_result_size_limit: u64,
/// This knob controls hard RAM limits behavior for AVMRunner.
pub hard_limit_enabled: bool,
} }
impl RunParameters { impl RunParameters {
@ -77,6 +80,7 @@ impl RunParameters {
air_size_limit: u64, air_size_limit: u64,
particle_size_limit: u64, particle_size_limit: u64,
call_result_size_limit: u64, call_result_size_limit: u64,
hard_limit_enabled: bool,
) -> Self { ) -> Self {
Self { Self {
init_peer_id, init_peer_id,
@ -89,6 +93,7 @@ impl RunParameters {
air_size_limit, air_size_limit,
particle_size_limit, particle_size_limit,
call_result_size_limit, call_result_size_limit,
hard_limit_enabled,
} }
} }
@ -105,6 +110,7 @@ impl RunParameters {
IValue::U64(self.air_size_limit), IValue::U64(self.air_size_limit),
IValue::U64(self.particle_size_limit), IValue::U64(self.particle_size_limit),
IValue::U64(self.call_result_size_limit), IValue::U64(self.call_result_size_limit),
IValue::Boolean(self.hard_limit_enabled),
]; ];
// unwrap is safe here because run_parameters is non-empty array // unwrap is safe here because run_parameters is non-empty array
let run_parameters = NEVec::new(run_parameters).unwrap(); let run_parameters = NEVec::new(run_parameters).unwrap();

View File

@ -21,6 +21,7 @@ use air_interpreter_interface::RunParameters;
use air_interpreter_sede::ToSerialized; use air_interpreter_sede::ToSerialized;
use avm_server::avm_runner::*; use avm_server::avm_runner::*;
use avm_server::into_raw_result; use avm_server::into_raw_result;
use avm_server::AVMRuntimeLimits;
use fluence_keypair::KeyPair; use fluence_keypair::KeyPair;
pub struct NativeAirRunner { pub struct NativeAirRunner {
@ -59,8 +60,12 @@ impl AirRunner for NativeAirRunner {
let key_format = keypair.key_format().into(); let key_format = keypair.key_format().into();
let secret_key_bytes = keypair.secret().unwrap(); let secret_key_bytes = keypair.secret().unwrap();
let (air_size_limit, particle_size_limit, call_result_size_limit) = let AVMRuntimeLimits {
self.test_init_parameters.to_attributes_w_default(); air_size_limit,
particle_size_limit,
call_result_size_limit,
hard_limit_enabled,
} = self.test_init_parameters.into();
let outcome = air::execute_air( let outcome = air::execute_air(
air.into(), air.into(),
@ -77,6 +82,7 @@ impl AirRunner for NativeAirRunner {
air_size_limit, air_size_limit,
particle_size_limit, particle_size_limit,
call_result_size_limit, call_result_size_limit,
hard_limit_enabled,
}, },
raw_call_results, raw_call_results,
); );

View File

@ -27,6 +27,8 @@ pub use crate::wasm_test_runner::WasmAirRunner;
use super::CallServiceClosure; use super::CallServiceClosure;
use avm_server::avm_runner::*; use avm_server::avm_runner::*;
use avm_server::AVMRuntimeLimits;
use avm_server::RuntimeLimits;
use fluence_keypair::KeyPair; use fluence_keypair::KeyPair;
use std::collections::HashMap; use std::collections::HashMap;
@ -69,11 +71,12 @@ pub struct TestRunParameters {
} }
/// This struct is used to set limits for the test runner creating AVMRunner. /// This struct is used to set limits for the test runner creating AVMRunner.
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone, Copy)]
pub struct TestInitParameters { pub struct TestInitParameters {
pub air_size_limit: Option<u64>, pub air_size_limit: Option<u64>,
pub particle_size_limit: Option<u64>, pub particle_size_limit: Option<u64>,
pub call_result_size_limit: Option<u64>, pub call_result_size_limit: Option<u64>,
pub hard_limit_enabled: bool,
} }
impl<R: AirRunner> TestRunner<R> { impl<R: AirRunner> TestRunner<R> {
@ -247,11 +250,17 @@ impl TestRunParameters {
} }
impl TestInitParameters { impl TestInitParameters {
pub fn new(air_size_limit: u64, particle_size_limit: u64, call_result_size_limit: u64) -> Self { pub fn new(
air_size_limit: u64,
particle_size_limit: u64,
call_result_size_limit: u64,
hard_limit_enabled: bool,
) -> Self {
Self { Self {
air_size_limit: Some(air_size_limit), air_size_limit: Some(air_size_limit),
particle_size_limit: Some(particle_size_limit), particle_size_limit: Some(particle_size_limit),
call_result_size_limit: Some(call_result_size_limit), call_result_size_limit: Some(call_result_size_limit),
hard_limit_enabled,
} }
} }
@ -260,18 +269,37 @@ impl TestInitParameters {
air_size_limit: Some(u64::MAX), air_size_limit: Some(u64::MAX),
particle_size_limit: Some(u64::MAX), particle_size_limit: Some(u64::MAX),
call_result_size_limit: Some(u64::MAX), call_result_size_limit: Some(u64::MAX),
hard_limit_enabled: false,
} }
} }
}
pub fn to_attributes_w_default(&self) -> (u64, u64, u64) { impl From<TestInitParameters> for RuntimeLimits {
fn from(value: TestInitParameters) -> Self {
RuntimeLimits::new(
value.air_size_limit,
value.particle_size_limit,
value.call_result_size_limit,
value.hard_limit_enabled,
)
}
}
impl From<TestInitParameters> for AVMRuntimeLimits {
fn from(value: TestInitParameters) -> Self {
use air_interpreter_interface::MAX_AIR_SIZE; use air_interpreter_interface::MAX_AIR_SIZE;
use air_interpreter_interface::MAX_CALL_RESULT_SIZE; use air_interpreter_interface::MAX_CALL_RESULT_SIZE;
use air_interpreter_interface::MAX_PARTICLE_SIZE; use air_interpreter_interface::MAX_PARTICLE_SIZE;
let air_size_limit = value.air_size_limit.unwrap_or(MAX_AIR_SIZE);
let particle_size_limit: u64 = value.particle_size_limit.unwrap_or(MAX_PARTICLE_SIZE);
let call_result_size_limit = value.call_result_size_limit.unwrap_or(MAX_CALL_RESULT_SIZE);
let air_size_limit = self.air_size_limit.unwrap_or(MAX_AIR_SIZE); AVMRuntimeLimits::new(
let particle_size_limit: u64 = self.particle_size_limit.unwrap_or(MAX_PARTICLE_SIZE); air_size_limit,
let call_result_size_limit = self.call_result_size_limit.unwrap_or(MAX_CALL_RESULT_SIZE); particle_size_limit,
(air_size_limit, particle_size_limit, call_result_size_limit) call_result_size_limit,
value.hard_limit_enabled,
)
} }
} }

View File

@ -35,15 +35,11 @@ pub struct WasmAirRunner {
fn make_pooled_avm_runner(test_init_parameters: TestInitParameters) -> AVMRunner { fn make_pooled_avm_runner(test_init_parameters: TestInitParameters) -> AVMRunner {
let logging_mask = i32::MAX; let logging_mask = i32::MAX;
let (air_size_limit, particle_size_limit, call_result_size_limit) =
test_init_parameters.to_attributes_w_default();
AVMRunner::new( AVMRunner::new(
PathBuf::from(AIR_WASM_PATH), PathBuf::from(AIR_WASM_PATH),
Some(AVM_MAX_HEAP_SIZE), Some(AVM_MAX_HEAP_SIZE),
Some(air_size_limit), test_init_parameters.into(),
Some(particle_size_limit),
Some(call_result_size_limit),
logging_mask, logging_mask,
) )
.expect("vm should be created") .expect("vm should be created")
@ -114,15 +110,11 @@ pub struct ReleaseWasmAirRunner {
impl AirRunner for ReleaseWasmAirRunner { impl AirRunner for ReleaseWasmAirRunner {
fn new(current_peer_id: impl Into<String>, test_init_parameters: TestInitParameters) -> Self { fn new(current_peer_id: impl Into<String>, test_init_parameters: TestInitParameters) -> Self {
let logging_mask = i32::MAX; let logging_mask = i32::MAX;
let (air_size_limit, particle_size_limit, call_result_size_limit) =
test_init_parameters.to_attributes_w_default();
let runner = AVMRunner::new( let runner = AVMRunner::new(
PathBuf::from(RELEASE_AIR_WASM_PATH), PathBuf::from(RELEASE_AIR_WASM_PATH),
Some(AVM_MAX_HEAP_SIZE), Some(AVM_MAX_HEAP_SIZE),
Some(air_size_limit), test_init_parameters.into(),
Some(particle_size_limit),
Some(call_result_size_limit),
logging_mask, logging_mask,
) )
.expect("vm should be created"); .expect("vm should be created");

View File

@ -17,6 +17,7 @@ avm-interface = { version = "0.31.2", path = "../../../avm/interface" }
air-interpreter-interface = { version = "0.17.2", path = "../../../crates/air-lib/interpreter-interface", default-features = false } air-interpreter-interface = { version = "0.17.2", path = "../../../crates/air-lib/interpreter-interface", default-features = false }
air-interpreter-data = { version = "0.17.0", path = "../../../crates/air-lib/interpreter-data" } air-interpreter-data = { version = "0.17.0", path = "../../../crates/air-lib/interpreter-data" }
air-interpreter-sede = { version = "0.1.0", path = "../../../crates/air-lib/interpreter-sede", default-features = false } air-interpreter-sede = { version = "0.1.0", path = "../../../crates/air-lib/interpreter-sede", default-features = false }
avm-server = { version = "0.35.0", path = "../../../avm/server" }
air-test-utils = { version = "0.15.1",path = "../../../crates/air-lib/test-utils", optional = true } air-test-utils = { version = "0.15.1",path = "../../../crates/air-lib/test-utils", optional = true }
clap = { version = "4.4.7", features = ["derive", "env"] } clap = { version = "4.4.7", features = ["derive", "env"] }

View File

@ -55,6 +55,9 @@ pub(crate) struct PlainDataArgs {
#[clap(long = "call-result-size-limit")] #[clap(long = "call-result-size-limit")]
call_result_size_limit: Option<u64>, call_result_size_limit: Option<u64>,
#[clap(long = "hard-limit-enabled", default_value = "false")]
hard_limit_enabled: bool,
} }
pub(crate) fn load(args: &PlainDataArgs) -> eyre::Result<ExecutionData<'_>> { pub(crate) fn load(args: &PlainDataArgs) -> eyre::Result<ExecutionData<'_>> {
@ -80,11 +83,12 @@ pub(crate) fn load(args: &PlainDataArgs) -> eyre::Result<ExecutionData<'_>> {
current_peer_id.into(), current_peer_id.into(),
); );
let test_init_parameters = TestInitParameters { let test_init_parameters = TestInitParameters::new(
air_size_limit: args.air_size_limit, args.air_size_limit,
particle_size_limit: args.particle_size_limit, args.particle_size_limit,
call_result_size_limit: args.call_result_size_limit, args.call_result_size_limit,
}; args.hard_limit_enabled,
);
Ok(ExecutionData { Ok(ExecutionData {
air_script, air_script,

View File

@ -21,14 +21,13 @@ use super::runner::TestInitParameters;
use air_interpreter_interface::CallResultsRepr; use air_interpreter_interface::CallResultsRepr;
use air_interpreter_interface::RunParameters; use air_interpreter_interface::RunParameters;
use avm_interface::raw_outcome::RawAVMOutcome; use avm_interface::raw_outcome::RawAVMOutcome;
use avm_server::AVMRuntimeLimits;
use fluence_keypair::KeyPair; use fluence_keypair::KeyPair;
use std::error::Error as StdError; use std::error::Error as StdError;
pub(crate) struct NativeAvmRunner { pub(crate) struct NativeAvmRunner {
pub air_size_limit: u64, pub avm_runtime_limits: AVMRuntimeLimits,
pub particle_size_limit: u64,
pub call_result_size_limit: u64,
} }
impl AirRunner for NativeAvmRunner { impl AirRunner for NativeAvmRunner {
@ -57,6 +56,12 @@ impl AirRunner for NativeAvmRunner {
let key_format = keypair.key_format().into(); let key_format = keypair.key_format().into();
let secret_key_bytes = keypair.secret().expect("Failed to get secret key"); let secret_key_bytes = keypair.secret().expect("Failed to get secret key");
let AVMRuntimeLimits {
air_size_limit,
particle_size_limit,
call_result_size_limit,
hard_limit_enabled,
} = self.avm_runtime_limits;
let outcome = air::execute_air( let outcome = air::execute_air(
air, air,
@ -67,12 +72,13 @@ impl AirRunner for NativeAvmRunner {
current_peer_id, current_peer_id,
timestamp, timestamp,
ttl, ttl,
air_size_limit: self.air_size_limit,
particle_size_limit: self.particle_size_limit,
call_result_size_limit: self.call_result_size_limit,
key_format, key_format,
secret_key_bytes, secret_key_bytes,
particle_id, particle_id,
air_size_limit,
particle_size_limit,
call_result_size_limit,
hard_limit_enabled,
}, },
raw_call_results, raw_call_results,
); );
@ -91,12 +97,7 @@ impl DataToHumanReadable for NativeAvmRunner {
pub(crate) fn create_native_avm_runner( pub(crate) fn create_native_avm_runner(
test_init_parameters: TestInitParameters, test_init_parameters: TestInitParameters,
) -> eyre::Result<Box<NativeAvmRunner>> { ) -> eyre::Result<Box<NativeAvmRunner>> {
let (air_size_limit, particle_size_limit, call_result_size_limit) = let avm_runtime_limits: AVMRuntimeLimits = test_init_parameters.into();
test_init_parameters.to_attributes_w_default();
Ok(Box::new(NativeAvmRunner { Ok(Box::new(NativeAvmRunner { avm_runtime_limits }))
air_size_limit,
particle_size_limit,
call_result_size_limit,
}))
} }

View File

@ -16,6 +16,8 @@
use avm_interface::raw_outcome::RawAVMOutcome; use avm_interface::raw_outcome::RawAVMOutcome;
use avm_interface::CallResults; use avm_interface::CallResults;
use avm_server::AVMRuntimeLimits;
use avm_server::RuntimeLimits;
use fluence_keypair::KeyPair; use fluence_keypair::KeyPair;
use std::error::Error as StdError; use std::error::Error as StdError;
@ -49,25 +51,54 @@ pub struct TestInitParameters {
pub air_size_limit: Option<u64>, pub air_size_limit: Option<u64>,
pub particle_size_limit: Option<u64>, pub particle_size_limit: Option<u64>,
pub call_result_size_limit: Option<u64>, pub call_result_size_limit: Option<u64>,
pub hard_limit_enabled: bool,
} }
impl TestInitParameters { impl TestInitParameters {
pub fn to_attributes_w_default(&self) -> (u64, u64, u64) { pub fn new(
use air_interpreter_interface::MAX_AIR_SIZE; air_size_limit: Option<u64>,
use air_interpreter_interface::MAX_CALL_RESULT_SIZE; particle_size_limit: Option<u64>,
use air_interpreter_interface::MAX_PARTICLE_SIZE; call_result_size_limit: Option<u64>,
hard_limit_enabled: bool,
let air_size_limit = self.air_size_limit.unwrap_or(MAX_AIR_SIZE); ) -> Self {
let particle_size_limit: u64 = self.particle_size_limit.unwrap_or(MAX_PARTICLE_SIZE); Self {
let call_result_size_limit = self.call_result_size_limit.unwrap_or(MAX_CALL_RESULT_SIZE); air_size_limit,
(air_size_limit, particle_size_limit, call_result_size_limit) particle_size_limit,
call_result_size_limit,
hard_limit_enabled,
}
} }
pub fn no_limits() -> Self { pub fn no_limits() -> Self {
Self { Self {
air_size_limit: Some(u64::MAX), air_size_limit: Some(u64::MAX),
particle_size_limit: Some(u64::MAX), particle_size_limit: Some(u64::MAX),
call_result_size_limit: Some(u64::MAX), call_result_size_limit: Some(u64::MAX),
hard_limit_enabled: false,
} }
} }
} }
impl From<TestInitParameters> for RuntimeLimits {
fn from(value: TestInitParameters) -> Self {
RuntimeLimits::new(
value.air_size_limit,
value.particle_size_limit,
value.call_result_size_limit,
value.hard_limit_enabled,
)
}
}
impl From<TestInitParameters> for AVMRuntimeLimits {
fn from(value: TestInitParameters) -> Self {
use air_interpreter_interface::MAX_AIR_SIZE;
use air_interpreter_interface::MAX_CALL_RESULT_SIZE;
use air_interpreter_interface::MAX_PARTICLE_SIZE;
AVMRuntimeLimits::new(
value.air_size_limit.unwrap_or(MAX_AIR_SIZE),
value.particle_size_limit.unwrap_or(MAX_PARTICLE_SIZE),
value.call_result_size_limit.unwrap_or(MAX_CALL_RESULT_SIZE),
value.hard_limit_enabled,
)
}
}

View File

@ -74,15 +74,10 @@ pub(crate) fn create_wasm_avm_runner(
max_heap_size: Option<u64>, max_heap_size: Option<u64>,
test_init_parameters: TestInitParameters, test_init_parameters: TestInitParameters,
) -> eyre::Result<Box<WasmAvmRunner>> { ) -> eyre::Result<Box<WasmAvmRunner>> {
let (air_size_limit, particle_size_limit, call_result_size_limit) =
test_init_parameters.to_attributes_w_default();
Ok(Box::new(WasmAvmRunner(AVMRunner::new( Ok(Box::new(WasmAvmRunner(AVMRunner::new(
air_interpreter_wasm_path.to_owned(), air_interpreter_wasm_path.to_owned(),
max_heap_size, max_heap_size,
Some(air_size_limit), test_init_parameters.into(),
Some(particle_size_limit),
Some(call_result_size_limit),
0, 0,
)?))) )?)))
} }