1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
use super::*;
impl<N: Network> Process<N> {
#[inline]
pub fn execute_additional_fee<A: circuit::Aleo<Network = N>, R: Rng + CryptoRng>(
&self,
private_key: &PrivateKey<N>,
credits: Record<N, Plaintext<N>>,
additional_fee_in_gates: u64,
rng: &mut R,
) -> Result<(Response<N>, AdditionalFee<N>)> {
let program_id = ProgramID::from_str("credits.aleo")?;
let function_name = Identifier::from_str("fee")?;
let input_types = self.get_program(&program_id)?.get_function(&function_name)?.input_types();
let inputs =
vec![Value::Record(credits), Value::from_str(&format!("{}", U64::<N>::new(additional_fee_in_gates)))?];
let request = Request::sign(private_key, program_id, function_name, &inputs, &input_types, rng)?;
let authorization = Authorization::new(&[request.clone()]);
let call_stack = CallStack::Authorize(vec![request], *private_key, authorization.clone());
let _response = self.get_stack(&program_id)?.execute_function::<A, R>(call_stack, rng)?;
let request = authorization.peek_next()?;
let stack = self.get_stack(request.program_id())?;
#[cfg(feature = "aleo-cli")]
println!("{}", format!(" • Calling '{}/{}'...", request.program_id(), request.function_name()).dimmed());
let execution = Arc::new(RwLock::new(Execution::new()));
let response = stack.execute_function::<A, R>(CallStack::execute(authorization, execution.clone())?, rng)?;
let execution = execution.read().clone();
ensure!(execution.len() == 1, "Execution of '{}/{}' does not contain 1 transition", program_id, function_name);
Ok((response, execution.peek()?))
}
#[inline]
pub fn verify_additional_fee(&self, additional_fee: &AdditionalFee<N>) -> Result<()> {
#[cfg(debug_assertions)]
println!("Verifying additional fee for {}/{}...", additional_fee.program_id(), additional_fee.function_name());
let fee_program_id = ProgramID::from_str("credits.aleo")?;
ensure!(*additional_fee.program_id() == fee_program_id, "Incorrect program ID for additional fee");
let fee_function = Identifier::from_str("fee")?;
ensure!(*additional_fee.function_name() == fee_function, "Incorrect function name for additional fee");
ensure!(**additional_fee.id() == additional_fee.to_root()?, "Transition ID of the additional fee is incorrect");
ensure!(additional_fee.inputs().len() <= N::MAX_INPUTS, "Additional fee exceeded maximum number of inputs");
ensure!(additional_fee.outputs().len() <= N::MAX_INPUTS, "Additional fee exceeded maximum number of outputs");
if additional_fee.inputs().iter().enumerate().any(|(index, input)| !input.verify(additional_fee.tcm(), index)) {
bail!("Failed to verify an additional fee input")
}
let num_inputs = additional_fee.inputs().len();
if additional_fee
.outputs()
.iter()
.enumerate()
.any(|(index, output)| !output.verify(additional_fee.tcm(), num_inputs + index))
{
bail!("Failed to verify an additional fee output")
}
ensure!(additional_fee.fee() >= &0, "The fee must be zero or positive");
let (tpk_x, tpk_y) = additional_fee.tpk().to_xy_coordinate();
let mut inputs = vec![N::Field::one(), *tpk_x, *tpk_y, **additional_fee.tcm()];
inputs.extend(additional_fee.inputs().iter().flat_map(|input| input.verifier_inputs()));
inputs.extend(additional_fee.outputs().iter().flat_map(|output| output.verifier_inputs()));
inputs.push(*I64::<N>::new(*additional_fee.fee()).to_field()?);
let stack = self.get_stack(additional_fee.program_id())?;
let function = stack.get_function(additional_fee.function_name())?;
if stack.get_number_of_calls(function.name())? != 1 {
bail!("The number of function calls in '{}/{}' should be 1", stack.program_id(), function.name())
}
#[cfg(debug_assertions)]
println!("Additional fee public inputs ({} elements): {:#?}", inputs.len(), inputs);
let verifying_key = self.get_verifying_key(stack.program_id(), function.name())?;
ensure!(
verifying_key.verify(function.name(), &inputs, additional_fee.proof()),
"The proof for the additional fee is invalid"
);
Ok(())
}
}