1use 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; pub const PRE_GENESIS_VERSION: Version = u64::max_value();
56
57#[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: AccountAddress,
72
73 payload: TransactionPayload,
75
76 expiration_timestamp_secs: u64,
78
79 chain_id: ChainId,
81}
82
83impl RawTransaction {
84 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 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 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 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 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 expiration_timestamp_secs: u64::max_value(),
202 chain_id: Default::default(),
203 })
204 }
205
206 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 pub fn sender(&self) -> AccountAddress { self.sender }
230}
231
232#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
238pub enum TransactionPayload {
239 #[doc(hidden)]
241 _LegacyWriteSet,
242 #[doc(hidden)]
244 _LegacyScript,
245 #[doc(hidden)]
247 _LegacyModule,
248 #[doc(hidden)]
250 _LegacyScriptFunction,
251
252 Election(ElectionPayload),
254
255 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 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#[derive(Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
398pub struct SignedTransaction {
399 raw_txn: RawTransaction,
401
402 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#[derive(Clone, Debug, Eq, PartialEq, Hash)]
424pub struct SignatureCheckedTransaction(SignedTransaction);
425
426impl SignatureCheckedTransaction {
427 pub fn into_inner(self) -> SignedTransaction { self.0 }
429
430 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 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 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 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#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
610pub enum TransactionStatus {
611 Discard(DiscardedVMStatus),
613
614 Keep(KeptVMStatus),
616
617 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#[derive(Clone, Debug, Eq, PartialEq)]
652pub struct TransactionOutput {
653 events: Vec<ContractEvent>,
655
656 gas_used: u64,
658
659 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#[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 transaction_hash: HashValue,
698
699 state_root_hash: HashValue,
702
703 event_root_hash: HashValue,
706
707 gas_used: u64,
709
710 status: KeptVMStatus,
715}
716
717impl TransactionInfo {
718 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 pub fn transaction_hash(&self) -> HashValue { self.transaction_hash }
735
736 pub fn state_root_hash(&self) -> HashValue { self.state_root_hash }
739
740 pub fn event_root_hash(&self) -> HashValue { self.event_root_hash }
743
744 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#[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 UserTransaction(SignedTransaction),
814
815 GenesisTransaction(Vec<ContractEvent>),
818
819 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}