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 ) -> Result<SignedTransaction> {
472 let signature = MultiConsensusSignature::new(signatures)?;
475 let authenticator = TransactionAuthenticator::multi_bls(signature);
476 Ok(SignedTransaction {
477 raw_txn,
478 authenticator,
479 })
480 }
481
482 pub fn authenticator(&self) -> TransactionAuthenticator {
483 self.authenticator.clone()
484 }
485
486 pub fn raw_txn(&self) -> RawTransaction { self.raw_txn.clone() }
487
488 pub fn hash(&self) -> HashValue { self.raw_txn.hash() }
489
490 pub fn sender(&self) -> AccountAddress { self.raw_txn.sender }
491
492 pub fn into_raw_transaction(self) -> RawTransaction { self.raw_txn }
493
494 pub fn chain_id(&self) -> ChainId { self.raw_txn.chain_id }
495
496 pub fn payload(&self) -> &TransactionPayload { &self.raw_txn.payload }
497
498 pub fn expiration_timestamp_secs(&self) -> u64 {
499 self.raw_txn.expiration_timestamp_secs
500 }
501
502 pub fn raw_txn_bytes_len(&self) -> usize {
503 bcs::to_bytes(&self.raw_txn)
504 .expect("Unable to serialize RawTransaction")
505 .len()
506 }
507
508 pub fn verify_signature(&self) -> Result<()> {
512 match self.payload() {
513 TransactionPayload::PivotDecision(pivot_decision) => {
514 self.authenticator.verify(pivot_decision)
515 }
516 _ => self.authenticator.verify(&self.raw_txn),
517 }
518 }
519
520 pub fn check_signature(self) -> Result<SignatureCheckedTransaction> {
523 self.verify_signature()?;
524 Ok(SignatureCheckedTransaction(self))
525 }
526}
527
528#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
529#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
530pub struct TransactionWithProof {
531 pub version: Version,
532 pub transaction: Transaction,
533 pub events: Option<Vec<ContractEvent>>,
534 pub proof: TransactionInfoWithProof,
535}
536
537impl TransactionWithProof {
538 pub fn new(
539 version: Version, transaction: Transaction,
540 events: Option<Vec<ContractEvent>>, proof: TransactionInfoWithProof,
541 ) -> Self {
542 Self {
543 version,
544 transaction,
545 events,
546 proof,
547 }
548 }
549
550 pub fn verify_user_txn(
561 &self, ledger_info: &LedgerInfo, version: Version,
562 sender: AccountAddress,
563 ) -> Result<()> {
564 let signed_transaction = self.transaction.as_signed_user_txn()?;
565
566 ensure!(
567 self.version == version,
568 "Version ({}) is not expected ({}).",
569 self.version,
570 version,
571 );
572 ensure!(
573 signed_transaction.sender() == sender,
574 "Sender ({}) not expected ({}).",
575 signed_transaction.sender(),
576 sender,
577 );
578 let txn_hash = self.transaction.hash();
579 ensure!(
580 txn_hash == self.proof.transaction_info().transaction_hash,
581 "Transaction hash ({}) not expected ({}).",
582 txn_hash,
583 self.proof.transaction_info().transaction_hash,
584 );
585
586 if let Some(events) = &self.events {
587 let event_hashes: Vec<_> =
588 events.iter().map(ContractEvent::hash).collect();
589 let event_root_hash =
590 InMemoryAccumulator::<EventAccumulatorHasher>::from_leaves(
591 &event_hashes[..],
592 )
593 .root_hash();
594 ensure!(
595 event_root_hash
596 == self.proof.transaction_info().event_root_hash,
597 "Event root hash ({}) not expected ({}).",
598 event_root_hash,
599 self.proof.transaction_info().event_root_hash,
600 );
601 }
602
603 self.proof.verify(ledger_info, version)
604 }
605}
606
607#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
612pub enum TransactionStatus {
613 Discard(DiscardedVMStatus),
615
616 Keep(KeptVMStatus),
618
619 Retry,
621}
622
623impl TransactionStatus {
624 pub fn status(&self) -> Result<KeptVMStatus, StatusCode> {
625 match self {
626 TransactionStatus::Keep(status) => Ok(status.clone()),
627 TransactionStatus::Discard(code) => Err(*code),
628 TransactionStatus::Retry => {
629 Err(StatusCode::UNKNOWN_VALIDATION_STATUS)
630 }
631 }
632 }
633
634 pub fn is_discarded(&self) -> bool {
635 match self {
636 TransactionStatus::Discard(_) => true,
637 TransactionStatus::Keep(_) => false,
638 TransactionStatus::Retry => true,
639 }
640 }
641}
642
643impl From<VMStatus> for TransactionStatus {
644 fn from(vm_status: VMStatus) -> Self {
645 match vm_status.keep_or_discard() {
646 Ok(recorded) => TransactionStatus::Keep(recorded),
647 Err(code) => TransactionStatus::Discard(code),
648 }
649 }
650}
651
652#[derive(Clone, Debug, Eq, PartialEq)]
654pub struct TransactionOutput {
655 events: Vec<ContractEvent>,
657
658 gas_used: u64,
660
661 status: TransactionStatus,
663}
664
665impl TransactionOutput {
666 pub fn new(
667 events: Vec<ContractEvent>, gas_used: u64, status: TransactionStatus,
668 ) -> Self {
669 TransactionOutput {
670 events,
671 gas_used,
672 status,
673 }
674 }
675
676 pub fn events(&self) -> &[ContractEvent] { &self.events }
677
678 pub fn gas_used(&self) -> u64 { self.gas_used }
679
680 pub fn status(&self) -> &TransactionStatus { &self.status }
681}
682
683#[derive(
687 Clone,
688 CryptoHasher,
689 BCSCryptoHash,
690 Debug,
691 Eq,
692 PartialEq,
693 Serialize,
694 Deserialize,
695)]
696#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
697pub struct TransactionInfo {
698 transaction_hash: HashValue,
700
701 state_root_hash: HashValue,
704
705 event_root_hash: HashValue,
708
709 gas_used: u64,
711
712 status: KeptVMStatus,
717}
718
719impl TransactionInfo {
720 pub fn new(
723 transaction_hash: HashValue, state_root_hash: HashValue,
724 event_root_hash: HashValue, gas_used: u64, status: KeptVMStatus,
725 ) -> TransactionInfo {
726 TransactionInfo {
727 transaction_hash,
728 state_root_hash,
729 event_root_hash,
730 gas_used,
731 status,
732 }
733 }
734
735 pub fn transaction_hash(&self) -> HashValue { self.transaction_hash }
737
738 pub fn state_root_hash(&self) -> HashValue { self.state_root_hash }
741
742 pub fn event_root_hash(&self) -> HashValue { self.event_root_hash }
745
746 pub fn gas_used(&self) -> u64 { self.gas_used }
748
749 pub fn status(&self) -> &KeptVMStatus { &self.status }
750}
751
752impl Display for TransactionInfo {
753 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
754 write!(
755 f,
756 "TransactionInfo: [txn_hash: {}, state_root_hash: {}, event_root_hash: {}, gas_used: {}, recorded_status: {:?}]",
757 self.transaction_hash(), self.state_root_hash(), self.event_root_hash(), self.gas_used(), self.status(),
758 )
759 }
760}
761
762#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
763pub struct TransactionToCommit {
764 transaction: Transaction,
765 events: Vec<ContractEvent>,
766 gas_used: u64,
767 status: KeptVMStatus,
768}
769
770impl TransactionToCommit {
771 pub fn new(
772 transaction: Transaction, events: Vec<ContractEvent>, gas_used: u64,
773 status: KeptVMStatus,
774 ) -> Self {
775 TransactionToCommit {
776 transaction,
777 events,
778 gas_used,
779 status,
780 }
781 }
782
783 pub fn transaction(&self) -> &Transaction { &self.transaction }
784
785 pub fn events(&self) -> &[ContractEvent] { &self.events }
786
787 pub fn gas_used(&self) -> u64 { self.gas_used }
788
789 pub fn status(&self) -> &KeptVMStatus { &self.status }
790}
791
792#[allow(clippy::large_enum_variant)]
798#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
799#[derive(
800 Clone,
801 Debug,
802 Eq,
803 PartialEq,
804 Serialize,
805 Deserialize,
806 CryptoHasher,
807 BCSCryptoHash,
808)]
809pub enum Transaction {
810 UserTransaction(SignedTransaction),
816
817 GenesisTransaction(Vec<ContractEvent>),
820
821 BlockMetadata(BlockMetadata),
824}
825
826#[derive(Deserialize)]
827pub enum TransactionUnchecked {
828 UserTransaction(SignedTransactionUnchecked),
829 GenesisTransaction(Vec<ContractEvent>),
830 BlockMetadata(BlockMetadata),
831}
832
833impl From<TransactionUnchecked> for Transaction {
834 fn from(t: TransactionUnchecked) -> Self {
835 match t {
836 TransactionUnchecked::UserTransaction(t) => {
837 Self::UserTransaction(t.into())
838 }
839 TransactionUnchecked::GenesisTransaction(t) => {
840 Self::GenesisTransaction(t)
841 }
842 TransactionUnchecked::BlockMetadata(t) => Self::BlockMetadata(t),
843 }
844 }
845}
846
847impl Transaction {
848 pub fn as_signed_user_txn(&self) -> Result<&SignedTransaction> {
849 match self {
850 Transaction::UserTransaction(txn) => Ok(txn),
851 _ => Err(format_err!("Not a user transaction.")),
852 }
853 }
854}
855
856impl TryFrom<Transaction> for SignedTransaction {
857 type Error = Error;
858
859 fn try_from(txn: Transaction) -> Result<Self> {
860 match txn {
861 Transaction::UserTransaction(txn) => Ok(txn),
862 _ => Err(format_err!("Not a user transaction.")),
863 }
864 }
865}