mirror of
https://github.com/fluencelabs/aquavm
synced 2025-04-24 23:02:16 +00:00
307 lines
10 KiB
Rust
307 lines
10 KiB
Rust
/*
|
|
* Copyright 2020 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 aqua_test_utils::call_vm;
|
|
use aqua_test_utils::create_aqua_vm;
|
|
use aqua_test_utils::CallServiceClosure;
|
|
use aqua_test_utils::IValue;
|
|
use aqua_test_utils::NEVec;
|
|
use interpreter_lib::ResolvedTriplet;
|
|
use interpreter_lib::SecurityTetraplet;
|
|
|
|
use std::cell::RefCell;
|
|
use std::rc::Rc;
|
|
|
|
type ArgTetraplets = Vec<Vec<SecurityTetraplet>>;
|
|
|
|
fn arg_host_function() -> (CallServiceClosure, Rc<RefCell<ArgTetraplets>>) {
|
|
let arg_tetraplets = Rc::new(RefCell::new(ArgTetraplets::new()));
|
|
|
|
let arg_tetraplets_inner = arg_tetraplets.clone();
|
|
let host_function: CallServiceClosure = Box::new(move |_, args| -> Option<IValue> {
|
|
let tetraplets = match &args[3] {
|
|
IValue::String(str) => str,
|
|
_ => unreachable!(),
|
|
};
|
|
|
|
let de_tetraplets: ArgTetraplets =
|
|
serde_json::from_str(tetraplets).expect("json deserialization shouldn't fail");
|
|
*arg_tetraplets_inner.borrow_mut() = de_tetraplets;
|
|
|
|
Some(IValue::Record(
|
|
NEVec::new(vec![IValue::S32(0), IValue::String(tetraplets.clone())]).unwrap(),
|
|
))
|
|
});
|
|
|
|
(host_function, arg_tetraplets)
|
|
}
|
|
|
|
#[test]
|
|
fn simple_fold() {
|
|
let return_numbers_call_service: CallServiceClosure = Box::new(|_, _| -> Option<IValue> {
|
|
Some(IValue::Record(
|
|
NEVec::new(vec![
|
|
IValue::S32(0),
|
|
IValue::String(String::from(
|
|
"[\"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"10\"]",
|
|
)),
|
|
])
|
|
.unwrap(),
|
|
))
|
|
});
|
|
|
|
let set_variable_vm_peer_id = String::from("some_peer_id_1");
|
|
let mut set_variable_vm = create_aqua_vm(return_numbers_call_service, set_variable_vm_peer_id.clone());
|
|
|
|
let mut client_vms = Vec::new();
|
|
for i in 1..=10 {
|
|
let (arg_host_func, arg_tetraplets) = arg_host_function();
|
|
let vm = create_aqua_vm(arg_host_func, i.to_string());
|
|
client_vms.push((vm, arg_tetraplets))
|
|
}
|
|
|
|
let service_id = String::from("some_service_id");
|
|
let function_name = String::from("some_function_name");
|
|
let script = format!(
|
|
r#"
|
|
(seq
|
|
(call "{}" ("{}" "{}") [] IterableResultPeer1)
|
|
(fold IterableResultPeer1 i
|
|
(par
|
|
(call i ("local_service_id" "local_fn_name") [i "some_text_literal"] acc[])
|
|
(next i)
|
|
)
|
|
)
|
|
)
|
|
"#,
|
|
set_variable_vm_peer_id, service_id, function_name
|
|
);
|
|
|
|
let init_peer_id = String::from("some_init_peer_id");
|
|
let res = call_vm!(set_variable_vm, init_peer_id.clone(), script.clone(), "", "");
|
|
let mut data = res.data;
|
|
|
|
let first_arg_triplet = ResolvedTriplet {
|
|
peer_pk: set_variable_vm_peer_id,
|
|
service_id,
|
|
function_name,
|
|
};
|
|
let first_arg_triplet = Rc::new(first_arg_triplet);
|
|
let first_arg_tetraplet = SecurityTetraplet {
|
|
triplet: first_arg_triplet,
|
|
json_path: String::new(),
|
|
};
|
|
|
|
let second_arg_triplet = ResolvedTriplet {
|
|
peer_pk: init_peer_id.clone(),
|
|
service_id: String::new(),
|
|
function_name: String::new(),
|
|
};
|
|
let second_arg_triplet = Rc::new(second_arg_triplet);
|
|
let second_arg_tetraplet = SecurityTetraplet {
|
|
triplet: second_arg_triplet,
|
|
json_path: String::new(),
|
|
};
|
|
|
|
let expected_tetraplets = vec![vec![first_arg_tetraplet], vec![second_arg_tetraplet]];
|
|
let expected_tetraplets = Rc::new(RefCell::new(expected_tetraplets));
|
|
for i in 0..10 {
|
|
let res = call_vm!(client_vms[i].0, init_peer_id.clone(), script.clone(), "[]", data);
|
|
data = res.data;
|
|
|
|
assert_eq!(client_vms[i].1, expected_tetraplets);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn fold_json_path() {
|
|
let return_numbers_call_service: CallServiceClosure = Box::new(|_, _| -> Option<IValue> {
|
|
Some(IValue::Record(
|
|
NEVec::new(vec![
|
|
IValue::S32(0),
|
|
IValue::String(String::from(
|
|
"{\"arg\": [\"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"10\"]}",
|
|
)),
|
|
])
|
|
.unwrap(),
|
|
))
|
|
});
|
|
|
|
let set_variable_vm_peer_id = String::from("some_peer_id_1");
|
|
let mut set_variable_vm = create_aqua_vm(return_numbers_call_service, set_variable_vm_peer_id.clone());
|
|
|
|
let (arg_host_func, arg_tetraplets) = arg_host_function();
|
|
let client_peer_id = String::from("client_id");
|
|
let mut client_vm = create_aqua_vm(arg_host_func, client_peer_id.clone());
|
|
|
|
let service_id = String::from("some_service_id");
|
|
let function_name = String::from("some_function_name");
|
|
let script = format!(
|
|
r#"
|
|
(seq
|
|
(call "{}" ("{}" "{}") [] IterableResultPeer1)
|
|
(fold IterableResultPeer1.$.arg i
|
|
(par
|
|
(call "{}" ("local_service_id" "local_fn_name") [i "some_text_literal"] acc[])
|
|
(next i)
|
|
)
|
|
)
|
|
)
|
|
"#,
|
|
set_variable_vm_peer_id, service_id, function_name, client_peer_id
|
|
);
|
|
|
|
let init_peer_id = String::from("some_init_peer_id");
|
|
let res = call_vm!(set_variable_vm, init_peer_id.clone(), script.clone(), "", "");
|
|
|
|
let first_arg_triplet = ResolvedTriplet {
|
|
peer_pk: set_variable_vm_peer_id,
|
|
service_id,
|
|
function_name,
|
|
};
|
|
let first_arg_triplet = Rc::new(first_arg_triplet);
|
|
let first_arg_tetraplet = SecurityTetraplet {
|
|
triplet: first_arg_triplet,
|
|
json_path: String::from("$.arg"),
|
|
};
|
|
|
|
let second_arg_triplet = ResolvedTriplet {
|
|
peer_pk: init_peer_id.clone(),
|
|
service_id: String::new(),
|
|
function_name: String::new(),
|
|
};
|
|
let second_arg_triplet = Rc::new(second_arg_triplet);
|
|
let second_arg_tetraplet = SecurityTetraplet {
|
|
triplet: second_arg_triplet,
|
|
json_path: String::new(),
|
|
};
|
|
|
|
let expected_tetraplets = vec![vec![first_arg_tetraplet], vec![second_arg_tetraplet]];
|
|
let expected_tetraplets = Rc::new(RefCell::new(expected_tetraplets));
|
|
call_vm!(client_vm, init_peer_id.clone(), script.clone(), "[]", res.data);
|
|
assert_eq!(arg_tetraplets, expected_tetraplets);
|
|
}
|
|
|
|
use fluence_app_service::AppService;
|
|
use fluence_app_service::AppServiceConfig;
|
|
use fluence_app_service::FaaSConfig;
|
|
|
|
use interpreter_lib::execution_trace::CallResult;
|
|
use interpreter_lib::execution_trace::ExecutedState;
|
|
use interpreter_lib::execution_trace::ExecutionTrace;
|
|
use std::path::PathBuf;
|
|
|
|
fn construct_service_config(module_name: impl Into<String>) -> AppServiceConfig {
|
|
let module_name = module_name.into();
|
|
let module_path = format!("./tests/security_tetraplets/{}/target/wasm32-wasi/debug/", module_name);
|
|
|
|
let faas_config = FaaSConfig {
|
|
modules_dir: Some(PathBuf::from(module_path)),
|
|
modules_config: vec![(module_name, <_>::default())],
|
|
default_modules_config: None,
|
|
};
|
|
|
|
let service_base_dir = std::env::temp_dir();
|
|
|
|
let config = AppServiceConfig {
|
|
service_base_dir,
|
|
faas_config,
|
|
};
|
|
|
|
config
|
|
}
|
|
|
|
#[test]
|
|
fn tetraplet_with_wasm_modules() {
|
|
use fluence::CallParameters;
|
|
use fluence::SecurityTetraplet as SDKTetraplet;
|
|
|
|
let auth_module_name = String::from("auth_module");
|
|
let auth_service_config = construct_service_config(auth_module_name.clone());
|
|
let auth_service = AppService::new(auth_service_config, auth_module_name.clone(), <_>::default()).unwrap();
|
|
|
|
let log_module_name = String::from("log_storage");
|
|
let log_service_config = construct_service_config(log_module_name.clone());
|
|
let log_service = AppService::new(log_service_config, log_module_name.clone(), <_>::default()).unwrap();
|
|
|
|
let services = maplit::hashmap!(
|
|
"auth" => auth_service,
|
|
"log_storage" => log_service,
|
|
);
|
|
let services = Rc::new(RefCell::new(services));
|
|
|
|
let services_inner = services.clone();
|
|
const ADMIN_PEER_PK: &str = "12D3KooWEXNUbCXooUwHrHBbrmjsrpHXoEphPwbjQXEGyzbqKnE1";
|
|
let host_func: CallServiceClosure = Box::new(move |_, args: Vec<IValue>| -> Option<IValue> {
|
|
let service_id = match &args[0] {
|
|
IValue::String(str) => str,
|
|
_ => unreachable!(),
|
|
};
|
|
|
|
let function_name = match &args[1] {
|
|
IValue::String(str) => str,
|
|
_ => unreachable!(),
|
|
};
|
|
|
|
let service_args = match &args[2] {
|
|
IValue::String(str) => str,
|
|
_ => unreachable!(),
|
|
};
|
|
|
|
let tetraplets = match &args[3] {
|
|
IValue::String(str) => str,
|
|
_ => unreachable!(),
|
|
};
|
|
|
|
let tetraplets: Vec<Vec<SDKTetraplet>> = serde_json::from_str(tetraplets).unwrap();
|
|
|
|
let mut call_parameters = CallParameters::default();
|
|
call_parameters.init_peer_id = ADMIN_PEER_PK.to_string();
|
|
call_parameters.tetraplets = tetraplets;
|
|
|
|
let service_args = serde_json::from_str(service_args).unwrap();
|
|
let mut service = services_inner.borrow_mut();
|
|
let service: &mut AppService = service.get_mut(service_id.as_str()).unwrap();
|
|
|
|
let result = service.call(function_name, service_args, call_parameters).unwrap();
|
|
|
|
Some(IValue::Record(
|
|
NEVec::new(vec![IValue::S32(0), IValue::String(result.to_string())]).unwrap(),
|
|
))
|
|
});
|
|
|
|
let local_peer_id = "local_peer_id";
|
|
let script = format!(
|
|
r#"
|
|
(seq
|
|
(call "{0}" ("auth" "is_authorized") [] auth_result)
|
|
(call "{0}" ("log_storage" "delete") [auth_result.$.is_authorized "1"])
|
|
)
|
|
"#,
|
|
local_peer_id,
|
|
);
|
|
|
|
let mut vm = create_aqua_vm(host_func, local_peer_id);
|
|
|
|
let result = call_vm!(vm, ADMIN_PEER_PK, script, "", "");
|
|
let actual_trace: ExecutionTrace = serde_json::from_slice(&result.data).unwrap();
|
|
let expected_state = ExecutedState::Call(CallResult::Executed(Rc::new(serde_json::Value::String(String::from(
|
|
"Ok",
|
|
)))));
|
|
|
|
assert_eq!(actual_trace[1], expected_state)
|
|
}
|