mod.rs
1 // Copyright (c) 2019-2025 Alpha-Delta Network Inc. 2 // This file is part of the alphavm 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 16 mod input; 17 pub use input::*; 18 19 mod output; 20 pub use output::*; 21 22 use crate::{ 23 atomic_batch_scope, 24 helpers::{Map, MapRead}, 25 }; 26 use alphavm_ledger_block::{Input, Output, Transition}; 27 use console::{ 28 network::prelude::*, 29 program::{Ciphertext, Identifier, Plaintext, ProgramID, Record}, 30 types::{Field, Group}, 31 }; 32 33 use alphastd_storage::StorageMode; 34 use anyhow::Result; 35 use std::borrow::Cow; 36 37 /// A trait for transition storage. 38 pub trait TransitionStorage<N: Network>: Clone + Send + Sync { 39 /// The transition program IDs and function names. 40 type LocatorMap: for<'a> Map<'a, N::TransitionID, (ProgramID<N>, Identifier<N>)>; 41 /// The transition inputs. 42 type InputStorage: InputStorage<N>; 43 /// The transition outputs. 44 type OutputStorage: OutputStorage<N>; 45 /// The transition public keys. 46 type TPKMap: for<'a> Map<'a, N::TransitionID, Group<N>>; 47 /// The mapping of `transition public key` to `transition ID`. 48 type ReverseTPKMap: for<'a> Map<'a, Group<N>, N::TransitionID>; 49 /// The transition commitments. 50 type TCMMap: for<'a> Map<'a, N::TransitionID, Field<N>>; 51 /// The mapping of `transition commitment` to `transition ID`. 52 type ReverseTCMMap: for<'a> Map<'a, Field<N>, N::TransitionID>; 53 /// The signer commitments. 54 type SCMMap: for<'a> Map<'a, N::TransitionID, Field<N>>; 55 56 /// Initializes the transition storage. 57 fn open<S: Into<StorageMode>>(storage: S) -> Result<Self>; 58 59 /// Returns the transition program IDs and function names. 60 fn locator_map(&self) -> &Self::LocatorMap; 61 /// Returns the transition input store. 62 fn input_store(&self) -> &InputStore<N, Self::InputStorage>; 63 /// Returns the transition output store. 64 fn output_store(&self) -> &OutputStore<N, Self::OutputStorage>; 65 /// Returns the transition public keys map. 66 fn tpk_map(&self) -> &Self::TPKMap; 67 /// Returns the reverse `tpk` map. 68 fn reverse_tpk_map(&self) -> &Self::ReverseTPKMap; 69 /// Returns the transition commitments map. 70 fn tcm_map(&self) -> &Self::TCMMap; 71 /// Returns the reverse `tcm` map. 72 fn reverse_tcm_map(&self) -> &Self::ReverseTCMMap; 73 /// Returns the signer commitments map. 74 fn scm_map(&self) -> &Self::SCMMap; 75 76 /// Returns the storage mode. 77 fn storage_mode(&self) -> &StorageMode { 78 debug_assert!(self.input_store().storage_mode() == self.output_store().storage_mode()); 79 self.input_store().storage_mode() 80 } 81 82 /// Starts an atomic batch write operation. 83 fn start_atomic(&self) { 84 self.locator_map().start_atomic(); 85 self.input_store().start_atomic(); 86 self.output_store().start_atomic(); 87 self.tpk_map().start_atomic(); 88 self.reverse_tpk_map().start_atomic(); 89 self.tcm_map().start_atomic(); 90 self.reverse_tcm_map().start_atomic(); 91 self.scm_map().start_atomic(); 92 } 93 94 /// Checks if an atomic batch is in progress. 95 fn is_atomic_in_progress(&self) -> bool { 96 self.locator_map().is_atomic_in_progress() 97 || self.input_store().is_atomic_in_progress() 98 || self.output_store().is_atomic_in_progress() 99 || self.tpk_map().is_atomic_in_progress() 100 || self.reverse_tpk_map().is_atomic_in_progress() 101 || self.tcm_map().is_atomic_in_progress() 102 || self.reverse_tcm_map().is_atomic_in_progress() 103 || self.scm_map().is_atomic_in_progress() 104 } 105 106 /// Checkpoints the atomic batch. 107 fn atomic_checkpoint(&self) { 108 self.locator_map().atomic_checkpoint(); 109 self.input_store().atomic_checkpoint(); 110 self.output_store().atomic_checkpoint(); 111 self.tpk_map().atomic_checkpoint(); 112 self.reverse_tpk_map().atomic_checkpoint(); 113 self.tcm_map().atomic_checkpoint(); 114 self.reverse_tcm_map().atomic_checkpoint(); 115 self.scm_map().atomic_checkpoint(); 116 } 117 118 /// Clears the latest atomic batch checkpoint. 119 fn clear_latest_checkpoint(&self) { 120 self.locator_map().clear_latest_checkpoint(); 121 self.input_store().clear_latest_checkpoint(); 122 self.output_store().clear_latest_checkpoint(); 123 self.tpk_map().clear_latest_checkpoint(); 124 self.reverse_tpk_map().clear_latest_checkpoint(); 125 self.tcm_map().clear_latest_checkpoint(); 126 self.reverse_tcm_map().clear_latest_checkpoint(); 127 self.scm_map().clear_latest_checkpoint(); 128 } 129 130 /// Rewinds the atomic batch to the previous checkpoint. 131 fn atomic_rewind(&self) { 132 self.locator_map().atomic_rewind(); 133 self.input_store().atomic_rewind(); 134 self.output_store().atomic_rewind(); 135 self.tpk_map().atomic_rewind(); 136 self.reverse_tpk_map().atomic_rewind(); 137 self.tcm_map().atomic_rewind(); 138 self.reverse_tcm_map().atomic_rewind(); 139 self.scm_map().atomic_rewind(); 140 } 141 142 /// Aborts an atomic batch write operation. 143 fn abort_atomic(&self) { 144 self.locator_map().abort_atomic(); 145 self.input_store().abort_atomic(); 146 self.output_store().abort_atomic(); 147 self.tpk_map().abort_atomic(); 148 self.reverse_tpk_map().abort_atomic(); 149 self.tcm_map().abort_atomic(); 150 self.reverse_tcm_map().abort_atomic(); 151 self.scm_map().abort_atomic(); 152 } 153 154 /// Finishes an atomic batch write operation. 155 fn finish_atomic(&self) -> Result<()> { 156 self.locator_map().finish_atomic()?; 157 self.input_store().finish_atomic()?; 158 self.output_store().finish_atomic()?; 159 self.tpk_map().finish_atomic()?; 160 self.reverse_tpk_map().finish_atomic()?; 161 self.tcm_map().finish_atomic()?; 162 self.reverse_tcm_map().finish_atomic()?; 163 self.scm_map().finish_atomic() 164 } 165 166 /// Stores the given `transition` into storage. 167 fn insert(&self, transition: &Transition<N>) -> Result<()> { 168 atomic_batch_scope!(self, { 169 // Retrieve the transition ID. 170 let transition_id = *transition.id(); 171 // Store the program ID and function name. 172 self.locator_map().insert(transition_id, (*transition.program_id(), *transition.function_name()))?; 173 // Store the inputs. 174 self.input_store().insert(transition_id, transition.inputs())?; 175 // Store the outputs. 176 self.output_store().insert(transition_id, transition.outputs())?; 177 // Store `tpk`. 178 self.tpk_map().insert(transition_id, *transition.tpk())?; 179 // Store the reverse `tpk` entry. 180 self.reverse_tpk_map().insert(*transition.tpk(), transition_id)?; 181 // Store `tcm`. 182 self.tcm_map().insert(transition_id, *transition.tcm())?; 183 // Store the reverse `tcm` entry. 184 self.reverse_tcm_map().insert(*transition.tcm(), transition_id)?; 185 // Store `scm`. 186 self.scm_map().insert(transition_id, *transition.scm())?; 187 188 Ok(()) 189 }) 190 } 191 192 /// Removes the input for the given `transition ID`. 193 fn remove(&self, transition_id: &N::TransitionID) -> Result<()> { 194 // Retrieve the `tpk`. 195 let Some(tpk) = self.tpk_map().get_confirmed(transition_id)?.map(|x| *x) else { 196 return Ok(()); 197 }; 198 // Retrieve the `tcm`. 199 let Some(tcm) = self.tcm_map().get_confirmed(transition_id)?.map(|x| *x) else { 200 return Ok(()); 201 }; 202 203 atomic_batch_scope!(self, { 204 // Remove the program ID and function name. 205 self.locator_map().remove(transition_id)?; 206 // Remove the inputs. 207 self.input_store().remove(transition_id)?; 208 // Remove the outputs. 209 self.output_store().remove(transition_id)?; 210 // Remove `tpk`. 211 self.tpk_map().remove(transition_id)?; 212 // Remove the reverse `tpk` entry. 213 self.reverse_tpk_map().remove(&tpk)?; 214 // Remove `tcm`. 215 self.tcm_map().remove(transition_id)?; 216 // Remove the reverse `tcm` entry. 217 self.reverse_tcm_map().remove(&tcm)?; 218 // Remove `scm`. 219 self.scm_map().remove(transition_id)?; 220 221 Ok(()) 222 }) 223 } 224 225 /// Returns the transition for the given `transition ID`. 226 fn get(&self, transition_id: &N::TransitionID) -> Result<Option<Transition<N>>> { 227 // Retrieve the program ID and function name. 228 let Some((program_id, function_name)) = 229 self.locator_map().get_confirmed(transition_id)?.map(|x| x.into_owned()) 230 else { 231 return Ok(None); 232 }; 233 // Retrieve the inputs. 234 let inputs = self.input_store().get_inputs(transition_id)?; 235 // Retrieve the outputs. 236 let outputs = self.output_store().get_outputs(transition_id)?; 237 // Retrieve `tpk`. 238 let tpk = self.tpk_map().get_confirmed(transition_id)?; 239 // Retrieve `tcm`. 240 let tcm = self.tcm_map().get_confirmed(transition_id)?; 241 // Retrieve `scm`. 242 let scm = self.scm_map().get_confirmed(transition_id)?; 243 244 match (tpk, tcm, scm) { 245 (Some(tpk), Some(tcm), Some(scm)) => { 246 // Construct the transition. 247 let transition = Transition::new( 248 program_id, 249 function_name, 250 inputs, 251 outputs, 252 tpk.into_owned(), 253 tcm.into_owned(), 254 scm.into_owned(), 255 )?; 256 // Ensure the transition ID matches. 257 match transition.id() == transition_id { 258 true => Ok(Some(transition)), 259 false => bail!("Mismatch in the transition ID '{transition_id}'"), 260 } 261 } 262 _ => bail!("Transition '{transition_id}' is missing some data (possible corruption)"), 263 } 264 } 265 } 266 267 /// The transition store. 268 #[derive(Clone)] 269 pub struct TransitionStore<N: Network, T: TransitionStorage<N>> { 270 /// The map of transition program IDs and function names. 271 locator: T::LocatorMap, 272 /// The map of transition inputs. 273 inputs: InputStore<N, T::InputStorage>, 274 /// The map of transition outputs. 275 outputs: OutputStore<N, T::OutputStorage>, 276 /// The map of transition public keys. 277 tpk: T::TPKMap, 278 /// The reverse `tpk` map. 279 reverse_tpk: T::ReverseTPKMap, 280 /// The map of transition commitments. 281 tcm: T::TCMMap, 282 /// The reverse `tcm` map. 283 reverse_tcm: T::ReverseTCMMap, 284 /// The map of signer commitments. 285 scm: T::SCMMap, 286 /// The transition storage. 287 storage: T, 288 } 289 290 impl<N: Network, T: TransitionStorage<N>> TransitionStore<N, T> { 291 /// Initializes the transition store. 292 pub fn open<S: Into<StorageMode>>(storage: S) -> Result<Self> { 293 // Initialize the transition storage. 294 let storage = T::open(storage)?; 295 // Return the transition store. 296 Ok(Self { 297 locator: storage.locator_map().clone(), 298 inputs: (*storage.input_store()).clone(), 299 outputs: (*storage.output_store()).clone(), 300 tpk: storage.tpk_map().clone(), 301 reverse_tpk: storage.reverse_tpk_map().clone(), 302 tcm: storage.tcm_map().clone(), 303 reverse_tcm: storage.reverse_tcm_map().clone(), 304 scm: storage.scm_map().clone(), 305 storage, 306 }) 307 } 308 309 /// Initializes a transition store from storage. 310 pub fn from(storage: T) -> Self { 311 Self { 312 locator: storage.locator_map().clone(), 313 inputs: (*storage.input_store()).clone(), 314 outputs: (*storage.output_store()).clone(), 315 tpk: storage.tpk_map().clone(), 316 reverse_tpk: storage.reverse_tpk_map().clone(), 317 tcm: storage.tcm_map().clone(), 318 reverse_tcm: storage.reverse_tcm_map().clone(), 319 scm: storage.scm_map().clone(), 320 storage, 321 } 322 } 323 324 /// Stores the given `transition` into storage. 325 pub fn insert(&self, transition: &Transition<N>) -> Result<()> { 326 self.storage.insert(transition) 327 } 328 329 /// Removes the input for the given `transition ID`. 330 pub fn remove(&self, transition_id: &N::TransitionID) -> Result<()> { 331 self.storage.remove(transition_id) 332 } 333 334 /// Starts an atomic batch write operation. 335 pub fn start_atomic(&self) { 336 self.storage.start_atomic(); 337 } 338 339 /// Checks if an atomic batch is in progress. 340 pub fn is_atomic_in_progress(&self) -> bool { 341 self.storage.is_atomic_in_progress() 342 } 343 344 /// Checkpoints the atomic batch. 345 pub fn atomic_checkpoint(&self) { 346 self.storage.atomic_checkpoint(); 347 } 348 349 /// Clears the latest atomic batch checkpoint. 350 pub fn clear_latest_checkpoint(&self) { 351 self.storage.clear_latest_checkpoint(); 352 } 353 354 /// Rewinds the atomic batch to the previous checkpoint. 355 pub fn atomic_rewind(&self) { 356 self.storage.atomic_rewind(); 357 } 358 359 /// Aborts an atomic batch write operation. 360 pub fn abort_atomic(&self) { 361 self.storage.abort_atomic(); 362 } 363 364 /// Finishes an atomic batch write operation. 365 pub fn finish_atomic(&self) -> Result<()> { 366 self.storage.finish_atomic() 367 } 368 369 /// Returns the storage mode. 370 pub fn storage_mode(&self) -> &StorageMode { 371 self.storage.storage_mode() 372 } 373 } 374 375 impl<N: Network, T: TransitionStorage<N>> TransitionStore<N, T> { 376 /// Returns the transition ID that contains the given `input ID` or `output ID`. 377 pub fn find_transition_id(&self, id: &Field<N>) -> Result<N::TransitionID> { 378 // Start by checking the output IDs (which is the more likely case). 379 if let Some(transition_id) = self.outputs.find_transition_id(id)? { 380 return Ok(transition_id); 381 } 382 // Then check the input IDs. 383 if let Some(transition_id) = self.inputs.find_transition_id(id)? { 384 return Ok(transition_id); 385 } 386 // Throw an error. 387 bail!("Failed to find the transition ID for the given input or output ID '{id}'") 388 } 389 } 390 391 impl<N: Network, T: TransitionStorage<N>> TransitionStore<N, T> { 392 /// Returns the transition for the given `transition ID`. 393 pub fn get_transition(&self, transition_id: &N::TransitionID) -> Result<Option<Transition<N>>> { 394 self.storage.get(transition_id) 395 } 396 397 /// Returns the program ID for the given `transition ID`. 398 pub fn get_program_id(&self, transition_id: &N::TransitionID) -> Result<Option<ProgramID<N>>> { 399 Ok(self.locator.get_confirmed(transition_id)?.map(|locator| match locator { 400 Cow::Borrowed((program_id, _)) => *program_id, 401 Cow::Owned((program_id, _)) => program_id, 402 })) 403 } 404 405 /// Returns the function name for the given `transition ID`. 406 pub fn get_function_name(&self, transition_id: &N::TransitionID) -> Result<Option<Identifier<N>>> { 407 Ok(self.locator.get_confirmed(transition_id)?.map(|locator| match locator { 408 Cow::Borrowed((_, function_name)) => *function_name, 409 Cow::Owned((_, function_name)) => function_name, 410 })) 411 } 412 413 /// Returns the input IDs for the given `transition ID`. 414 pub fn get_input_ids(&self, transition_id: &N::TransitionID) -> Result<Vec<Field<N>>> { 415 self.inputs.get_input_ids(transition_id) 416 } 417 418 /// Returns the inputs for the given `transition ID`. 419 pub fn get_inputs(&self, transition_id: &N::TransitionID) -> Result<Vec<Input<N>>> { 420 self.inputs.get_inputs(transition_id) 421 } 422 423 /// Returns the output IDs for the given `transition ID`. 424 pub fn get_output_ids(&self, transition_id: &N::TransitionID) -> Result<Vec<Field<N>>> { 425 self.outputs.get_output_ids(transition_id) 426 } 427 428 /// Returns the outputs for the given `transition ID`. 429 pub fn get_outputs(&self, transition_id: &N::TransitionID) -> Result<Vec<Output<N>>> { 430 self.outputs.get_outputs(transition_id) 431 } 432 433 /// Returns the record for the given `commitment`. 434 /// 435 /// If the record exists, `Ok(Some(record))` is returned. 436 /// If the record was purged, `Ok(None)` is returned. 437 /// If the record does not exist, `Err(error)` is returned. 438 pub fn get_record(&self, commitment: &Field<N>) -> Result<Option<Record<N, Ciphertext<N>>>> { 439 self.outputs.get_record(commitment) 440 } 441 } 442 443 impl<N: Network, T: TransitionStorage<N>> TransitionStore<N, T> { 444 /// Returns `true` if the given transition ID exists. 445 pub fn contains_transition_id(&self, transition_id: &N::TransitionID) -> Result<bool> { 446 self.locator.contains_key_confirmed(transition_id) 447 } 448 449 /* Input */ 450 451 /// Returns `true` if the given input ID exists. 452 pub fn contains_input_id(&self, input_id: &Field<N>) -> Result<bool> { 453 self.inputs.contains_input_id(input_id) 454 } 455 456 /// Returns `true` if the given serial number exists. 457 pub fn contains_serial_number(&self, serial_number: &Field<N>) -> Result<bool> { 458 self.inputs.contains_serial_number(serial_number) 459 } 460 461 /// Returns `true` if the given tag exists. 462 pub fn contains_tag(&self, tag: &Field<N>) -> Result<bool> { 463 self.inputs.contains_tag(tag) 464 } 465 466 /* Output */ 467 468 /// Returns `true` if the given output ID exists. 469 pub fn contains_output_id(&self, output_id: &Field<N>) -> Result<bool> { 470 self.outputs.contains_output_id(output_id) 471 } 472 473 /// Returns `true` if the given commitment exists. 474 pub fn contains_commitment(&self, commitment: &Field<N>) -> Result<bool> { 475 self.outputs.contains_commitment(commitment) 476 } 477 478 /// Returns `true` if the given checksum exists. 479 pub fn contains_checksum(&self, checksum: &Field<N>) -> bool { 480 self.outputs.contains_checksum(checksum) 481 } 482 483 /// Returns `true` if the given nonce exists. 484 pub fn contains_nonce(&self, nonce: &Group<N>) -> Result<bool> { 485 self.outputs.contains_nonce(nonce) 486 } 487 488 /* Metadata */ 489 490 /// Returns `true` if the given transition public key exists. 491 pub fn contains_tpk(&self, tpk: &Group<N>) -> Result<bool> { 492 self.reverse_tpk.contains_key_confirmed(tpk) 493 } 494 495 /// Returns `true` if the given transition commitment exists. 496 pub fn contains_tcm(&self, tcm: &Field<N>) -> Result<bool> { 497 self.reverse_tcm.contains_key_confirmed(tcm) 498 } 499 } 500 501 impl<N: Network, T: TransitionStorage<N>> TransitionStore<N, T> { 502 /// Returns an iterator over the transition IDs, for all transitions. 503 pub fn transition_ids(&self) -> impl '_ + Iterator<Item = Cow<'_, N::TransitionID>> { 504 self.tcm.keys_confirmed() 505 } 506 507 /* Input */ 508 509 /// Returns an iterator over the input IDs, for all transition inputs. 510 pub fn input_ids(&self) -> impl '_ + Iterator<Item = Cow<'_, Field<N>>> { 511 self.inputs.input_ids() 512 } 513 514 /// Returns an iterator over the constant input IDs, for all transition inputs that are constant. 515 pub fn constant_input_ids(&self) -> impl '_ + Iterator<Item = Cow<'_, Field<N>>> { 516 self.inputs.constant_input_ids() 517 } 518 519 /// Returns an iterator over the public input IDs, for all transition inputs that are public. 520 pub fn public_input_ids(&self) -> impl '_ + Iterator<Item = Cow<'_, Field<N>>> { 521 self.inputs.public_input_ids() 522 } 523 524 /// Returns an iterator over the private input IDs, for all transition inputs that are private. 525 pub fn private_input_ids(&self) -> impl '_ + Iterator<Item = Cow<'_, Field<N>>> { 526 self.inputs.private_input_ids() 527 } 528 529 /// Returns an iterator over the serial numbers, for all transition inputs that are records. 530 pub fn serial_numbers(&self) -> impl '_ + Iterator<Item = Cow<'_, Field<N>>> { 531 self.inputs.serial_numbers() 532 } 533 534 /// Returns an iterator over the external record input IDs, for all transition inputs that are external records. 535 pub fn external_input_ids(&self) -> impl '_ + Iterator<Item = Cow<'_, Field<N>>> { 536 self.inputs.external_input_ids() 537 } 538 539 /* Output */ 540 541 /// Returns an iterator over the output IDs, for all transition outputs. 542 pub fn output_ids(&self) -> impl '_ + Iterator<Item = Cow<'_, Field<N>>> { 543 self.outputs.output_ids() 544 } 545 546 /// Returns an iterator over the constant output IDs, for all transition outputs that are constant. 547 pub fn constant_output_ids(&self) -> impl '_ + Iterator<Item = Cow<'_, Field<N>>> { 548 self.outputs.constant_output_ids() 549 } 550 551 /// Returns an iterator over the public output IDs, for all transition outputs that are public. 552 pub fn public_output_ids(&self) -> impl '_ + Iterator<Item = Cow<'_, Field<N>>> { 553 self.outputs.public_output_ids() 554 } 555 556 /// Returns an iterator over the private output IDs, for all transition outputs that are private. 557 pub fn private_output_ids(&self) -> impl '_ + Iterator<Item = Cow<'_, Field<N>>> { 558 self.outputs.private_output_ids() 559 } 560 561 /// Returns an iterator over the commitments, for all transition outputs that are records. 562 pub fn commitments(&self) -> impl '_ + Iterator<Item = Cow<'_, Field<N>>> { 563 self.outputs.commitments() 564 } 565 566 /// Returns an iterator over the external record output IDs, for all transition outputs that are external records. 567 pub fn external_output_ids(&self) -> impl '_ + Iterator<Item = Cow<'_, Field<N>>> { 568 self.outputs.external_output_ids() 569 } 570 } 571 572 impl<N: Network, T: TransitionStorage<N>> TransitionStore<N, T> { 573 /* Input */ 574 575 /// Returns an iterator over the constant inputs, for all transitions. 576 pub fn constant_inputs(&self) -> impl '_ + Iterator<Item = Cow<'_, Plaintext<N>>> { 577 self.inputs.constant_inputs() 578 } 579 580 /// Returns an iterator over the constant inputs, for all transitions. 581 pub fn public_inputs(&self) -> impl '_ + Iterator<Item = Cow<'_, Plaintext<N>>> { 582 self.inputs.public_inputs() 583 } 584 585 /// Returns an iterator over the private inputs, for all transitions. 586 pub fn private_inputs(&self) -> impl '_ + Iterator<Item = Cow<'_, Ciphertext<N>>> { 587 self.inputs.private_inputs() 588 } 589 590 /// Returns an iterator over the tags, for all transition inputs that are records. 591 pub fn tags(&self) -> impl '_ + Iterator<Item = Cow<'_, Field<N>>> { 592 self.inputs.tags() 593 } 594 595 /* Output */ 596 597 /// Returns an iterator over the constant outputs, for all transitions. 598 pub fn constant_outputs(&self) -> impl '_ + Iterator<Item = Cow<'_, Plaintext<N>>> { 599 self.outputs.constant_outputs() 600 } 601 602 /// Returns an iterator over the constant outputs, for all transitions. 603 pub fn public_outputs(&self) -> impl '_ + Iterator<Item = Cow<'_, Plaintext<N>>> { 604 self.outputs.public_outputs() 605 } 606 607 /// Returns an iterator over the private outputs, for all transitions. 608 pub fn private_outputs(&self) -> impl '_ + Iterator<Item = Cow<'_, Ciphertext<N>>> { 609 self.outputs.private_outputs() 610 } 611 612 /// Returns an iterator over the checksums, for all transition outputs that are records. 613 pub fn checksums(&self) -> impl '_ + Iterator<Item = Cow<'_, Field<N>>> { 614 self.outputs.checksums() 615 } 616 617 /// Returns an iterator over the nonces, for all transition outputs that are records. 618 pub fn nonces(&self) -> impl '_ + Iterator<Item = Cow<'_, Group<N>>> { 619 self.outputs.nonces() 620 } 621 622 /// Returns an iterator over the `(commitment, record)` pairs, for all transition outputs that are records. 623 #[allow(clippy::type_complexity)] 624 pub fn records(&self) -> impl '_ + Iterator<Item = (Cow<'_, Field<N>>, Cow<'_, Record<N, Ciphertext<N>>>)> { 625 self.outputs.records() 626 } 627 628 /* Metadata */ 629 630 /// Returns an iterator over the transition public keys, for all transitions. 631 pub fn tpks(&self) -> impl '_ + Iterator<Item = Cow<'_, Group<N>>> { 632 self.tpk.values_confirmed() 633 } 634 635 /// Returns an iterator over the transition commitments, for all transitions. 636 pub fn tcms(&self) -> impl '_ + Iterator<Item = Cow<'_, Field<N>>> { 637 self.tcm.values_confirmed() 638 } 639 640 /// Returns an iterator over the signer commitments, for all transitions. 641 pub fn scms(&self) -> impl '_ + Iterator<Item = Cow<'_, Field<N>>> { 642 self.scm.values_confirmed() 643 } 644 } 645 646 #[cfg(test)] 647 mod tests { 648 use super::*; 649 use crate::helpers::memory::TransitionMemory; 650 651 #[test] 652 fn test_insert_get_remove() { 653 let rng = &mut TestRng::default(); 654 655 // Sample the transactions. 656 let transaction_0 = alphavm_ledger_test_helpers::sample_execution_transaction_with_fee(true, rng, 0); 657 let transaction_1 = alphavm_ledger_test_helpers::sample_execution_transaction_with_fee(false, rng, 0); 658 let transactions = vec![transaction_0, transaction_1]; 659 660 for transaction in transactions { 661 let transitions = transaction.transitions().cloned().collect::<Vec<_>>(); 662 663 // Ensure there is at least 2 transition. 664 println!("\n\nNumber of transitions: {}\n", transitions.len()); 665 assert!(transitions.len() > 1, "\n\nNumber of transitions: {}\n", transitions.len()); 666 667 // Initialize a new transition store. 668 let transition_store = TransitionMemory::open(StorageMode::Test(None)).unwrap(); 669 670 // Test each transition in isolation. 671 for transition in transitions.iter() { 672 // Retrieve the transition ID. 673 let transition_id = *transition.id(); 674 675 // Ensure the transition does not exist. 676 let candidate = transition_store.get(&transition_id).unwrap(); 677 assert_eq!(None, candidate); 678 679 // Insert the transition. 680 transition_store.insert(transition).unwrap(); 681 682 // Retrieve the transition. 683 let candidate = transition_store.get(&transition_id).unwrap(); 684 assert_eq!(Some(transition.clone()), candidate); 685 686 // Remove the transition. 687 transition_store.remove(&transition_id).unwrap(); 688 689 // Retrieve the transition. 690 let candidate = transition_store.get(&transition_id).unwrap(); 691 assert_eq!(None, candidate); 692 } 693 694 // Insert every transition. 695 for transition in transitions.iter() { 696 // Retrieve the transition ID. 697 let transition_id = *transition.id(); 698 699 // Ensure the transition does not exist. 700 let candidate = transition_store.get(&transition_id).unwrap(); 701 assert_eq!(None, candidate); 702 703 // Insert the transition. 704 transition_store.insert(transition).unwrap(); 705 706 // Ensure the transition exists. 707 let candidate = transition_store.get(&transition_id).unwrap(); 708 assert_eq!(Some(transition.clone()), candidate); 709 } 710 711 // Get every transition (in reverse). 712 for transition in transitions.iter().rev() { 713 // Retrieve the transition ID. 714 let transition_id = *transition.id(); 715 716 // Retrieve the transition. 717 let candidate = transition_store.get(&transition_id).unwrap(); 718 assert_eq!(Some(transition.clone()), candidate); 719 } 720 721 // Remove every transition (in reverse). 722 for transition in transitions.iter().rev() { 723 // Retrieve the transition ID. 724 let transition_id = *transition.id(); 725 726 // Remove the transition. 727 transition_store.remove(&transition_id).unwrap(); 728 729 // Ensure the transition does not exist. 730 let candidate = transition_store.get(&transition_id).unwrap(); 731 assert_eq!(None, candidate); 732 } 733 } 734 } 735 }