Skip to main content

nargo/foreign_calls/
layers.rs

1use acvm::{AcirField, acir::brillig::ForeignCallResult, pwg::ForeignCallWaitInfo};
2
3use super::{ForeignCallError, ForeignCallExecutor};
4
5/// Returns an empty result when called.
6///
7/// If all executors have no handler for the given foreign call then we cannot
8/// return a correct response to the ACVM. The best we can do is to return an empty response,
9/// this allows us to ignore any foreign calls which exist solely to pass information from inside
10/// the circuit to the environment (e.g. custom logging) as the execution will still be able to progress.
11///
12/// We optimistically return an empty response for all oracle calls as the ACVM will error
13/// should a response have been required.
14pub struct Empty;
15
16impl<F: AcirField> ForeignCallExecutor<F> for Empty {
17    fn execute(
18        &mut self,
19        _foreign_call: &ForeignCallWaitInfo<F>,
20    ) -> Result<ForeignCallResult<F>, ForeignCallError> {
21        Ok(ForeignCallResult::default())
22    }
23}
24
25/// Returns `NoHandler` for every call.
26pub struct Unhandled;
27
28impl<F: AcirField> ForeignCallExecutor<F> for Unhandled {
29    fn execute(
30        &mut self,
31        foreign_call: &ForeignCallWaitInfo<F>,
32    ) -> Result<ForeignCallResult<F>, ForeignCallError> {
33        Err(ForeignCallError::NoHandler(foreign_call.function.clone()))
34    }
35}
36
37/// Forwards to the inner executor if its own handler doesn't handle the call.
38pub struct Layer<H, I> {
39    pub handler: H,
40    pub inner: I,
41}
42
43impl<H, I, F> ForeignCallExecutor<F> for Layer<H, I>
44where
45    H: ForeignCallExecutor<F>,
46    I: ForeignCallExecutor<F>,
47{
48    fn execute(
49        &mut self,
50        foreign_call: &ForeignCallWaitInfo<F>,
51    ) -> Result<ForeignCallResult<F>, ForeignCallError> {
52        match self.handler.execute(foreign_call) {
53            Err(ForeignCallError::NoHandler(_)) => self.inner.execute(foreign_call),
54            handled => handled,
55        }
56    }
57}
58
59impl<H, I> Layer<H, I> {
60    /// Create a layer from two handlers
61    pub fn new(handler: H, inner: I) -> Self {
62        Self { handler, inner }
63    }
64}
65
66impl<H> Layer<H, Empty> {
67    /// Create a layer from a handler.
68    /// If the handler doesn't handle a call, a default empty response is returned.
69    pub fn or_empty(handler: H) -> Self {
70        Self { handler, inner: Empty }
71    }
72}
73
74impl<H> Layer<H, Unhandled> {
75    /// Create a layer from a handler.
76    /// If the handler doesn't handle a call, `NoHandler` error is returned.
77    pub fn or_unhandled(handler: H) -> Self {
78        Self { handler, inner: Unhandled }
79    }
80}
81
82impl Layer<Unhandled, Unhandled> {
83    /// A base layer that doesn't handle anything.
84    pub fn unhandled() -> Self {
85        Self { handler: Unhandled, inner: Unhandled }
86    }
87}
88
89impl<H, I> Layer<H, I> {
90    /// Add another layer on top of this one.
91    pub fn add_layer<J>(self, handler: J) -> Layer<J, Self> {
92        Layer::new(handler, self)
93    }
94
95    pub fn handler(&self) -> &H {
96        &self.handler
97    }
98
99    pub fn inner(&self) -> &I {
100        &self.inner
101    }
102}
103
104/// Compose handlers.
105pub trait Layering {
106    /// Layer an executor on top of this one.
107    /// The `other` executor will be called first.
108    fn add_layer<L, F>(self, other: L) -> Layer<L, Self>
109    where
110        Self: Sized + ForeignCallExecutor<F>,
111        L: ForeignCallExecutor<F>;
112}
113
114impl<T> Layering for T {
115    fn add_layer<L, F>(self, other: L) -> Layer<L, T>
116    where
117        T: Sized + ForeignCallExecutor<F>,
118        L: ForeignCallExecutor<F>,
119    {
120        Layer::new(other, self)
121    }
122}
123
124/// A case where we can have either this or that type of handler.
125pub enum Either<L, R> {
126    Left(L),
127    Right(R),
128}
129
130impl<L, R, F> ForeignCallExecutor<F> for Either<L, R>
131where
132    L: ForeignCallExecutor<F>,
133    R: ForeignCallExecutor<F>,
134{
135    fn execute(
136        &mut self,
137        foreign_call: &ForeignCallWaitInfo<F>,
138    ) -> Result<ForeignCallResult<F>, ForeignCallError> {
139        match self {
140            Either::Left(left) => left.execute(foreign_call),
141            Either::Right(right) => right.execute(foreign_call),
142        }
143    }
144}
145
146/// Support disabling a layer by making it optional.
147/// This way we can still have a known static type for a composition,
148/// because layers are always added, potentially wrapped in an `Option`.
149impl<H, F> ForeignCallExecutor<F> for Option<H>
150where
151    H: ForeignCallExecutor<F>,
152{
153    fn execute(
154        &mut self,
155        foreign_call: &ForeignCallWaitInfo<F>,
156    ) -> Result<ForeignCallResult<F>, ForeignCallError> {
157        match self {
158            Some(handler) => handler.execute(foreign_call),
159            None => Err(ForeignCallError::NoHandler(foreign_call.function.clone())),
160        }
161    }
162}