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, ElectionEvent, NodeID, RegisterEvent, RetireEvent,
37 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
377#[derive(Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
387pub struct SignedTransaction {
388 raw_txn: RawTransaction,
390
391 authenticator: TransactionAuthenticator,
393}
394
395#[derive(Deserialize)]
396pub struct SignedTransactionUnchecked {
397 pub raw_txn: RawTransaction,
398 pub authenticator: TransactionAuthenticatorUnchecked,
399}
400
401impl From<SignedTransactionUnchecked> for SignedTransaction {
402 fn from(t: SignedTransactionUnchecked) -> Self {
403 Self {
404 raw_txn: t.raw_txn,
405 authenticator: t.authenticator.into(),
406 }
407 }
408}
409
410#[derive(Clone, Debug, Eq, PartialEq, Hash)]
413pub struct SignatureCheckedTransaction(SignedTransaction);
414
415impl SignatureCheckedTransaction {
416 pub fn into_inner(self) -> SignedTransaction { self.0 }
418
419 pub fn into_raw_transaction(self) -> RawTransaction {
421 self.0.into_raw_transaction()
422 }
423}
424
425impl Deref for SignatureCheckedTransaction {
426 type Target = SignedTransaction;
427
428 fn deref(&self) -> &Self::Target { &self.0 }
429}
430
431impl fmt::Debug for SignedTransaction {
432 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
433 write!(
434 f,
435 "SignedTransaction {{ \n \
436 {{ raw_txn: {:#?}, \n \
437 authenticator: {:#?}, \n \
438 }} \n \
439 }}",
440 self.raw_txn, self.authenticator
441 )
442 }
443}
444
445impl SignedTransaction {
446 pub fn new(
447 raw_txn: RawTransaction, public_key: ConsensusPublicKey,
448 signature: ConsensusSignature,
449 ) -> SignedTransaction {
450 let authenticator =
451 TransactionAuthenticator::bls(public_key, signature);
452 SignedTransaction {
453 raw_txn,
454 authenticator,
455 }
456 }
457
458 pub fn new_multisig(
459 raw_txn: RawTransaction, signatures: Vec<(ConsensusSignature, usize)>,
460 ) -> SignedTransaction {
461 let signature = MultiConsensusSignature::new(signatures).unwrap();
462 let authenticator = TransactionAuthenticator::multi_bls(signature);
463 SignedTransaction {
464 raw_txn,
465 authenticator,
466 }
467 }
468
469 pub fn authenticator(&self) -> TransactionAuthenticator {
470 self.authenticator.clone()
471 }
472
473 pub fn raw_txn(&self) -> RawTransaction { self.raw_txn.clone() }
474
475 pub fn hash(&self) -> HashValue { self.raw_txn.hash() }
476
477 pub fn sender(&self) -> AccountAddress { self.raw_txn.sender }
478
479 pub fn into_raw_transaction(self) -> RawTransaction { self.raw_txn }
480
481 pub fn chain_id(&self) -> ChainId { self.raw_txn.chain_id }
482
483 pub fn payload(&self) -> &TransactionPayload { &self.raw_txn.payload }
484
485 pub fn expiration_timestamp_secs(&self) -> u64 {
486 self.raw_txn.expiration_timestamp_secs
487 }
488
489 pub fn raw_txn_bytes_len(&self) -> usize {
490 bcs::to_bytes(&self.raw_txn)
491 .expect("Unable to serialize RawTransaction")
492 .len()
493 }
494
495 pub fn verify_signature(&self) -> Result<()> {
499 match self.payload() {
500 TransactionPayload::PivotDecision(pivot_decision) => {
501 self.authenticator.verify(pivot_decision)
502 }
503 _ => self.authenticator.verify(&self.raw_txn),
504 }
505 }
506
507 pub fn check_signature(self) -> Result<SignatureCheckedTransaction> {
510 self.verify_signature()?;
511 Ok(SignatureCheckedTransaction(self))
512 }
513}
514
515#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
516#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
517pub struct TransactionWithProof {
518 pub version: Version,
519 pub transaction: Transaction,
520 pub events: Option<Vec<ContractEvent>>,
521 pub proof: TransactionInfoWithProof,
522}
523
524impl TransactionWithProof {
525 pub fn new(
526 version: Version, transaction: Transaction,
527 events: Option<Vec<ContractEvent>>, proof: TransactionInfoWithProof,
528 ) -> Self {
529 Self {
530 version,
531 transaction,
532 events,
533 proof,
534 }
535 }
536
537 pub fn verify_user_txn(
548 &self, ledger_info: &LedgerInfo, version: Version,
549 sender: AccountAddress,
550 ) -> Result<()> {
551 let signed_transaction = self.transaction.as_signed_user_txn()?;
552
553 ensure!(
554 self.version == version,
555 "Version ({}) is not expected ({}).",
556 self.version,
557 version,
558 );
559 ensure!(
560 signed_transaction.sender() == sender,
561 "Sender ({}) not expected ({}).",
562 signed_transaction.sender(),
563 sender,
564 );
565 let txn_hash = self.transaction.hash();
566 ensure!(
567 txn_hash == self.proof.transaction_info().transaction_hash,
568 "Transaction hash ({}) not expected ({}).",
569 txn_hash,
570 self.proof.transaction_info().transaction_hash,
571 );
572
573 if let Some(events) = &self.events {
574 let event_hashes: Vec<_> =
575 events.iter().map(ContractEvent::hash).collect();
576 let event_root_hash =
577 InMemoryAccumulator::<EventAccumulatorHasher>::from_leaves(
578 &event_hashes[..],
579 )
580 .root_hash();
581 ensure!(
582 event_root_hash
583 == self.proof.transaction_info().event_root_hash,
584 "Event root hash ({}) not expected ({}).",
585 event_root_hash,
586 self.proof.transaction_info().event_root_hash,
587 );
588 }
589
590 self.proof.verify(ledger_info, version)
591 }
592}
593
594#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
599pub enum TransactionStatus {
600 Discard(DiscardedVMStatus),
602
603 Keep(KeptVMStatus),
605
606 Retry,
608}
609
610impl TransactionStatus {
611 pub fn status(&self) -> Result<KeptVMStatus, StatusCode> {
612 match self {
613 TransactionStatus::Keep(status) => Ok(status.clone()),
614 TransactionStatus::Discard(code) => Err(*code),
615 TransactionStatus::Retry => {
616 Err(StatusCode::UNKNOWN_VALIDATION_STATUS)
617 }
618 }
619 }
620
621 pub fn is_discarded(&self) -> bool {
622 match self {
623 TransactionStatus::Discard(_) => true,
624 TransactionStatus::Keep(_) => false,
625 TransactionStatus::Retry => true,
626 }
627 }
628}
629
630impl From<VMStatus> for TransactionStatus {
631 fn from(vm_status: VMStatus) -> Self {
632 match vm_status.keep_or_discard() {
633 Ok(recorded) => TransactionStatus::Keep(recorded),
634 Err(code) => TransactionStatus::Discard(code),
635 }
636 }
637}
638
639#[derive(Clone, Debug, Eq, PartialEq)]
641pub struct TransactionOutput {
642 events: Vec<ContractEvent>,
644
645 gas_used: u64,
647
648 status: TransactionStatus,
650}
651
652impl TransactionOutput {
653 pub fn new(
654 events: Vec<ContractEvent>, gas_used: u64, status: TransactionStatus,
655 ) -> Self {
656 TransactionOutput {
657 events,
658 gas_used,
659 status,
660 }
661 }
662
663 pub fn events(&self) -> &[ContractEvent] { &self.events }
664
665 pub fn gas_used(&self) -> u64 { self.gas_used }
666
667 pub fn status(&self) -> &TransactionStatus { &self.status }
668}
669
670#[derive(
674 Clone,
675 CryptoHasher,
676 BCSCryptoHash,
677 Debug,
678 Eq,
679 PartialEq,
680 Serialize,
681 Deserialize,
682)]
683#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
684pub struct TransactionInfo {
685 transaction_hash: HashValue,
687
688 state_root_hash: HashValue,
691
692 event_root_hash: HashValue,
695
696 gas_used: u64,
698
699 status: KeptVMStatus,
704}
705
706impl TransactionInfo {
707 pub fn new(
710 transaction_hash: HashValue, state_root_hash: HashValue,
711 event_root_hash: HashValue, gas_used: u64, status: KeptVMStatus,
712 ) -> TransactionInfo {
713 TransactionInfo {
714 transaction_hash,
715 state_root_hash,
716 event_root_hash,
717 gas_used,
718 status,
719 }
720 }
721
722 pub fn transaction_hash(&self) -> HashValue { self.transaction_hash }
724
725 pub fn state_root_hash(&self) -> HashValue { self.state_root_hash }
728
729 pub fn event_root_hash(&self) -> HashValue { self.event_root_hash }
732
733 pub fn gas_used(&self) -> u64 { self.gas_used }
735
736 pub fn status(&self) -> &KeptVMStatus { &self.status }
737}
738
739impl Display for TransactionInfo {
740 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
741 write!(
742 f,
743 "TransactionInfo: [txn_hash: {}, state_root_hash: {}, event_root_hash: {}, gas_used: {}, recorded_status: {:?}]",
744 self.transaction_hash(), self.state_root_hash(), self.event_root_hash(), self.gas_used(), self.status(),
745 )
746 }
747}
748
749#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
750pub struct TransactionToCommit {
751 transaction: Transaction,
752 events: Vec<ContractEvent>,
753 gas_used: u64,
754 status: KeptVMStatus,
755}
756
757impl TransactionToCommit {
758 pub fn new(
759 transaction: Transaction, events: Vec<ContractEvent>, gas_used: u64,
760 status: KeptVMStatus,
761 ) -> Self {
762 TransactionToCommit {
763 transaction,
764 events,
765 gas_used,
766 status,
767 }
768 }
769
770 pub fn transaction(&self) -> &Transaction { &self.transaction }
771
772 pub fn events(&self) -> &[ContractEvent] { &self.events }
773
774 pub fn gas_used(&self) -> u64 { self.gas_used }
775
776 pub fn status(&self) -> &KeptVMStatus { &self.status }
777}
778
779#[allow(clippy::large_enum_variant)]
785#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
786#[derive(
787 Clone,
788 Debug,
789 Eq,
790 PartialEq,
791 Serialize,
792 Deserialize,
793 CryptoHasher,
794 BCSCryptoHash,
795)]
796pub enum Transaction {
797 UserTransaction(SignedTransaction),
803
804 GenesisTransaction(Vec<ContractEvent>),
807
808 BlockMetadata(BlockMetadata),
811}
812
813#[derive(Deserialize)]
814pub enum TransactionUnchecked {
815 UserTransaction(SignedTransactionUnchecked),
816 GenesisTransaction(Vec<ContractEvent>),
817 BlockMetadata(BlockMetadata),
818}
819
820impl From<TransactionUnchecked> for Transaction {
821 fn from(t: TransactionUnchecked) -> Self {
822 match t {
823 TransactionUnchecked::UserTransaction(t) => {
824 Self::UserTransaction(t.into())
825 }
826 TransactionUnchecked::GenesisTransaction(t) => {
827 Self::GenesisTransaction(t)
828 }
829 TransactionUnchecked::BlockMetadata(t) => Self::BlockMetadata(t),
830 }
831 }
832}
833
834impl Transaction {
835 pub fn as_signed_user_txn(&self) -> Result<&SignedTransaction> {
836 match self {
837 Transaction::UserTransaction(txn) => Ok(txn),
838 _ => Err(format_err!("Not a user transaction.")),
839 }
840 }
841}
842
843impl TryFrom<Transaction> for SignedTransaction {
844 type Error = Error;
845
846 fn try_from(txn: Transaction) -> Result<Self> {
847 match txn {
848 Transaction::UserTransaction(txn) => Ok(txn),
849 _ => Err(format_err!("Not a user transaction.")),
850 }
851 }
852}