miden_protocol/protocol_config/
mod.rs1use alloc::string::ToString;
2use alloc::vec::Vec;
3
4use crate::asset::AssetId;
5use crate::batch::BatchKernel;
6use crate::constants::MIN_PROOF_SECURITY_LEVEL;
7use crate::crypto::SequentialCommit;
8use crate::errors::ProtocolConfigError;
9use crate::transaction::TransactionKernel;
10use crate::utils::serde::{
11 ByteReader,
12 ByteWriter,
13 Deserializable,
14 DeserializationError,
15 Serializable,
16};
17use crate::{Felt, Word};
18
19mod kernel_config;
20pub use kernel_config::KernelConfig;
21
22mod next_protocol_config;
23pub use next_protocol_config::NextProtocolConfig;
24
25mod proof_verification;
26pub use proof_verification::{ProofSecurityPolicy, ProofVerificationConfig};
27
28#[derive(Debug, Clone, PartialEq, Eq)]
37pub struct ProtocolConfig {
38 fee_asset_id: AssetId,
40
41 tx_kernel: KernelConfig,
43
44 batch_kernel: KernelConfig,
46
47 block_kernel: KernelConfig,
49
50 proof_verification: ProofVerificationConfig,
52}
53
54impl ProtocolConfig {
55 const MINIMUM_SECURITY_BITS: u8 = {
60 assert!(MIN_PROOF_SECURITY_LEVEL <= u8::MAX as u32);
61 MIN_PROOF_SECURITY_LEVEL as u8
62 };
63
64 pub fn new(
73 fee_asset_id: AssetId,
74 tx_kernel: KernelConfig,
75 batch_kernel: KernelConfig,
76 block_kernel: KernelConfig,
77 proof_verification: ProofVerificationConfig,
78 ) -> Result<Self, ProtocolConfigError> {
79 if !fee_asset_id.composition().is_fungible() {
80 return Err(ProtocolConfigError::FeeAssetMustBeFungible(fee_asset_id.composition()));
81 }
82
83 Ok(Self {
84 fee_asset_id,
85 tx_kernel,
86 batch_kernel,
87 block_kernel,
88 proof_verification,
89 })
90 }
91
92 pub fn current(fee_asset_id: AssetId) -> Result<Self, ProtocolConfigError> {
101 let tx_kernel = KernelConfig::new(
102 TransactionKernel::main().hash(),
103 TransactionKernel::PROCEDURES.to_vec(),
104 )?;
105 let batch_kernel = KernelConfig::new(BatchKernel::main().hash(), Vec::new())?;
106 let block_kernel = KernelConfig::new(Word::empty(), Vec::new())?;
107
108 let security_policy = ProofSecurityPolicy::new(Word::empty(), Self::MINIMUM_SECURITY_BITS)?;
110 let proof_verification =
111 ProofVerificationConfig::new(Word::empty(), Word::empty(), security_policy);
112
113 Self::new(fee_asset_id, tx_kernel, batch_kernel, block_kernel, proof_verification)
114 }
115
116 pub fn fee_asset_id(&self) -> AssetId {
121 self.fee_asset_id
122 }
123
124 pub fn tx_kernel(&self) -> &KernelConfig {
126 &self.tx_kernel
127 }
128
129 pub fn batch_kernel(&self) -> &KernelConfig {
131 &self.batch_kernel
132 }
133
134 pub fn block_kernel(&self) -> &KernelConfig {
136 &self.block_kernel
137 }
138
139 pub fn proof_verification(&self) -> &ProofVerificationConfig {
141 &self.proof_verification
142 }
143
144 pub fn to_commitment(&self) -> Word {
146 <Self as SequentialCommit>::to_commitment(self)
147 }
148
149 pub fn to_elements(&self) -> Vec<Felt> {
164 <Self as SequentialCommit>::to_elements(self)
165 }
166}
167
168impl SequentialCommit for ProtocolConfig {
169 type Commitment = Word;
170
171 fn to_elements(&self) -> Vec<Felt> {
172 let fee_asset_id = self.fee_asset_id.to_word();
173 let tx_kernel = self.tx_kernel.to_commitment();
174 let batch_kernel = self.batch_kernel.to_commitment();
175 let block_kernel = self.block_kernel.to_commitment();
176 let proof_verification = self.proof_verification.to_commitment();
177
178 [
179 fee_asset_id.as_elements(),
180 tx_kernel.as_elements(),
181 batch_kernel.as_elements(),
182 block_kernel.as_elements(),
183 proof_verification.as_elements(),
184 Word::empty().as_elements(),
185 ]
186 .concat()
187 }
188}
189
190impl Serializable for ProtocolConfig {
194 fn write_into<W: ByteWriter>(&self, target: &mut W) {
195 let Self {
196 fee_asset_id,
197 tx_kernel,
198 batch_kernel,
199 block_kernel,
200 proof_verification,
201 } = self;
202
203 fee_asset_id.write_into(target);
204 tx_kernel.write_into(target);
205 batch_kernel.write_into(target);
206 block_kernel.write_into(target);
207 proof_verification.write_into(target);
208 }
209}
210
211impl Deserializable for ProtocolConfig {
212 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
213 let fee_asset_id = source.read()?;
214 let tx_kernel = source.read()?;
215 let batch_kernel = source.read()?;
216 let block_kernel = source.read()?;
217 let proof_verification = source.read()?;
218
219 Self::new(fee_asset_id, tx_kernel, batch_kernel, block_kernel, proof_verification)
220 .map_err(|err| DeserializationError::InvalidValue(err.to_string()))
221 }
222}
223
224#[cfg(test)]
228mod tests {
229 use assert_matches::assert_matches;
230
231 use super::*;
232 use crate::account::AccountId;
233 use crate::asset::{AssetClass, AssetComposition};
234 use crate::testing::account_id::{
235 ACCOUNT_ID_PRIVATE_NON_FUNGIBLE_FAUCET,
236 ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET,
237 };
238
239 fn fee_asset_id() -> AssetId {
240 let faucet_id = AccountId::try_from(ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET)
241 .expect("test faucet ID should be valid");
242 AssetId::new_fungible(faucet_id)
243 }
244
245 #[test]
246 fn to_elements_is_pipeable() {
247 let config = ProtocolConfig::current(fee_asset_id()).unwrap();
250
251 assert_eq!(config.to_elements().len(), 24);
252 }
253
254 #[test]
255 fn current_commits_to_the_linked_tx_kernel() {
256 let config = ProtocolConfig::current(fee_asset_id()).unwrap();
257
258 assert_eq!(config.tx_kernel().main_proc(), TransactionKernel::main().hash());
259 assert_eq!(config.tx_kernel().kernel_procs(), TransactionKernel::PROCEDURES);
260 }
261
262 #[test]
263 fn new_rejects_non_fungible_fee_asset() {
264 let faucet_id = AccountId::try_from(ACCOUNT_ID_PRIVATE_NON_FUNGIBLE_FAUCET)
265 .expect("test faucet ID should be valid");
266 let fee_asset_id =
267 AssetId::new(AssetClass::default(), faucet_id, AssetComposition::None).unwrap();
268
269 let error = ProtocolConfig::new(
270 fee_asset_id,
271 KernelConfig::dummy(),
272 KernelConfig::dummy(),
273 KernelConfig::dummy(),
274 ProofVerificationConfig::new(
275 Word::empty(),
276 Word::empty(),
277 ProofSecurityPolicy::new(Word::empty(), 96).unwrap(),
278 ),
279 )
280 .unwrap_err();
281
282 assert_matches!(error, ProtocolConfigError::FeeAssetMustBeFungible(AssetComposition::None));
283 }
284
285 #[test]
286 fn serde_round_trip() -> anyhow::Result<()> {
287 let config = ProtocolConfig::current(fee_asset_id())?;
288
289 let deserialized = ProtocolConfig::read_from_bytes(&config.to_bytes())
290 .map_err(|err| anyhow::anyhow!("{err}"))?;
291
292 assert_eq!(config, deserialized);
293 Ok(())
294 }
295}