snarkvm_synthesizer_debug/vm/helpers/
cost.rs1use crate::VM;
16use console::{
17 prelude::*,
18 program::{LiteralType, PlaintextType},
19};
20use ledger_block::{Deployment, Execution};
21use ledger_store::ConsensusStorage;
22use synthesizer_program::{Command, Finalize, Instruction};
23
24use std::collections::HashMap;
25
26pub fn deployment_cost<N: Network>(deployment: &Deployment<N>) -> Result<(u64, (u64, u64))> {
28 let size_in_bytes = deployment.size_in_bytes()?;
30 let program_id = deployment.program_id();
32 let num_characters = u32::try_from(program_id.name().to_string().len())?;
34
35 let storage_cost = size_in_bytes
37 .checked_mul(N::DEPLOYMENT_FEE_MULTIPLIER)
38 .ok_or(anyhow!("The storage cost computation overflowed for a deployment"))?;
39
40 let namespace_cost = 10u64
42 .checked_pow(10u32.saturating_sub(num_characters))
43 .ok_or(anyhow!("The namespace cost computation overflowed for a deployment"))?
44 .saturating_mul(1_000_000); let total_cost = storage_cost
48 .checked_add(namespace_cost)
49 .ok_or(anyhow!("The total cost computation overflowed for a deployment"))?;
50
51 Ok((total_cost, (storage_cost, namespace_cost)))
52}
53
54pub fn execution_cost<N: Network, C: ConsensusStorage<N>>(
56 vm: &VM<N, C>,
57 execution: &Execution<N>,
58) -> Result<(u64, (u64, u64))> {
59 let storage_cost = execution.size_in_bytes()?;
61
62 let lookup = execution
64 .transitions()
65 .map(|transition| {
66 let program_id = transition.program_id();
67 Ok((*program_id, vm.process().read().get_program(program_id)?.clone()))
68 })
69 .collect::<Result<HashMap<_, _>>>()?;
70
71 let mut finalize_cost = 0u64;
73 for transition in execution.transitions() {
75 let program_id = transition.program_id();
77 let function_name = transition.function_name();
79 let program = lookup.get(program_id).ok_or(anyhow!("Program '{program_id}' is missing"))?;
81 let cost = match program.get_function(function_name)?.finalize_logic() {
83 Some(finalize) => cost_in_microcredits(finalize)?,
84 None => continue,
85 };
86 finalize_cost = finalize_cost
88 .checked_add(cost)
89 .ok_or(anyhow!("The finalize cost computation overflowed for an execution"))?;
90 }
91
92 let total_cost = storage_cost
94 .checked_add(finalize_cost)
95 .ok_or(anyhow!("The total cost computation overflowed for an execution"))?;
96
97 Ok((total_cost, (storage_cost, finalize_cost)))
98}
99
100pub fn cost_in_microcredits<N: Network>(finalize: &Finalize<N>) -> Result<u64> {
102 let cost = |command: &Command<N>| match command {
104 Command::Instruction(Instruction::Abs(_)) => Ok(2_000),
105 Command::Instruction(Instruction::AbsWrapped(_)) => Ok(2_000),
106 Command::Instruction(Instruction::Add(_)) => Ok(2_000),
107 Command::Instruction(Instruction::AddWrapped(_)) => Ok(2_000),
108 Command::Instruction(Instruction::And(_)) => Ok(2_000),
109 Command::Instruction(Instruction::AssertEq(_)) => Ok(2_000),
110 Command::Instruction(Instruction::AssertNeq(_)) => Ok(2_000),
111 Command::Instruction(Instruction::Async(_)) => bail!("`async` is not supported in finalize."),
112 Command::Instruction(Instruction::Call(_)) => bail!("`call` is not supported in finalize."),
113 Command::Instruction(Instruction::Cast(_)) => Ok(2_000),
114 Command::Instruction(Instruction::CastLossy(_)) => Ok(2_000),
115 Command::Instruction(Instruction::CommitBHP256(_)) => Ok(200_000),
116 Command::Instruction(Instruction::CommitBHP512(_)) => Ok(200_000),
117 Command::Instruction(Instruction::CommitBHP768(_)) => Ok(200_000),
118 Command::Instruction(Instruction::CommitBHP1024(_)) => Ok(200_000),
119 Command::Instruction(Instruction::CommitPED64(_)) => Ok(100_000),
120 Command::Instruction(Instruction::CommitPED128(_)) => Ok(100_000),
121 Command::Instruction(Instruction::Div(_)) => Ok(10_000),
122 Command::Instruction(Instruction::DivWrapped(_)) => Ok(2_000),
123 Command::Instruction(Instruction::Double(_)) => Ok(2_000),
124 Command::Instruction(Instruction::GreaterThan(_)) => Ok(2_000),
125 Command::Instruction(Instruction::GreaterThanOrEqual(_)) => Ok(2_000),
126 Command::Instruction(Instruction::HashBHP256(_)) => Ok(100_000),
127 Command::Instruction(Instruction::HashBHP512(_)) => Ok(100_000),
128 Command::Instruction(Instruction::HashBHP768(_)) => Ok(100_000),
129 Command::Instruction(Instruction::HashBHP1024(_)) => Ok(100_000),
130 Command::Instruction(Instruction::HashKeccak256(_)) => Ok(100_000),
131 Command::Instruction(Instruction::HashKeccak384(_)) => Ok(100_000),
132 Command::Instruction(Instruction::HashKeccak512(_)) => Ok(100_000),
133 Command::Instruction(Instruction::HashPED64(_)) => Ok(20_000),
134 Command::Instruction(Instruction::HashPED128(_)) => Ok(30_000),
135 Command::Instruction(Instruction::HashPSD2(hash)) => match hash.destination_type() {
136 PlaintextType::Literal(LiteralType::Address) | PlaintextType::Literal(LiteralType::Group) => Ok(600_000),
137 PlaintextType::Literal(..) => Ok(60_000),
138 plaintext_type => bail!("`hash.psd2` is not supported for plaintext type '{plaintext_type}'"),
139 },
140 Command::Instruction(Instruction::HashPSD4(hash)) => match hash.destination_type() {
141 PlaintextType::Literal(LiteralType::Address) | PlaintextType::Literal(LiteralType::Group) => Ok(700_000),
142 PlaintextType::Literal(..) => Ok(100_000),
143 plaintext_type => bail!("`hash.psd4` is not supported for plaintext type '{plaintext_type}'"),
144 },
145 Command::Instruction(Instruction::HashPSD8(hash)) => match hash.destination_type() {
146 PlaintextType::Literal(LiteralType::Address) | PlaintextType::Literal(LiteralType::Group) => Ok(800_000),
147 PlaintextType::Literal(..) => Ok(200_000),
148 plaintext_type => bail!("`hash.psd8` is not supported for plaintext type '{plaintext_type}'"),
149 },
150 Command::Instruction(Instruction::HashSha3_256(_)) => Ok(100_000),
151 Command::Instruction(Instruction::HashSha3_384(_)) => Ok(100_000),
152 Command::Instruction(Instruction::HashSha3_512(_)) => Ok(100_000),
153 Command::Instruction(Instruction::HashManyPSD2(_)) => {
154 bail!("`hash_many.psd2` is not supported in finalize.")
155 }
156 Command::Instruction(Instruction::HashManyPSD4(_)) => {
157 bail!("`hash_many.psd4` is not supported in finalize.")
158 }
159 Command::Instruction(Instruction::HashManyPSD8(_)) => {
160 bail!("`hash_many.psd8` is not supported in finalize.")
161 }
162 Command::Instruction(Instruction::Inv(_)) => Ok(10_000),
163 Command::Instruction(Instruction::IsEq(_)) => Ok(2_000),
164 Command::Instruction(Instruction::IsNeq(_)) => Ok(2_000),
165 Command::Instruction(Instruction::LessThan(_)) => Ok(2_000),
166 Command::Instruction(Instruction::LessThanOrEqual(_)) => Ok(2_000),
167 Command::Instruction(Instruction::Modulo(_)) => Ok(2_000),
168 Command::Instruction(Instruction::Mul(_)) => Ok(150_000),
169 Command::Instruction(Instruction::MulWrapped(_)) => Ok(2_000),
170 Command::Instruction(Instruction::Nand(_)) => Ok(2_000),
171 Command::Instruction(Instruction::Neg(_)) => Ok(2_000),
172 Command::Instruction(Instruction::Nor(_)) => Ok(2_000),
173 Command::Instruction(Instruction::Not(_)) => Ok(2_000),
174 Command::Instruction(Instruction::Or(_)) => Ok(2_000),
175 Command::Instruction(Instruction::Pow(_)) => Ok(20_000),
176 Command::Instruction(Instruction::PowWrapped(_)) => Ok(2_000),
177 Command::Instruction(Instruction::Rem(_)) => Ok(2_000),
178 Command::Instruction(Instruction::RemWrapped(_)) => Ok(2_000),
179 Command::Instruction(Instruction::SignVerify(_)) => Ok(250_000),
180 Command::Instruction(Instruction::Shl(_)) => Ok(2_000),
181 Command::Instruction(Instruction::ShlWrapped(_)) => Ok(2_000),
182 Command::Instruction(Instruction::Shr(_)) => Ok(2_000),
183 Command::Instruction(Instruction::ShrWrapped(_)) => Ok(2_000),
184 Command::Instruction(Instruction::Square(_)) => Ok(2_000),
185 Command::Instruction(Instruction::SquareRoot(_)) => Ok(120_000),
186 Command::Instruction(Instruction::Sub(_)) => Ok(10_000),
187 Command::Instruction(Instruction::SubWrapped(_)) => Ok(2_000),
188 Command::Instruction(Instruction::Ternary(_)) => Ok(2_000),
189 Command::Instruction(Instruction::Xor(_)) => Ok(2_000),
190 Command::Await(_) => Ok(2_000),
193 Command::Contains(_) => Ok(12_500),
194 Command::Get(_) => Ok(25_000),
195 Command::GetOrUse(_) => Ok(25_000),
196 Command::RandChaCha(_) => Ok(25_000),
197 Command::Remove(_) => Ok(10_000),
198 Command::Set(_) => Ok(100_000),
199 Command::BranchEq(_) | Command::BranchNeq(_) => Ok(5_000),
200 Command::Position(_) => Ok(1_000),
201 };
202 finalize
203 .commands()
204 .iter()
205 .map(cost)
206 .try_fold(0u64, |acc, res| res.and_then(|x| acc.checked_add(x).ok_or(anyhow!("Finalize cost overflowed"))))
207}