1use super::*;
2use crate::internal_prelude::*;
3
4#[derive(Debug, Clone, PartialEq, Eq, ManifestSbor, ScryptoDescribe)]
5pub enum LedgerTransaction {
6 #[sbor(discriminator(GENESIS_LEDGER_TRANSACTION_DISCRIMINATOR))]
7 Genesis(Box<GenesisTransaction>),
8 #[sbor(discriminator(USER_V1_LEDGER_TRANSACTION_DISCRIMINATOR))]
9 UserV1(Box<NotarizedTransactionV1>),
10 #[sbor(discriminator(ROUND_UPDATE_V1_LEDGER_TRANSACTION_DISCRIMINATOR))]
11 RoundUpdateV1(Box<RoundUpdateTransactionV1>),
12 #[sbor(discriminator(FLASH_V1_LEDGER_TRANSACTION_DISCRIMINATOR))]
13 FlashV1(Box<FlashTransactionV1>),
14 #[sbor(discriminator(USER_V2_LEDGER_TRANSACTION_DISCRIMINATOR))]
15 UserV2(Box<NotarizedTransactionV2>),
16}
17
18const GENESIS_LEDGER_TRANSACTION_DISCRIMINATOR: u8 = 0;
19const USER_V1_LEDGER_TRANSACTION_DISCRIMINATOR: u8 = 1;
20const ROUND_UPDATE_V1_LEDGER_TRANSACTION_DISCRIMINATOR: u8 = 2;
21const FLASH_V1_LEDGER_TRANSACTION_DISCRIMINATOR: u8 = 3;
22const USER_V2_LEDGER_TRANSACTION_DISCRIMINATOR: u8 = 4;
23
24enum LedgerTransactionKind {
25 Genesis,
26 User,
27 Validator,
28 ProtocolUpdate,
29}
30
31impl LedgerTransactionKind {
32 fn discriminator_for_hash(&self) -> u8 {
33 match self {
34 LedgerTransactionKind::Genesis => GENESIS_LEDGER_TRANSACTION_DISCRIMINATOR,
35 LedgerTransactionKind::User => USER_V1_LEDGER_TRANSACTION_DISCRIMINATOR,
36 LedgerTransactionKind::Validator => ROUND_UPDATE_V1_LEDGER_TRANSACTION_DISCRIMINATOR,
37 LedgerTransactionKind::ProtocolUpdate => FLASH_V1_LEDGER_TRANSACTION_DISCRIMINATOR,
38 }
39 }
40}
41
42define_raw_transaction_payload!(
43 RawLedgerTransaction,
44 TransactionPayloadKind::LedgerTransaction
45);
46
47impl RawLedgerTransaction {
48 pub fn prepare(
49 &self,
50 settings: &PreparationSettings,
51 ) -> Result<PreparedLedgerTransaction, PrepareError> {
52 PreparedLedgerTransaction::prepare(self, settings)
53 }
54
55 pub fn validate(
56 &self,
57 validator: &TransactionValidator,
58 accepted_kind: AcceptedLedgerTransactionKind,
59 ) -> Result<ValidatedLedgerTransaction, LedgerTransactionValidationError> {
60 let prepared = PreparedLedgerTransaction::prepare(self, validator.preparation_settings())?;
61 prepared.validate(validator, accepted_kind)
62 }
63
64 pub fn create_executable(
65 &self,
66 validator: &TransactionValidator,
67 accepted_kind: AcceptedLedgerTransactionKind,
68 ) -> Result<ExecutableTransaction, LedgerTransactionValidationError> {
69 let validated = self.validate(validator, accepted_kind)?;
70 validated.create_executable()
71 }
72
73 pub fn create_identifiable_ledger_executable(
74 &self,
75 validator: &TransactionValidator,
76 accepted_kind: AcceptedLedgerTransactionKind,
77 ) -> Result<IdentifiedLedgerExecutable, LedgerTransactionValidationError> {
78 let validated = self.validate(validator, accepted_kind)?;
79 let hashes = validated.create_hashes();
80 let executable = validated.create_ledger_executable();
81 Ok(IdentifiedLedgerExecutable { executable, hashes })
82 }
83}
84
85impl IntoExecutable for RawLedgerTransaction {
86 type Error = LedgerTransactionValidationError;
87
88 fn into_executable(
89 self,
90 validator: &TransactionValidator,
91 ) -> Result<ExecutableTransaction, Self::Error> {
92 self.create_executable(validator, AcceptedLedgerTransactionKind::Any)
93 }
94}
95
96#[derive(Debug, Clone)]
97pub enum LedgerTransactionValidationError {
98 ValidationError(TransactionValidationError),
99 GenesisTransactionNotCurrentlyPermitted,
100 UserTransactionNotCurrentlyPermitted,
101 ValidateTransactionNotCurrentlyPermitted,
102 ProtocolUpdateNotCurrentlyPermitted,
103 FlashNotCurrentlyPermitted,
104}
105
106impl From<TransactionValidationError> for LedgerTransactionValidationError {
107 fn from(value: TransactionValidationError) -> Self {
108 Self::ValidationError(value)
109 }
110}
111
112impl From<PrepareError> for LedgerTransactionValidationError {
113 fn from(value: PrepareError) -> Self {
114 Self::ValidationError(value.into())
115 }
116}
117
118impl TransactionPayload for LedgerTransaction {
119 type Prepared = PreparedLedgerTransaction;
120 type Raw = RawLedgerTransaction;
121}
122
123#[derive(Debug, Clone, PartialEq, Eq, ManifestSbor, ScryptoDescribe)]
124pub enum GenesisTransaction {
125 #[sbor(discriminator(GENESIS_TRANSACTION_FLASH_DISCRIMINATOR))]
126 Flash,
127 #[sbor(discriminator(GENESIS_TRANSACTION_SYSTEM_TRANSACTION_DISCRIMINATOR))]
128 Transaction(Box<SystemTransactionV1>),
129}
130
131const GENESIS_TRANSACTION_FLASH_DISCRIMINATOR: u8 = 0;
132const GENESIS_TRANSACTION_SYSTEM_TRANSACTION_DISCRIMINATOR: u8 = 1;
133
134pub struct PreparedLedgerTransaction {
135 pub inner: PreparedLedgerTransactionInner,
136 pub summary: Summary,
137}
138
139impl PreparedLedgerTransaction {
140 pub fn into_user(self) -> Option<PreparedUserTransaction> {
141 match self.inner {
142 PreparedLedgerTransactionInner::User(t) => Some(t),
143 _ => None,
144 }
145 }
146
147 pub fn as_user(&self) -> Option<&PreparedUserTransaction> {
148 match &self.inner {
149 PreparedLedgerTransactionInner::User(t) => Some(t),
150 _ => None,
151 }
152 }
153
154 pub fn create_hashes(&self) -> LedgerTransactionHashes {
155 LedgerTransactionHashes {
156 ledger_transaction_hash: self.ledger_transaction_hash(),
157 kinded: match &self.inner {
158 PreparedLedgerTransactionInner::Genesis(t) => KindedTransactionHashes::Genesis {
159 system_transaction_hash: t.system_transaction_hash(),
160 },
161 PreparedLedgerTransactionInner::User(t) => {
162 KindedTransactionHashes::User(t.hashes())
163 }
164 PreparedLedgerTransactionInner::Validator(t) => {
165 KindedTransactionHashes::RoundUpdateV1 {
166 round_update_hash: t.round_update_transaction_hash(),
167 }
168 }
169 PreparedLedgerTransactionInner::ProtocolUpdate(t) => {
170 KindedTransactionHashes::FlashV1 {
171 flash_transaction_hash: t.flash_transaction_hash(),
172 }
173 }
174 },
175 }
176 }
177
178 pub fn validate(
179 self,
180 validator: &TransactionValidator,
181 accepted_kind: AcceptedLedgerTransactionKind,
182 ) -> Result<ValidatedLedgerTransaction, LedgerTransactionValidationError> {
183 let validated_inner = match self.inner {
184 PreparedLedgerTransactionInner::Genesis(t) => {
185 if !accepted_kind.permits_genesis() {
186 return Err(
187 LedgerTransactionValidationError::GenesisTransactionNotCurrentlyPermitted,
188 );
189 }
190 ValidatedLedgerTransactionInner::Genesis(t)
191 }
192 PreparedLedgerTransactionInner::User(t) => {
193 if !accepted_kind.permits_user() {
194 return Err(
195 LedgerTransactionValidationError::UserTransactionNotCurrentlyPermitted,
196 );
197 }
198 ValidatedLedgerTransactionInner::User(t.validate(validator)?)
199 }
200 PreparedLedgerTransactionInner::Validator(t) => {
201 if !accepted_kind.permits_validator() {
202 return Err(
203 LedgerTransactionValidationError::ValidateTransactionNotCurrentlyPermitted,
204 );
205 }
206 ValidatedLedgerTransactionInner::Validator(t)
207 }
208 PreparedLedgerTransactionInner::ProtocolUpdate(t) => {
209 if !accepted_kind.permits_protocol_update() {
210 return Err(
211 LedgerTransactionValidationError::ProtocolUpdateNotCurrentlyPermitted,
212 );
213 }
214 ValidatedLedgerTransactionInner::ProtocolUpdate(t)
215 }
216 };
217 Ok(ValidatedLedgerTransaction {
218 inner: validated_inner,
219 summary: self.summary,
220 })
221 }
222}
223
224#[derive(Debug, Copy, Clone)]
225pub enum AcceptedLedgerTransactionKind {
226 Any,
227 UserOnly,
228 GenesisOnly,
229 ValidatorOnly,
230 ProtocolUpdateOnly,
231 UserOrValidator,
232}
233
234impl AcceptedLedgerTransactionKind {
235 fn permits_genesis(&self) -> bool {
236 match self {
237 AcceptedLedgerTransactionKind::Any => true,
238 AcceptedLedgerTransactionKind::UserOnly => false,
239 AcceptedLedgerTransactionKind::GenesisOnly => true,
240 AcceptedLedgerTransactionKind::ValidatorOnly => false,
241 AcceptedLedgerTransactionKind::ProtocolUpdateOnly => false,
242 AcceptedLedgerTransactionKind::UserOrValidator => false,
243 }
244 }
245
246 fn permits_user(&self) -> bool {
247 match self {
248 AcceptedLedgerTransactionKind::Any => true,
249 AcceptedLedgerTransactionKind::UserOnly => true,
250 AcceptedLedgerTransactionKind::GenesisOnly => false,
251 AcceptedLedgerTransactionKind::ValidatorOnly => false,
252 AcceptedLedgerTransactionKind::ProtocolUpdateOnly => false,
253 AcceptedLedgerTransactionKind::UserOrValidator => true,
254 }
255 }
256
257 fn permits_validator(&self) -> bool {
258 match self {
259 AcceptedLedgerTransactionKind::Any => true,
260 AcceptedLedgerTransactionKind::UserOnly => false,
261 AcceptedLedgerTransactionKind::GenesisOnly => false,
262 AcceptedLedgerTransactionKind::ValidatorOnly => true,
263 AcceptedLedgerTransactionKind::ProtocolUpdateOnly => false,
264 AcceptedLedgerTransactionKind::UserOrValidator => true,
265 }
266 }
267
268 fn permits_protocol_update(&self) -> bool {
269 match self {
270 AcceptedLedgerTransactionKind::Any => true,
271 AcceptedLedgerTransactionKind::UserOnly => false,
272 AcceptedLedgerTransactionKind::GenesisOnly => false,
273 AcceptedLedgerTransactionKind::ValidatorOnly => false,
274 AcceptedLedgerTransactionKind::ProtocolUpdateOnly => true,
275 AcceptedLedgerTransactionKind::UserOrValidator => false,
276 }
277 }
278}
279
280impl_has_summary!(PreparedLedgerTransaction);
281
282pub enum PreparedLedgerTransactionInner {
283 Genesis(PreparedGenesisTransaction),
284 User(PreparedUserTransaction),
285 Validator(PreparedRoundUpdateTransactionV1),
286 ProtocolUpdate(PreparedFlashTransactionV1),
287}
288
289impl PreparedLedgerTransactionInner {
290 fn get_kind(&self) -> LedgerTransactionKind {
291 match self {
292 Self::Genesis(_) => LedgerTransactionKind::Genesis,
293 Self::User(_) => LedgerTransactionKind::User,
294 Self::Validator(_) => LedgerTransactionKind::Validator,
295 Self::ProtocolUpdate(_) => LedgerTransactionKind::ProtocolUpdate,
296 }
297 }
298
299 pub fn get_ledger_hash(&self) -> LedgerTransactionHash {
300 LedgerTransactionHash::for_kind(self.get_kind(), &self.get_summary().hash)
301 }
302}
303
304impl HasSummary for PreparedLedgerTransactionInner {
305 fn get_summary(&self) -> &Summary {
306 match self {
307 Self::Genesis(t) => t.get_summary(),
308 Self::User(t) => t.get_summary(),
309 Self::Validator(t) => t.get_summary(),
310 Self::ProtocolUpdate(t) => t.get_summary(),
311 }
312 }
313
314 fn summary_mut(&mut self) -> &mut Summary {
315 match self {
316 Self::Genesis(t) => t.summary_mut(),
317 Self::User(t) => t.summary_mut(),
318 Self::Validator(t) => t.summary_mut(),
319 Self::ProtocolUpdate(t) => t.summary_mut(),
320 }
321 }
322}
323
324impl TransactionPreparableFromValue for PreparedLedgerTransactionInner {
325 fn prepare_from_value(decoder: &mut TransactionDecoder) -> Result<Self, PrepareError> {
326 decoder.track_stack_depth_increase()?;
327 let (discriminator, length) = decoder.read_enum_header()?;
328 let prepared_inner = match discriminator {
329 GENESIS_LEDGER_TRANSACTION_DISCRIMINATOR => {
330 check_length(length, 1)?;
331 let (discriminator, length) = decoder.read_enum_header()?;
332 let genesis_transaction = match discriminator {
333 GENESIS_TRANSACTION_FLASH_DISCRIMINATOR => {
334 check_length(length, 0)?;
335 PreparedGenesisTransaction::Flash(Summary {
336 effective_length: 0,
337 total_bytes_hashed: 0,
338 hash: hash("Genesis Flash"),
339 })
340 }
341 GENESIS_TRANSACTION_SYSTEM_TRANSACTION_DISCRIMINATOR => {
342 check_length(length, 1)?;
343 let prepared = PreparedSystemTransactionV1::prepare_from_value(decoder)?;
344 PreparedGenesisTransaction::Transaction(prepared)
345 }
346 _ => return Err(unknown_discriminator(discriminator)),
347 };
348 PreparedLedgerTransactionInner::Genesis(genesis_transaction)
349 }
350 USER_V1_LEDGER_TRANSACTION_DISCRIMINATOR => {
351 check_length(length, 1)?;
352 let prepared = PreparedNotarizedTransactionV1::prepare_from_value(decoder)?;
353 PreparedLedgerTransactionInner::User(PreparedUserTransaction::V1(prepared))
354 }
355 ROUND_UPDATE_V1_LEDGER_TRANSACTION_DISCRIMINATOR => {
356 check_length(length, 1)?;
357 let prepared = PreparedRoundUpdateTransactionV1::prepare_from_value(decoder)?;
358 PreparedLedgerTransactionInner::Validator(prepared)
359 }
360 FLASH_V1_LEDGER_TRANSACTION_DISCRIMINATOR => {
361 check_length(length, 1)?;
362 let prepared = PreparedFlashTransactionV1::prepare_from_value(decoder)?;
363 PreparedLedgerTransactionInner::ProtocolUpdate(prepared)
364 }
365 USER_V2_LEDGER_TRANSACTION_DISCRIMINATOR => {
366 check_length(length, 1)?;
367 let prepared = PreparedNotarizedTransactionV2::prepare_from_value(decoder)?;
368 PreparedLedgerTransactionInner::User(PreparedUserTransaction::V2(prepared))
369 }
370 _ => return Err(unknown_discriminator(discriminator)),
371 };
372 decoder.track_stack_depth_decrease()?;
373
374 Ok(prepared_inner)
375 }
376}
377
378fn check_length(actual: usize, expected: usize) -> Result<(), PrepareError> {
379 if actual != expected {
380 return Err(PrepareError::DecodeError(DecodeError::UnexpectedSize {
381 expected,
382 actual,
383 }));
384 }
385 Ok(())
386}
387
388fn unknown_discriminator(discriminator: u8) -> PrepareError {
389 PrepareError::DecodeError(DecodeError::UnknownDiscriminator(discriminator))
390}
391
392pub enum PreparedGenesisTransaction {
393 Flash(Summary),
394 Transaction(PreparedSystemTransactionV1),
395}
396
397impl HasSummary for PreparedGenesisTransaction {
398 fn get_summary(&self) -> &Summary {
399 match self {
400 PreparedGenesisTransaction::Flash(summary) => summary,
401 PreparedGenesisTransaction::Transaction(t) => t.get_summary(),
402 }
403 }
404
405 fn summary_mut(&mut self) -> &mut Summary {
406 match self {
407 PreparedGenesisTransaction::Flash(summary) => summary,
408 PreparedGenesisTransaction::Transaction(t) => t.summary_mut(),
409 }
410 }
411}
412
413impl HasSystemTransactionHash for PreparedGenesisTransaction {
414 fn system_transaction_hash(&self) -> SystemTransactionHash {
415 match self {
416 PreparedGenesisTransaction::Flash(summary) => SystemTransactionHash(summary.hash),
417 PreparedGenesisTransaction::Transaction(transaction) => {
418 transaction.system_transaction_hash()
419 }
420 }
421 }
422}
423
424impl PreparedTransaction for PreparedLedgerTransaction {
425 type Raw = RawLedgerTransaction;
426
427 fn prepare_from_transaction_enum(
428 decoder: &mut TransactionDecoder,
429 ) -> Result<Self, PrepareError> {
430 decoder.track_stack_depth_increase()?;
431 decoder.read_header(
432 ExpectedTupleHeader::EnumWithValueKind {
433 discriminator: TransactionDiscriminator::Ledger as u8,
434 },
435 1,
436 )?;
437 let inner = PreparedLedgerTransactionInner::prepare_from_value(decoder)?;
438 decoder.track_stack_depth_decrease()?;
439
440 let summary = Summary {
441 effective_length: inner.get_summary().effective_length,
442 total_bytes_hashed: inner.get_summary().total_bytes_hashed,
443 hash: inner.get_ledger_hash().0,
444 };
445 Ok(Self { inner, summary })
446 }
447}
448
449impl IntoExecutable for PreparedLedgerTransaction {
450 type Error = LedgerTransactionValidationError;
451
452 fn into_executable(
453 self,
454 validator: &TransactionValidator,
455 ) -> Result<ExecutableTransaction, Self::Error> {
456 self.validate(validator, AcceptedLedgerTransactionKind::Any)?
457 .into_executable(validator)
458 }
459}
460
461pub struct ValidatedLedgerTransaction {
462 pub inner: ValidatedLedgerTransactionInner,
463 pub summary: Summary,
464}
465
466pub enum ValidatedLedgerTransactionInner {
467 Genesis(PreparedGenesisTransaction),
468 User(ValidatedUserTransaction),
469 Validator(PreparedRoundUpdateTransactionV1),
470 ProtocolUpdate(PreparedFlashTransactionV1),
471}
472
473impl ValidatedLedgerTransaction {
474 pub fn intent_hash_if_user(&self) -> Option<TransactionIntentHash> {
475 match &self.inner {
476 ValidatedLedgerTransactionInner::Genesis(_) => None,
477 ValidatedLedgerTransactionInner::User(t) => Some(t.transaction_intent_hash()),
478 ValidatedLedgerTransactionInner::Validator(_) => None,
479 ValidatedLedgerTransactionInner::ProtocolUpdate(_) => None,
480 }
481 }
482
483 pub fn create_ledger_executable(self) -> LedgerExecutable {
484 match self.inner {
485 ValidatedLedgerTransactionInner::Genesis(genesis) => match genesis {
486 PreparedGenesisTransaction::Flash(_) => LedgerExecutable::GenesisFlash,
487 PreparedGenesisTransaction::Transaction(t) => LedgerExecutable::Transaction {
488 executable: t
489 .create_executable(btreeset!(system_execution(SystemExecution::Protocol))),
490 },
491 },
492 ValidatedLedgerTransactionInner::User(t) => LedgerExecutable::Transaction {
493 executable: t.create_executable(),
494 },
495 ValidatedLedgerTransactionInner::Validator(t) => LedgerExecutable::Transaction {
496 executable: t.create_executable(),
497 },
498 ValidatedLedgerTransactionInner::ProtocolUpdate(t) => LedgerExecutable::Flash {
499 updates: t.state_updates,
500 },
501 }
502 }
503
504 pub fn create_executable(
506 self,
507 ) -> Result<ExecutableTransaction, LedgerTransactionValidationError> {
508 match self.create_ledger_executable() {
509 LedgerExecutable::GenesisFlash | LedgerExecutable::Flash { .. } => {
510 Err(LedgerTransactionValidationError::FlashNotCurrentlyPermitted)
511 }
512 LedgerExecutable::Transaction { executable } => Ok(executable),
513 }
514 }
515
516 pub fn create_hashes(&self) -> LedgerTransactionHashes {
517 LedgerTransactionHashes {
518 ledger_transaction_hash: self.ledger_transaction_hash(),
519 kinded: match &self.inner {
520 ValidatedLedgerTransactionInner::Genesis(t) => KindedTransactionHashes::Genesis {
521 system_transaction_hash: t.system_transaction_hash(),
522 },
523 ValidatedLedgerTransactionInner::User(t) => {
524 KindedTransactionHashes::User(t.hashes())
525 }
526 ValidatedLedgerTransactionInner::Validator(t) => {
527 KindedTransactionHashes::RoundUpdateV1 {
528 round_update_hash: t.round_update_transaction_hash(),
529 }
530 }
531 ValidatedLedgerTransactionInner::ProtocolUpdate(t) => {
532 KindedTransactionHashes::FlashV1 {
533 flash_transaction_hash: t.flash_transaction_hash(),
534 }
535 }
536 },
537 }
538 }
539}
540
541#[derive(Debug, Clone, PartialEq, Eq)]
542pub struct IdentifiedLedgerExecutable {
543 pub executable: LedgerExecutable,
544 pub hashes: LedgerTransactionHashes,
545}
546
547#[derive(Debug, Clone, PartialEq, Eq)]
548pub enum LedgerExecutable {
549 GenesisFlash,
551 Flash {
552 updates: StateUpdates,
555 },
556 Transaction {
557 executable: ExecutableTransaction,
558 },
559}
560
561impl IntoExecutable for ValidatedLedgerTransaction {
562 type Error = LedgerTransactionValidationError;
563
564 fn into_executable(
565 self,
566 _validator: &TransactionValidator,
567 ) -> Result<ExecutableTransaction, Self::Error> {
568 self.create_executable()
569 }
570}
571
572define_versioned! {
573 #[derive(Debug, Clone, ScryptoSbor)]
577 pub VersionedLedgerTransactionHashes(LedgerTransactionHashesVersions) {
578 previous_versions: [
579 1 => LedgerTransactionHashesV1: { updates_to: 2 },
580 ],
581 latest_version: {
582 2 => LedgerTransactionHashes = LedgerTransactionHashesV2,
583 },
584 },
585 outer_attributes: [
586 #[derive(ScryptoSborAssertion)]
587 #[sbor_assert(backwards_compatible(
588 bottlenose = "FILE:ledger_transaction_hashes_bottlenose.bin",
589 cuttlefish = "FILE:ledger_transaction_hashes_cuttlefish.bin"
590 ))]
591 ]
592}
593
594#[derive(Debug, Clone, PartialEq, Eq, Sbor)]
595pub struct LedgerTransactionHashesV2 {
596 pub ledger_transaction_hash: LedgerTransactionHash,
597 pub kinded: KindedTransactionHashesV2,
598}
599
600#[derive(Debug, Clone, PartialEq, Eq, Sbor)]
601pub struct LedgerTransactionHashesV1 {
602 pub ledger_transaction_hash: LedgerTransactionHash,
603 pub kinded: KindedTransactionHashesV1,
604}
605
606impl From<LedgerTransactionHashesV1> for LedgerTransactionHashesV2 {
607 fn from(value: LedgerTransactionHashesV1) -> Self {
608 let LedgerTransactionHashesV1 {
609 ledger_transaction_hash,
610 kinded,
611 } = value;
612 LedgerTransactionHashesV2 {
613 ledger_transaction_hash,
614 kinded: kinded.into(),
615 }
616 }
617}
618
619impl LedgerTransactionHashes {
620 pub fn as_user(&self) -> Option<&UserTransactionHashes> {
621 self.kinded.as_user()
622 }
623}
624
625pub type KindedTransactionHashes = KindedTransactionHashesV2;
626
627impl From<KindedTransactionHashesV1> for KindedTransactionHashesV2 {
628 fn from(value: KindedTransactionHashesV1) -> Self {
629 match value {
630 KindedTransactionHashesV1::Genesis {
631 system_transaction_hash,
632 } => KindedTransactionHashesV2::Genesis {
633 system_transaction_hash,
634 },
635 KindedTransactionHashesV1::User(user_transaction_hashes_v1) => {
636 KindedTransactionHashesV2::User(user_transaction_hashes_v1.into())
637 }
638 KindedTransactionHashesV1::RoundUpdateV1 { round_update_hash } => {
639 KindedTransactionHashesV2::RoundUpdateV1 { round_update_hash }
640 }
641 KindedTransactionHashesV1::FlashV1 {
642 flash_transaction_hash,
643 } => KindedTransactionHashesV2::FlashV1 {
644 flash_transaction_hash,
645 },
646 }
647 }
648}
649
650#[derive(Debug, Clone, PartialEq, Eq, Sbor)]
651pub enum KindedTransactionHashesV1 {
652 Genesis {
653 system_transaction_hash: SystemTransactionHash,
654 },
655 User(#[sbor(flatten)] UserTransactionHashesV1),
656 RoundUpdateV1 {
657 round_update_hash: RoundUpdateTransactionHash,
658 },
659 FlashV1 {
660 flash_transaction_hash: FlashTransactionHash,
661 },
662}
663
664#[derive(Debug, Clone, PartialEq, Eq, Sbor)]
665pub enum KindedTransactionHashesV2 {
666 Genesis {
667 system_transaction_hash: SystemTransactionHash,
668 },
669 User(#[sbor(flatten)] UserTransactionHashesV2),
670 RoundUpdateV1 {
671 round_update_hash: RoundUpdateTransactionHash,
672 },
673 FlashV1 {
674 flash_transaction_hash: FlashTransactionHash,
675 },
676}
677
678impl KindedTransactionHashes {
679 pub fn as_user(&self) -> Option<&UserTransactionHashes> {
680 match self {
681 KindedTransactionHashes::User(user) => Some(user),
682 _ => None,
683 }
684 }
685}
686
687impl HasLedgerTransactionHash for ValidatedLedgerTransaction {
688 fn ledger_transaction_hash(&self) -> LedgerTransactionHash {
689 LedgerTransactionHash::from_hash(self.summary.hash)
690 }
691}
692
693define_wrapped_hash!(LedgerTransactionHash);
694
695impl LedgerTransactionHash {
696 pub fn for_genesis(hash: &SystemTransactionHash) -> Self {
697 Self::for_kind(LedgerTransactionKind::Genesis, &hash.0)
698 }
699
700 pub fn for_user(hash: &NotarizedTransactionHash) -> Self {
701 Self::for_kind(LedgerTransactionKind::User, &hash.0)
702 }
703
704 pub fn for_round_update(hash: &RoundUpdateTransactionHash) -> Self {
705 Self::for_kind(LedgerTransactionKind::Validator, &hash.0)
706 }
707
708 fn for_kind(kind: LedgerTransactionKind, inner: &Hash) -> Self {
709 Self(
710 HashAccumulator::new()
711 .concat([
712 TRANSACTION_HASHABLE_PAYLOAD_PREFIX,
713 TransactionDiscriminator::Ledger as u8,
714 kind.discriminator_for_hash(),
715 ])
716 .concat(inner.as_slice())
717 .finalize(),
718 )
719 }
720}
721
722impl IsTransactionHashWithStaticHrp for LedgerTransactionHash {
723 fn static_hrp(hrp_set: &HrpSet) -> &str {
724 &hrp_set.ledger_transaction
725 }
726}
727
728pub trait HasLedgerTransactionHash {
729 fn ledger_transaction_hash(&self) -> LedgerTransactionHash;
730}
731
732impl HasLedgerTransactionHash for PreparedLedgerTransaction {
733 fn ledger_transaction_hash(&self) -> LedgerTransactionHash {
734 LedgerTransactionHash::from_hash(self.summary.hash)
735 }
736}
737
738#[cfg(test)]
739mod tests {
740 use super::*;
741
742 #[test]
743 pub fn v1_ledger_transaction_structure() {
744 let sig_1_private_key = Secp256k1PrivateKey::from_u64(1).unwrap();
745 let sig_2_private_key = Ed25519PrivateKey::from_u64(2).unwrap();
746 let notary_private_key = Ed25519PrivateKey::from_u64(3).unwrap();
747
748 let notarized = TransactionBuilder::new()
749 .header(TransactionHeaderV1 {
750 network_id: 21,
751 start_epoch_inclusive: Epoch::of(0),
752 end_epoch_exclusive: Epoch::of(100),
753 nonce: 0,
754 notary_public_key: notary_private_key.public_key().into(),
755 notary_is_signatory: true,
756 tip_percentage: 0,
757 })
758 .manifest(ManifestBuilder::new().drop_all_proofs().build())
759 .sign(&sig_1_private_key)
760 .sign(&sig_2_private_key)
761 .notarize(¬ary_private_key)
762 .build();
763
764 let prepared_notarized = notarized
765 .prepare(PreparationSettings::latest_ref())
766 .expect("Notarized can be prepared");
767
768 let ledger = LedgerTransaction::UserV1(Box::new(notarized));
769 let raw_ledger_transaction = ledger.to_raw().expect("Can be encoded");
770 LedgerTransaction::from_raw(&raw_ledger_transaction).expect("Can be decoded");
771 let prepared_ledger_transaction = raw_ledger_transaction
772 .prepare(PreparationSettings::latest_ref())
773 .expect("Can be prepared");
774
775 let expected_intent_hash = LedgerTransactionHash::from_hash(hash(
776 [
777 [
778 TRANSACTION_HASHABLE_PAYLOAD_PREFIX,
779 TransactionDiscriminator::Ledger as u8,
780 USER_V1_LEDGER_TRANSACTION_DISCRIMINATOR,
781 ]
782 .as_slice(),
783 prepared_notarized.notarized_transaction_hash().0.as_slice(),
784 ]
785 .concat(),
786 ));
787 assert_eq!(
788 prepared_ledger_transaction.ledger_transaction_hash(),
789 expected_intent_hash
790 );
791 assert_eq!(
792 LedgerTransactionHash::for_user(&prepared_notarized.notarized_transaction_hash()),
793 expected_intent_hash
794 );
795 }
796}