mirror of
https://github.com/fluencelabs/aquavm
synced 2024-12-04 15:20:16 +00:00
Fix Par state serialization in xor with inner par (#19)
This commit is contained in:
parent
19ff54e66e
commit
bcb0f18e9e
59
Cargo.lock
generated
59
Cargo.lock
generated
@ -67,7 +67,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "aquamarine-vm"
|
||||
version = "0.1.2"
|
||||
source = "git+https://github.com/fluencelabs/fce#c8114d48c6de55fea75f04c6998df7c685e8ce7b"
|
||||
source = "git+https://github.com/fluencelabs/fce#ddd3448af7b63017f68205c62ec7591888499a70"
|
||||
dependencies = [
|
||||
"fluence-faas",
|
||||
"maplit",
|
||||
@ -638,10 +638,11 @@ checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
|
||||
|
||||
[[package]]
|
||||
name = "fce"
|
||||
version = "0.1.9"
|
||||
source = "git+https://github.com/fluencelabs/fce#c8114d48c6de55fea75f04c6998df7c685e8ce7b"
|
||||
version = "0.1.10"
|
||||
source = "git+https://github.com/fluencelabs/fce#ddd3448af7b63017f68205c62ec7591888499a70"
|
||||
dependencies = [
|
||||
"boolinator",
|
||||
"fce-utils",
|
||||
"fce-wit-interfaces",
|
||||
"fce-wit-parser",
|
||||
"log",
|
||||
@ -657,10 +658,15 @@ dependencies = [
|
||||
"wasmer-wasi-fl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fce-utils"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/fluencelabs/fce#ddd3448af7b63017f68205c62ec7591888499a70"
|
||||
|
||||
[[package]]
|
||||
name = "fce-wit-interfaces"
|
||||
version = "0.1.6"
|
||||
source = "git+https://github.com/fluencelabs/fce#c8114d48c6de55fea75f04c6998df7c685e8ce7b"
|
||||
version = "0.1.7"
|
||||
source = "git+https://github.com/fluencelabs/fce#ddd3448af7b63017f68205c62ec7591888499a70"
|
||||
dependencies = [
|
||||
"multimap",
|
||||
"wasmer-interface-types-fl",
|
||||
@ -668,8 +674,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "fce-wit-parser"
|
||||
version = "0.1.8"
|
||||
source = "git+https://github.com/fluencelabs/fce#c8114d48c6de55fea75f04c6998df7c685e8ce7b"
|
||||
version = "0.1.9"
|
||||
source = "git+https://github.com/fluencelabs/fce#ddd3448af7b63017f68205c62ec7591888499a70"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"fce-wit-interfaces",
|
||||
@ -695,11 +701,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "fluence-faas"
|
||||
version = "0.1.10"
|
||||
source = "git+https://github.com/fluencelabs/fce#c8114d48c6de55fea75f04c6998df7c685e8ce7b"
|
||||
version = "0.1.11"
|
||||
source = "git+https://github.com/fluencelabs/fce#ddd3448af7b63017f68205c62ec7591888499a70"
|
||||
dependencies = [
|
||||
"cmd_lib",
|
||||
"fce",
|
||||
"fce-utils",
|
||||
"fluence-sdk-main 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itertools",
|
||||
"log",
|
||||
@ -714,6 +721,14 @@ dependencies = [
|
||||
"wasmer-wasi-fl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fluence-sdk-macro"
|
||||
version = "0.2.8"
|
||||
source = "git+https://github.com/fluencelabs/rust-sdk#a6c587db0b6f22c3d3af81f10b187f148f8e9d30"
|
||||
dependencies = [
|
||||
"fluence-sdk-wit 0.2.8 (git+https://github.com/fluencelabs/rust-sdk)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fluence-sdk-macro"
|
||||
version = "0.2.8"
|
||||
@ -724,11 +739,13 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fluence-sdk-macro"
|
||||
name = "fluence-sdk-main"
|
||||
version = "0.2.8"
|
||||
source = "git+https://github.com/fluencelabs/rust-sdk#a6c587db0b6f22c3d3af81f10b187f148f8e9d30"
|
||||
dependencies = [
|
||||
"fluence-sdk-wit 0.2.8 (git+https://github.com/fluencelabs/rust-sdk)",
|
||||
"fluence-sdk-macro 0.2.8 (git+https://github.com/fluencelabs/rust-sdk)",
|
||||
"log",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -742,21 +759,10 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fluence-sdk-main"
|
||||
version = "0.2.8"
|
||||
source = "git+https://github.com/fluencelabs/rust-sdk#a6c587db0b6f22c3d3af81f10b187f148f8e9d30"
|
||||
dependencies = [
|
||||
"fluence-sdk-macro 0.2.8 (git+https://github.com/fluencelabs/rust-sdk)",
|
||||
"log",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fluence-sdk-wit"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "560baf91197ded38a99a5c94ff366a3dd971ebf33f5d987ecce31d3dedf86d17"
|
||||
source = "git+https://github.com/fluencelabs/rust-sdk#a6c587db0b6f22c3d3af81f10b187f148f8e9d30"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -769,7 +775,8 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "fluence-sdk-wit"
|
||||
version = "0.2.8"
|
||||
source = "git+https://github.com/fluencelabs/rust-sdk#a6c587db0b6f22c3d3af81f10b187f148f8e9d30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "560baf91197ded38a99a5c94ff366a3dd971ebf33f5d987ecce31d3dedf86d17"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1981,9 +1988,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmer-interface-types-fl"
|
||||
version = "0.17.10"
|
||||
version = "0.17.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1de496e366bd1c198942248fc1de4b94e4647b263dd60099d5f7776f0d621656"
|
||||
checksum = "e916b92f2d315ea27d5ff1d3d6410fe852c51d21bb91a8d1ba7adbf701de7f53"
|
||||
dependencies = [
|
||||
"log",
|
||||
"nom",
|
||||
|
@ -108,13 +108,13 @@ impl<'i> ParsedCall<'i> {
|
||||
use crate::call_evidence::CallResult::*;
|
||||
use crate::call_evidence::EvidenceState::*;
|
||||
|
||||
if call_ctx.current_subtree_elements_count == 0 {
|
||||
if call_ctx.current_subtree_size == 0 {
|
||||
log::info!(target: EVIDENCE_CHANGING, " previous call evidence state wasn't found");
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
call_ctx.current_subtree_elements_count -= 1;
|
||||
// unwrap is safe here, because current_subtree_elements_count depends on current_path len,
|
||||
call_ctx.current_subtree_size -= 1;
|
||||
// unwrap is safe here, because current_subtree_size depends on current_path len,
|
||||
// and it's been checked previously
|
||||
let prev_state = call_ctx.current_path.pop_front().unwrap();
|
||||
|
||||
|
@ -39,12 +39,12 @@ pub(crate) trait ExecutableInstruction<'i> {
|
||||
impl<'i> ExecutableInstruction<'i> for Instruction<'i> {
|
||||
fn execute(&self, exec_ctx: &mut ExecutionCtx<'i>, call_ctx: &mut CallEvidenceCtx) -> Result<()> {
|
||||
match self {
|
||||
Instruction::Seq(seq) => seq.execute(exec_ctx, call_ctx),
|
||||
Instruction::Call(call) => call.execute(exec_ctx, call_ctx),
|
||||
Instruction::Null(null) => null.execute(exec_ctx, call_ctx),
|
||||
Instruction::Fold(fold) => fold.execute(exec_ctx, call_ctx),
|
||||
Instruction::Next(next) => next.execute(exec_ctx, call_ctx),
|
||||
Instruction::Null(null) => null.execute(exec_ctx, call_ctx),
|
||||
Instruction::Par(par) => par.execute(exec_ctx, call_ctx),
|
||||
Instruction::Seq(seq) => seq.execute(exec_ctx, call_ctx),
|
||||
Instruction::Xor(xor) => xor.execute(exec_ctx, call_ctx),
|
||||
Instruction::Error => unreachable!("should not execute if parsing failed. QED."),
|
||||
}
|
||||
@ -84,7 +84,7 @@ macro_rules! log_instruction {
|
||||
log::info!(
|
||||
target: crate::log_targets::SUBTREE_ELEMENTS,
|
||||
" subtree elements count: {:?}",
|
||||
$call_ctx.current_subtree_elements_count
|
||||
$call_ctx.current_subtree_size
|
||||
);
|
||||
log::info!(
|
||||
target: crate::log_targets::NEW_CALL_EVIDENCE_PATH,
|
||||
|
@ -25,37 +25,49 @@ use crate::Result;
|
||||
|
||||
use air_parser::ast::Par;
|
||||
|
||||
enum SubtreeType {
|
||||
Left,
|
||||
Right,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for SubtreeType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Left => write!(f, "left"),
|
||||
Self::Right => write!(f, "right"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'i> ExecutableInstruction<'i> for Par<'i> {
|
||||
fn execute(&self, exec_ctx: &mut ExecutionCtx<'i>, call_ctx: &mut CallEvidenceCtx) -> Result<()> {
|
||||
use SubtreeType::*;
|
||||
|
||||
log_instruction!(par, exec_ctx, call_ctx);
|
||||
|
||||
let (left_subtree_size, right_subtree_size) = extract_subtree_sizes(call_ctx)?;
|
||||
|
||||
let pre_states_count = call_ctx.current_path.len();
|
||||
let pre_unused_elements = call_ctx.current_subtree_elements_count;
|
||||
let before_path_size = call_ctx.current_path.len();
|
||||
let before_subtree_size = call_ctx.current_subtree_size;
|
||||
|
||||
let pre_new_states_count = call_ctx.new_path.len();
|
||||
let par_pos = call_ctx.new_path.len();
|
||||
call_ctx.new_path.push_back(EvidenceState::Par(0, 0));
|
||||
|
||||
let new_left_subtree_size = execute_subtree(&self.0, left_subtree_size, exec_ctx, call_ctx)?;
|
||||
// execute a left subtree of this par
|
||||
execute_subtree(&self.0, left_subtree_size, exec_ctx, call_ctx, par_pos, Left)?;
|
||||
let left_subtree_complete = exec_ctx.subtree_complete;
|
||||
|
||||
let new_right_subtree_size = execute_subtree(&self.1, right_subtree_size, exec_ctx, call_ctx)?;
|
||||
// execute a right subtree of this par
|
||||
execute_subtree(&self.1, right_subtree_size, exec_ctx, call_ctx, par_pos, Right)?;
|
||||
let right_subtree_complete = exec_ctx.subtree_complete;
|
||||
|
||||
// par is completed if at least one of its subtrees is completed
|
||||
exec_ctx.subtree_complete = left_subtree_complete || right_subtree_complete;
|
||||
|
||||
let new_par_evidence_state = EvidenceState::Par(new_left_subtree_size, new_right_subtree_size);
|
||||
log::info!(
|
||||
target: EVIDENCE_CHANGING,
|
||||
" adding new call evidence state {:?}",
|
||||
new_par_evidence_state
|
||||
);
|
||||
call_ctx.new_path[pre_new_states_count] = new_par_evidence_state;
|
||||
|
||||
let post_states_count = call_ctx.current_path.len();
|
||||
call_ctx.current_subtree_elements_count = pre_unused_elements - (pre_states_count - post_states_count);
|
||||
// decrease current subtree size by used elements from current_path
|
||||
let after_path_size = call_ctx.current_path.len();
|
||||
let used_path_elements = before_path_size - after_path_size;
|
||||
call_ctx.current_subtree_size = before_subtree_size - used_path_elements;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -64,11 +76,10 @@ impl<'i> ExecutableInstruction<'i> for Par<'i> {
|
||||
fn extract_subtree_sizes(call_ctx: &mut CallEvidenceCtx) -> Result<(usize, usize)> {
|
||||
use crate::AquamarineError::InvalidEvidenceState;
|
||||
|
||||
if call_ctx.current_subtree_elements_count == 0 {
|
||||
if call_ctx.current_subtree_size == 0 {
|
||||
return Ok((0, 0));
|
||||
}
|
||||
|
||||
call_ctx.current_subtree_elements_count -= 1;
|
||||
call_ctx.current_subtree_size -= 1;
|
||||
|
||||
log::info!(
|
||||
target: EVIDENCE_CHANGING,
|
||||
@ -83,21 +94,36 @@ fn extract_subtree_sizes(call_ctx: &mut CallEvidenceCtx) -> Result<(usize, usize
|
||||
}
|
||||
}
|
||||
|
||||
/// Execute provided subtree and update Par state in call_ctx.new_path.
|
||||
fn execute_subtree<'i>(
|
||||
subtree: &Instruction<'i>,
|
||||
subtree_size: usize,
|
||||
exec_ctx: &mut ExecutionCtx<'i>,
|
||||
call_ctx: &mut CallEvidenceCtx,
|
||||
) -> Result<usize> {
|
||||
call_ctx.current_subtree_elements_count = subtree_size;
|
||||
let before_states_count = call_ctx.new_path.len();
|
||||
current_par_pos: usize,
|
||||
subtree_type: SubtreeType,
|
||||
) -> Result<()> {
|
||||
use crate::AquamarineError::LocalServiceError;
|
||||
|
||||
call_ctx.current_subtree_size = subtree_size;
|
||||
let before_new_path_len = call_ctx.new_path.len();
|
||||
|
||||
exec_ctx.subtree_complete = determine_subtree_complete(&subtree);
|
||||
|
||||
// execute subtree
|
||||
subtree.execute(exec_ctx, call_ctx)?;
|
||||
|
||||
Ok(call_ctx.new_path.len() - before_states_count)
|
||||
match subtree.execute(exec_ctx, call_ctx) {
|
||||
res @ Ok(_) => {
|
||||
update_par_state(call_ctx, subtree_type, current_par_pos, before_new_path_len);
|
||||
res
|
||||
}
|
||||
// if there is a service error, update already added Par state
|
||||
// and then bubble the error up
|
||||
err @ Err(LocalServiceError(_)) => {
|
||||
update_par_state(call_ctx, subtree_type, current_par_pos, before_new_path_len);
|
||||
err
|
||||
}
|
||||
err @ Err(_) => err,
|
||||
}
|
||||
}
|
||||
|
||||
fn determine_subtree_complete(next_instruction: &Instruction<'_>) -> bool {
|
||||
@ -108,10 +134,40 @@ fn determine_subtree_complete(next_instruction: &Instruction<'_>) -> bool {
|
||||
// (next i)
|
||||
// )
|
||||
// )
|
||||
// par will be executed after the last next that wouldn't change subtree_complete
|
||||
// par will be completed after the last next that wouldn't change subtree_complete
|
||||
!matches!(next_instruction, Instruction::Next(_))
|
||||
}
|
||||
|
||||
/// Set left or right fields of a Par identified by current_par_pos.
|
||||
fn update_par_state(
|
||||
call_ctx: &mut CallEvidenceCtx,
|
||||
subtree_type: SubtreeType,
|
||||
current_par_pos: usize,
|
||||
before_new_path_len: usize,
|
||||
) {
|
||||
let new_subtree_size = call_ctx.new_path.len() - before_new_path_len;
|
||||
|
||||
// unwrap is safe here, because this par is added at the beginning of this par instruction.
|
||||
let par_state = call_ctx.new_path.get_mut(current_par_pos).unwrap();
|
||||
match par_state {
|
||||
EvidenceState::Par(left, right) => {
|
||||
if let SubtreeType::Left = subtree_type {
|
||||
*left = new_subtree_size;
|
||||
} else {
|
||||
*right = new_subtree_size;
|
||||
}
|
||||
|
||||
log::info!(
|
||||
target: EVIDENCE_CHANGING,
|
||||
" set {} par subtree size to {}",
|
||||
subtree_type,
|
||||
new_subtree_size
|
||||
);
|
||||
}
|
||||
_ => unreachable!("current_pas_pos must point to a par state"),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use aqua_test_utils::call_vm;
|
||||
|
@ -50,19 +50,15 @@ mod tests {
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
#[test]
|
||||
fn xor() {
|
||||
use crate::call_evidence::CallResult::*;
|
||||
use crate::call_evidence::EvidenceState::*;
|
||||
|
||||
let call_service: HostExportedFunc = Box::new(|_, args| -> Option<IValue> {
|
||||
fn fallible_call_service(fallible_service_id: String) -> HostExportedFunc {
|
||||
Box::new(move |_, args| -> Option<IValue> {
|
||||
let builtin_service = match &args[0] {
|
||||
IValue::String(str) => str,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
if builtin_service == "service_id_1" {
|
||||
// return a error for service with id service_id_1
|
||||
// return a error for service with such id
|
||||
if builtin_service == &fallible_service_id {
|
||||
Some(IValue::Record(
|
||||
Vec1::new(vec![IValue::S32(1), IValue::String(String::from(r#""error""#))]).unwrap(),
|
||||
))
|
||||
@ -72,9 +68,16 @@ mod tests {
|
||||
Vec1::new(vec![IValue::S32(0), IValue::String(String::from(r#""res""#))]).unwrap(),
|
||||
))
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
let mut vm = create_aqua_vm(call_service, "");
|
||||
#[test]
|
||||
fn xor() {
|
||||
use crate::call_evidence::CallResult::*;
|
||||
use crate::call_evidence::EvidenceState::*;
|
||||
|
||||
let fallible_service_id = String::from("service_id_1");
|
||||
let mut vm = create_aqua_vm(fallible_call_service(fallible_service_id), "");
|
||||
|
||||
let script = String::from(
|
||||
r#"
|
||||
@ -111,4 +114,54 @@ mod tests {
|
||||
Call(Executed(Rc::new(JValue::String(String::from("res")))))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn xor_par() {
|
||||
use crate::call_evidence::CallResult::*;
|
||||
use crate::call_evidence::EvidenceState::*;
|
||||
|
||||
let fallible_service_id = String::from("service_id_1");
|
||||
let mut vm = create_aqua_vm(fallible_call_service(fallible_service_id), "");
|
||||
|
||||
let script = String::from(
|
||||
r#"
|
||||
(xor
|
||||
(par
|
||||
(seq
|
||||
(call %current_peer_id% ("service_id_2" "local_fn_name") [] result_1)
|
||||
(call %current_peer_id% ("service_id_2" "local_fn_name") [] result_2)
|
||||
)
|
||||
(par
|
||||
(call %current_peer_id% ("service_id_1" "local_fn_name") [] result_3)
|
||||
(call %current_peer_id% ("service_id_2" "local_fn_name") [] result_4)
|
||||
)
|
||||
)
|
||||
(seq
|
||||
(call %current_peer_id% ("service_id_2" "local_fn_name") [] result_4)
|
||||
(call %current_peer_id% ("service_id_2" "local_fn_name") [] result_5)
|
||||
)
|
||||
)"#,
|
||||
);
|
||||
|
||||
let result = call_vm!(vm, "asd", script.clone(), "[]", "[]");
|
||||
let result_path: CallEvidencePath = serde_json::from_str(&result.data).expect("should be valid json");
|
||||
|
||||
let res = String::from("res");
|
||||
|
||||
let right_path = vec![
|
||||
Par(2, 2),
|
||||
Call(Executed(Rc::new(JValue::String(res.clone())))),
|
||||
Call(Executed(Rc::new(JValue::String(res.clone())))),
|
||||
Par(1, 0),
|
||||
Call(CallServiceFailed(String::from(r#""error""#))),
|
||||
Call(Executed(Rc::new(JValue::String(res.clone())))),
|
||||
Call(Executed(Rc::new(JValue::String(res)))),
|
||||
];
|
||||
|
||||
assert_eq!(result_path, right_path);
|
||||
|
||||
let result = call_vm!(vm, "asd", script, "[]", result.data);
|
||||
let result_path: CallEvidencePath = serde_json::from_str(&result.data).expect("should be valid json");
|
||||
assert_eq!(result_path, right_path);
|
||||
}
|
||||
}
|
||||
|
@ -24,17 +24,17 @@ use std::fmt::Formatter;
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||
pub(crate) struct CallEvidenceCtx {
|
||||
pub(crate) current_path: CallEvidencePath,
|
||||
pub(crate) current_subtree_elements_count: usize,
|
||||
pub(crate) current_subtree_size: usize,
|
||||
// TODO: consider change it to Vec for optimization
|
||||
pub(crate) new_path: CallEvidencePath,
|
||||
}
|
||||
|
||||
impl CallEvidenceCtx {
|
||||
pub fn new(current_path: CallEvidencePath) -> Self {
|
||||
let current_subtree_elements_count = current_path.len();
|
||||
let current_subtree_size = current_path.len();
|
||||
Self {
|
||||
current_path,
|
||||
current_subtree_elements_count,
|
||||
current_subtree_size,
|
||||
new_path: CallEvidencePath::new(),
|
||||
}
|
||||
}
|
||||
@ -43,11 +43,7 @@ impl CallEvidenceCtx {
|
||||
impl Display for CallEvidenceCtx {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
writeln!(f, "current path:\n{:?}", self.current_path)?;
|
||||
writeln!(
|
||||
f,
|
||||
"current subtree elements count:\n{:?}",
|
||||
self.current_subtree_elements_count
|
||||
)?;
|
||||
writeln!(f, "current subtree elements count:\n{:?}", self.current_subtree_size)?;
|
||||
writeln!(f, "new path:\n{:?}", self.new_path)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user