Skip to main content

snarkvm_synthesizer_process/
authorize.rs

1// Copyright (c) 2019-2026 Provable Inc.
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use super::*;
17
18use snarkvm_synthesizer_error::*;
19
20impl<N: Network> Process<N> {
21    /// Authorizes a call to the program function for the given inputs.
22    ///
23    // This method is meant to be completely stateless. It has no notion of block height or consensus version.
24    #[inline]
25    pub fn authorize<A: circuit::Aleo<Network = N>, R: Rng + CryptoRng>(
26        &self,
27        private_key: &PrivateKey<N>,
28        program_id: impl TryInto<ProgramID<N>>,
29        function_name: impl TryInto<Identifier<N>>,
30        inputs: impl ExactSizeIterator<Item = impl TryInto<Value<N>>>,
31        rng: &mut R,
32    ) -> Result<Authorization<N>, ProcessAuthError> {
33        // Authorize the call.
34        self.get_stack(program_id)?
35            .authorize::<A, R>(private_key, function_name, inputs, rng)
36            .map_err(ProcessAuthError::from)
37    }
38
39    /// Authorizes a call to the program function for the given inputs.
40    /// Compared to `authorize`, this method does not check for circuit satisfiability of the request.
41    #[inline]
42    pub fn authorize_unchecked<A: circuit::Aleo<Network = N>, R: Rng + CryptoRng>(
43        &self,
44        private_key: &PrivateKey<N>,
45        program_id: impl TryInto<ProgramID<N>>,
46        function_name: impl TryInto<Identifier<N>>,
47        inputs: impl ExactSizeIterator<Item = impl TryInto<Value<N>>>,
48        rng: &mut R,
49    ) -> Result<Authorization<N>, ProcessAuthError> {
50        // Authorize the call.
51        self.get_stack(program_id)?
52            .authorize_unchecked::<A, R>(private_key, function_name, inputs, rng)
53            .map_err(ProcessAuthError::from)
54    }
55
56    /// Authorizes a call to the program function for the given inputs.
57    /// Compared to `authorize`, no private key is needed, but this only works for single public requests.
58    #[inline]
59    pub fn authorize_request<A: circuit::Aleo<Network = N>, R: Rng + CryptoRng>(
60        &self,
61        request: Request<N>,
62        rng: &mut R,
63    ) -> Result<Authorization<N>, ProcessAuthError> {
64        // Initialize the program id.
65        let program_id = request.program_id();
66        // Authorize the call.
67        self.get_stack(program_id)?.authorize_request::<A, R>(request, rng).map_err(ProcessAuthError::from)
68    }
69
70    /// Authorizes the fee given the credits record, the fee amount (in microcredits),
71    /// and the deployment or execution ID.
72    #[inline]
73    pub fn authorize_fee_private<A: circuit::Aleo<Network = N>, R: Rng + CryptoRng>(
74        &self,
75        private_key: &PrivateKey<N>,
76        credits: Record<N, Plaintext<N>>,
77        base_fee_in_microcredits: u64,
78        priority_fee_in_microcredits: u64,
79        deployment_or_execution_id: Field<N>,
80        rng: &mut R,
81    ) -> Result<Authorization<N>, ProcessAuthError> {
82        let timer = timer!("Process::authorize_fee_private");
83
84        // Ensure the fee has the correct program ID.
85        let program_id = ProgramID::from_str("credits.aleo")?;
86        // Ensure the fee has the correct function.
87        let function_name = Identifier::from_str("fee_private")?;
88
89        // Ensure the record contains a sufficient balance to pay the fee.
90        ensure_record_microcredits_is_sufficient(
91            &credits,
92            base_fee_in_microcredits.saturating_add(priority_fee_in_microcredits),
93        )?;
94
95        // Construct the inputs.
96        let inputs = [
97            Value::Record(credits),
98            Value::from(Literal::U64(U64::<N>::new(base_fee_in_microcredits))),
99            Value::from(Literal::U64(U64::<N>::new(priority_fee_in_microcredits))),
100            Value::from(Literal::Field(deployment_or_execution_id)),
101        ]
102        .into_iter();
103        lap!(timer, "Construct the inputs");
104
105        // Authorize the call.
106        let authorization = self.get_stack(program_id)?.authorize::<A, R>(private_key, function_name, inputs, rng)?;
107        finish!(timer, "Compute the authorization");
108
109        // Return the authorization.
110        Ok(authorization)
111    }
112
113    /// Authorizes the fee given the the fee amount (in microcredits) and the deployment or execution ID.
114    #[inline]
115    pub fn authorize_fee_public<A: circuit::Aleo<Network = N>, R: Rng + CryptoRng>(
116        &self,
117        private_key: &PrivateKey<N>,
118        base_fee_in_microcredits: u64,
119        priority_fee_in_microcredits: u64,
120        deployment_or_execution_id: Field<N>,
121        rng: &mut R,
122    ) -> Result<Authorization<N>, ProcessAuthError> {
123        let timer = timer!("Process::authorize_fee_public");
124
125        // Ensure the fee has the correct program ID.
126        let program_id = ProgramID::from_str("credits.aleo")?;
127        // Ensure the fee has the correct function.
128        let function_name = Identifier::from_str("fee_public")?;
129
130        // Construct the inputs.
131        let inputs = [
132            Value::from(Literal::U64(U64::<N>::new(base_fee_in_microcredits))),
133            Value::from(Literal::U64(U64::<N>::new(priority_fee_in_microcredits))),
134            Value::from(Literal::Field(deployment_or_execution_id)),
135        ]
136        .into_iter();
137        lap!(timer, "Construct the inputs");
138
139        // Authorize the call.
140        let authorization = self.get_stack(program_id)?.authorize::<A, R>(private_key, function_name, inputs, rng)?;
141        finish!(timer, "Compute the authorization");
142
143        // Return the authorization.
144        Ok(authorization)
145    }
146}
147
148/// Ensures the record contains a sufficient balance to pay the fee.
149fn ensure_record_microcredits_is_sufficient<N: Network>(
150    record: &Record<N, Plaintext<N>>,
151    fee_in_microcredits: u64,
152) -> Result<()> {
153    // Retrieve the balance from the record.
154    let balance = match record.find(&[Identifier::from_str("microcredits")?]) {
155        Ok(console::program::Entry::Private(Plaintext::Literal(Literal::U64(amount), _))) => *amount,
156        _ => bail!("The fee record does not contain a 'microcredits' entry"),
157    };
158    // Ensure the balance is sufficient to pay the fee.
159    ensure!(balance >= fee_in_microcredits, "Credits record balance is insufficient to pay the fee");
160    Ok(())
161}