diem_types/
contract_event.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 crate::{
9    event::EventKey, ledger_info::LedgerInfo, proof::EventProof,
10    transaction::Version,
11};
12use anyhow::{ensure, Result};
13use diem_crypto::hash::CryptoHash;
14use diem_crypto_derive::{BCSCryptoHash, CryptoHasher};
15
16#[cfg(any(test, feature = "fuzzing"))]
17use proptest_derive::Arbitrary;
18use serde::{Deserialize, Serialize};
19use std::ops::Deref;
20
21/// Support versioning of the data structure.
22#[derive(
23    Hash,
24    Clone,
25    Eq,
26    PartialEq,
27    Serialize,
28    Deserialize,
29    CryptoHasher,
30    BCSCryptoHash,
31)]
32pub enum ContractEvent {
33    V0(ContractEventV0),
34}
35
36impl ContractEvent {
37    pub fn new(key: EventKey, event_data: Vec<u8>) -> Self {
38        ContractEvent::V0(ContractEventV0::new(key, event_data))
39    }
40}
41
42// Temporary hack to avoid massive changes, it won't work when new variant comes
43// and needs proper dispatch at that time.
44impl Deref for ContractEvent {
45    type Target = ContractEventV0;
46
47    fn deref(&self) -> &Self::Target {
48        match self {
49            ContractEvent::V0(event) => event,
50        }
51    }
52}
53
54/// Entry produced via a call to the `emit_event` builtin.
55#[derive(Hash, Clone, Eq, PartialEq, Serialize, Deserialize, CryptoHasher)]
56pub struct ContractEventV0 {
57    /// The unique key that the event was emitted to
58    key: EventKey,
59    /// The data payload of the event
60    #[serde(with = "serde_bytes")]
61    event_data: Vec<u8>,
62}
63
64impl ContractEventV0 {
65    pub fn new(key: EventKey, event_data: Vec<u8>) -> Self {
66        Self { key, event_data }
67    }
68
69    pub fn key(&self) -> &EventKey { &self.key }
70
71    pub fn event_data(&self) -> &[u8] { &self.event_data }
72}
73
74impl std::fmt::Debug for ContractEvent {
75    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
76        write!(
77            f,
78            "ContractEvent {{ key: {:?}, event_data: {:?} }}",
79            self.key,
80            hex::encode(&self.event_data)
81        )
82    }
83}
84
85impl std::fmt::Display for ContractEvent {
86    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87        write!(f, "{:?}", self)
88    }
89}
90
91#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
92#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
93pub struct EventWithProof {
94    pub transaction_version: u64, // Should be `Version`
95    pub event_index: u64,
96    pub event: ContractEvent,
97    pub proof: EventProof,
98}
99
100impl std::fmt::Display for EventWithProof {
101    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
102        write!(
103            f,
104            "EventWithProof {{ \n\ttransaction_version: {}, \n\tevent_index: {}, \
105             \n\tevent: {}, \n\tproof: {:?} \n}}",
106            self.transaction_version, self.event_index, self.event, self.proof
107        )
108    }
109}
110
111impl EventWithProof {
112    /// Constructor.
113    pub fn new(
114        transaction_version: Version, event_index: u64, event: ContractEvent,
115        proof: EventProof,
116    ) -> Self {
117        Self {
118            transaction_version,
119            event_index,
120            event,
121            proof,
122        }
123    }
124
125    /// Verifies the event with the proof, both carried by `self`.
126    ///
127    /// Two things are ensured if no error is raised:
128    ///   1. This event exists in the ledger represented by `ledger_info`.
129    ///   2. And this event has the same `event_key`, `sequence_number`,
130    /// `transaction_version`, and `event_index` as indicated in the
131    /// parameter list. If any of these parameter is unknown to the call
132    /// site and is supposed to be informed by this struct, get it from the
133    /// struct itself, such as: `event_with_proof.event.access_path()`,
134    /// `event_with_proof.event_index()`, etc.
135    pub fn verify(
136        &self, ledger_info: &LedgerInfo, event_key: &EventKey,
137        _sequence_number: u64, transaction_version: Version, event_index: u64,
138    ) -> Result<()> {
139        ensure!(
140            self.event.key() == event_key,
141            "Event key ({}) not expected ({}).",
142            self.event.key(),
143            *event_key,
144        );
145        ensure!(
146            self.transaction_version == transaction_version,
147            "Transaction version ({}) not expected ({}).",
148            self.transaction_version,
149            transaction_version,
150        );
151        ensure!(
152            self.event_index == event_index,
153            "Event index ({}) not expected ({}).",
154            self.event_index,
155            event_index,
156        );
157
158        self.proof.verify(
159            ledger_info,
160            self.event.hash(),
161            transaction_version,
162            event_index,
163        )?;
164
165        Ok(())
166    }
167}