Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expressive human #213

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
96 changes: 82 additions & 14 deletions src/human_encoding/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,15 +208,23 @@ impl<J: Jet> Forest<J> {
ret
}

/// Convert the forest into a witness node.
///
/// Succeeds if the forest contains a "main" root and returns `None` otherwise.
/// Convert the main root of the forest into a witness node, if the root exists.
pub fn to_witness_node(
&self,
witness: &HashMap<Arc<str>, Arc<Value>>,
) -> Option<Arc<WitnessNode<J>>> {
let main = self.roots.get("main")?;
Some(main.to_witness_node(witness, self.roots()))
self.to_witness_node_expression(witness, "main")
}

/// Convert the given root of the forest into a witness node, if the root exists.
pub fn to_witness_node_expression(
&self,
witness: &HashMap<Arc<str>, Arc<Value>>,
root: &str,
) -> Option<Arc<WitnessNode<J>>> {
self.roots
.get(root)
.map(|commit| commit.to_witness_node(witness, self.roots()))
}
}

Expand All @@ -228,30 +236,43 @@ mod tests {
use std::collections::HashMap;
use std::sync::Arc;

fn get_root(input: &Option<Arc<Value>>) -> &'static str {
if input.is_none() {
"main"
} else {
"expr"
}
}

fn assert_finalize_ok<J: Jet>(
s: &str,
witness: &HashMap<Arc<str>, Arc<Value>>,
env: &J::Environment,
input: Option<Arc<Value>>,
) {
let program = Forest::<J>::parse(s)
.expect("Failed to parse human encoding")
.to_witness_node(witness)
.to_witness_node_expression(witness, get_root(&input))
.expect("Forest is missing expected root")
.finalize()
.expect("Failed to finalize");
let mut mac = BitMachine::for_program(&program);
if let Some(value) = input {
mac.input(&value).expect("Failed to provide input");
}
mac.exec(&program, env).expect("Failed to run program");
}

fn assert_finalize_err<J: Jet>(
s: &str,
witness: &HashMap<Arc<str>, Arc<Value>>,
env: &J::Environment,
input: Option<Arc<Value>>,
err_msg: &'static str,
) {
let program = match Forest::<J>::parse(s)
.expect("Failed to parse human encoding")
.to_witness_node(witness)
.to_witness_node_expression(witness, get_root(&input))
.expect("Forest is missing expected root")
.finalize()
{
Expand All @@ -262,6 +283,12 @@ mod tests {
}
};
let mut mac = BitMachine::for_program(&program);
if let Some(value) = input {
if let Err(error) = mac.input(&value) {
assert_eq!(error.to_string().as_str(), err_msg);
return;
}
}
match mac.exec(&program, env) {
Ok(_) => panic!("Execution is expected to fail"),
Err(error) => assert_eq!(&error.to_string(), err_msg),
Expand All @@ -284,13 +311,19 @@ mod tests {
(Arc::from("a"), Value::u8(0x00)),
(Arc::from("b"), Value::u8(0x01)),
]);
assert_finalize_ok::<Core>(s, &a_less_than_b, &());
assert_finalize_ok::<Core>(s, &a_less_than_b, &(), None);

let b_greater_equal_a = HashMap::from([
(Arc::from("a"), Value::u8(0x01)),
(Arc::from("b"), Value::u8(0x01)),
]);
assert_finalize_err::<Core>(s, &b_greater_equal_a, &(), "Jet failed during execution");
assert_finalize_err::<Core>(
s,
&b_greater_equal_a,
&(),
None,
"Jet failed during execution",
);
}

#[test]
Expand All @@ -306,6 +339,7 @@ mod tests {
",
&witness,
&(),
None,
"unable to satisfy program",
);
}
Expand All @@ -318,7 +352,7 @@ mod tests {
main := comp (pair wit1 unit) case unit wit2
";
let wit2_is_pruned = HashMap::from([(Arc::from("wit1"), Value::u1(0))]);
assert_finalize_ok::<Core>(s, &wit2_is_pruned, &());
assert_finalize_ok::<Core>(s, &wit2_is_pruned, &(), None);

let wit2_is_missing = HashMap::from([(Arc::from("wit1"), Value::u1(1))]);
// FIXME The finalization should fail
Expand All @@ -327,15 +361,15 @@ mod tests {
assert_finalize_err::<Core>(
s,
&wit2_is_missing,
&(),
&(), None,
"Execution reached a pruned branch: bf12681a76fc7c00c63e583c25cc97237337d6aca30d3f4a664075445385c648"
);

let wit2_is_present = HashMap::from([
(Arc::from("wit1"), Value::u1(1)),
(Arc::from("wit2"), Value::unit()),
]);
assert_finalize_ok::<Core>(s, &wit2_is_present, &());
assert_finalize_ok::<Core>(s, &wit2_is_present, &(), None);
}

#[test]
Expand All @@ -349,6 +383,7 @@ mod tests {
",
&empty,
&(),
None,
);
}

Expand All @@ -362,6 +397,7 @@ mod tests {
",
&empty,
&(),
None,
"unable to satisfy program",
);
}
Expand All @@ -374,9 +410,41 @@ mod tests {
main := comp wit2 iden
";
let wit1_populated = HashMap::from([(Arc::from("wit1"), Value::unit())]);
assert_finalize_err::<Core>(s, &wit1_populated, &(), "unable to satisfy program");
assert_finalize_err::<Core>(s, &wit1_populated, &(), None, "unable to satisfy program");

let wit2_populated = HashMap::from([(Arc::from("wit2"), Value::unit())]);
assert_finalize_ok::<Core>(s, &wit2_populated, &());
assert_finalize_ok::<Core>(s, &wit2_populated, &(), None);
}

#[test]
fn expression() {
let s = "
expr := iden
";
let empty = HashMap::new();
assert_finalize_ok::<Core>(s, &empty, &(), Some(Value::unit()));

let s = "
expr := comp
comp
pair iden (comp unit const 0xff)
jet_eq_8
jet_verify
";
assert_finalize_err::<Core>(
s,
&empty,
&(),
Some(Value::unit()),
"Expected input of type: 2^8",
);
assert_finalize_ok::<Core>(s, &empty, &(), Some(Value::u8(0xff)));
assert_finalize_err::<Core>(
s,
&empty,
&(),
Some(Value::u8(0x00)),
"Jet failed during execution",
);
}
}
21 changes: 13 additions & 8 deletions src/node/witness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,16 +197,21 @@ impl<J: Jet> WitnessNode<J> {

// 1. First, prune everything that we can
let pruned_self = self.prune_and_retype();

// 2. Then, set the root arrow to 1->1
let unit_ty = types::Type::unit();
pruned_self
.arrow()
.source
.unify(&unit_ty, "setting root source to unit")?;
pruned_self
.arrow()
.target
.unify(&unit_ty, "setting root source to unit")?;
if pruned_self.arrow().source.final_data().is_none() {
pruned_self
.arrow()
.source
.unify(&unit_ty, "setting root source to unit")?;
}
if pruned_self.arrow().target.final_data().is_none() {
pruned_self
.arrow()
.target
.unify(&unit_ty, "setting root source to unit")?;
}

// 3. Then attempt to convert the whole program to a RedeemNode.
// Despite all of the above this can still fail due to the
Expand Down