Introduce %ttl% (#253)

This commit is contained in:
Mike Voronov 2022-04-21 11:44:18 +03:00 committed by GitHub
parent 490791b177
commit 7e0c87d72a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 1155 additions and 845 deletions

View File

@ -1,5 +1,10 @@
## Version 0.24.0 (2021-04-21)
[PR 253](https://github.com/fluencelabs/aquavm/pull/253):
Introduced %ttl% keyword
## Version 0.24.0 (2021-04-20)
[PR 250](https://github.com/fluencelabs/aquavm/pull/250):
Introduced %timestamp% keyword

4
Cargo.lock generated
View File

@ -75,7 +75,7 @@ dependencies = [
[[package]]
name = "air-interpreter-interface"
version = "0.9.0"
version = "0.10.0"
dependencies = [
"fluence-it-types",
"marine-rs-sdk",
@ -216,7 +216,7 @@ version = "0.1.0"
[[package]]
name = "avm-server"
version = "0.19.0"
version = "0.20.0"
dependencies = [
"air-interpreter-interface",
"avm-data-store",

View File

@ -1,6 +1,6 @@
[package]
name = "air-interpreter"
version = "0.23.0"
version = "0.24.0"
description = "Crate-wrapper for air"
authors = ["Fluence Labs"]
edition = "2018"

View File

@ -1,6 +1,6 @@
[package]
name = "air"
version = "0.23.0"
version = "0.24.0"
description = "Interpreter of AIR scripts intended to coordinate request flow in the Fluence network"
authors = ["Fluence Labs"]
edition = "2018"

View File

@ -31,6 +31,7 @@ pub(super) fn apply_to_arg(
LastError(error_accessor) => apply_last_error(error_accessor, exec_ctx, trace_ctx)?,
Literal(value) => apply_const(*value, exec_ctx, trace_ctx),
Timestamp => apply_const(exec_ctx.run_parameters.timestamp, exec_ctx, trace_ctx),
TTL => apply_const(exec_ctx.run_parameters.ttl, exec_ctx, trace_ctx),
Number(value) => apply_const(value, exec_ctx, trace_ctx),
Boolean(value) => apply_const(*value, exec_ctx, trace_ctx),
EmptyArray => apply_const(serde_json::json!([]), exec_ctx, trace_ctx),

View File

@ -54,6 +54,13 @@ pub(crate) fn are_matchable_eq<'ctx>(
make_object_comparator(JValue::Number(exec_ctx.run_parameters.timestamp.into())),
),
(TTL, TTL) => Ok(true),
(TTL, matchable) | (matchable, TTL) => compare_matchable(
matchable,
exec_ctx,
make_object_comparator(JValue::Number(exec_ctx.run_parameters.ttl.into())),
),
(EmptyArray, EmptyArray) => Ok(true),
(EmptyArray, matchable) | (matchable, EmptyArray) => {
compare_matchable(matchable, exec_ctx, make_object_comparator(JValue::Array(vec![])))
@ -106,6 +113,10 @@ fn compare_matchable<'ctx>(
let jvalue = exec_ctx.run_parameters.timestamp.into();
Ok(comparator(Cow::Owned(jvalue)))
}
TTL => {
let jvalue = exec_ctx.run_parameters.ttl.into();
Ok(comparator(Cow::Owned(jvalue)))
}
Number(number) => {
let jvalue = number.into();
Ok(comparator(Cow::Owned(jvalue)))

View File

@ -98,6 +98,7 @@ pub(crate) struct RcRunParameters {
pub(crate) init_peer_id: Rc<String>,
pub(crate) current_peer_id: Rc<String>,
pub(crate) timestamp: u64,
pub(crate) ttl: u32,
}
impl RcRunParameters {
@ -106,6 +107,7 @@ impl RcRunParameters {
init_peer_id: Rc::new(run_parameters.init_peer_id),
current_peer_id: Rc::new(run_parameters.current_peer_id),
timestamp: run_parameters.timestamp,
ttl: run_parameters.ttl,
}
}
}

View File

@ -41,6 +41,7 @@ pub(crate) fn resolve_to_args<'i>(
LastError(error_accessor) => prepare_last_error(error_accessor, ctx),
Literal(value) => prepare_const(value.to_string(), ctx),
Timestamp => prepare_const(ctx.run_parameters.timestamp, ctx),
TTL => prepare_const(ctx.run_parameters.ttl, ctx),
Boolean(value) => prepare_const(*value, ctx),
Number(value) => prepare_const(value, ctx),
EmptyArray => prepare_const(json!([]), ctx),

View File

@ -157,6 +157,27 @@ fn ap_with_timestamp() {
assert_eq!(actual_trace, expected_state);
}
#[test]
fn ap_with_ttl() {
let vm_1_peer_id = "vm_1_peer_id";
let mut vm_1 = create_avm(echo_call_service(), vm_1_peer_id);
let script = f!(r#"
(seq
(ap %ttl% scalar)
(call "{vm_1_peer_id}" ("" "") [scalar])
)
"#);
let test_params = TestRunParameters::from_ttl(1337);
let result = checked_call_vm!(vm_1, test_params.clone(), script, "", "");
let actual_trace = trace_from_result(&result);
let expected_state = vec![executed_state::scalar_number(test_params.ttl)];
assert_eq!(actual_trace, expected_state);
}
#[test]
fn ap_with_dst_stream() {
let vm_1_peer_id = "vm_1_peer_id";

View File

@ -57,7 +57,7 @@ fn call_with_timestamp() {
let script = r#"(call %init_peer_id% ("" "") [%timestamp%] result_name)"#;
let test_params = TestRunParameters::new(vm_peer_id, 1337);
let test_params = TestRunParameters::new(vm_peer_id, 1337, 0);
let result = checked_call_vm!(vm, test_params.clone(), script, "", "");
let actual_trace = trace_from_result(&result);
@ -66,6 +66,22 @@ fn call_with_timestamp() {
assert_eq!(actual_trace, expected_trace);
}
#[test]
fn call_with_ttl() {
let vm_peer_id = "test_peer_id";
let mut vm = create_avm(echo_call_service(), vm_peer_id);
let script = f!(r#"(call "{vm_peer_id}" ("" "") [%ttl%] result_name)"#);
let test_params = TestRunParameters::from_ttl(1337);
let result = checked_call_vm!(vm, test_params.clone(), script, "", "");
let actual_trace = trace_from_result(&result);
let expected_trace = vec![executed_state::scalar_number(test_params.ttl)];
assert_eq!(actual_trace, expected_trace);
}
// Check that specifying remote peer id in call will result its appearing in next_peer_pks.
#[test]
fn remote_peer_id_call() {

View File

@ -171,6 +171,37 @@ fn match_with_timestamp() {
assert_eq!(actual_trace[1], expected_executed_call_result);
}
#[test]
fn match_with_ttl() {
let set_variable_peer_id = "set_variable_peer_id";
let mut set_variable_vm = create_avm(echo_call_service(), set_variable_peer_id);
let local_peer_id = "local_peer_id";
let mut vm = create_avm(echo_call_service(), local_peer_id);
let ttl = 1337;
let script = f!(r#"
(seq
(call "{set_variable_peer_id}" ("" "") [{ttl}] value_1)
(xor
(match value_1 %ttl%
(call "{local_peer_id}" ("service_id_2" "local_fn_name") ["result_1"] result_1)
)
(call "{local_peer_id}" ("service_id_2" "local_fn_name") ["result_2"] result_2)
)
)"#);
let test_params = TestRunParameters::from_ttl(ttl);
let result = checked_call_vm!(set_variable_vm, test_params.clone(), &script, "", "");
let result = checked_call_vm!(vm, test_params.clone(), script, "", result.data);
let actual_trace = trace_from_result(&result);
let expected_executed_call_result = executed_state::scalar_string("result_1");
assert_eq!(actual_trace.len(), 2);
assert_eq!(actual_trace[1], expected_executed_call_result);
}
#[test]
fn match_with_equal_numbers() {
let local_peer_id = "local_peer_id";

View File

@ -45,7 +45,7 @@ fn issue_177() {
// client 1: demand result for (call %init_peer_id% ("getDataSrv" "-relay-") [] -relay-)
let client_result_1 = client
.runner
.call(script, "", "", client_peer_id, 0, HashMap::new())
.call(script, "", "", client_peer_id, 0, 0, HashMap::new())
.expect("call should be success");
let expected_call_requests = maplit::hashmap! {
1 => CallRequestParams::new("getDataSrv", "-relay-", vec![], vec![]),
@ -59,7 +59,7 @@ fn issue_177() {
// client 2: send result to the specified relay
let client_result_2 = client
.runner
.call(script, client_result_1.data, "", client_peer_id, 0, call_results)
.call(script, client_result_1.data, "", client_peer_id, 0, 0, call_results)
.expect("call should be success");
assert!(client_result_2.call_requests.is_empty());
assert_eq!(client_result_2.next_peer_pks, vec![relay_peer_id.to_string()]);
@ -73,6 +73,7 @@ fn issue_177() {
client_result_2.data.clone(),
client_peer_id,
0,
0,
HashMap::new(),
)
.expect("call should be success");
@ -88,7 +89,15 @@ fn issue_177() {
};
let relay_result_2 = relay
.runner
.call(script, relay_result_1.data.clone(), "", client_peer_id, 0, call_results)
.call(
script,
relay_result_1.data.clone(),
"",
client_peer_id,
0,
0,
call_results,
)
.expect("call should be success");
assert!(relay_result_2.next_peer_pks.is_empty());
@ -98,7 +107,15 @@ fn issue_177() {
};
let relay_result_3 = relay
.runner
.call(script, relay_result_2.data.clone(), "", client_peer_id, 0, call_results)
.call(
script,
relay_result_2.data.clone(),
"",
client_peer_id,
0,
0,
call_results,
)
.expect("call should be success");
assert!(relay_result_3.next_peer_pks.is_empty());
@ -108,7 +125,15 @@ fn issue_177() {
};
let relay_result_4 = relay
.runner
.call(script, relay_result_3.data.clone(), "", client_peer_id, 0, call_results)
.call(
script,
relay_result_3.data.clone(),
"",
client_peer_id,
0,
0,
call_results,
)
.expect("call should be success");
// client 4: receive result from the relay
@ -121,6 +146,7 @@ fn issue_177() {
relay_result_4.data.clone(),
client_peer_id,
0,
0,
HashMap::new(),
)
.expect("call should be success");
@ -137,7 +163,7 @@ fn issue_177() {
// demand a result for (call %init_peer_id% ("peer" "timeout") [1000 "timeout"])
let client_result_4 = client
.runner
.call(script, client_result_3.data, "", client_peer_id, 0, call_results)
.call(script, client_result_3.data, "", client_peer_id, 0, 0, call_results)
.expect("call should be success");
let expected_call_requests = maplit::hashmap! {
3 => CallRequestParams::new("peer", "timeout", vec![json!(1000u64), json!("timeout")], vec![
@ -154,7 +180,7 @@ fn issue_177() {
// timeout requests provided
let client_result_5 = client
.runner
.call(script, client_result_4.data, "", client_peer_id, 0, call_results);
.call(script, client_result_4.data, "", client_peer_id, 0, 0, call_results);
// before patch the interpreter crashed here
assert!(client_result_5.is_ok());
}

View File

@ -1,7 +1,7 @@
[package]
name = "avm-server"
description = "Fluence AIR VM"
version = "0.19.0"
version = "0.20.0"
authors = ["Fluence Labs"]
edition = "2018"
license = "Apache-2.0"
@ -16,7 +16,7 @@ name = "avm_server"
path = "src/lib.rs"
[dependencies]
air-interpreter-interface = { version = "0.9.0", path = "../../crates/air-lib/interpreter-interface" }
air-interpreter-interface = { version = "0.10.0", path = "../../crates/air-lib/interpreter-interface" }
avm-data-store = { version = "0.1.0", path = "../../crates/data-store" }
fluence-faas = "0.16.0"
polyplets = { version = "0.2.0", path = "../../crates/air-lib/polyplets" }

View File

@ -90,6 +90,7 @@ impl<E> AVM<E> {
data,
particle_parameters.init_peer_id.into_owned(),
particle_parameters.timestamp,
particle_parameters.ttl,
call_results,
)
.map_err(AVMError::RunnerError)?;

View File

@ -21,6 +21,7 @@ pub struct ParticleParameters<'init_peer_id, 'particle_id> {
pub init_peer_id: Cow<'init_peer_id, String>,
pub particle_id: Cow<'particle_id, String>,
pub timestamp: u64,
pub ttl: u32,
}
impl<'init_peer_id, 'particle_id> ParticleParameters<'init_peer_id, 'particle_id> {
@ -28,11 +29,13 @@ impl<'init_peer_id, 'particle_id> ParticleParameters<'init_peer_id, 'particle_id
init_peer_id: Cow<'init_peer_id, String>,
particle_id: Cow<'particle_id, String>,
timestamp: u64,
ttl: u32,
) -> Self {
Self {
init_peer_id,
particle_id,
timestamp,
ttl,
}
}
}

View File

@ -73,6 +73,7 @@ impl AVMRunner {
data: impl Into<Vec<u8>>,
init_peer_id: impl Into<String>,
timestamp: u64,
ttl: u32,
call_results: CallResults,
) -> RunnerResult<RawAVMOutcome> {
let args = prepare_args(
@ -82,6 +83,7 @@ impl AVMRunner {
self.current_peer_id.clone(),
init_peer_id.into(),
timestamp,
ttl,
call_results,
);
@ -117,11 +119,16 @@ fn prepare_args(
current_peer_id: String,
init_peer_id: String,
timestamp: u64,
ttl: u32,
call_results: CallResults,
) -> Vec<IValue> {
let run_parameters =
air_interpreter_interface::RunParameters::new(init_peer_id, current_peer_id, timestamp)
.into_ivalue();
let run_parameters = air_interpreter_interface::RunParameters::new(
init_peer_id,
current_peer_id,
timestamp,
ttl,
)
.into_ivalue();
let call_results = crate::interface::into_raw_result(call_results);
let call_results =

View File

@ -64,6 +64,7 @@ pub enum Value<'i> {
InitPeerId,
LastError(Option<LambdaAST<'i>>),
Timestamp,
TTL,
Literal(&'i str),
Number(Number),
Boolean(bool),
@ -81,6 +82,7 @@ pub enum CallOutputValue<'i> {
pub enum ApArgument<'i> {
InitPeerId,
Timestamp,
TTL,
LastError(Option<LambdaAST<'i>>),
Literal(&'i str),
Number(Number),

View File

@ -26,6 +26,7 @@ impl fmt::Display for Value<'_> {
LastError(error_accessor) => display_last_error(f, error_accessor),
Literal(literal) => write!(f, r#""{}""#, literal),
Timestamp => write!(f, "%timestamp%"),
TTL => write!(f, "%ttl%"),
Number(number) => write!(f, "{}", number),
Boolean(bool) => write!(f, "{}", bool),
EmptyArray => write!(f, "[]"),
@ -66,6 +67,7 @@ impl fmt::Display for ApArgument<'_> {
LastError(error_accessor) => display_last_error(f, error_accessor),
Literal(str) => write!(f, r#""{}""#, str),
Timestamp => write!(f, "%timestamp%"),
TTL => write!(f, "%ttl%"),
Number(number) => write!(f, "{}", number),
Boolean(bool) => write!(f, "{}", bool),
EmptyArray => write!(f, "[]"),

View File

@ -179,6 +179,7 @@ Value: Value<'input> = {
<le:LastErrorWithLambda> => Value::LastError(Some(le)),
<l:Literal> => Value::Literal(l),
Timestamp => Value::Timestamp,
TTL => Value::TTL,
<n:Number> => Value::Number(n),
<b:Boolean> => Value::Boolean(b),
"[" "]" => Value::EmptyArray,
@ -193,6 +194,7 @@ ApArgument: ApArgument<'input> = {
<LastError> => ApArgument::LastError(None),
<le:LastErrorWithLambda> => ApArgument::LastError(Some(le)),
Timestamp => ApArgument::Timestamp,
TTL => ApArgument::TTL,
<l:Literal> => ApArgument::Literal(l),
<n:Number> => ApArgument::Number(n),
<b:Boolean> => ApArgument::Boolean(b),
@ -225,6 +227,7 @@ extern {
LastError => Token::LastError,
LastErrorWithLambda => Token::LastErrorWithLambda(<LambdaAST<'input>>),
Timestamp => Token::Timestamp,
TTL => Token::TTL,
call => Token::Call,
ap => Token::Ap,

File diff suppressed because it is too large Load Diff

View File

@ -191,6 +191,7 @@ fn string_to_token(input: &str, start_pos: usize) -> LexerResult<Token> {
INIT_PEER_ID => Ok(Token::InitPeerId),
_ if input.starts_with(LAST_ERROR) => parse_last_error(input, start_pos),
TIMESTAMP => Ok(Token::Timestamp),
TTL => Ok(Token::TTL),
TRUE_VALUE => Ok(Token::Boolean(true)),
FALSE_VALUE => Ok(Token::Boolean(false)),
@ -240,6 +241,7 @@ const MISMATCH_INSTR: &str = "mismatch";
const INIT_PEER_ID: &str = "%init_peer_id%";
const LAST_ERROR: &str = "%last_error%";
const TIMESTAMP: &str = "%timestamp%";
const TTL: &str = "%ttl%";
const TRUE_VALUE: &str = "true";
const FALSE_VALUE: &str = "false";

View File

@ -168,6 +168,13 @@ fn timestamp() {
);
}
#[test]
fn ttl() {
const TTL: &str = "%ttl%";
lexer_test(TTL, Single(Ok((0, Token::TTL, TTL.len()))));
}
#[test]
fn stream() {
const STREAM: &str = "$stream____asdasd";

View File

@ -19,6 +19,7 @@ use crate::LambdaAST;
use serde::Deserialize;
use serde::Serialize;
#[allow(clippy::upper_case_acronyms)]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Token<'input> {
OpenRoundBracket,
@ -54,6 +55,7 @@ pub enum Token<'input> {
LastError,
LastErrorWithLambda(LambdaAST<'input>),
Timestamp,
TTL,
Call,
Ap,

View File

@ -116,3 +116,15 @@ fn ap_with_timestamp() {
assert_eq!(actual, expected);
}
#[test]
fn ap_with_ttl() {
let source_code = r#"
(ap %ttl% $stream)
"#;
let actual = parse(source_code);
let expected = ap(ApArgument::TTL, Variable::stream("$stream", 19));
assert_eq!(actual, expected);
}

View File

@ -392,6 +392,24 @@ fn parse_timestamp() {
assert_eq!(instruction, expected);
}
#[test]
fn parse_ttl() {
let source_code = r#"
(call "peer_id" ("service_id" "fn_name") [%ttl%])
"#;
let instruction = parse(source_code);
let expected = call(
CallInstrValue::Literal("peer_id"),
CallInstrValue::Literal("service_id"),
CallInstrValue::Literal("fn_name"),
Rc::new(vec![Value::TTL]),
CallOutputValue::None,
);
assert_eq!(instruction, expected);
}
#[test]
fn parse_last_error() {
let source_code = format!(

View File

@ -66,6 +66,22 @@ fn parse_match_with_timestamp() {
assert_eq!(instruction, expected);
}
#[test]
fn parse_match_with_ttl() {
let source_code = r#"
(match %ttl% v1
(null)
)
"#;
let instruction = parse(source_code);
let expected = match_(
Value::TTL,
Value::Variable(VariableWithLambda::scalar("v1", 22)),
null(),
);
assert_eq!(instruction, expected);
}
#[test]
fn parse_mismatch() {
let source_code = r#"

View File

@ -121,6 +121,7 @@ impl<'i> VariableValidator<'i> {
match &ap.argument {
ApArgument::Number(_)
| ApArgument::Timestamp
| ApArgument::TTL
| ApArgument::InitPeerId
| ApArgument::Boolean(_)
| ApArgument::Literal(_)
@ -231,6 +232,7 @@ impl<'i> VariableValidator<'i> {
match matchable {
Value::InitPeerId
| Value::Timestamp
| Value::TTL
| Value::Number(_)
| Value::Boolean(_)
| Value::Literal(_)

View File

@ -1,7 +1,7 @@
[package]
name = "air-interpreter-interface"
description = "Interface of the AIR interpreter"
version = "0.9.0"
version = "0.10.0"
authors = ["Fluence Labs"]
edition = "2018"
license = "Apache-2.0"

View File

@ -33,14 +33,18 @@ pub struct RunParameters {
/// Unix timestamp from a particle in milliseconds.
/// It represents time when this particle was sent from the init peer id.
pub timestamp: u64,
/// TTL set by init peer id in milliseconds.
pub ttl: u32,
}
impl RunParameters {
pub fn new(init_peer_id: String, current_peer_id: String, timestamp: u64) -> Self {
pub fn new(init_peer_id: String, current_peer_id: String, timestamp: u64, ttl: u32) -> Self {
Self {
init_peer_id,
current_peer_id,
timestamp,
ttl,
}
}
@ -49,6 +53,7 @@ impl RunParameters {
IValue::String(self.init_peer_id),
IValue::String(self.current_peer_id),
IValue::U64(self.timestamp),
IValue::U32(self.ttl),
];
// unwrap is safe here because run_parameters is non-empty array
let run_parameters = NEVec::new(run_parameters).unwrap();

View File

@ -33,6 +33,7 @@ pub struct TestRunner {
pub struct TestRunParameters {
pub init_peer_id: String,
pub timestamp: u64,
pub ttl: u32,
}
impl TestRunner {
@ -50,6 +51,7 @@ impl TestRunner {
let TestRunParameters {
init_peer_id,
timestamp,
ttl,
} = test_run_params;
let mut call_results = HashMap::new();
@ -64,6 +66,7 @@ impl TestRunner {
data,
init_peer_id.clone(),
timestamp,
ttl,
call_results,
)
.map_err(|e| e.to_string())?;
@ -112,10 +115,11 @@ pub fn create_avm(
}
impl TestRunParameters {
pub fn new(init_peer_id: impl Into<String>, timestamp: u64) -> Self {
pub fn new(init_peer_id: impl Into<String>, timestamp: u64, ttl: u32) -> Self {
Self {
init_peer_id: init_peer_id.into(),
timestamp,
ttl,
}
}
@ -123,6 +127,7 @@ impl TestRunParameters {
Self {
init_peer_id: init_peer_id.into(),
timestamp: 0,
ttl: 0,
}
}
@ -130,6 +135,15 @@ impl TestRunParameters {
Self {
init_peer_id: String::new(),
timestamp,
ttl: 0,
}
}
pub fn from_ttl(ttl: u32) -> Self {
Self {
init_peer_id: String::new(),
timestamp: 0,
ttl,
}
}
}