use crate::executor::*;
use crate::predicates::*;
pub struct ThereExistsPredicate<'a, Ext: ExternalCall> {
pub ext: &'a Ext,
}
impl<'a, Ext: ExternalCall> ThereExistsPredicate<'a, Ext> {
fn replace_variable(
&self,
property_bytes: &Vec<u8>,
placeholder: &Vec<u8>,
quantified: &Vec<u8>,
) -> ExecResultT<Vec<u8>, AddressOf<Ext>> {
if Ext::is_placeholder(property_bytes) {
if &Ext::get_input_value(property_bytes) == placeholder {
return Ok(quantified.clone());
}
}
let mut property: Property<AddressOf<Ext>> = Ext::bytes_to_property(&property_bytes)?;
if property.predicate_address == Ext::not_address() {
require!(property.inputs.len() > 0);
property.inputs[0] =
self.replace_variable(&property.inputs[0], placeholder, quantified)?;
} else if property.predicate_address == self.ext.ext_address() {
require!(property.inputs.len() > 2);
property.inputs[2] =
self.replace_variable(&property.inputs[2], placeholder, quantified)?;
} else if property.predicate_address == Ext::and_address()
|| property.predicate_address == Ext::or_address()
{
property.inputs = property
.inputs
.iter()
.map(|input| self.replace_variable(input, placeholder, quantified))
.collect::<Result<Vec<_>, _>>()?;
} else {
property.inputs = property
.inputs
.iter()
.map(|input| {
if Ext::is_placeholder(input) {
if &Ext::get_input_value(input) == placeholder {
return quantified.clone();
}
}
input.clone()
})
.collect();
}
Ok(property.encode())
}
}
impl<'a, Ext: ExternalCall> LogicalConnectiveInterface<AddressOf<Ext>>
for ThereExistsPredicate<'a, Ext>
{
fn is_valid_challenge(
&self,
inputs: Vec<Vec<u8>>,
_challenge_inputs: Vec<Vec<u8>>,
challenge: Property<AddressOf<Ext>>,
) -> ExecResult<AddressOf<Ext>> {
require_with_message!(
challenge.predicate_address == Ext::for_all_address(),
"challenge must be ForAllSuchThat"
);
require!(inputs.len() > 2);
let new_inputs = vec![inputs[2].clone()];
let p = Property::<AddressOf<Ext>> {
predicate_address: Ext::not_address().clone(),
inputs: new_inputs,
};
require!(challenge.inputs.len() > 2);
require_with_message!(inputs[1] == challenge.inputs[1], "variable must be same");
require_with_message!(p.encode() == challenge.inputs[2], "inputs must be same");
Ok(true)
}
}
impl<'a, Ext: ExternalCall> DecidablePredicateInterface<AddressOf<Ext>>
for ThereExistsPredicate<'a, Ext>
{
fn decide_with_witness(
&self,
inputs: Vec<Vec<u8>>,
witness: Vec<Vec<u8>>,
) -> ExecResult<AddressOf<Ext>> {
require!(inputs.len() > 2);
require!(witness.len() > 0);
let property_bytes = self.replace_variable(&inputs[2], &inputs[1], &witness[0])?;
let property: Property<AddressOf<Ext>> = Ext::bytes_to_property(&property_bytes)?;
Ok(Ext::bytes_to_bool(
&self.ext.ext_call(
&property.predicate_address,
PredicateCallInputs::DecidablePredicate(
DecidablePredicateCallInputs::DecideWithWitness {
inputs: property.inputs,
witness: witness
.as_slice()
.get(1..)
.unwrap_or(vec![].as_slice())
.to_vec(),
},
),
)?,
)?)
}
}