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,
82
83 chain_id: ChainId,
85}
86
87impl RawTransaction {
88 pub fn new(
93 sender: AccountAddress, payload: TransactionPayload,
94 expiration_timestamp_secs: u64, chain_id: ChainId,
95 ) -> Self {
96 RawTransaction {
97 sender,
98 payload,
99 expiration_timestamp_secs,
100 chain_id,
101 }
102 }
103
104 pub fn new_pivot_decision(
105 sender: AccountAddress, pivot_decision: PivotBlockDecision,
106 chain_id: ChainId,
107 ) -> Self {
108 RawTransaction {
109 sender,
110 payload: TransactionPayload::PivotDecision(pivot_decision),
111 expiration_timestamp_secs: u64::max_value(),
114 chain_id,
115 }
116 }
117
118 pub fn new_election(
119 sender: AccountAddress, election_payload: ElectionPayload,
120 chain_id: ChainId,
121 ) -> Self {
122 RawTransaction {
123 sender,
124 payload: TransactionPayload::Election(election_payload),
125 expiration_timestamp_secs: u64::max_value(),
128 chain_id,
129 }
130 }
131
132 pub fn new_dispute(
133 sender: AccountAddress, dispute_payload: DisputePayload,
134 ) -> Self {
135 RawTransaction {
136 sender,
137 payload: TransactionPayload::Dispute(dispute_payload),
138 expiration_timestamp_secs: u64::max_value(),
141 chain_id: Default::default(),
142 }
143 }
144
145 pub fn new_retire(
146 sender: AccountAddress, retire_payload: RetirePayload,
147 ) -> Self {
148 RawTransaction {
149 sender,
150 payload: TransactionPayload::Retire(retire_payload),
151 expiration_timestamp_secs: u64::max_value(),
154 chain_id: Default::default(),
155 }
156 }
157
158 pub fn from_staking_event(
159 staking_event: &StakingEvent, sender: AccountAddress,
160 ) -> Result<Self> {
161 let payload = match staking_event {
162 StakingEvent::Register(
163 addr_h256,
164 bls_pub_key_bytes,
165 vrf_pub_key_bytes,
166 ) => {
167 let addr = AccountAddress::from_bytes(addr_h256)?;
168 let public_key =
169 ConsensusPublicKey::try_from(bls_pub_key_bytes.as_slice())?;
170 let vrf_public_key = ConsensusVRFPublicKey::try_from(
171 vrf_pub_key_bytes.as_slice(),
172 )?;
173 let node_id =
174 NodeID::new(public_key.clone(), vrf_public_key.clone());
175 ensure!(
176 node_id.addr == addr,
177 "register event has unmatching address and keys"
178 );
179 TransactionPayload::Register(RegisterPayload {
180 public_key,
181 vrf_public_key,
182 })
183 }
184 StakingEvent::IncreaseStake(addr_h256, updated_voting_power) => {
185 let addr = AccountAddress::from_bytes(addr_h256)?;
186 TransactionPayload::UpdateVotingPower(
187 UpdateVotingPowerPayload {
188 node_address: addr,
189 voting_power: *updated_voting_power,
190 },
191 )
192 }
193 StakingEvent::Retire(identifier, votes) => {
194 TransactionPayload::Retire(RetirePayload {
195 node_id: AccountAddress::new(identifier.0),
196 votes: *votes,
197 })
198 }
199 };
200 Ok(RawTransaction {
201 sender,
202 payload,
203 expiration_timestamp_secs: u64::max_value(),
206 chain_id: Default::default(),
207 })
208 }
209
210 pub fn sign(
216 self, private_key: &ConsensusPrivateKey,
217 ) -> Result<SignatureCheckedTransaction> {
218 let signature = match self.payload {
219 TransactionPayload::PivotDecision(ref pivot_decision) => {
220 private_key.sign(pivot_decision)
221 }
222 _ => private_key.sign(&self),
223 };
224 let public_key = private_key.public_key();
225 Ok(SignatureCheckedTransaction(SignedTransaction::new(
226 self, public_key, signature,
227 )))
228 }
229
230 pub fn into_payload(self) -> TransactionPayload { self.payload }
231
232 pub fn sender(&self) -> AccountAddress { self.sender }
234}
235
236#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
242pub enum TransactionPayload {
243 #[doc(hidden)]
245 _LegacyWriteSet,
246 #[doc(hidden)]
248 _LegacyScript,
249 #[doc(hidden)]
251 _LegacyModule,
252 #[doc(hidden)]
254 _LegacyScriptFunction,
255
256 Election(ElectionPayload),
258
259 Retire(RetirePayload),
262
263 Register(RegisterPayload),
264
265 UpdateVotingPower(UpdateVotingPowerPayload),
266
267 PivotDecision(PivotBlockDecision),
268
269 Dispute(DisputePayload),
270}
271
272#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
273#[serde(rename_all = "camelCase")]
274pub struct ElectionPayload {
275 pub public_key: ConsensusPublicKey,
276 pub vrf_public_key: ConsensusVRFPublicKey,
277 pub target_term: u64,
278 pub vrf_proof: ConsensusVRFProof,
279}
280
281impl ElectionPayload {
282 pub fn to_event(&self) -> ContractEvent {
283 let event = ElectionEvent::new(
284 self.public_key.clone(),
285 self.vrf_public_key.clone(),
286 self.vrf_proof.to_hash().unwrap(),
287 self.target_term,
288 );
289 ContractEvent::new(
290 ElectionEvent::event_key(),
291 bcs::to_bytes(&event).unwrap(),
292 )
293 }
294}
295
296#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
297#[serde(rename_all = "camelCase")]
298pub struct RetirePayload {
299 pub node_id: AccountAddress,
300 pub votes: u64,
301}
302
303impl RetirePayload {
304 pub fn to_event(&self) -> ContractEvent {
305 let event = RetireEvent::new(self.node_id, self.votes);
306 ContractEvent::new(
307 RetireEvent::event_key(),
308 bcs::to_bytes(&event).unwrap(),
309 )
310 }
311}
312
313#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
314#[serde(rename_all = "camelCase")]
315pub struct RegisterPayload {
316 pub public_key: ConsensusPublicKey,
317 pub vrf_public_key: ConsensusVRFPublicKey,
318}
319
320impl RegisterPayload {
321 pub fn to_event(&self) -> ContractEvent {
322 let event = RegisterEvent::new(
323 self.public_key.clone(),
324 self.vrf_public_key.clone(),
325 );
326 ContractEvent::new(
327 RegisterEvent::event_key(),
328 bcs::to_bytes(&event).unwrap(),
329 )
330 }
331}
332
333#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
334#[serde(rename_all = "camelCase")]
335pub struct UpdateVotingPowerPayload {
336 pub node_address: AccountAddress,
337 pub voting_power: u64,
338}
339
340impl UpdateVotingPowerPayload {
341 pub fn to_event(&self) -> ContractEvent {
342 let event = UpdateVotingPowerEvent::new(
343 self.node_address.clone(),
344 self.voting_power,
345 );
346 ContractEvent::new(
347 UpdateVotingPowerEvent::event_key(),
348 bcs::to_bytes(&event).unwrap(),
349 )
350 }
351}
352
353#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
354#[serde(rename_all = "camelCase")]
355pub struct DisputePayload {
356 pub address: AccountAddress,
357 pub bls_pub_key: ConsensusPublicKey,
358 pub vrf_pub_key: ConsensusVRFPublicKey,
359 pub conflicting_votes: ConflictSignature,
360}
361
362#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
363pub enum ConflictSignature {
364 Proposal((Vec<u8>, Vec<u8>)),
366 Vote((Vec<u8>, Vec<u8>)),
367}
368
369impl DisputePayload {
370 pub fn to_event(&self) -> ContractEvent {
371 let event = DisputeEvent {
372 node_id: self.address,
373 };
374 ContractEvent::new(
375 DisputeEvent::event_key(),
376 bcs::to_bytes(&event).unwrap(),
377 )
378 }
379}
380
381#[derive(Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
391pub struct SignedTransaction {
392 raw_txn: RawTransaction,
394
395 authenticator: TransactionAuthenticator,
397}
398
399#[derive(Deserialize)]
400pub struct SignedTransactionUnchecked {
401 pub raw_txn: RawTransaction,
402 pub authenticator: TransactionAuthenticatorUnchecked,
403}
404
405impl From<SignedTransactionUnchecked> for SignedTransaction {
406 fn from(t: SignedTransactionUnchecked) -> Self {
407 Self {
408 raw_txn: t.raw_txn,
409 authenticator: t.authenticator.into(),
410 }
411 }
412}
413
414#[derive(Clone, Debug, Eq, PartialEq, Hash)]
417pub struct SignatureCheckedTransaction(SignedTransaction);
418
419impl SignatureCheckedTransaction {
420 pub fn into_inner(self) -> SignedTransaction { self.0 }
422
423 pub fn into_raw_transaction(self) -> RawTransaction {
425 self.0.into_raw_transaction()
426 }
427}
428
429impl Deref for SignatureCheckedTransaction {
430 type Target = SignedTransaction;
431
432 fn deref(&self) -> &Self::Target { &self.0 }
433}
434
435impl fmt::Debug for SignedTransaction {
436 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
437 write!(
438 f,
439 "SignedTransaction {{ \n \
440 {{ raw_txn: {:#?}, \n \
441 authenticator: {:#?}, \n \
442 }} \n \
443 }}",
444 self.raw_txn, self.authenticator
445 )
446 }
447}
448
449impl SignedTransaction {
450 pub fn new(
451 raw_txn: RawTransaction, public_key: ConsensusPublicKey,
452 signature: ConsensusSignature,
453 ) -> SignedTransaction {
454 let authenticator =
455 TransactionAuthenticator::bls(public_key, signature);
456 SignedTransaction {
457 raw_txn,
458 authenticator,
459 }
460 }
461
462 pub fn new_multisig(
463 raw_txn: RawTransaction, signatures: Vec<(ConsensusSignature, usize)>,
464 ) -> SignedTransaction {
465 let signature = MultiConsensusSignature::new(signatures).unwrap();
466 let authenticator = TransactionAuthenticator::multi_bls(signature);
467 SignedTransaction {
468 raw_txn,
469 authenticator,
470 }
471 }
472
473 pub fn authenticator(&self) -> TransactionAuthenticator {
474 self.authenticator.clone()
475 }
476
477 pub fn raw_txn(&self) -> RawTransaction { self.raw_txn.clone() }
478
479 pub fn hash(&self) -> HashValue { self.raw_txn.hash() }
480
481 pub fn sender(&self) -> AccountAddress { self.raw_txn.sender }
482
483 pub fn into_raw_transaction(self) -> RawTransaction { self.raw_txn }
484
485 pub fn chain_id(&self) -> ChainId { self.raw_txn.chain_id }
486
487 pub fn payload(&self) -> &TransactionPayload { &self.raw_txn.payload }
488
489 pub fn expiration_timestamp_secs(&self) -> u64 {
490 self.raw_txn.expiration_timestamp_secs
491 }
492
493 pub fn raw_txn_bytes_len(&self) -> usize {
494 bcs::to_bytes(&self.raw_txn)
495 .expect("Unable to serialize RawTransaction")
496 .len()
497 }
498
499 pub fn check_signature(self) -> Result<SignatureCheckedTransaction> {
502 match self.payload() {
503 TransactionPayload::PivotDecision(pivot_decision) => {
504 self.authenticator.verify(pivot_decision)?
505 }
506 _ => self.authenticator.verify(&self.raw_txn)?,
507 }
508 Ok(SignatureCheckedTransaction(self))
509 }
510}
511
512#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
513#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
514pub struct TransactionWithProof {
515 pub version: Version,
516 pub transaction: Transaction,
517 pub events: Option<Vec<ContractEvent>>,
518 pub proof: TransactionInfoWithProof,
519}
520
521impl TransactionWithProof {
522 pub fn new(
523 version: Version, transaction: Transaction,
524 events: Option<Vec<ContractEvent>>, proof: TransactionInfoWithProof,
525 ) -> Self {
526 Self {
527 version,
528 transaction,
529 events,
530 proof,
531 }
532 }
533
534 pub fn verify_user_txn(
545 &self, ledger_info: &LedgerInfo, version: Version,
546 sender: AccountAddress,
547 ) -> Result<()> {
548 let signed_transaction = self.transaction.as_signed_user_txn()?;
549
550 ensure!(
551 self.version == version,
552 "Version ({}) is not expected ({}).",
553 self.version,
554 version,
555 );
556 ensure!(
557 signed_transaction.sender() == sender,
558 "Sender ({}) not expected ({}).",
559 signed_transaction.sender(),
560 sender,
561 );
562 let txn_hash = self.transaction.hash();
563 ensure!(
564 txn_hash == self.proof.transaction_info().transaction_hash,
565 "Transaction hash ({}) not expected ({}).",
566 txn_hash,
567 self.proof.transaction_info().transaction_hash,
568 );
569
570 if let Some(events) = &self.events {
571 let event_hashes: Vec<_> =
572 events.iter().map(ContractEvent::hash).collect();
573 let event_root_hash =
574 InMemoryAccumulator::<EventAccumulatorHasher>::from_leaves(
575 &event_hashes[..],
576 )
577 .root_hash();
578 ensure!(
579 event_root_hash
580 == self.proof.transaction_info().event_root_hash,
581 "Event root hash ({}) not expected ({}).",
582 event_root_hash,
583 self.proof.transaction_info().event_root_hash,
584 );
585 }
586
587 self.proof.verify(ledger_info, version)
588 }
589}
590
591#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
596pub enum TransactionStatus {
597 Discard(DiscardedVMStatus),
599
600 Keep(KeptVMStatus),
602
603 Retry,
605}
606
607impl TransactionStatus {
608 pub fn status(&self) -> Result<KeptVMStatus, StatusCode> {
609 match self {
610 TransactionStatus::Keep(status) => Ok(status.clone()),
611 TransactionStatus::Discard(code) => Err(*code),
612 TransactionStatus::Retry => {
613 Err(StatusCode::UNKNOWN_VALIDATION_STATUS)
614 }
615 }
616 }
617
618 pub fn is_discarded(&self) -> bool {
619 match self {
620 TransactionStatus::Discard(_) => true,
621 TransactionStatus::Keep(_) => false,
622 TransactionStatus::Retry => true,
623 }
624 }
625}
626
627impl From<VMStatus> for TransactionStatus {
628 fn from(vm_status: VMStatus) -> Self {
629 match vm_status.keep_or_discard() {
630 Ok(recorded) => TransactionStatus::Keep(recorded),
631 Err(code) => TransactionStatus::Discard(code),
632 }
633 }
634}
635
636#[derive(Clone, Debug, Eq, PartialEq)]
638pub struct TransactionOutput {
639 events: Vec<ContractEvent>,
641
642 gas_used: u64,
644
645 status: TransactionStatus,
647}
648
649impl TransactionOutput {
650 pub fn new(
651 events: Vec<ContractEvent>, gas_used: u64, status: TransactionStatus,
652 ) -> Self {
653 TransactionOutput {
654 events,
655 gas_used,
656 status,
657 }
658 }
659
660 pub fn events(&self) -> &[ContractEvent] { &self.events }
661
662 pub fn gas_used(&self) -> u64 { self.gas_used }
663
664 pub fn status(&self) -> &TransactionStatus { &self.status }
665}
666
667#[derive(
671 Clone,
672 CryptoHasher,
673 BCSCryptoHash,
674 Debug,
675 Eq,
676 PartialEq,
677 Serialize,
678 Deserialize,
679)]
680#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
681pub struct TransactionInfo {
682 transaction_hash: HashValue,
684
685 state_root_hash: HashValue,
688
689 event_root_hash: HashValue,
692
693 gas_used: u64,
695
696 status: KeptVMStatus,
701}
702
703impl TransactionInfo {
704 pub fn new(
707 transaction_hash: HashValue, state_root_hash: HashValue,
708 event_root_hash: HashValue, gas_used: u64, status: KeptVMStatus,
709 ) -> TransactionInfo {
710 TransactionInfo {
711 transaction_hash,
712 state_root_hash,
713 event_root_hash,
714 gas_used,
715 status,
716 }
717 }
718
719 pub fn transaction_hash(&self) -> HashValue { self.transaction_hash }
721
722 pub fn state_root_hash(&self) -> HashValue { self.state_root_hash }
725
726 pub fn event_root_hash(&self) -> HashValue { self.event_root_hash }
729
730 pub fn gas_used(&self) -> u64 { self.gas_used }
732
733 pub fn status(&self) -> &KeptVMStatus { &self.status }
734}
735
736impl Display for TransactionInfo {
737 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
738 write!(
739 f,
740 "TransactionInfo: [txn_hash: {}, state_root_hash: {}, event_root_hash: {}, gas_used: {}, recorded_status: {:?}]",
741 self.transaction_hash(), self.state_root_hash(), self.event_root_hash(), self.gas_used(), self.status(),
742 )
743 }
744}
745
746#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
747pub struct TransactionToCommit {
748 transaction: Transaction,
749 events: Vec<ContractEvent>,
750 gas_used: u64,
751 status: KeptVMStatus,
752}
753
754impl TransactionToCommit {
755 pub fn new(
756 transaction: Transaction, events: Vec<ContractEvent>, gas_used: u64,
757 status: KeptVMStatus,
758 ) -> Self {
759 TransactionToCommit {
760 transaction,
761 events,
762 gas_used,
763 status,
764 }
765 }
766
767 pub fn transaction(&self) -> &Transaction { &self.transaction }
768
769 pub fn events(&self) -> &[ContractEvent] { &self.events }
770
771 pub fn gas_used(&self) -> u64 { self.gas_used }
772
773 pub fn status(&self) -> &KeptVMStatus { &self.status }
774}
775
776#[allow(clippy::large_enum_variant)]
782#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
783#[derive(
784 Clone,
785 Debug,
786 Eq,
787 PartialEq,
788 Serialize,
789 Deserialize,
790 CryptoHasher,
791 BCSCryptoHash,
792)]
793pub enum Transaction {
794 UserTransaction(SignedTransaction),
800
801 GenesisTransaction(Vec<ContractEvent>),
804
805 BlockMetadata(BlockMetadata),
808}
809
810#[derive(Deserialize)]
811pub enum TransactionUnchecked {
812 UserTransaction(SignedTransactionUnchecked),
813 GenesisTransaction(Vec<ContractEvent>),
814 BlockMetadata(BlockMetadata),
815}
816
817impl From<TransactionUnchecked> for Transaction {
818 fn from(t: TransactionUnchecked) -> Self {
819 match t {
820 TransactionUnchecked::UserTransaction(t) => {
821 Self::UserTransaction(t.into())
822 }
823 TransactionUnchecked::GenesisTransaction(t) => {
824 Self::GenesisTransaction(t)
825 }
826 TransactionUnchecked::BlockMetadata(t) => Self::BlockMetadata(t),
827 }
828 }
829}
830
831impl Transaction {
832 pub fn as_signed_user_txn(&self) -> Result<&SignedTransaction> {
833 match self {
834 Transaction::UserTransaction(txn) => Ok(txn),
835 _ => Err(format_err!("Not a user transaction.")),
836 }
837 }
838}
839
840impl TryFrom<Transaction> for SignedTransaction {
841 type Error = Error;
842
843 fn try_from(txn: Transaction) -> Result<Self> {
844 match txn {
845 Transaction::UserTransaction(txn) => Ok(txn),
846 _ => Err(format_err!("Not a user transaction.")),
847 }
848 }
849}