mod from_outputs;
mod process_outputs_from_callback;
use crate::{Identifier, ProgramID, Value, compute_function_id};
use snarkvm_circuit_network::Aleo;
use snarkvm_circuit_types::{Address, Field, U16, environment::prelude::*};
pub enum OutputID<A: Aleo> {
Constant(Field<A>),
Public(Field<A>),
Private(Field<A>),
Record(Field<A>, Field<A>, Field<A>),
ExternalRecord(Field<A>),
Future(Field<A>),
DynamicRecord(Field<A>),
DynamicFuture(Field<A>),
}
impl<A: Aleo> Inject for OutputID<A> {
type Primitive = console::OutputID<A::Network>;
fn new(_: Mode, output: Self::Primitive) -> Self {
match output {
console::OutputID::Constant(field) => Self::Constant(Field::new(Mode::Public, field)),
console::OutputID::Public(field) => Self::Public(Field::new(Mode::Public, field)),
console::OutputID::Private(field) => Self::Private(Field::new(Mode::Public, field)),
console::OutputID::Record(commitment, checksum, sender_ciphertext) => Self::Record(
Field::new(Mode::Public, commitment),
Field::new(Mode::Public, checksum),
Field::new(Mode::Public, sender_ciphertext),
),
console::OutputID::ExternalRecord(hash) => Self::ExternalRecord(Field::new(Mode::Public, hash)),
console::OutputID::Future(hash) => Self::Future(Field::new(Mode::Public, hash)),
console::OutputID::DynamicRecord(hash) => Self::DynamicRecord(Field::new(Mode::Public, hash)),
console::OutputID::DynamicFuture(hash) => Self::DynamicFuture(Field::new(Mode::Public, hash)),
}
}
}
impl<A: Aleo> OutputID<A> {
fn constant(expected_hash: Field<A>) -> Self {
let output_hash = Field::new(Mode::Public, expected_hash.eject_value());
A::assert_eq(&output_hash, expected_hash).expect("Constant output hash mismatch");
Self::Constant(output_hash)
}
fn public(expected_hash: Field<A>) -> Self {
let output_hash = Field::new(Mode::Public, expected_hash.eject_value());
A::assert_eq(&output_hash, expected_hash).expect("Public output hash mismatch");
Self::Public(output_hash)
}
fn private(expected_hash: Field<A>) -> Self {
let output_hash = Field::new(Mode::Public, expected_hash.eject_value());
A::assert_eq(&output_hash, expected_hash).expect("Private output hash mismatch");
Self::Private(output_hash)
}
fn record(
expected_commitment: Field<A>,
expected_checksum: Field<A>,
expected_sender_ciphertext: Field<A>,
) -> Self {
let output_commitment = Field::new(Mode::Public, expected_commitment.eject_value());
let output_checksum = Field::new(Mode::Public, expected_checksum.eject_value());
let output_sender_ciphertext = Field::new(Mode::Public, expected_sender_ciphertext.eject_value()); A::assert_eq(&output_commitment, expected_commitment).expect("Record output commitment mismatch");
A::assert_eq(&output_checksum, expected_checksum).expect("Record output checksum mismatch");
let is_sender_ciphertext_equal = output_sender_ciphertext.is_equal(&expected_sender_ciphertext);
let is_sender_ciphertext_zero = output_sender_ciphertext.is_zero();
A::assert(is_sender_ciphertext_equal | is_sender_ciphertext_zero).expect("Record sender ciphertext mismatch");
Self::Record(output_commitment, output_checksum, output_sender_ciphertext)
}
fn external_record(expected_hash: Field<A>) -> Self {
let output_hash = Field::new(Mode::Public, expected_hash.eject_value());
A::assert_eq(&output_hash, expected_hash).expect("ExternalRecord output hash mismatch");
Self::ExternalRecord(output_hash)
}
fn future(expected_hash: Field<A>) -> Self {
let output_hash = Field::new(Mode::Public, expected_hash.eject_value());
A::assert_eq(&output_hash, expected_hash).expect("Future output hash mismatch");
Self::Future(output_hash)
}
fn dynamic_record(expected_hash: Field<A>) -> Self {
let output_hash = Field::new(Mode::Public, expected_hash.eject_value());
A::assert_eq(&output_hash, expected_hash).expect("DynamicRecord output hash mismatch");
Self::DynamicRecord(output_hash)
}
fn dynamic_future(expected_hash: Field<A>) -> Self {
let output_hash = Field::new(Mode::Public, expected_hash.eject_value());
A::assert_eq(&output_hash, expected_hash).expect("DynamicFuture output hash mismatch");
Self::DynamicFuture(output_hash)
}
}
impl<A: Aleo> Eject for OutputID<A> {
type Primitive = console::OutputID<A::Network>;
fn eject_mode(&self) -> Mode {
match self {
Self::Constant(field) => field.eject_mode(),
Self::Public(field) => field.eject_mode(),
Self::Private(field) => field.eject_mode(),
Self::Record(commitment, checksum, sender_ciphertext) => {
Mode::combine(commitment.eject_mode(), [checksum.eject_mode(), sender_ciphertext.eject_mode()])
}
Self::ExternalRecord(hash) => hash.eject_mode(),
Self::Future(hash) => hash.eject_mode(),
Self::DynamicRecord(hash) => hash.eject_mode(),
Self::DynamicFuture(hash) => hash.eject_mode(),
}
}
fn eject_value(&self) -> Self::Primitive {
match self {
Self::Constant(field) => console::OutputID::Constant(field.eject_value()),
Self::Public(field) => console::OutputID::Public(field.eject_value()),
Self::Private(field) => console::OutputID::Private(field.eject_value()),
Self::Record(commitment, checksum, sender_ciphertext) => console::OutputID::Record(
commitment.eject_value(),
checksum.eject_value(),
sender_ciphertext.eject_value(),
),
Self::ExternalRecord(hash) => console::OutputID::ExternalRecord(hash.eject_value()),
Self::Future(hash) => console::OutputID::Future(hash.eject_value()),
Self::DynamicRecord(hash) => console::OutputID::DynamicRecord(hash.eject_value()),
Self::DynamicFuture(hash) => console::OutputID::DynamicFuture(hash.eject_value()),
}
}
}
pub struct Response<A: Aleo> {
output_ids: Vec<OutputID<A>>,
outputs: Vec<Value<A>>,
}
impl<A: Aleo> Response<A> {
pub fn output_ids(&self) -> &[OutputID<A>] {
&self.output_ids
}
pub fn outputs(&self) -> &[Value<A>] {
&self.outputs
}
}
impl<A: Aleo> Eject for Response<A> {
type Primitive = console::Response<A::Network>;
fn eject_mode(&self) -> Mode {
Mode::combine(self.output_ids.eject_mode(), [self.outputs.eject_mode()])
}
fn eject_value(&self) -> Self::Primitive {
Self::Primitive::from((
self.output_ids.iter().map(|output_id| output_id.eject_value()).collect(),
self.outputs.eject_value(),
))
}
}