aquavm/stepper/src/execution.rs

148 lines
4.8 KiB
Rust
Raw Normal View History

/*
* 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 super::StepperOutcome;
use crate::air::ExecutableInstruction;
2020-10-15 17:31:56 +03:00
use crate::air::ExecutionCtx;
use crate::air::Instruction;
2020-10-15 17:31:56 +03:00
use crate::call_evidence::EvidenceState;
2020-10-08 14:27:59 +03:00
use crate::get_current_peer_id;
use crate::AquaData;
use crate::AquamarineError;
use crate::Result;
2020-10-15 17:31:56 +03:00
use crate::call_evidence::CallEvidenceCtx;
use std::collections::VecDeque;
pub(crate) fn execute_aqua(init_user_id: String, aqua: String, data: String) -> StepperOutcome {
log::info!(
"stepper invoked with user_id = {}, aqua = {:?}, data = {:?}",
init_user_id,
aqua,
data
);
execute_aqua_impl(init_user_id, aqua, data).unwrap_or_else(Into::into)
}
fn execute_aqua_impl(_init_user_id: String, aqua: String, data: String) -> Result<StepperOutcome> {
2020-10-15 17:31:56 +03:00
let mut parsed_data: AquaData =
serde_json::from_str(&data).map_err(AquamarineError::DataDeserializationError)?;
let formatted_aqua = format_aqua(aqua);
let parsed_aqua = serde_sexpr::from_str::<Instruction>(&formatted_aqua)?;
log::info!(
"\nparsed_aqua: {:?}\nparsed_data: {:?}",
parsed_aqua,
parsed_data
);
2020-10-08 14:27:59 +03:00
let current_peer_id = get_current_peer_id()
.map_err(|e| AquamarineError::CurrentPeerIdEnvError(e, String::from("CURRENT_PEER_ID")))?;
2020-10-15 17:31:56 +03:00
let call_evidence_ctx_key: &str = "__call";
let current_states: VecDeque<EvidenceState> = match parsed_data.remove(call_evidence_ctx_key) {
Some(jvalue) => serde_json::from_value(jvalue)
.map_err(AquamarineError::CallEvidenceDeserializationError)?,
None => VecDeque::new(),
};
let mut execution_ctx = ExecutionCtx::new(parsed_data, current_peer_id);
let mut call_evidence_ctx = CallEvidenceCtx::new(current_states);
parsed_aqua.execute(&mut execution_ctx, &mut call_evidence_ctx)?;
let serialized_call_ctx = serde_json::to_value(call_evidence_ctx.new_states)
.map_err(AquamarineError::CallEvidenceSerializationError)?;
execution_ctx
.data
.insert(call_evidence_ctx_key.to_string(), serialized_call_ctx);
2020-10-15 17:31:56 +03:00
let data = serde_json::to_string(&execution_ctx.data)
.map_err(AquamarineError::DataSerializationError)?;
Ok(StepperOutcome {
ret_code: 0,
data,
2020-10-15 17:31:56 +03:00
next_peer_pks: dedup(execution_ctx.next_peer_pks),
})
}
/// Formats aqua script in a form of S-expressions to a form compatible with the serde_sexpr crate.
fn format_aqua(aqua: String) -> String {
use std::iter::FromIterator;
let mut formatted_aqua = Vec::with_capacity(aqua.len());
// whether to skip the next whitespace
let mut skip_next_whitespace = false;
// whether c was a closing brace
let mut was_cbr = false;
for c in aqua.chars() {
let is_whitespace = c == ' ';
if (skip_next_whitespace && is_whitespace) || c == '\n' {
continue;
}
let is_cbr = c == ')';
skip_next_whitespace = is_whitespace || c == '(' || is_cbr;
if was_cbr && !is_cbr {
formatted_aqua.push(' ');
}
was_cbr = is_cbr;
formatted_aqua.push(c)
}
String::from_iter(formatted_aqua.into_iter())
}
2020-10-15 17:31:56 +03:00
use std::hash::Hash;
fn dedup<T: Eq + Hash>(mut vec: Vec<T>) -> Vec<T> {
use std::collections::HashSet;
let set: HashSet<_> = vec.drain(..).collect(); // dedup
set.into_iter().collect()
}
#[cfg(test)]
mod tests {
#[test]
fn format_aqua_test() {
let aqua = format!(
r#"(( (( (seq (
(call (%current_peer_id% (add_module ||) (module) module))
(seq (
(call (%current_peer_id% (add_blueprint ||) (blueprint) blueprint_id))
(seq (
(call (%current_peer_id% (create ||) (blueprint_id) service_id))
(call ({} (|| ||) (service_id) client_result))
) )
) )
))"#,
"abc"
);
let aqua = super::format_aqua(aqua);
let formatted_aqua = String::from("(((((seq ((call (%current_peer_id% (add_module ||) (module) module)) (seq ((call (%current_peer_id% (add_blueprint ||) (blueprint) blueprint_id)) (seq ((call (%current_peer_id% (create ||) (blueprint_id) service_id)) (call (abc (|| ||) (service_id) client_result))))))))");
assert_eq!(aqua, formatted_aqua);
}
}