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 bytes; 17 mod serialize; 18 mod string; 19 20 use crate::{Transaction, rejected::Rejected}; 21 use alphavm_synthesizer_program::FinalizeOperation; 22 use console::{network::prelude::*, program::FINALIZE_ID_DEPTH, types::Field}; 23 24 pub type NumFinalizeSize = u16; 25 26 /// The confirmed transaction. 27 #[derive(Clone, PartialEq, Eq)] 28 pub enum ConfirmedTransaction<N: Network> { 29 /// The accepted deploy transaction is composed of `(index, deploy_transaction, finalize_operations)`. 30 /// The finalize operations may contain operations from the executing the constructor and fee transition. 31 AcceptedDeploy(u32, Transaction<N>, Vec<FinalizeOperation<N>>), 32 /// The accepted execute transaction is composed of `(index, execute_transaction, finalize_operations)`. 33 /// The finalize operations can contain operations from the executing the finalize scope and fee transition. 34 AcceptedExecute(u32, Transaction<N>, Vec<FinalizeOperation<N>>), 35 /// The rejected deploy transaction is composed of `(index, fee_transaction, rejected_deployment, finalize_operations)`. 36 /// The finalize operations can contain operations from the fee transition. 37 RejectedDeploy(u32, Transaction<N>, Rejected<N>, Vec<FinalizeOperation<N>>), 38 /// The rejected execute transaction is composed of `(index, fee_transaction, rejected_execution, finalize_operations)`. 39 /// The finalize operations can contain operations from the fee transition. 40 RejectedExecute(u32, Transaction<N>, Rejected<N>, Vec<FinalizeOperation<N>>), 41 } 42 43 impl<N: Network> ConfirmedTransaction<N> { 44 /// Returns a new instance of an accepted deploy transaction. 45 pub fn accepted_deploy( 46 index: u32, 47 transaction: Transaction<N>, 48 finalize_operations: Vec<FinalizeOperation<N>>, 49 ) -> Result<Self> { 50 // Retrieve the program and fee from the deployment transaction, and ensure the transaction is a deploy transaction. 51 let (program, fee) = match &transaction { 52 Transaction::Deploy(_, _, _, deployment, fee) => (deployment.program(), fee), 53 Transaction::Execute(..) | Transaction::Fee(..) => { 54 bail!("Transaction '{}' is not a deploy transaction", transaction.id()) 55 } 56 }; 57 58 // Count the number of `InitializeMapping` and `*KeyValue` finalize operations. 59 let (num_initialize_mappings, num_key_values) = 60 finalize_operations.iter().try_fold((0, 0), |(init, key_value), operation| match operation { 61 FinalizeOperation::InitializeMapping(..) => Ok((init + 1, key_value)), 62 FinalizeOperation::InsertKeyValue(..) // At the time of writing, `InsertKeyValue` is only used in tests. However, it is added for completeness, as it is a valid operation. 63 | FinalizeOperation::RemoveKeyValue(..) 64 | FinalizeOperation::UpdateKeyValue(..) => Ok((init, key_value + 1)), 65 op => { 66 bail!("Transaction '{}' (deploy) contains an invalid finalize operation ({op})", transaction.id()) 67 } 68 })?; 69 70 // Perform safety checks on the finalize operations. 71 { 72 // Ensure the number of finalize operations matches the number of 'InitializeMapping' and '*KeyValue' finalize operations. 73 if num_initialize_mappings + num_key_values != finalize_operations.len() { 74 bail!( 75 "Transaction '{}' (deploy) must contain '{}' operations", 76 transaction.id(), 77 finalize_operations.len() 78 ); 79 } 80 // Ensure the number of program mappings upper bounds the number of 'InitializeMapping' finalize operations. 81 // The upper bound is due to the fact that some mappings may have been initialized in earlier deployments or upgrades. 82 ensure!( 83 num_initialize_mappings <= program.mappings().len(), 84 "Transaction '{}' (deploy) must contain at most '{}' 'InitializeMapping' operations (found '{num_initialize_mappings}')", 85 transaction.id(), 86 program.mappings().len(), 87 ); 88 // Ensure the number of fee finalize operations lower bounds the number of '*KeyValue' finalize operations. 89 // The lower bound is due to the fact that constructors can issue '*KeyValue' operations as part of the deployment. 90 ensure!( 91 fee.num_finalize_operations() <= num_key_values, 92 "Transaction '{}' (deploy) must contain at least {} '*KeyValue' operations (found '{num_key_values}')", 93 transaction.id(), 94 fee.num_finalize_operations() 95 ); 96 // Ensure the number of fee finalize operations and the number of "write" operations in the constructor upper bounds the number of '*KeyValue' finalize operations. 97 // This is an upper bound because a constructor may contain `branch.*` commands so that a subset of writes are executed. 98 let num_constructor_writes = usize::from(program.constructor().map(|c| c.num_writes()).unwrap_or_default()); 99 ensure!( 100 fee.num_finalize_operations().saturating_add(num_constructor_writes) >= num_key_values, 101 "Transaction '{}' (deploy) must contain at most {} '*KeyValue' operations (found '{num_key_values}')", 102 transaction.id(), 103 fee.num_finalize_operations().saturating_add(num_constructor_writes) 104 ); 105 } 106 107 // Return the accepted deploy transaction. 108 Ok(Self::AcceptedDeploy(index, transaction, finalize_operations)) 109 } 110 111 /// Returns a new instance of an accepted execute transaction. 112 pub fn accepted_execute( 113 index: u32, 114 transaction: Transaction<N>, 115 finalize_operations: Vec<FinalizeOperation<N>>, 116 ) -> Result<Self> { 117 // Ensure the finalize operations contain the correct types. 118 for operation in finalize_operations.iter() { 119 // Ensure the finalize operation is an insert or update key-value operation. 120 match operation { 121 FinalizeOperation::InsertKeyValue(..) 122 | FinalizeOperation::UpdateKeyValue(..) 123 | FinalizeOperation::RemoveKeyValue(..) => (), 124 FinalizeOperation::InitializeMapping(..) 125 | FinalizeOperation::ReplaceMapping(..) 126 | FinalizeOperation::RemoveMapping(..) => { 127 bail!("Transaction '{}' (execute) contains an invalid finalize operation type", transaction.id()) 128 } 129 } 130 } 131 // Ensure the transaction is an execute transaction. 132 match transaction.is_execute() { 133 true => Ok(Self::AcceptedExecute(index, transaction, finalize_operations)), 134 false => bail!("Transaction '{}' is not an execute transaction", transaction.id()), 135 } 136 } 137 138 /// Returns a new instance of a rejected deploy transaction. 139 pub fn rejected_deploy( 140 index: u32, 141 transaction: Transaction<N>, 142 rejected: Rejected<N>, 143 finalize_operations: Vec<FinalizeOperation<N>>, 144 ) -> Result<Self> { 145 // Ensure the rejected object is a deployment. 146 ensure!(rejected.is_deployment(), "Rejected deployment is not a deployment"); 147 // Ensure the finalize operations contain the correct types. 148 for operation in finalize_operations.iter() { 149 // Ensure the finalize operation is an insert or update key-value operation. 150 match operation { 151 FinalizeOperation::InsertKeyValue(..) 152 | FinalizeOperation::UpdateKeyValue(..) 153 | FinalizeOperation::RemoveKeyValue(..) => (), 154 FinalizeOperation::InitializeMapping(..) 155 | FinalizeOperation::ReplaceMapping(..) 156 | FinalizeOperation::RemoveMapping(..) => { 157 bail!("Transaction '{}' (fee) contains an invalid finalize operation type", transaction.id()) 158 } 159 } 160 } 161 // Ensure the transaction is a fee transaction. 162 match transaction.is_fee() { 163 true => Ok(Self::RejectedDeploy(index, transaction, rejected, finalize_operations)), 164 false => bail!("Transaction '{}' is not a fee transaction", transaction.id()), 165 } 166 } 167 168 /// Returns a new instance of a rejected execute transaction. 169 /// 170 /// Arguments: 171 /// - `index`: The index of the transaction within the block. 172 /// - `transaction`: The associated fee transaction. 173 /// - `rejected`: The rejected execute transaction. 174 /// - `finalize_operations`: The finalize operations for the fee transaction. 175 pub fn rejected_execute( 176 index: u32, 177 transaction: Transaction<N>, 178 rejected: Rejected<N>, 179 finalize_operations: Vec<FinalizeOperation<N>>, 180 ) -> Result<Self> { 181 // Ensure the rejected object is an execution. 182 ensure!(rejected.is_execution(), "Rejected execution is not an execution"); 183 // Ensure the finalize operations contain the correct types. 184 for operation in finalize_operations.iter() { 185 // Ensure the finalize operation is an insert or update key-value operation. 186 match operation { 187 FinalizeOperation::InsertKeyValue(..) 188 | FinalizeOperation::UpdateKeyValue(..) 189 | FinalizeOperation::RemoveKeyValue(..) => (), 190 FinalizeOperation::InitializeMapping(..) 191 | FinalizeOperation::ReplaceMapping(..) 192 | FinalizeOperation::RemoveMapping(..) => { 193 bail!("Transaction '{}' (fee) contains an invalid finalize operation type", transaction.id()) 194 } 195 } 196 } 197 // Ensure the transaction is a fee transaction. 198 match transaction.is_fee() { 199 true => Ok(Self::RejectedExecute(index, transaction, rejected, finalize_operations)), 200 false => bail!("Transaction '{}' is not a fee transaction", transaction.id()), 201 } 202 } 203 } 204 205 impl<N: Network> ConfirmedTransaction<N> { 206 /// Returns 'true' if the confirmed transaction is accepted. 207 pub const fn is_accepted(&self) -> bool { 208 match self { 209 Self::AcceptedDeploy(..) | Self::AcceptedExecute(..) => true, 210 Self::RejectedDeploy(..) | Self::RejectedExecute(..) => false, 211 } 212 } 213 214 /// Returns 'true' if the confirmed transaction is rejected. 215 pub const fn is_rejected(&self) -> bool { 216 !self.is_accepted() 217 } 218 219 /// Returns `true` if the confirmed transaction represents the given unconfirmed transaction ID. 220 pub fn contains_unconfirmed_transaction_id(&self, unconfirmed_transaction_id: &N::TransactionID) -> bool { 221 self.to_unconfirmed_transaction_id().is_ok_and(|id| &id == unconfirmed_transaction_id) 222 } 223 } 224 225 impl<N: Network> ConfirmedTransaction<N> { 226 /// Returns the confirmed transaction index. 227 pub const fn index(&self) -> u32 { 228 match self { 229 Self::AcceptedDeploy(index, ..) => *index, 230 Self::AcceptedExecute(index, ..) => *index, 231 Self::RejectedDeploy(index, ..) => *index, 232 Self::RejectedExecute(index, ..) => *index, 233 } 234 } 235 236 /// Returns the human-readable variant of the confirmed transaction. 237 pub const fn variant(&self) -> &str { 238 match self { 239 Self::AcceptedDeploy(..) => "accepted deploy", 240 Self::AcceptedExecute(..) => "accepted execute", 241 Self::RejectedDeploy(..) => "rejected deploy", 242 Self::RejectedExecute(..) => "rejected execute", 243 } 244 } 245 246 /// Returns the underlying transaction. 247 /// 248 /// For an accepted transaction, it is the original/unconfirmed transaction issued by the client. 249 /// For a rejected transaction, it is the fee transaction, not the original transaction. 250 pub const fn transaction(&self) -> &Transaction<N> { 251 match self { 252 Self::AcceptedDeploy(_, transaction, _) => transaction, 253 Self::AcceptedExecute(_, transaction, _) => transaction, 254 Self::RejectedDeploy(_, transaction, _, _) => transaction, 255 Self::RejectedExecute(_, transaction, _, _) => transaction, 256 } 257 } 258 259 /// Returns the transaction. 260 pub fn into_transaction(self) -> Transaction<N> { 261 match self { 262 Self::AcceptedDeploy(_, transaction, _) => transaction, 263 Self::AcceptedExecute(_, transaction, _) => transaction, 264 Self::RejectedDeploy(_, transaction, _, _) => transaction, 265 Self::RejectedExecute(_, transaction, _, _) => transaction, 266 } 267 } 268 269 /// Returns the number of finalize operations. 270 pub fn num_finalize(&self) -> usize { 271 match self { 272 Self::AcceptedDeploy(_, _, finalize) => finalize.len(), 273 Self::AcceptedExecute(_, _, finalize) => finalize.len(), 274 Self::RejectedDeploy(_, _, _, finalize) => finalize.len(), 275 Self::RejectedExecute(_, _, _, finalize) => finalize.len(), 276 } 277 } 278 279 /// Returns the finalize operations for the confirmed transaction. 280 pub const fn finalize_operations(&self) -> &Vec<FinalizeOperation<N>> { 281 match self { 282 Self::AcceptedDeploy(_, _, finalize) => finalize, 283 Self::AcceptedExecute(_, _, finalize) => finalize, 284 Self::RejectedDeploy(_, _, _, finalize) => finalize, 285 Self::RejectedExecute(_, _, _, finalize) => finalize, 286 } 287 } 288 289 /// Returns the finalize ID, by computing the root of a (small) Merkle tree comprised of 290 /// the ordered finalize operations for the transaction. 291 pub fn to_finalize_id(&self) -> Result<Field<N>> { 292 // Prepare the leaves. 293 let leaves = self.finalize_operations().iter().map(ToBits::to_bits_le).collect::<Vec<_>>(); 294 // Compute the finalize ID. 295 // Note: This call will ensure the number of finalize operations is within the size of the Merkle tree. 296 Ok(*N::merkle_tree_bhp::<FINALIZE_ID_DEPTH>(&leaves)?.root()) 297 } 298 299 /// Returns the rejected ID, if the confirmed transaction is rejected. 300 pub fn to_rejected_id(&self) -> Result<Option<Field<N>>> { 301 match self { 302 ConfirmedTransaction::AcceptedDeploy(..) | ConfirmedTransaction::AcceptedExecute(..) => Ok(None), 303 ConfirmedTransaction::RejectedDeploy(_, _, rejected, _) => Ok(Some(rejected.to_id()?)), 304 ConfirmedTransaction::RejectedExecute(_, _, rejected, _) => Ok(Some(rejected.to_id()?)), 305 } 306 } 307 308 /// Returns the rejected object, if the confirmed transaction is rejected. 309 pub fn to_rejected(&self) -> Option<&Rejected<N>> { 310 match self { 311 ConfirmedTransaction::AcceptedDeploy(..) | ConfirmedTransaction::AcceptedExecute(..) => None, 312 ConfirmedTransaction::RejectedDeploy(_, _, rejected, _) => Some(rejected), 313 ConfirmedTransaction::RejectedExecute(_, _, rejected, _) => Some(rejected), 314 } 315 } 316 317 /// Returns the unconfirmed transaction ID, which is defined as the transaction ID prior to confirmation. 318 /// When a transaction is rejected, its fee transition is used to construct the confirmed transaction ID, 319 /// changing the original transaction ID. 320 pub fn to_unconfirmed_transaction_id(&self) -> Result<N::TransactionID> { 321 match self { 322 Self::AcceptedDeploy(_, transaction, _) => Ok(transaction.id()), 323 Self::AcceptedExecute(_, transaction, _) => Ok(transaction.id()), 324 Self::RejectedDeploy(_, fee_transaction, rejected, _) 325 | Self::RejectedExecute(_, fee_transaction, rejected, _) => { 326 Ok(rejected.to_unconfirmed_id(&fee_transaction.fee_transition())?.into()) 327 } 328 } 329 } 330 331 /// Returns the unconfirmed transaction, which is defined as the transaction prior to confirmation. 332 /// When a transaction is rejected, its fee transition is used to construct the confirmed transaction, 333 /// changing the original transaction. 334 pub fn to_unconfirmed_transaction(&self) -> Result<Transaction<N>> { 335 match self { 336 Self::AcceptedDeploy(_, transaction, _) => Ok(transaction.clone()), 337 Self::AcceptedExecute(_, transaction, _) => Ok(transaction.clone()), 338 Self::RejectedDeploy(_, fee_transaction, rejected, _) => Transaction::from_deployment( 339 rejected 340 .program_owner() 341 .copied() 342 .ok_or_else(|| anyhow!("Missing program owner for rejected transaction"))?, 343 rejected.deployment().cloned().ok_or_else(|| anyhow!("Missing deployment for rejected transaction"))?, 344 fee_transaction.fee_transition().ok_or_else(|| anyhow!("Missing fee for rejected deployment"))?, 345 ), 346 Self::RejectedExecute(_, fee_transaction, rejected, _) => Transaction::from_execution( 347 rejected.execution().cloned().ok_or_else(|| anyhow!("Missing execution for rejected transaction"))?, 348 fee_transaction.fee_transition(), 349 ), 350 } 351 } 352 } 353 354 impl<N: Network> Deref for ConfirmedTransaction<N> { 355 type Target = Transaction<N>; 356 357 /// Returns a reference to the valid transaction. 358 fn deref(&self) -> &Self::Target { 359 self.transaction() 360 } 361 } 362 363 #[cfg(test)] 364 pub mod test_helpers { 365 use super::*; 366 use console::network::MainnetV0; 367 368 type CurrentNetwork = MainnetV0; 369 370 /// Samples an accepted deploy transaction at the given index. 371 pub(crate) fn sample_accepted_deploy( 372 index: u32, 373 version: u8, 374 edition: u16, 375 is_fee_private: bool, 376 rng: &mut TestRng, 377 ) -> ConfirmedTransaction<CurrentNetwork> { 378 // Sample a deploy transaction. 379 let tx = crate::transaction::test_helpers::sample_deployment_transaction(version, edition, is_fee_private, rng); 380 381 // Construct the finalize operations based on if the fee is public or private. 382 let finalize_operations = match is_fee_private { 383 true => vec![FinalizeOperation::InitializeMapping(Uniform::rand(rng))], 384 false => vec![ 385 FinalizeOperation::InitializeMapping(Uniform::rand(rng)), 386 FinalizeOperation::UpdateKeyValue(Uniform::rand(rng), Uniform::rand(rng), Uniform::rand(rng)), 387 ], 388 }; 389 390 // Return the confirmed transaction. 391 ConfirmedTransaction::accepted_deploy(index, tx, finalize_operations).unwrap() 392 } 393 394 /// Samples an accepted execute transaction at the given index. 395 pub(crate) fn sample_accepted_execute( 396 index: u32, 397 is_fee_private: bool, 398 rng: &mut TestRng, 399 ) -> ConfirmedTransaction<CurrentNetwork> { 400 // Sample an execute transaction. 401 let tx = crate::transaction::test_helpers::sample_execution_transaction_with_fee(is_fee_private, rng, 0); 402 // Return the confirmed transaction. 403 ConfirmedTransaction::accepted_execute(index, tx, vec![]).unwrap() 404 } 405 406 /// Samples a rejected deploy transaction at the given index. 407 pub(crate) fn sample_rejected_deploy( 408 index: u32, 409 version: u8, 410 edition: u16, 411 is_fee_private: bool, 412 rng: &mut TestRng, 413 ) -> ConfirmedTransaction<CurrentNetwork> { 414 // Sample a fee transaction. 415 let fee_transaction = match is_fee_private { 416 true => crate::transaction::test_helpers::sample_private_fee_transaction(rng), 417 false => crate::transaction::test_helpers::sample_fee_public_transaction(rng), 418 }; 419 420 // Extract the rejected deployment. 421 let rejected = crate::rejected::test_helpers::sample_rejected_deployment(version, edition, is_fee_private, rng); 422 423 // Return the confirmed transaction. 424 ConfirmedTransaction::rejected_deploy(index, fee_transaction, rejected, vec![]).unwrap() 425 } 426 427 /// Samples a rejected execute transaction at the given index. 428 pub(crate) fn sample_rejected_execute( 429 index: u32, 430 is_fee_private: bool, 431 rng: &mut TestRng, 432 ) -> ConfirmedTransaction<CurrentNetwork> { 433 // Sample a fee transaction. 434 let fee_transaction = match is_fee_private { 435 true => crate::transaction::test_helpers::sample_private_fee_transaction(rng), 436 false => crate::transaction::test_helpers::sample_fee_public_transaction(rng), 437 }; 438 439 // Extract the rejected execution. 440 let rejected = crate::rejected::test_helpers::sample_rejected_execution(is_fee_private, rng); 441 442 // Return the confirmed transaction. 443 ConfirmedTransaction::rejected_execute(index, fee_transaction, rejected, vec![]).unwrap() 444 } 445 446 /// Sample a list of randomly confirmed transactions. 447 pub(crate) fn sample_confirmed_transactions() -> Vec<ConfirmedTransaction<CurrentNetwork>> { 448 let rng = &mut TestRng::default(); 449 450 vec![ 451 sample_accepted_deploy(0, 1, Uniform::rand(rng), true, rng), 452 sample_accepted_deploy(0, 1, Uniform::rand(rng), true, rng), 453 sample_accepted_deploy(0, 2, Uniform::rand(rng), true, rng), 454 sample_accepted_deploy(0, 2, Uniform::rand(rng), true, rng), 455 sample_accepted_execute(1, true, rng), 456 sample_accepted_execute(1, false, rng), 457 sample_rejected_deploy(2, 1, Uniform::rand(rng), true, rng), 458 sample_rejected_deploy(2, 1, Uniform::rand(rng), true, rng), 459 sample_rejected_deploy(2, 2, Uniform::rand(rng), true, rng), 460 sample_rejected_deploy(2, 2, Uniform::rand(rng), true, rng), 461 sample_rejected_execute(3, true, rng), 462 sample_rejected_execute(3, false, rng), 463 sample_accepted_execute(Uniform::rand(rng), true, rng), 464 sample_accepted_execute(Uniform::rand(rng), false, rng), 465 sample_rejected_deploy(Uniform::rand(rng), 1, Uniform::rand(rng), true, rng), 466 sample_rejected_deploy(Uniform::rand(rng), 1, Uniform::rand(rng), false, rng), 467 sample_rejected_deploy(Uniform::rand(rng), 1, Uniform::rand(rng), true, rng), 468 sample_rejected_deploy(Uniform::rand(rng), 1, Uniform::rand(rng), false, rng), 469 sample_rejected_deploy(Uniform::rand(rng), 2, Uniform::rand(rng), true, rng), 470 sample_rejected_deploy(Uniform::rand(rng), 2, Uniform::rand(rng), false, rng), 471 sample_rejected_deploy(Uniform::rand(rng), 2, Uniform::rand(rng), true, rng), 472 sample_rejected_deploy(Uniform::rand(rng), 2, Uniform::rand(rng), false, rng), 473 sample_rejected_execute(Uniform::rand(rng), true, rng), 474 sample_rejected_execute(Uniform::rand(rng), false, rng), 475 ] 476 } 477 } 478 479 #[cfg(test)] 480 mod test { 481 use super::*; 482 use crate::transactions::confirmed::test_helpers; 483 484 type CurrentNetwork = console::network::MainnetV0; 485 486 #[test] 487 fn test_accepted_execute() { 488 let rng = &mut TestRng::default(); 489 490 let index = Uniform::rand(rng); 491 let tx = crate::transaction::test_helpers::sample_execution_transaction_with_fee(true, rng, 0); 492 493 // Create an `AcceptedExecution` with valid `FinalizeOperation`s. 494 let finalize_operations = vec![ 495 FinalizeOperation::InsertKeyValue(Uniform::rand(rng), Uniform::rand(rng), Uniform::rand(rng)), 496 FinalizeOperation::UpdateKeyValue(Uniform::rand(rng), Uniform::rand(rng), Uniform::rand(rng)), 497 FinalizeOperation::RemoveKeyValue(Uniform::rand(rng), Uniform::rand(rng)), 498 ]; 499 let confirmed = ConfirmedTransaction::accepted_execute(index, tx.clone(), finalize_operations.clone()).unwrap(); 500 501 assert_eq!(confirmed.index(), index); 502 assert_eq!(confirmed.transaction(), &tx); 503 assert_eq!(confirmed.num_finalize(), finalize_operations.len()); 504 assert_eq!(confirmed.finalize_operations(), &finalize_operations); 505 506 // Attempt to create an `AcceptedExecution` with invalid `FinalizeOperation`s. 507 let finalize_operations = vec![FinalizeOperation::InitializeMapping(Uniform::rand(rng))]; 508 let confirmed = ConfirmedTransaction::accepted_execute(index, tx.clone(), finalize_operations); 509 assert!(confirmed.is_err()); 510 511 let finalize_operations = vec![FinalizeOperation::RemoveMapping(Uniform::rand(rng))]; 512 let confirmed = ConfirmedTransaction::accepted_execute(index, tx, finalize_operations); 513 assert!(confirmed.is_err()); 514 } 515 516 #[test] 517 fn test_contains_unconfirmed_transaction_id() { 518 let rng = &mut TestRng::default(); 519 520 // A helper function to check that the unconfirmed transaction ID is correct. 521 let check_contains_unconfirmed_transaction_id = |confirmed: ConfirmedTransaction<CurrentNetwork>| { 522 let rng = &mut TestRng::default(); 523 let unconfirmed_transaction_id = confirmed.to_unconfirmed_transaction_id().unwrap(); 524 assert!(confirmed.contains_unconfirmed_transaction_id(&unconfirmed_transaction_id)); 525 assert!(!confirmed.contains_unconfirmed_transaction_id(&<CurrentNetwork as Network>::TransactionID::from( 526 Field::rand(rng) 527 ))); 528 }; 529 530 // Ensure that the unconfirmed transaction ID of an accepted deployment is equivalent to its confirmed transaction ID. 531 let accepted_deploy = 532 test_helpers::sample_accepted_deploy(Uniform::rand(rng), 1, Uniform::rand(rng), true, rng); 533 check_contains_unconfirmed_transaction_id(accepted_deploy); 534 let accepted_deploy = 535 test_helpers::sample_accepted_deploy(Uniform::rand(rng), 1, Uniform::rand(rng), false, rng); 536 check_contains_unconfirmed_transaction_id(accepted_deploy); 537 let accepted_deploy = 538 test_helpers::sample_accepted_deploy(Uniform::rand(rng), 2, Uniform::rand(rng), true, rng); 539 check_contains_unconfirmed_transaction_id(accepted_deploy); 540 let accepted_deploy = 541 test_helpers::sample_accepted_deploy(Uniform::rand(rng), 2, Uniform::rand(rng), false, rng); 542 check_contains_unconfirmed_transaction_id(accepted_deploy); 543 544 // Ensure that the unconfirmed transaction ID of an accepted execute is equivalent to its confirmed transaction ID. 545 let accepted_execution = test_helpers::sample_accepted_execute(Uniform::rand(rng), true, rng); 546 check_contains_unconfirmed_transaction_id(accepted_execution); 547 let accepted_execution = test_helpers::sample_accepted_execute(Uniform::rand(rng), false, rng); 548 check_contains_unconfirmed_transaction_id(accepted_execution); 549 550 // Ensure that the unconfirmed transaction ID of a rejected deployment is not equivalent to its confirmed transaction ID. 551 let rejected_deploy = 552 test_helpers::sample_rejected_deploy(Uniform::rand(rng), 1, Uniform::rand(rng), true, rng); 553 check_contains_unconfirmed_transaction_id(rejected_deploy); 554 let rejected_deploy = 555 test_helpers::sample_rejected_deploy(Uniform::rand(rng), 1, Uniform::rand(rng), false, rng); 556 check_contains_unconfirmed_transaction_id(rejected_deploy); 557 let rejected_deploy = 558 test_helpers::sample_rejected_deploy(Uniform::rand(rng), 2, Uniform::rand(rng), true, rng); 559 check_contains_unconfirmed_transaction_id(rejected_deploy); 560 let rejected_deploy = 561 test_helpers::sample_rejected_deploy(Uniform::rand(rng), 2, Uniform::rand(rng), false, rng); 562 check_contains_unconfirmed_transaction_id(rejected_deploy); 563 564 // Ensure that the unconfirmed transaction ID of a rejected execute is not equivalent to its confirmed transaction ID. 565 let rejected_execution = test_helpers::sample_rejected_execute(Uniform::rand(rng), true, rng); 566 check_contains_unconfirmed_transaction_id(rejected_execution); 567 let rejected_execution = test_helpers::sample_rejected_execute(Uniform::rand(rng), false, rng); 568 check_contains_unconfirmed_transaction_id(rejected_execution); 569 } 570 571 #[test] 572 fn test_unconfirmed_transaction_ids() { 573 let rng = &mut TestRng::default(); 574 575 // Ensure that the unconfirmed transaction ID of an accepted deployment is equivalent to its confirmed transaction ID. 576 let accepted_deploy = 577 test_helpers::sample_accepted_deploy(Uniform::rand(rng), 1, Uniform::rand(rng), true, rng); 578 assert_eq!(accepted_deploy.to_unconfirmed_transaction_id().unwrap(), accepted_deploy.id()); 579 let accepted_deploy = 580 test_helpers::sample_accepted_deploy(Uniform::rand(rng), 1, Uniform::rand(rng), false, rng); 581 assert_eq!(accepted_deploy.to_unconfirmed_transaction_id().unwrap(), accepted_deploy.id()); 582 let accepted_deploy = 583 test_helpers::sample_accepted_deploy(Uniform::rand(rng), 2, Uniform::rand(rng), true, rng); 584 assert_eq!(accepted_deploy.to_unconfirmed_transaction_id().unwrap(), accepted_deploy.id()); 585 let accepted_deploy = 586 test_helpers::sample_accepted_deploy(Uniform::rand(rng), 2, Uniform::rand(rng), false, rng); 587 assert_eq!(accepted_deploy.to_unconfirmed_transaction_id().unwrap(), accepted_deploy.id()); 588 589 // Ensure that the unconfirmed transaction ID of an accepted execute is equivalent to its confirmed transaction ID. 590 let accepted_execution = test_helpers::sample_accepted_execute(Uniform::rand(rng), true, rng); 591 assert_eq!(accepted_execution.to_unconfirmed_transaction_id().unwrap(), accepted_execution.id()); 592 let accepted_execution = test_helpers::sample_accepted_execute(Uniform::rand(rng), false, rng); 593 assert_eq!(accepted_execution.to_unconfirmed_transaction_id().unwrap(), accepted_execution.id()); 594 595 // Ensure that the unconfirmed transaction ID of a rejected deployment is not equivalent to its confirmed transaction ID. 596 let rejected_deploy = 597 test_helpers::sample_rejected_deploy(Uniform::rand(rng), 1, Uniform::rand(rng), true, rng); 598 assert_ne!(rejected_deploy.to_unconfirmed_transaction_id().unwrap(), rejected_deploy.id()); 599 let rejected_deploy = 600 test_helpers::sample_rejected_deploy(Uniform::rand(rng), 1, Uniform::rand(rng), false, rng); 601 assert_ne!(rejected_deploy.to_unconfirmed_transaction_id().unwrap(), rejected_deploy.id()); 602 let rejected_deploy = 603 test_helpers::sample_rejected_deploy(Uniform::rand(rng), 2, Uniform::rand(rng), true, rng); 604 assert_ne!(rejected_deploy.to_unconfirmed_transaction_id().unwrap(), rejected_deploy.id()); 605 let rejected_deploy = 606 test_helpers::sample_rejected_deploy(Uniform::rand(rng), 2, Uniform::rand(rng), false, rng); 607 assert_ne!(rejected_deploy.to_unconfirmed_transaction_id().unwrap(), rejected_deploy.id()); 608 609 // Ensure that the unconfirmed transaction ID of a rejected execute is not equivalent to its confirmed transaction ID. 610 let rejected_execution = test_helpers::sample_rejected_execute(Uniform::rand(rng), true, rng); 611 assert_ne!(rejected_execution.to_unconfirmed_transaction_id().unwrap(), rejected_execution.id()); 612 let rejected_execution = test_helpers::sample_rejected_execute(Uniform::rand(rng), false, rng); 613 assert_ne!(rejected_execution.to_unconfirmed_transaction_id().unwrap(), rejected_execution.id()); 614 } 615 616 #[test] 617 fn test_unconfirmed_transactions() { 618 let rng = &mut TestRng::default(); 619 620 // Ensure that the unconfirmed transaction of an accepted deployment is equivalent to its confirmed transaction. 621 let accepted_deploy = 622 test_helpers::sample_accepted_deploy(Uniform::rand(rng), 1, Uniform::rand(rng), true, rng); 623 assert_eq!(&accepted_deploy.to_unconfirmed_transaction().unwrap(), accepted_deploy.transaction()); 624 let accepted_deploy = 625 test_helpers::sample_accepted_deploy(Uniform::rand(rng), 1, Uniform::rand(rng), false, rng); 626 assert_eq!(&accepted_deploy.to_unconfirmed_transaction().unwrap(), accepted_deploy.transaction()); 627 let accepted_deploy = 628 test_helpers::sample_accepted_deploy(Uniform::rand(rng), 2, Uniform::rand(rng), true, rng); 629 assert_eq!(&accepted_deploy.to_unconfirmed_transaction().unwrap(), accepted_deploy.transaction()); 630 let accepted_deploy = 631 test_helpers::sample_accepted_deploy(Uniform::rand(rng), 2, Uniform::rand(rng), false, rng); 632 assert_eq!(&accepted_deploy.to_unconfirmed_transaction().unwrap(), accepted_deploy.transaction()); 633 634 // Ensure that the unconfirmed transaction of an accepted execute is equivalent to its confirmed transaction. 635 let accepted_execution = test_helpers::sample_accepted_execute(Uniform::rand(rng), true, rng); 636 assert_eq!(&accepted_execution.to_unconfirmed_transaction().unwrap(), accepted_execution.transaction()); 637 let accepted_execution = test_helpers::sample_accepted_execute(Uniform::rand(rng), false, rng); 638 assert_eq!(&accepted_execution.to_unconfirmed_transaction().unwrap(), accepted_execution.transaction()); 639 640 // Ensure that the unconfirmed transaction of a rejected deployment is not equivalent to its confirmed transaction. 641 let deployment_transaction = 642 crate::transaction::test_helpers::sample_deployment_transaction(1, Uniform::rand(rng), true, rng); 643 let rejected = Rejected::new_deployment( 644 *deployment_transaction.owner().unwrap(), 645 deployment_transaction.deployment().unwrap().clone(), 646 ); 647 let fee = Transaction::from_fee(deployment_transaction.fee_transition().unwrap()).unwrap(); 648 let rejected_deploy = ConfirmedTransaction::rejected_deploy(Uniform::rand(rng), fee, rejected, vec![]).unwrap(); 649 assert_eq!(rejected_deploy.to_unconfirmed_transaction_id().unwrap(), deployment_transaction.id()); 650 assert_eq!(rejected_deploy.to_unconfirmed_transaction().unwrap(), deployment_transaction); 651 652 let deployment_transaction = 653 crate::transaction::test_helpers::sample_deployment_transaction(1, Uniform::rand(rng), false, rng); 654 let rejected = Rejected::new_deployment( 655 *deployment_transaction.owner().unwrap(), 656 deployment_transaction.deployment().unwrap().clone(), 657 ); 658 let fee = Transaction::from_fee(deployment_transaction.fee_transition().unwrap()).unwrap(); 659 let rejected_deploy = ConfirmedTransaction::rejected_deploy(Uniform::rand(rng), fee, rejected, vec![]).unwrap(); 660 assert_eq!(rejected_deploy.to_unconfirmed_transaction_id().unwrap(), deployment_transaction.id()); 661 assert_eq!(rejected_deploy.to_unconfirmed_transaction().unwrap(), deployment_transaction); 662 663 let deployment_transaction = 664 crate::transaction::test_helpers::sample_deployment_transaction(2, Uniform::rand(rng), true, rng); 665 let rejected = Rejected::new_deployment( 666 *deployment_transaction.owner().unwrap(), 667 deployment_transaction.deployment().unwrap().clone(), 668 ); 669 let fee = Transaction::from_fee(deployment_transaction.fee_transition().unwrap()).unwrap(); 670 let rejected_deploy = ConfirmedTransaction::rejected_deploy(Uniform::rand(rng), fee, rejected, vec![]).unwrap(); 671 assert_eq!(rejected_deploy.to_unconfirmed_transaction_id().unwrap(), deployment_transaction.id()); 672 assert_eq!(rejected_deploy.to_unconfirmed_transaction().unwrap(), deployment_transaction); 673 674 let deployment_transaction = 675 crate::transaction::test_helpers::sample_deployment_transaction(2, Uniform::rand(rng), false, rng); 676 let rejected = Rejected::new_deployment( 677 *deployment_transaction.owner().unwrap(), 678 deployment_transaction.deployment().unwrap().clone(), 679 ); 680 let fee = Transaction::from_fee(deployment_transaction.fee_transition().unwrap()).unwrap(); 681 let rejected_deploy = ConfirmedTransaction::rejected_deploy(Uniform::rand(rng), fee, rejected, vec![]).unwrap(); 682 assert_eq!(rejected_deploy.to_unconfirmed_transaction_id().unwrap(), deployment_transaction.id()); 683 assert_eq!(rejected_deploy.to_unconfirmed_transaction().unwrap(), deployment_transaction); 684 685 // Ensure that the unconfirmed transaction of a rejected execute is not equivalent to its confirmed transaction. 686 let execution_transaction = 687 crate::transaction::test_helpers::sample_execution_transaction_with_fee(true, rng, 0); 688 let rejected = Rejected::new_execution(execution_transaction.execution().unwrap().clone()); 689 let fee = Transaction::from_fee(execution_transaction.fee_transition().unwrap()).unwrap(); 690 let rejected_execute = 691 ConfirmedTransaction::rejected_execute(Uniform::rand(rng), fee, rejected, vec![]).unwrap(); 692 assert_eq!(rejected_execute.to_unconfirmed_transaction_id().unwrap(), execution_transaction.id()); 693 assert_eq!(rejected_execute.to_unconfirmed_transaction().unwrap(), execution_transaction); 694 695 let execution_transaction = 696 crate::transaction::test_helpers::sample_execution_transaction_with_fee(false, rng, 0); 697 let rejected = Rejected::new_execution(execution_transaction.execution().unwrap().clone()); 698 let fee = Transaction::from_fee(execution_transaction.fee_transition().unwrap()).unwrap(); 699 let rejected_execute = 700 ConfirmedTransaction::rejected_execute(Uniform::rand(rng), fee, rejected, vec![]).unwrap(); 701 assert_eq!(rejected_execute.to_unconfirmed_transaction_id().unwrap(), execution_transaction.id()); 702 assert_eq!(rejected_execute.to_unconfirmed_transaction().unwrap(), execution_transaction); 703 } 704 }