fix(aquavm): temporary fix entire value in canon (#358)

This commit is contained in:
Mike Voronov 2022-10-10 22:15:28 +03:00 committed by GitHub
parent 076045124c
commit eafdec5d86
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 128 additions and 192 deletions

View File

@ -40,7 +40,7 @@ jobs:
uses: fluencelabs/fluence-js/.github/workflows/tests.yml@master uses: fluencelabs/fluence-js/.github/workflows/tests.yml@master
with: with:
avm-version: ${{ needs.snapshot.outputs.avm-version }} avm-version: "${{ needs.snapshot.outputs.avm-version }}"
fluence-js-snapshot: fluence-js-snapshot:
name: "fluence-js" name: "fluence-js"
@ -49,7 +49,7 @@ jobs:
uses: fluencelabs/fluence-js/.github/workflows/snapshot.yml@master uses: fluencelabs/fluence-js/.github/workflows/snapshot.yml@master
with: with:
avm-version: ${{ needs.snapshot.outputs.avm-version }} avm-version: "${{ needs.snapshot.outputs.avm-version }}"
aqua-snapshot: aqua-snapshot:
name: "aqua" name: "aqua"
@ -58,7 +58,7 @@ jobs:
uses: fluencelabs/aqua/.github/workflows/snapshot.yml@main uses: fluencelabs/aqua/.github/workflows/snapshot.yml@main
with: with:
fluence-js-version: ${{ needs.fluence-js-snapshot.outputs.fluence-js-version }} fluence-js-version: "${{ needs.fluence-js-snapshot.outputs.fluence-js-version }}"
aqua-playground: aqua-playground:
needs: needs:
@ -68,9 +68,9 @@ jobs:
uses: fluencelabs/aqua-playground/.github/workflows/tests.yml@master uses: fluencelabs/aqua-playground/.github/workflows/tests.yml@master
with: with:
fluence-js-version: ${{ needs.fluence-js-snapshot.outputs.fluence-js-version }} fluence-js-version: "${{ needs.fluence-js-snapshot.outputs.fluence-js-version }}"
aqua-version: ${{ needs.aqua-snapshot.outputs.aqua-version }} aqua-version: "${{ needs.aqua-snapshot.outputs.aqua-version }}"
rust-peer-image: ${{ needs.rust-peer.outputs.rust-peer-image }} rust-peer-image: "${{ needs.rust-peer.outputs.rust-peer-image }}"
registry: registry:
needs: needs:
@ -79,7 +79,7 @@ jobs:
uses: fluencelabs/registry/.github/workflows/tests.yml@main uses: fluencelabs/registry/.github/workflows/tests.yml@main
with: with:
aqua-version: ${{ needs.aqua-snapshot.outputs.aqua-version }} aqua-version: "${{ needs.aqua-snapshot.outputs.aqua-version }}"
rust-peer-image: ${{ needs.rust-peer.outputs.rust-peer-image }} rust-peer-image: "${{ needs.rust-peer.outputs.rust-peer-image }}"
# uncomment and change to branch name to run against # uncomment and change to branch name to run against
# ref: some-branch # ref: show-aqua-version

View File

@ -18,15 +18,14 @@ use super::ExecutionCtx;
use super::ExecutionResult; use super::ExecutionResult;
use super::TraceHandler; use super::TraceHandler;
use crate::execution_step::boxed_value::CanonStream; use crate::execution_step::boxed_value::CanonStream;
use crate::execution_step::Generation;
use crate::execution_step::Stream; use crate::execution_step::Stream;
use crate::log_instruction; use crate::log_instruction;
use crate::trace_to_exec_err; use crate::trace_to_exec_err;
use crate::ExecutionError; use crate::ExecutionError;
use crate::JValue;
use crate::UncatchableError; use crate::UncatchableError;
use air_interpreter_data::CanonResult; use air_interpreter_data::CanonResult;
use air_interpreter_data::TracePos;
use air_parser::ast; use air_parser::ast;
use air_trace_handler::merger::MergerCanonResult; use air_trace_handler::merger::MergerCanonResult;
@ -39,8 +38,8 @@ impl<'i> super::ExecutableInstruction<'i> for ast::Canon<'i> {
let canon_result = trace_to_exec_err!(trace_ctx.meet_canon_start(), self)?; let canon_result = trace_to_exec_err!(trace_ctx.meet_canon_start(), self)?;
match canon_result { match canon_result {
MergerCanonResult::CanonResult { stream_elements_pos } => { MergerCanonResult::CanonResult { canonicalized_element } => {
handle_seen_canon(self, stream_elements_pos, exec_ctx, trace_ctx) handle_seen_canon(self, canonicalized_element, exec_ctx, trace_ctx)
} }
MergerCanonResult::Empty => handle_unseen_canon(self, exec_ctx, trace_ctx), MergerCanonResult::Empty => handle_unseen_canon(self, exec_ctx, trace_ctx),
} }
@ -49,17 +48,22 @@ impl<'i> super::ExecutableInstruction<'i> for ast::Canon<'i> {
fn handle_seen_canon( fn handle_seen_canon(
ast_canon: &ast::Canon<'_>, ast_canon: &ast::Canon<'_>,
stream_elements_pos: Vec<TracePos>, se_canon_stream: JValue,
exec_ctx: &mut ExecutionCtx<'_>, exec_ctx: &mut ExecutionCtx<'_>,
trace_ctx: &mut TraceHandler, trace_ctx: &mut TraceHandler,
) -> ExecutionResult<()> { ) -> ExecutionResult<()> {
let canon_stream = create_canon_stream_from_pos(&stream_elements_pos, ast_canon, exec_ctx)?; let canon_stream = serde_json::from_value(se_canon_stream.clone()).map_err(|de_error| {
let stream_with_positions = StreamWithPositions { ExecutionError::Uncatchable(UncatchableError::InvalidCanonStreamInData {
canonicalized_stream: se_canon_stream.clone(),
de_error,
})
})?;
let canon_stream_with_se = StreamWithSerializedView {
canon_stream, canon_stream,
stream_elements_pos, se_canon_stream,
}; };
epilog(ast_canon.canon_stream.name, stream_with_positions, exec_ctx, trace_ctx) epilog(ast_canon.canon_stream.name, canon_stream_with_se, exec_ctx, trace_ctx)
} }
fn handle_unseen_canon( fn handle_unseen_canon(
@ -85,72 +89,43 @@ fn handle_unseen_canon(
epilog(ast_canon.canon_stream.name, stream_with_positions, exec_ctx, trace_ctx) epilog(ast_canon.canon_stream.name, stream_with_positions, exec_ctx, trace_ctx)
} }
fn create_canon_stream_from_pos(
stream_elements_pos: &[TracePos],
ast_canon: &ast::Canon<'_>,
exec_ctx: &ExecutionCtx<'_>,
) -> ExecutionResult<CanonStream> {
let stream = get_stream_or_default(ast_canon, exec_ctx);
let values = stream_elements_pos
.iter()
.map(|&position| {
stream
.get_value_by_pos(position)
.ok_or(ExecutionError::Uncatchable(UncatchableError::VariableNotFoundByPos(
position,
)))
.cloned()
})
.collect::<Result<Vec<_>, _>>()?;
let peer_id = crate::execution_step::air::resolve_to_string(&ast_canon.peer_pk, exec_ctx)?;
let canon_stream = CanonStream::new(values, peer_id);
Ok(canon_stream)
}
fn epilog( fn epilog(
canon_stream_name: &str, canon_stream_name: &str,
stream_with_positions: StreamWithPositions, stream_with_positions: StreamWithSerializedView,
exec_ctx: &mut ExecutionCtx<'_>, exec_ctx: &mut ExecutionCtx<'_>,
trace_ctx: &mut TraceHandler, trace_ctx: &mut TraceHandler,
) -> ExecutionResult<()> { ) -> ExecutionResult<()> {
let StreamWithPositions { let StreamWithSerializedView {
canon_stream, canon_stream,
stream_elements_pos, se_canon_stream,
} = stream_with_positions; } = stream_with_positions;
exec_ctx exec_ctx
.scalars .scalars
.set_canon_value(canon_stream_name, canon_stream) .set_canon_value(canon_stream_name, canon_stream)
.map(|_| ())?; .map(|_| ())?;
trace_ctx.meet_canon_end(CanonResult::new(stream_elements_pos)); trace_ctx.meet_canon_end(CanonResult::new(se_canon_stream));
Ok(()) Ok(())
} }
struct StreamWithPositions { struct StreamWithSerializedView {
canon_stream: CanonStream, canon_stream: CanonStream,
stream_elements_pos: Vec<TracePos>, se_canon_stream: JValue,
} }
fn create_canon_stream_from_name( fn create_canon_stream_from_name(
ast_canon: &ast::Canon<'_>, ast_canon: &ast::Canon<'_>,
peer_id: String, peer_id: String,
exec_ctx: &ExecutionCtx<'_>, exec_ctx: &ExecutionCtx<'_>,
) -> ExecutionResult<StreamWithPositions> { ) -> ExecutionResult<StreamWithSerializedView> {
let stream = get_stream_or_default(ast_canon, exec_ctx); let stream = get_stream_or_default(ast_canon, exec_ctx);
let canon_stream = CanonStream::from_stream(stream.as_ref(), peer_id); let canon_stream = CanonStream::from_stream(stream.as_ref(), peer_id);
let stream_elements_pos = stream let se_canon_stream = serde_json::to_value(&canon_stream).expect("default serialized shouldn't fail");
.iter(Generation::Last)
// it's always safe to iter over all generations
.unwrap()
.map(|value| value.trace_pos)
.collect::<Vec<_>>();
let result = StreamWithPositions { let result = StreamWithSerializedView {
canon_stream, canon_stream,
stream_elements_pos, se_canon_stream,
}; };
Ok(result) Ok(result)

View File

@ -20,12 +20,14 @@ use crate::execution_step::Generation;
use crate::JValue; use crate::JValue;
use polyplets::SecurityTetraplet; use polyplets::SecurityTetraplet;
use serde::Deserialize;
use serde::Serialize;
use std::rc::Rc; use std::rc::Rc;
/// Canon stream is a value type lies between a scalar and a stream, it has the same algebra as /// Canon stream is a value type lies between a scalar and a stream, it has the same algebra as
/// scalars, and represent a stream fixed at some execution point. /// scalars, and represent a stream fixed at some execution point.
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone, Deserialize, Serialize)]
pub struct CanonStream { pub struct CanonStream {
values: Vec<ValueAggregate>, values: Vec<ValueAggregate>,
// tetraplet is needed to handle adding canon streams as a whole to a stream // tetraplet is needed to handle adding canon streams as a whole to a stream
@ -33,15 +35,6 @@ pub struct CanonStream {
} }
impl CanonStream { impl CanonStream {
pub(crate) fn new(values: Vec<ValueAggregate>, peer_pk: String) -> Self {
// tetraplet is comprised only from peer_pk here
let tetraplet = SecurityTetraplet::new(peer_pk, "", "", "");
Self {
values,
tetraplet: Rc::new(tetraplet),
}
}
pub(crate) fn from_stream(stream: &Stream, peer_pk: String) -> Self { pub(crate) fn from_stream(stream: &Stream, peer_pk: String) -> Self {
// it's always possible to iter over all generations of a stream // it's always possible to iter over all generations of a stream
let values = stream.iter(Generation::Last).unwrap().cloned().collect::<Vec<_>>(); let values = stream.iter(Generation::Last).unwrap().cloned().collect::<Vec<_>>();

View File

@ -156,6 +156,7 @@ impl Stream {
Some(JValue::Array(jvalue_array)) Some(JValue::Array(jvalue_array))
} }
#[allow(dead_code)]
pub(crate) fn get_value_by_pos(&self, position: TracePos) -> Option<&ValueAggregate> { pub(crate) fn get_value_by_pos(&self, position: TracePos) -> Option<&ValueAggregate> {
let StreamValueLocation { let StreamValueLocation {
generation, generation,

View File

@ -14,6 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
use crate::JValue;
use crate::ToErrorCode; use crate::ToErrorCode;
use air_interpreter_data::TracePos; use air_interpreter_data::TracePos;
@ -83,6 +84,12 @@ pub enum UncatchableError {
/// as a hard error. /// as a hard error.
#[error("variable with position '{0}' wasn't defined during script execution")] #[error("variable with position '{0}' wasn't defined during script execution")]
VariableNotFoundByPos(TracePos), VariableNotFoundByPos(TracePos),
#[error("can't deserialize stream {canonicalized_stream:?} with error: {de_error}")]
InvalidCanonStreamInData {
canonicalized_stream: JValue,
de_error: serde_json::Error,
},
} }
impl ToErrorCode for UncatchableError { impl ToErrorCode for UncatchableError {

View File

@ -265,7 +265,9 @@ fn canon_with_empty_behaviour() {
let expected_trace = vec![ let expected_trace = vec![
executed_state::par(1, 1), executed_state::par(1, 1),
executed_state::request_sent_by(peer_2_id), executed_state::request_sent_by(peer_2_id),
executed_state::canon(vec![]), executed_state::canon(
json!({"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "peer_2_id", "service_id": ""}, "values": []}),
),
]; ];
assert_eq!(actual_trace, expected_trace); assert_eq!(actual_trace, expected_trace);

View File

@ -133,7 +133,12 @@ fn length_functor_for_canon_stream() {
let expected_trace = vec![ let expected_trace = vec![
executed_state::ap(0), executed_state::ap(0),
executed_state::ap(0), executed_state::ap(0),
executed_state::canon(vec![0.into(), 1.into()]), executed_state::canon(
json!({"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "init_peer_id", "service_id": ""},
"values": [{"result": 1, "tetraplet": {"function_name": "", "json_path": "", "peer_pk": "init_peer_id", "service_id": ""}, "trace_pos": 0},
{"result": 1, "tetraplet": {"function_name": "", "json_path": "", "peer_pk": "init_peer_id", "service_id": ""}, "trace_pos": 1}
]} ),
),
executed_state::scalar_number(2), executed_state::scalar_number(2),
]; ];
assert_eq!(actual_trace, expected_trace); assert_eq!(actual_trace, expected_trace);
@ -157,7 +162,12 @@ fn length_functor_for_empty_canon_stream() {
let result = executor.execute_one(init_peer_id).unwrap(); let result = executor.execute_one(init_peer_id).unwrap();
let actual_trace = trace_from_result(&result); let actual_trace = trace_from_result(&result);
let expected_trace = vec![executed_state::canon(vec![]), executed_state::scalar_number(0)]; let expected_trace = vec![
executed_state::canon(
json!({"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "init_peer_id", "service_id": ""}, "values": []} ),
),
executed_state::scalar_number(0),
];
assert_eq!(actual_trace, expected_trace); assert_eq!(actual_trace, expected_trace);
} }

View File

@ -236,7 +236,11 @@ fn ap_canon_stream_with_lambda() {
let expected_state = vec![ let expected_state = vec![
executed_state::stream_number(0, 0), executed_state::stream_number(0, 0),
executed_state::stream_number(1, 1), executed_state::stream_number(1, 1),
executed_state::canon(vec![0.into(), 1.into()]), executed_state::canon(
json!({"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "vm_1_peer_id", "service_id": ""},
"values": [{"result": 0, "tetraplet": {"function_name": "", "json_path": "", "peer_pk": "vm_1_peer_id", "service_id": ""}, "trace_pos": 0},
{"result": 1, "tetraplet": {"function_name": "some_function_name", "json_path": "", "peer_pk": "vm_1_peer_id", "service_id": "some_service_name"}, "trace_pos": 1}]}),
),
executed_state::ap(0), executed_state::ap(0),
executed_state::scalar(json!([1])), executed_state::scalar(json!([1])),
]; ];
@ -277,7 +281,11 @@ fn ap_canon_stream() {
let expected_state = vec![ let expected_state = vec![
executed_state::stream_number(0, 0), executed_state::stream_number(0, 0),
executed_state::stream_number(1, 1), executed_state::stream_number(1, 1),
executed_state::canon(vec![0.into(), 1.into()]), executed_state::canon(
json!({"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "vm_1_peer_id", "service_id": ""},
"values": [{"result": 0, "tetraplet": {"function_name": "", "json_path": "", "peer_pk": "vm_1_peer_id", "service_id": ""}, "trace_pos": 0},
{"result": 1, "tetraplet": {"function_name": "some_function_name", "json_path": "", "peer_pk": "vm_1_peer_id", "service_id": "some_service_name"}, "trace_pos": 1}]}),
),
executed_state::ap(0), executed_state::ap(0),
executed_state::scalar(json!([[0, 1]])), executed_state::scalar(json!([[0, 1]])),
]; ];

View File

@ -18,7 +18,6 @@ use air_test_utils::prelude::*;
use fstrings::f; use fstrings::f;
use fstrings::format_args_f; use fstrings::format_args_f;
use pretty_assertions::assert_eq;
use std::ops::Deref; use std::ops::Deref;
@ -62,7 +61,14 @@ fn basic_canon() {
let result = checked_call_vm!(vm, <_>::default(), script, "", result.data); let result = checked_call_vm!(vm, <_>::default(), script, "", result.data);
let actual_state = &trace_from_result(&result)[6.into()]; let actual_state = &trace_from_result(&result)[6.into()];
let expected_state = executed_state::canon(vec![1.into(), 2.into(), 3.into(), 4.into(), 5.into()]); let expected_state = executed_state::canon(
json!({"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "A", "service_id": ""},
"values": [{"result": "1", "tetraplet": {"function_name": "", "json_path": "", "peer_pk": "A", "service_id": ""}, "trace_pos": 1},
{"result": "2", "tetraplet": {"function_name": "", "json_path": "", "peer_pk": "A", "service_id": ""}, "trace_pos": 2},
{"result": "3", "tetraplet": {"function_name": "", "json_path": "", "peer_pk": "A", "service_id": ""}, "trace_pos": 3},
{"result": "4", "tetraplet": {"function_name": "", "json_path": "", "peer_pk": "A", "service_id": ""}, "trace_pos": 4},
{"result": "5", "tetraplet": {"function_name": "", "json_path": "", "peer_pk": "A", "service_id": ""}, "trace_pos": 5}]}),
);
assert_eq!(actual_state, &expected_state); assert_eq!(actual_state, &expected_state);
} }
@ -106,7 +112,11 @@ fn canon_fixes_stream_correct() {
executed_state::stream_number(2, 0), executed_state::stream_number(2, 0),
executed_state::stream_number(3, 1), executed_state::stream_number(3, 1),
executed_state::scalar_number(4), executed_state::scalar_number(4),
executed_state::canon(vec![3.into(), 4.into()]), executed_state::canon(
json!({"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "peer_id_3", "service_id": ""},
"values": [{"result": 2, "tetraplet": {"function_name": "", "json_path": "", "peer_pk": "peer_id_2", "service_id": ""}, "trace_pos": 3},
{"result": 3, "tetraplet": {"function_name": "", "json_path": "", "peer_pk": "peer_id_3", "service_id": ""}, "trace_pos": 4}]}),
),
executed_state::par(1, 1), executed_state::par(1, 1),
executed_state::scalar(json!([2, 3])), executed_state::scalar(json!([2, 3])),
executed_state::request_sent_by(peer_id_3), executed_state::request_sent_by(peer_id_3),
@ -122,7 +132,11 @@ fn canon_fixes_stream_correct() {
executed_state::stream_number(2, 1), executed_state::stream_number(2, 1),
executed_state::stream_number(3, 2), executed_state::stream_number(3, 2),
executed_state::scalar_number(4), executed_state::scalar_number(4),
executed_state::canon(vec![3.into(), 4.into()]), executed_state::canon(
json!({"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "peer_id_3", "service_id": ""},
"values": [{"result": 2, "tetraplet": {"function_name": "", "json_path": "", "peer_pk": "peer_id_2", "service_id": ""}, "trace_pos": 3},
{"result": 3, "tetraplet": {"function_name": "", "json_path": "", "peer_pk": "peer_id_3", "service_id": ""}, "trace_pos": 4}]}),
),
executed_state::par(1, 1), executed_state::par(1, 1),
executed_state::scalar(json!([2, 3])), executed_state::scalar(json!([2, 3])),
executed_state::scalar(json!([2, 3])), executed_state::scalar(json!([2, 3])),
@ -228,12 +242,22 @@ fn canon_empty_stream() {
let result = checked_call_vm!(vm_1, <_>::default(), &script, "", ""); let result = checked_call_vm!(vm_1, <_>::default(), &script, "", "");
let actual_trace = trace_from_result(&result); let actual_trace = trace_from_result(&result);
let expected_trace = vec![executed_state::canon(vec![]), executed_state::scalar(json!([]))]; let expected_trace = vec![
executed_state::canon(
json!({"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "peer_id_1", "service_id": ""}, "values": []}),
),
executed_state::scalar(json!([])),
];
assert_eq!(actual_trace, expected_trace); assert_eq!(actual_trace, expected_trace);
let result = checked_call_vm!(vm_2, <_>::default(), script, "", result.data); let result = checked_call_vm!(vm_2, <_>::default(), script, "", result.data);
let actual_trace = trace_from_result(&result); let actual_trace = trace_from_result(&result);
let expected_trace = vec![executed_state::canon(vec![]), executed_state::scalar(json!([]))]; let expected_trace = vec![
executed_state::canon(
json!({"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "peer_id_1", "service_id": ""}, "values": []} ),
),
executed_state::scalar(json!([])),
];
assert_eq!(actual_trace, expected_trace); assert_eq!(actual_trace, expected_trace);
} }
@ -248,7 +272,9 @@ fn canon_empty_not_writable_stream() {
let result = checked_call_vm!(vm, <_>::default(), &script, "", ""); let result = checked_call_vm!(vm, <_>::default(), &script, "", "");
let actual_trace = trace_from_result(&result); let actual_trace = trace_from_result(&result);
let expected_trace = vec![executed_state::canon(vec![])]; let expected_trace = vec![executed_state::canon(
json!({"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "peer_id", "service_id": ""}, "values": []} ),
)];
assert_eq!(actual_trace, expected_trace); assert_eq!(actual_trace, expected_trace);
} }
@ -281,7 +307,9 @@ fn canon_over_later_defined_stream() {
let expected_trace = vec![ let expected_trace = vec![
executed_state::par(1, 2), executed_state::par(1, 2),
executed_state::stream_number(1, 0), executed_state::stream_number(1, 0),
executed_state::canon(vec![]), executed_state::canon(
json!({"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "vm_peer_id_1", "service_id": ""},"values": []}),
),
executed_state::scalar(json!([])), executed_state::scalar(json!([])),
]; ];
assert_eq!(actual_trace, expected_trace); assert_eq!(actual_trace, expected_trace);

View File

@ -582,7 +582,9 @@ fn fold_scalar_seq_next_completes_with_null() {
executed_state::stream(service_result.clone(), 0), executed_state::stream(service_result.clone(), 0),
executed_state::par(1, 0), executed_state::par(1, 0),
executed_state::stream(service_result.clone(), 0), executed_state::stream(service_result.clone(), 0),
executed_state::canon(vec![]), executed_state::canon(
json!({"tetraplet": {"function_name": "", "json_path": "", "peer_pk": "vm_peer_id", "service_id": ""}, "values": []}),
),
executed_state::scalar(service_result), executed_state::scalar(service_result),
]; ];
assert_eq!(actual_trace, expected_trace); assert_eq!(actual_trace, expected_trace);

View File

@ -128,8 +128,7 @@ pub struct ApResult {
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
pub struct CanonResult { pub struct CanonResult {
#[serde(rename = "ids")] pub canonicalized_element: JValue,
pub stream_elements_pos: Vec<TracePos>,
} }
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]

View File

@ -87,9 +87,9 @@ impl ApResult {
} }
impl CanonResult { impl CanonResult {
pub fn new(stream_elements_pos: Vec<TracePos>) -> Self { pub fn new(canonicalized_element: JValue) -> Self {
Self { Self {
stream_elements_pos, canonicalized_element,
} }
} }
} }
@ -129,8 +129,8 @@ impl std::fmt::Display for ExecutedState {
Ap(ap) => { Ap(ap) => {
write!(f, "ap: _ -> {:?}", ap.res_generations) write!(f, "ap: _ -> {:?}", ap.res_generations)
} }
Canon(canon) => { Canon(_) => {
write!(f, "canon {:?}", canon.stream_elements_pos) write!(f, "canon [<object>]")
} }
} }
} }

View File

@ -137,7 +137,7 @@ pub fn ap(generation: u32) -> ExecutedState {
ExecutedState::Ap(ap_result) ExecutedState::Ap(ap_result)
} }
pub fn canon(stream_elements_pos: Vec<TracePos>) -> ExecutedState { pub fn canon(canonicalized_element: JValue) -> ExecutedState {
let canon_result = CanonResult::new(stream_elements_pos); let canon_result = CanonResult::new(canonicalized_element);
ExecutedState::Canon(canon_result) ExecutedState::Canon(canon_result)
} }

View File

@ -17,7 +17,7 @@
use super::*; use super::*;
use crate::merger::errors::CanonResultError; use crate::merger::errors::CanonResultError;
use bimap::BiHashMap; use serde_json::Value as JValue;
const EXPECTED_STATE_NAME: &str = "canon"; const EXPECTED_STATE_NAME: &str = "canon";
@ -28,8 +28,7 @@ pub enum MergerCanonResult {
/// There was a state in at least one of the contexts. If there were two states in /// There was a state in at least one of the contexts. If there were two states in
/// both contexts, they were successfully merged. /// both contexts, they were successfully merged.
/// Positions correspond to a new data trace. CanonResult { canonicalized_element: JValue },
CanonResult { stream_elements_pos: Vec<TracePos> },
} }
pub(crate) fn try_merge_next_state_as_canon(data_keeper: &mut DataKeeper) -> MergeResult<MergerCanonResult> { pub(crate) fn try_merge_next_state_as_canon(data_keeper: &mut DataKeeper) -> MergeResult<MergerCanonResult> {
@ -39,13 +38,9 @@ pub(crate) fn try_merge_next_state_as_canon(data_keeper: &mut DataKeeper) -> Mer
let current_state = data_keeper.current_slider_mut().next_state(); let current_state = data_keeper.current_slider_mut().next_state();
match (prev_state, current_state) { match (prev_state, current_state) {
(Some(Canon(prev_canon)), Some(Canon(current_canon))) => { (Some(Canon(prev_canon)), Some(Canon(current_canon))) => prepare_both_canon_result(prev_canon, &current_canon),
prepare_both_canon_result(&prev_canon, &current_canon, data_keeper) (Some(Canon(prev_canon)), None) => prepare_single_canon_result(prev_canon),
} (None, Some(Canon(current_canon))) => prepare_single_canon_result(current_canon),
(Some(Canon(prev_canon)), None) => prepare_single_canon_result(&prev_canon, &data_keeper.new_to_prev_pos),
(None, Some(Canon(current_canon))) => {
prepare_single_canon_result(&current_canon, &data_keeper.new_to_current_pos)
}
(None, None) => Ok(MergerCanonResult::Empty), (None, None) => Ok(MergerCanonResult::Empty),
(prev_state, current_state) => Err(MergeError::incompatible_states( (prev_state, current_state) => Err(MergeError::incompatible_states(
prev_state, prev_state,
@ -56,78 +51,29 @@ pub(crate) fn try_merge_next_state_as_canon(data_keeper: &mut DataKeeper) -> Mer
} }
fn prepare_both_canon_result( fn prepare_both_canon_result(
prev_canon_result: &CanonResult, prev_canon_result: CanonResult,
current_canon_result: &CanonResult, current_canon_result: &CanonResult,
data_keeper: &DataKeeper,
) -> MergeResult<MergerCanonResult> { ) -> MergeResult<MergerCanonResult> {
check_canon_results(prev_canon_result, current_canon_result, data_keeper) check_canon_results(&prev_canon_result, current_canon_result).map_err(MergeError::IncorrectCanonResult)?;
.map_err(MergeError::IncorrectCanonResult)?; prepare_single_canon_result(prev_canon_result)
prepare_single_canon_result(prev_canon_result, &data_keeper.new_to_prev_pos)
} }
fn prepare_single_canon_result( fn prepare_single_canon_result(canon_result: CanonResult) -> MergeResult<MergerCanonResult> {
canon_result: &CanonResult,
new_to_other_pos: &BiHashMap<TracePos, TracePos>,
) -> MergeResult<MergerCanonResult> {
let new_positions = canon_result
.stream_elements_pos
.iter()
.map(|pos| {
new_to_other_pos
.get_by_right(pos)
.cloned()
.ok_or_else(|| CanonResultError::not_met_position(canon_result.clone(), *pos))
})
.collect::<Result<Vec<_>, _>>()?;
Ok(MergerCanonResult::CanonResult { Ok(MergerCanonResult::CanonResult {
stream_elements_pos: new_positions, canonicalized_element: canon_result.canonicalized_element,
}) })
} }
fn check_canon_results( fn check_canon_results(
prev_canon_result: &CanonResult, prev_canon_result: &CanonResult,
current_canon_result: &CanonResult, current_canon_result: &CanonResult,
data_keeper: &DataKeeper,
) -> Result<(), CanonResultError> { ) -> Result<(), CanonResultError> {
if prev_canon_result.stream_elements_pos.len() != current_canon_result.stream_elements_pos.len() { if prev_canon_result.canonicalized_element != current_canon_result.canonicalized_element {
return Err(CanonResultError::different_lens( return Err(CanonResultError::incompatible_state(
prev_canon_result.clone(), prev_canon_result.clone(),
current_canon_result.clone(), current_canon_result.clone(),
)); ));
} }
let prev_slider = data_keeper.prev_slider();
let current_slider = data_keeper.current_slider();
for (position, (prev_idx, current_idx)) in prev_canon_result
.stream_elements_pos
.iter()
.zip(current_canon_result.stream_elements_pos.iter())
.enumerate()
{
let prev_state = prev_slider.state_at_position(*prev_idx);
let current_state = current_slider.state_at_position(*current_idx);
match (prev_state, current_state) {
(Some(ExecutedState::Call(prev_call_result)), Some(ExecutedState::Call(current_call_result)))
if prev_call_result == current_call_result =>
{
continue;
}
(Some(ExecutedState::Ap(_)), Some(ExecutedState::Ap(_))) => {
continue;
}
_ => {
return Err(CanonResultError::incompatible_state(
prev_canon_result.clone(),
current_canon_result.clone(),
prev_state.cloned(),
current_state.cloned(),
position,
))
}
}
}
Ok(()) Ok(())
} }

View File

@ -75,25 +75,10 @@ pub enum CallResultError {
#[derive(ThisError, Debug)] #[derive(ThisError, Debug)]
pub enum CanonResultError { pub enum CanonResultError {
#[error("canon results have different length: {prev_canon_result:?} != {current_canon_result:?}")] #[error("canon results {prev_canon_result:?} {current_canon_result:?} points to incompatible execution states")]
LensNotEqual {
prev_canon_result: CanonResult,
current_canon_result: CanonResult,
},
#[error("canon results {prev_canon_result:?} {current_canon_result:?} at position {position} points to incompatible execution states: {prev_state:?} {current_state:?}")]
IncompatibleState { IncompatibleState {
prev_canon_result: CanonResult, prev_canon_result: CanonResult,
current_canon_result: CanonResult, current_canon_result: CanonResult,
prev_state: Option<ExecutedState>,
current_state: Option<ExecutedState>,
position: usize,
},
#[error("position {position} from canon result {canon_result:?} hasn't been met yet")]
NotMetPosition {
canon_result: CanonResult,
position: TracePos,
}, },
} }
@ -155,32 +140,12 @@ impl CallResultError {
} }
impl CanonResultError { impl CanonResultError {
pub(crate) fn different_lens(prev_canon_result: CanonResult, current_canon_result: CanonResult) -> Self { pub(crate) fn incompatible_state(prev_canon_result: CanonResult, current_canon_result: CanonResult) -> Self {
Self::LensNotEqual {
prev_canon_result,
current_canon_result,
}
}
pub(crate) fn incompatible_state(
prev_canon_result: CanonResult,
current_canon_result: CanonResult,
prev_state: Option<ExecutedState>,
current_state: Option<ExecutedState>,
position: usize,
) -> Self {
Self::IncompatibleState { Self::IncompatibleState {
prev_canon_result, prev_canon_result,
current_canon_result, current_canon_result,
prev_state,
current_state,
position,
} }
} }
pub(crate) fn not_met_position(canon_result: CanonResult, position: TracePos) -> Self {
Self::NotMetPosition { canon_result, position }
}
} }
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]