diem_types/transaction/
mod.rs

1// Copyright (c) The Diem Core Contributors
2// SPDX-License-Identifier: Apache-2.0
3
4// Copyright 2021 Conflux Foundation. All rights reserved.
5// Conflux is free software and distributed under GNU General Public License.
6// See http://www.gnu.org/licenses/
7
8use std::{
9    convert::TryFrom,
10    fmt::{self, Display, Formatter},
11    ops::Deref,
12};
13
14use anyhow::{ensure, format_err, Error, Result};
15#[cfg(any(test, feature = "fuzzing"))]
16use proptest_derive::Arbitrary;
17use serde::{Deserialize, Serialize};
18
19use diem_crypto::{
20    hash::{CryptoHash, EventAccumulatorHasher},
21    traits::SigningKey,
22    HashValue, PrivateKey, VRFProof,
23};
24use diem_crypto_derive::{BCSCryptoHash, CryptoHasher};
25use pow_types::StakingEvent;
26
27use crate::{
28    account_address::AccountAddress,
29    block_info::PivotBlockDecision,
30    block_metadata::BlockMetadata,
31    chain_id::ChainId,
32    contract_event::ContractEvent,
33    ledger_info::LedgerInfo,
34    proof::{accumulator::InMemoryAccumulator, TransactionInfoWithProof},
35    term_state::{
36        DisputeEvent, DisputeEventV2, ElectionEvent, NodeID, RegisterEvent,
37        RetireEvent, UpdateVotingPowerEvent,
38    },
39    transaction::authenticator::{
40        TransactionAuthenticator, TransactionAuthenticatorUnchecked,
41    },
42    validator_config::{
43        ConsensusPrivateKey, ConsensusPublicKey, ConsensusSignature,
44        ConsensusVRFProof, ConsensusVRFPublicKey, MultiConsensusSignature,
45    },
46    vm_status::{DiscardedVMStatus, KeptVMStatus, StatusCode, VMStatus},
47};
48
49pub mod authenticator;
50
51pub type Version = u64; // Height - also used for MVCC in StateDB
52
53// In StateDB, things readable by the genesis transaction are under this
54// version.
55pub const PRE_GENESIS_VERSION: Version = u64::max_value();
56
57/// RawTransaction is the portion of a transaction that a client signs.
58#[derive(
59    Clone,
60    Debug,
61    Hash,
62    Eq,
63    PartialEq,
64    Serialize,
65    Deserialize,
66    CryptoHasher,
67    BCSCryptoHash,
68)]
69pub struct RawTransaction {
70    /// Sender's address.
71    sender: AccountAddress,
72
73    /// The transaction payload, e.g., a script to execute.
74    payload: TransactionPayload,
75
76    /// Always u64::MAX. Other values are regarded invalid.
77    expiration_timestamp_secs: u64,
78
79    /// Chain ID of the Diem network this transaction is intended for.
80    chain_id: ChainId,
81}
82
83impl RawTransaction {
84    /// Create a new `RawTransaction` with a payload.
85    ///
86    /// It can be either to publish a module, to execute a script, or to issue a
87    /// writeset transaction.
88    pub fn new(
89        sender: AccountAddress, payload: TransactionPayload,
90        expiration_timestamp_secs: u64, chain_id: ChainId,
91    ) -> Self {
92        RawTransaction {
93            sender,
94            payload,
95            expiration_timestamp_secs,
96            chain_id,
97        }
98    }
99
100    pub fn new_pivot_decision(
101        sender: AccountAddress, pivot_decision: PivotBlockDecision,
102        chain_id: ChainId,
103    ) -> Self {
104        RawTransaction {
105            sender,
106            payload: TransactionPayload::PivotDecision(pivot_decision),
107            // Write-set transactions are special and important and shouldn't
108            // expire.
109            expiration_timestamp_secs: u64::max_value(),
110            chain_id,
111        }
112    }
113
114    pub fn new_election(
115        sender: AccountAddress, election_payload: ElectionPayload,
116        chain_id: ChainId,
117    ) -> Self {
118        RawTransaction {
119            sender,
120            payload: TransactionPayload::Election(election_payload),
121            // Write-set transactions are special and important and shouldn't
122            // expire.
123            expiration_timestamp_secs: u64::max_value(),
124            chain_id,
125        }
126    }
127
128    pub fn new_dispute(
129        sender: AccountAddress, dispute_payload: DisputePayload,
130    ) -> Self {
131        RawTransaction {
132            sender,
133            payload: TransactionPayload::Dispute(dispute_payload),
134            // Write-set transactions are special and important and shouldn't
135            // expire.
136            expiration_timestamp_secs: u64::max_value(),
137            chain_id: Default::default(),
138        }
139    }
140
141    pub fn new_retire(
142        sender: AccountAddress, retire_payload: RetirePayload,
143    ) -> Self {
144        RawTransaction {
145            sender,
146            payload: TransactionPayload::Retire(retire_payload),
147            // Write-set transactions are special and important and shouldn't
148            // expire.
149            expiration_timestamp_secs: u64::max_value(),
150            chain_id: Default::default(),
151        }
152    }
153
154    pub fn from_staking_event(
155        staking_event: &StakingEvent, sender: AccountAddress,
156    ) -> Result<Self> {
157        let payload = match staking_event {
158            StakingEvent::Register(
159                addr_h256,
160                bls_pub_key_bytes,
161                vrf_pub_key_bytes,
162            ) => {
163                let addr = AccountAddress::from_bytes(addr_h256)?;
164                let public_key =
165                    ConsensusPublicKey::try_from(bls_pub_key_bytes.as_slice())?;
166                let vrf_public_key = ConsensusVRFPublicKey::try_from(
167                    vrf_pub_key_bytes.as_slice(),
168                )?;
169                let node_id =
170                    NodeID::new(public_key.clone(), vrf_public_key.clone());
171                ensure!(
172                    node_id.addr == addr,
173                    "register event has unmatching address and keys"
174                );
175                TransactionPayload::Register(RegisterPayload {
176                    public_key,
177                    vrf_public_key,
178                })
179            }
180            StakingEvent::IncreaseStake(addr_h256, updated_voting_power) => {
181                let addr = AccountAddress::from_bytes(addr_h256)?;
182                TransactionPayload::UpdateVotingPower(
183                    UpdateVotingPowerPayload {
184                        node_address: addr,
185                        voting_power: *updated_voting_power,
186                    },
187                )
188            }
189            StakingEvent::Retire(identifier, votes) => {
190                TransactionPayload::Retire(RetirePayload {
191                    node_id: AccountAddress::new(identifier.0),
192                    votes: *votes,
193                })
194            }
195        };
196        Ok(RawTransaction {
197            sender,
198            payload,
199            // Write-set transactions are special and important and shouldn't
200            // expire.
201            expiration_timestamp_secs: u64::max_value(),
202            chain_id: Default::default(),
203        })
204    }
205
206    /// Signs the given `RawTransaction`. Note that this consumes the
207    /// `RawTransaction` and turns it into a `SignatureCheckedTransaction`.
208    ///
209    /// For a transaction that has just been signed, its signature is expected
210    /// to be valid.
211    pub fn sign(
212        self, private_key: &ConsensusPrivateKey,
213    ) -> Result<SignatureCheckedTransaction> {
214        let signature = match self.payload {
215            TransactionPayload::PivotDecision(ref pivot_decision) => {
216                private_key.sign(pivot_decision)
217            }
218            _ => private_key.sign(&self),
219        };
220        let public_key = private_key.public_key();
221        Ok(SignatureCheckedTransaction(SignedTransaction::new(
222            self, public_key, signature,
223        )))
224    }
225
226    pub fn into_payload(self) -> TransactionPayload { self.payload }
227
228    /// Return the sender of this transaction.
229    pub fn sender(&self) -> AccountAddress { self.sender }
230}
231
232/// Different kinds of transactions.
233///
234/// **BCS serialization note:** Variant indices must remain stable for
235/// database compatibility. Indices 1-3 are legacy Diem Move variants that
236/// were never used in Conflux PoS but must be preserved as placeholders.
237#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
238pub enum TransactionPayload {
239    /// Legacy Diem variant (index 0). Never used in Conflux PoS.
240    #[doc(hidden)]
241    _LegacyWriteSet,
242    /// Legacy Diem variant (index 1). Never used in Conflux PoS.
243    #[doc(hidden)]
244    _LegacyScript,
245    /// Legacy Diem variant (index 2). Never used in Conflux PoS.
246    #[doc(hidden)]
247    _LegacyModule,
248    /// Legacy Diem variant (index 3). Never used in Conflux PoS.
249    #[doc(hidden)]
250    _LegacyScriptFunction,
251
252    /// A transaction that add a node to committee candidates.
253    Election(ElectionPayload),
254
255    /// A transaction that sets a node to `Retire` status so the node will not
256    /// be elected.
257    Retire(RetirePayload),
258
259    Register(RegisterPayload),
260
261    UpdateVotingPower(UpdateVotingPowerPayload),
262
263    PivotDecision(PivotBlockDecision),
264
265    Dispute(DisputePayload),
266}
267
268#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
269#[serde(rename_all = "camelCase")]
270pub struct ElectionPayload {
271    pub public_key: ConsensusPublicKey,
272    pub vrf_public_key: ConsensusVRFPublicKey,
273    pub target_term: u64,
274    pub vrf_proof: ConsensusVRFProof,
275}
276
277impl ElectionPayload {
278    pub fn to_event(&self) -> ContractEvent {
279        let event = ElectionEvent::new(
280            self.public_key.clone(),
281            self.vrf_public_key.clone(),
282            self.vrf_proof.to_hash().unwrap(),
283            self.target_term,
284        );
285        ContractEvent::new(
286            ElectionEvent::event_key(),
287            bcs::to_bytes(&event).unwrap(),
288        )
289    }
290}
291
292#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
293#[serde(rename_all = "camelCase")]
294pub struct RetirePayload {
295    pub node_id: AccountAddress,
296    pub votes: u64,
297}
298
299impl RetirePayload {
300    pub fn to_event(&self) -> ContractEvent {
301        let event = RetireEvent::new(self.node_id, self.votes);
302        ContractEvent::new(
303            RetireEvent::event_key(),
304            bcs::to_bytes(&event).unwrap(),
305        )
306    }
307}
308
309#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
310#[serde(rename_all = "camelCase")]
311pub struct RegisterPayload {
312    pub public_key: ConsensusPublicKey,
313    pub vrf_public_key: ConsensusVRFPublicKey,
314}
315
316impl RegisterPayload {
317    pub fn to_event(&self) -> ContractEvent {
318        let event = RegisterEvent::new(
319            self.public_key.clone(),
320            self.vrf_public_key.clone(),
321        );
322        ContractEvent::new(
323            RegisterEvent::event_key(),
324            bcs::to_bytes(&event).unwrap(),
325        )
326    }
327}
328
329#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
330#[serde(rename_all = "camelCase")]
331pub struct UpdateVotingPowerPayload {
332    pub node_address: AccountAddress,
333    pub voting_power: u64,
334}
335
336impl UpdateVotingPowerPayload {
337    pub fn to_event(&self) -> ContractEvent {
338        let event = UpdateVotingPowerEvent::new(
339            self.node_address.clone(),
340            self.voting_power,
341        );
342        ContractEvent::new(
343            UpdateVotingPowerEvent::event_key(),
344            bcs::to_bytes(&event).unwrap(),
345        )
346    }
347}
348
349#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
350#[serde(rename_all = "camelCase")]
351pub struct DisputePayload {
352    pub address: AccountAddress,
353    pub bls_pub_key: ConsensusPublicKey,
354    pub vrf_pub_key: ConsensusVRFPublicKey,
355    pub conflicting_votes: ConflictSignature,
356}
357
358#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
359pub enum ConflictSignature {
360    // Use raw bytes instead of `Proposal` or `Vote` to avoid dependency loop.
361    Proposal((Vec<u8>, Vec<u8>)),
362    Vote((Vec<u8>, Vec<u8>)),
363}
364
365impl DisputePayload {
366    pub fn to_event(&self) -> ContractEvent {
367        let event = DisputeEvent {
368            node_id: self.address,
369        };
370        ContractEvent::new(
371            DisputeEvent::event_key(),
372            bcs::to_bytes(&event).unwrap(),
373        )
374    }
375
376    pub fn to_event_v2(&self, offense_epoch: u64) -> ContractEvent {
377        let event = DisputeEventV2 {
378            node_id: self.address,
379            offense_epoch,
380        };
381        ContractEvent::new(
382            DisputeEventV2::event_key(),
383            bcs::to_bytes(&event).unwrap(),
384        )
385    }
386}
387
388/// A transaction that has been signed.
389///
390/// A `SignedTransaction` is a single transaction that can be atomically
391/// executed. Clients submit these to validator nodes, and the validator and
392/// executor submits these to the VM.
393///
394/// **IMPORTANT:** The signature of a `SignedTransaction` is not guaranteed to
395/// be verified. For a transaction whose signature is statically guaranteed to
396/// be verified, see [`SignatureCheckedTransaction`].
397#[derive(Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
398pub struct SignedTransaction {
399    /// The raw transaction
400    raw_txn: RawTransaction,
401
402    /// Public key and signature to authenticate
403    authenticator: TransactionAuthenticator,
404}
405
406#[derive(Deserialize)]
407pub struct SignedTransactionUnchecked {
408    pub raw_txn: RawTransaction,
409    pub authenticator: TransactionAuthenticatorUnchecked,
410}
411
412impl From<SignedTransactionUnchecked> for SignedTransaction {
413    fn from(t: SignedTransactionUnchecked) -> Self {
414        Self {
415            raw_txn: t.raw_txn,
416            authenticator: t.authenticator.into(),
417        }
418    }
419}
420
421/// A transaction for which the signature has been verified. Created by
422/// [`SignedTransaction::check_signature`] and [`RawTransaction::sign`].
423#[derive(Clone, Debug, Eq, PartialEq, Hash)]
424pub struct SignatureCheckedTransaction(SignedTransaction);
425
426impl SignatureCheckedTransaction {
427    /// Returns the `SignedTransaction` within.
428    pub fn into_inner(self) -> SignedTransaction { self.0 }
429
430    /// Returns the `RawTransaction` within.
431    pub fn into_raw_transaction(self) -> RawTransaction {
432        self.0.into_raw_transaction()
433    }
434}
435
436impl Deref for SignatureCheckedTransaction {
437    type Target = SignedTransaction;
438
439    fn deref(&self) -> &Self::Target { &self.0 }
440}
441
442impl fmt::Debug for SignedTransaction {
443    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
444        write!(
445            f,
446            "SignedTransaction {{ \n \
447             {{ raw_txn: {:#?}, \n \
448             authenticator: {:#?}, \n \
449             }} \n \
450             }}",
451            self.raw_txn, self.authenticator
452        )
453    }
454}
455
456impl SignedTransaction {
457    pub fn new(
458        raw_txn: RawTransaction, public_key: ConsensusPublicKey,
459        signature: ConsensusSignature,
460    ) -> SignedTransaction {
461        let authenticator =
462            TransactionAuthenticator::bls(public_key, signature);
463        SignedTransaction {
464            raw_txn,
465            authenticator,
466        }
467    }
468
469    pub fn new_multisig(
470        raw_txn: RawTransaction, signatures: Vec<(ConsensusSignature, usize)>,
471    ) -> SignedTransaction {
472        let signature = MultiConsensusSignature::new(signatures).unwrap();
473        let authenticator = TransactionAuthenticator::multi_bls(signature);
474        SignedTransaction {
475            raw_txn,
476            authenticator,
477        }
478    }
479
480    pub fn authenticator(&self) -> TransactionAuthenticator {
481        self.authenticator.clone()
482    }
483
484    pub fn raw_txn(&self) -> RawTransaction { self.raw_txn.clone() }
485
486    pub fn hash(&self) -> HashValue { self.raw_txn.hash() }
487
488    pub fn sender(&self) -> AccountAddress { self.raw_txn.sender }
489
490    pub fn into_raw_transaction(self) -> RawTransaction { self.raw_txn }
491
492    pub fn chain_id(&self) -> ChainId { self.raw_txn.chain_id }
493
494    pub fn payload(&self) -> &TransactionPayload { &self.raw_txn.payload }
495
496    pub fn expiration_timestamp_secs(&self) -> u64 {
497        self.raw_txn.expiration_timestamp_secs
498    }
499
500    pub fn raw_txn_bytes_len(&self) -> usize {
501        bcs::to_bytes(&self.raw_txn)
502            .expect("Unable to serialize RawTransaction")
503            .len()
504    }
505
506    /// Verifies the authenticator's signature against the appropriate
507    /// signed message without consuming `self`. Returns `Ok(())` on a
508    /// valid signature.
509    pub fn verify_signature(&self) -> Result<()> {
510        match self.payload() {
511            TransactionPayload::PivotDecision(pivot_decision) => {
512                self.authenticator.verify(pivot_decision)
513            }
514            _ => self.authenticator.verify(&self.raw_txn),
515        }
516    }
517
518    /// Same as `verify_signature`, but consumes `self` and returns a
519    /// `SignatureCheckedTransaction` newtype that proves the check ran.
520    pub fn check_signature(self) -> Result<SignatureCheckedTransaction> {
521        self.verify_signature()?;
522        Ok(SignatureCheckedTransaction(self))
523    }
524}
525
526#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
527#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
528pub struct TransactionWithProof {
529    pub version: Version,
530    pub transaction: Transaction,
531    pub events: Option<Vec<ContractEvent>>,
532    pub proof: TransactionInfoWithProof,
533}
534
535impl TransactionWithProof {
536    pub fn new(
537        version: Version, transaction: Transaction,
538        events: Option<Vec<ContractEvent>>, proof: TransactionInfoWithProof,
539    ) -> Self {
540        Self {
541            version,
542            transaction,
543            events,
544            proof,
545        }
546    }
547
548    /// Verifies the transaction with the proof, both carried by `self`.
549    ///
550    /// A few things are ensured if no error is raised:
551    ///   1. This transaction exists in the ledger represented by `ledger_info`.
552    ///   2. This transaction is a `UserTransaction`.
553    ///   3. And this user transaction has the same `version`, `sender`, and
554    /// `sequence_number` as      indicated by the parameter list. If any of
555    /// these parameter is unknown to the call site      that is supposed to
556    /// be informed via this struct, get it from the struct itself, such
557    ///      as version and sender.
558    pub fn verify_user_txn(
559        &self, ledger_info: &LedgerInfo, version: Version,
560        sender: AccountAddress,
561    ) -> Result<()> {
562        let signed_transaction = self.transaction.as_signed_user_txn()?;
563
564        ensure!(
565            self.version == version,
566            "Version ({}) is not expected ({}).",
567            self.version,
568            version,
569        );
570        ensure!(
571            signed_transaction.sender() == sender,
572            "Sender ({}) not expected ({}).",
573            signed_transaction.sender(),
574            sender,
575        );
576        let txn_hash = self.transaction.hash();
577        ensure!(
578            txn_hash == self.proof.transaction_info().transaction_hash,
579            "Transaction hash ({}) not expected ({}).",
580            txn_hash,
581            self.proof.transaction_info().transaction_hash,
582        );
583
584        if let Some(events) = &self.events {
585            let event_hashes: Vec<_> =
586                events.iter().map(ContractEvent::hash).collect();
587            let event_root_hash =
588                InMemoryAccumulator::<EventAccumulatorHasher>::from_leaves(
589                    &event_hashes[..],
590                )
591                .root_hash();
592            ensure!(
593                event_root_hash
594                    == self.proof.transaction_info().event_root_hash,
595                "Event root hash ({}) not expected ({}).",
596                event_root_hash,
597                self.proof.transaction_info().event_root_hash,
598            );
599        }
600
601        self.proof.verify(ledger_info, version)
602    }
603}
604
605/// The status of executing a transaction. The VM decides whether or not we
606/// should `Keep` the transaction output or `Discard` it based upon the
607/// execution of the transaction. We wrap these decisions around a `VMStatus`
608/// that provides more detail on the final execution state of the VM.
609#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
610pub enum TransactionStatus {
611    /// Discard the transaction output
612    Discard(DiscardedVMStatus),
613
614    /// Keep the transaction output
615    Keep(KeptVMStatus),
616
617    /// Retry the transaction, e.g., after a reconfiguration
618    Retry,
619}
620
621impl TransactionStatus {
622    pub fn status(&self) -> Result<KeptVMStatus, StatusCode> {
623        match self {
624            TransactionStatus::Keep(status) => Ok(status.clone()),
625            TransactionStatus::Discard(code) => Err(*code),
626            TransactionStatus::Retry => {
627                Err(StatusCode::UNKNOWN_VALIDATION_STATUS)
628            }
629        }
630    }
631
632    pub fn is_discarded(&self) -> bool {
633        match self {
634            TransactionStatus::Discard(_) => true,
635            TransactionStatus::Keep(_) => false,
636            TransactionStatus::Retry => true,
637        }
638    }
639}
640
641impl From<VMStatus> for TransactionStatus {
642    fn from(vm_status: VMStatus) -> Self {
643        match vm_status.keep_or_discard() {
644            Ok(recorded) => TransactionStatus::Keep(recorded),
645            Err(code) => TransactionStatus::Discard(code),
646        }
647    }
648}
649
650/// The output of executing a transaction.
651#[derive(Clone, Debug, Eq, PartialEq)]
652pub struct TransactionOutput {
653    /// The list of events emitted during this transaction.
654    events: Vec<ContractEvent>,
655
656    /// The amount of gas used during execution.
657    gas_used: u64,
658
659    /// The execution status.
660    status: TransactionStatus,
661}
662
663impl TransactionOutput {
664    pub fn new(
665        events: Vec<ContractEvent>, gas_used: u64, status: TransactionStatus,
666    ) -> Self {
667        TransactionOutput {
668            events,
669            gas_used,
670            status,
671        }
672    }
673
674    pub fn events(&self) -> &[ContractEvent] { &self.events }
675
676    pub fn gas_used(&self) -> u64 { self.gas_used }
677
678    pub fn status(&self) -> &TransactionStatus { &self.status }
679}
680
681/// `TransactionInfo` is the object we store in the transaction accumulator. It
682/// consists of the transaction as well as the execution result of this
683/// transaction.
684#[derive(
685    Clone,
686    CryptoHasher,
687    BCSCryptoHash,
688    Debug,
689    Eq,
690    PartialEq,
691    Serialize,
692    Deserialize,
693)]
694#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
695pub struct TransactionInfo {
696    /// The hash of this transaction.
697    transaction_hash: HashValue,
698
699    /// The root hash of Sparse Merkle Tree describing the world state at the
700    /// end of this transaction.
701    state_root_hash: HashValue,
702
703    /// The root hash of Merkle Accumulator storing all events emitted during
704    /// this transaction.
705    event_root_hash: HashValue,
706
707    /// The amount of gas used.
708    gas_used: u64,
709
710    /// The vm status. If it is not `Executed`, this will provide the general
711    /// error class. Execution failures and Move abort's recieve more
712    /// detailed information. But other errors are generally categorized
713    /// with no status code or other information
714    status: KeptVMStatus,
715}
716
717impl TransactionInfo {
718    /// Constructs a new `TransactionInfo` object using transaction hash, state
719    /// root hash and event root hash.
720    pub fn new(
721        transaction_hash: HashValue, state_root_hash: HashValue,
722        event_root_hash: HashValue, gas_used: u64, status: KeptVMStatus,
723    ) -> TransactionInfo {
724        TransactionInfo {
725            transaction_hash,
726            state_root_hash,
727            event_root_hash,
728            gas_used,
729            status,
730        }
731    }
732
733    /// Returns the hash of this transaction.
734    pub fn transaction_hash(&self) -> HashValue { self.transaction_hash }
735
736    /// Returns root hash of Sparse Merkle Tree describing the world state at
737    /// the end of this transaction.
738    pub fn state_root_hash(&self) -> HashValue { self.state_root_hash }
739
740    /// Returns the root hash of Merkle Accumulator storing all events emitted
741    /// during this transaction.
742    pub fn event_root_hash(&self) -> HashValue { self.event_root_hash }
743
744    /// Returns the amount of gas used by this transaction.
745    pub fn gas_used(&self) -> u64 { self.gas_used }
746
747    pub fn status(&self) -> &KeptVMStatus { &self.status }
748}
749
750impl Display for TransactionInfo {
751    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
752        write!(
753            f,
754            "TransactionInfo: [txn_hash: {}, state_root_hash: {}, event_root_hash: {}, gas_used: {}, recorded_status: {:?}]",
755            self.transaction_hash(), self.state_root_hash(), self.event_root_hash(), self.gas_used(), self.status(),
756        )
757    }
758}
759
760#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
761pub struct TransactionToCommit {
762    transaction: Transaction,
763    events: Vec<ContractEvent>,
764    gas_used: u64,
765    status: KeptVMStatus,
766}
767
768impl TransactionToCommit {
769    pub fn new(
770        transaction: Transaction, events: Vec<ContractEvent>, gas_used: u64,
771        status: KeptVMStatus,
772    ) -> Self {
773        TransactionToCommit {
774            transaction,
775            events,
776            gas_used,
777            status,
778        }
779    }
780
781    pub fn transaction(&self) -> &Transaction { &self.transaction }
782
783    pub fn events(&self) -> &[ContractEvent] { &self.events }
784
785    pub fn gas_used(&self) -> u64 { self.gas_used }
786
787    pub fn status(&self) -> &KeptVMStatus { &self.status }
788}
789
790/// `Transaction` will be the transaction type used internally in the diem node
791/// to represent the transaction to be processed and persisted.
792///
793/// We suppress the clippy warning here as we would expect most of the
794/// transaction to be user transaction.
795#[allow(clippy::large_enum_variant)]
796#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
797#[derive(
798    Clone,
799    Debug,
800    Eq,
801    PartialEq,
802    Serialize,
803    Deserialize,
804    CryptoHasher,
805    BCSCryptoHash,
806)]
807pub enum Transaction {
808    /// Transaction submitted by the user. e.g: P2P payment transaction,
809    /// publishing module transaction, etc.
810    /// TODO: We need to rename SignedTransaction to SignedUserTransaction, as
811    /// well as all the other       transaction types we had in our
812    /// codebase.
813    UserTransaction(SignedTransaction),
814
815    /// Genesis transaction carrying the epoch-change event for the
816    /// initial validator set.
817    GenesisTransaction(Vec<ContractEvent>),
818
819    /// Transaction to update the block metadata resource at the beginning
820    /// of a block.
821    BlockMetadata(BlockMetadata),
822}
823
824#[derive(Deserialize)]
825pub enum TransactionUnchecked {
826    UserTransaction(SignedTransactionUnchecked),
827    GenesisTransaction(Vec<ContractEvent>),
828    BlockMetadata(BlockMetadata),
829}
830
831impl From<TransactionUnchecked> for Transaction {
832    fn from(t: TransactionUnchecked) -> Self {
833        match t {
834            TransactionUnchecked::UserTransaction(t) => {
835                Self::UserTransaction(t.into())
836            }
837            TransactionUnchecked::GenesisTransaction(t) => {
838                Self::GenesisTransaction(t)
839            }
840            TransactionUnchecked::BlockMetadata(t) => Self::BlockMetadata(t),
841        }
842    }
843}
844
845impl Transaction {
846    pub fn as_signed_user_txn(&self) -> Result<&SignedTransaction> {
847        match self {
848            Transaction::UserTransaction(txn) => Ok(txn),
849            _ => Err(format_err!("Not a user transaction.")),
850        }
851    }
852}
853
854impl TryFrom<Transaction> for SignedTransaction {
855    type Error = Error;
856
857    fn try_from(txn: Transaction) -> Result<Self> {
858        match txn {
859            Transaction::UserTransaction(txn) => Ok(txn),
860            _ => Err(format_err!("Not a user transaction.")),
861        }
862    }
863}