use super::*;
impl<N: Network> Stack<N> {
pub fn sample_plaintext<R: Rng + CryptoRng>(
&self,
plaintext_type: &PlaintextType<N>,
rng: &mut R,
) -> Result<Plaintext<N>> {
let plaintext = self.sample_plaintext_internal(plaintext_type, 0, rng)?;
self.matches_plaintext(&plaintext, plaintext_type)?;
Ok(plaintext)
}
pub fn sample_future<R: Rng + CryptoRng>(&self, locator: &Locator<N>, rng: &mut R) -> Result<Future<N>> {
let future = self.sample_future_internal(locator, 0, rng)?;
self.matches_future(&future, locator)?;
Ok(future)
}
pub(crate) fn sample_record_internal<R: Rng + CryptoRng>(
&self,
burner_address: &Address<N>,
record_name: &Identifier<N>,
nonce: Group<N>,
depth: usize,
rng: &mut R,
) -> Result<Record<N, Plaintext<N>>> {
ensure!(depth <= N::MAX_DATA_DEPTH, "Plaintext exceeded maximum depth of {}", N::MAX_DATA_DEPTH);
let record_type = self.program.get_record(record_name)?;
let owner = match record_type.owner().is_public() {
true => RecordOwner::Public(*burner_address),
false => RecordOwner::Private(Plaintext::Literal(Literal::Address(*burner_address), Default::default())),
};
let data = record_type
.entries()
.iter()
.map(|(entry_name, entry_type)| {
let entry = self.sample_entry_internal(entry_type, depth + 1, rng)?;
Ok((*entry_name, entry))
})
.collect::<Result<IndexMap<_, _>>>()?;
let version = U8::<N>::rand(rng);
Record::<N, Plaintext<N>>::from_plaintext(owner, data, nonce, version)
}
fn sample_entry_internal<R: Rng + CryptoRng>(
&self,
entry_type: &EntryType<N>,
depth: usize,
rng: &mut R,
) -> Result<Entry<N, Plaintext<N>>> {
ensure!(depth <= N::MAX_DATA_DEPTH, "Entry exceeded maximum depth of {}", N::MAX_DATA_DEPTH);
match entry_type {
EntryType::Constant(plaintext_type)
| EntryType::Public(plaintext_type)
| EntryType::Private(plaintext_type) => {
let plaintext = self.sample_plaintext_internal(plaintext_type, depth, rng)?;
match entry_type {
EntryType::Constant(..) => Ok(Entry::Constant(plaintext)),
EntryType::Public(..) => Ok(Entry::Public(plaintext)),
EntryType::Private(..) => Ok(Entry::Private(plaintext)),
}
}
}
}
fn sample_plaintext_internal<R: Rng + CryptoRng>(
&self,
plaintext_type: &PlaintextType<N>,
depth: usize,
rng: &mut R,
) -> Result<Plaintext<N>> {
ensure!(depth <= N::MAX_DATA_DEPTH, "Plaintext exceeded maximum depth of {}", N::MAX_DATA_DEPTH);
let plaintext = match plaintext_type {
PlaintextType::Literal(literal_type) => {
Plaintext::Literal(Literal::sample(*literal_type, rng), Default::default())
}
PlaintextType::Struct(struct_name) => {
let struct_ = self.program.get_struct(struct_name)?;
let members = struct_
.members()
.iter()
.map(|(member_name, member_type)| {
let member = self.sample_plaintext_internal(member_type, depth + 1, rng)?;
Ok((*member_name, member))
})
.collect::<Result<IndexMap<_, _>>>()?;
Plaintext::Struct(members, Default::default())
}
PlaintextType::Array(array_type) => {
let elements = (0..**array_type.length())
.map(|_| {
self.sample_plaintext_internal(array_type.next_element_type(), depth + 1, rng)
})
.collect::<Result<Vec<_>>>()?;
Plaintext::Array(elements, Default::default())
}
};
Ok(plaintext)
}
fn sample_future_internal<R: Rng + CryptoRng>(
&self,
locator: &Locator<N>,
depth: usize,
rng: &mut R,
) -> Result<Future<N>> {
let external_stack = match locator.program_id() == self.program_id() {
true => None,
false => Some(self.get_external_stack(locator.program_id())?),
};
let function = match &external_stack {
Some(external_stack) => external_stack.get_function_ref(locator.resource())?,
None => self.get_function_ref(locator.resource())?,
};
let inputs = match function.finalize_logic() {
Some(finalize_logic) => finalize_logic.inputs(),
None => bail!("Function '{locator}' does not have a finalize block"),
};
let arguments = inputs
.into_iter()
.map(|input| {
match input.finalize_type() {
FinalizeType::Plaintext(plaintext_type) => {
let plaintext = self.sample_plaintext_internal(plaintext_type, depth + 1, rng)?;
Ok(Argument::Plaintext(plaintext))
}
FinalizeType::Future(locator) => {
let future = self.sample_future_internal(locator, depth + 1, rng)?;
Ok(Argument::Future(future))
}
}
})
.collect::<Result<Vec<_>>>()?;
Ok(Future::new(*locator.program_id(), *locator.resource(), arguments))
}
}