1use crate::{
5 account_config::{
6 AdminTransactionEvent, BaseUrlRotationEvent, BurnEvent, CancelBurnEvent,
7 ComplianceKeyRotationEvent, CreateAccountEvent, MintEvent, NewBlockEvent, NewEpochEvent,
8 PreburnEvent, ReceivedMintEvent, ReceivedPaymentEvent, SentPaymentEvent,
9 ToXDXExchangeRateUpdateEvent, VASPDomainEvent,
10 },
11 event::EventKey,
12 ledger_info::LedgerInfo,
13 proof::EventProof,
14 transaction::{TransactionInfoTrait, Version},
15};
16use anyhow::{ensure, Context, Error, Result};
17use diem_crypto::hash::CryptoHash;
18use diem_crypto_derive::{BCSCryptoHash, CryptoHasher};
19use move_core_types::{language_storage::TypeTag, move_resource::MoveStructType};
20
21#[cfg(any(test, feature = "fuzzing"))]
22use proptest_derive::Arbitrary;
23use serde::{Deserialize, Serialize};
24use std::{convert::TryFrom, ops::Deref};
25
26#[derive(Hash, Clone, Eq, PartialEq, Serialize, Deserialize, CryptoHasher, BCSCryptoHash)]
28pub enum ContractEvent {
29 V0(ContractEventV0),
30}
31
32impl ContractEvent {
33 pub fn new(
34 key: EventKey,
35 sequence_number: u64,
36 type_tag: TypeTag,
37 event_data: Vec<u8>,
38 ) -> Self {
39 ContractEvent::V0(ContractEventV0::new(
40 key,
41 sequence_number,
42 type_tag,
43 event_data,
44 ))
45 }
46}
47
48impl Deref for ContractEvent {
51 type Target = ContractEventV0;
52
53 fn deref(&self) -> &Self::Target {
54 match self {
55 ContractEvent::V0(event) => event,
56 }
57 }
58}
59
60#[derive(Hash, Clone, Eq, PartialEq, Serialize, Deserialize, CryptoHasher)]
62pub struct ContractEventV0 {
63 key: EventKey,
65 sequence_number: u64,
67 type_tag: TypeTag,
69 #[serde(with = "serde_bytes")]
71 event_data: Vec<u8>,
72}
73
74impl ContractEventV0 {
75 pub fn new(
76 key: EventKey,
77 sequence_number: u64,
78 type_tag: TypeTag,
79 event_data: Vec<u8>,
80 ) -> Self {
81 Self {
82 key,
83 sequence_number,
84 type_tag,
85 event_data,
86 }
87 }
88
89 pub fn key(&self) -> &EventKey {
90 &self.key
91 }
92
93 pub fn sequence_number(&self) -> u64 {
94 self.sequence_number
95 }
96
97 pub fn event_data(&self) -> &[u8] {
98 &self.event_data
99 }
100
101 pub fn type_tag(&self) -> &TypeTag {
102 &self.type_tag
103 }
104}
105
106impl TryFrom<&ContractEvent> for SentPaymentEvent {
107 type Error = Error;
108
109 fn try_from(event: &ContractEvent) -> Result<Self> {
110 if event.type_tag != TypeTag::Struct(SentPaymentEvent::struct_tag()) {
111 anyhow::bail!("Expected Sent Payment")
112 }
113 Self::try_from_bytes(&event.event_data)
114 }
115}
116
117impl TryFrom<&ContractEvent> for ReceivedPaymentEvent {
118 type Error = Error;
119
120 fn try_from(event: &ContractEvent) -> Result<Self> {
121 if event.type_tag != TypeTag::Struct(ReceivedPaymentEvent::struct_tag()) {
122 anyhow::bail!("Expected Received Payment")
123 }
124 Self::try_from_bytes(&event.event_data)
125 }
126}
127
128impl TryFrom<&ContractEvent> for ToXDXExchangeRateUpdateEvent {
129 type Error = Error;
130
131 fn try_from(event: &ContractEvent) -> Result<Self> {
132 if event.type_tag != TypeTag::Struct(ToXDXExchangeRateUpdateEvent::struct_tag()) {
133 anyhow::bail!("Expected ToXDXExchangeRateUpdateEvent")
134 }
135 Self::try_from_bytes(&event.event_data)
136 }
137}
138
139impl TryFrom<&ContractEvent> for MintEvent {
140 type Error = Error;
141
142 fn try_from(event: &ContractEvent) -> Result<Self> {
143 if event.type_tag != TypeTag::Struct(MintEvent::struct_tag()) {
144 anyhow::bail!("Expected MintEvent")
145 }
146 Self::try_from_bytes(&event.event_data)
147 }
148}
149
150impl TryFrom<&ContractEvent> for ReceivedMintEvent {
151 type Error = Error;
152
153 fn try_from(event: &ContractEvent) -> Result<Self> {
154 if event.type_tag != TypeTag::Struct(ReceivedMintEvent::struct_tag()) {
155 anyhow::bail!("Expected ReceivedMintEvent")
156 }
157 Self::try_from_bytes(&event.event_data)
158 }
159}
160
161impl TryFrom<&ContractEvent> for BurnEvent {
162 type Error = Error;
163
164 fn try_from(event: &ContractEvent) -> Result<Self> {
165 if event.type_tag != TypeTag::Struct(BurnEvent::struct_tag()) {
166 anyhow::bail!("Expected BurnEvent")
167 }
168 Self::try_from_bytes(&event.event_data)
169 }
170}
171
172impl TryFrom<&ContractEvent> for PreburnEvent {
173 type Error = Error;
174
175 fn try_from(event: &ContractEvent) -> Result<Self> {
176 if event.type_tag != TypeTag::Struct(PreburnEvent::struct_tag()) {
177 anyhow::bail!("Expected PreburnEvent")
178 }
179 Self::try_from_bytes(&event.event_data)
180 }
181}
182
183impl TryFrom<&ContractEvent> for CancelBurnEvent {
184 type Error = Error;
185
186 fn try_from(event: &ContractEvent) -> Result<Self> {
187 if event.type_tag != TypeTag::Struct(CancelBurnEvent::struct_tag()) {
188 anyhow::bail!("Expected CancelBurnEvent")
189 }
190 Self::try_from_bytes(&event.event_data)
191 }
192}
193
194impl TryFrom<&ContractEvent> for AdminTransactionEvent {
195 type Error = Error;
196
197 fn try_from(event: &ContractEvent) -> Result<Self> {
198 if event.type_tag != TypeTag::Struct(Self::struct_tag()) {
199 anyhow::bail!("Expected AdminTransactionEvent")
200 }
201 Self::try_from_bytes(&event.event_data)
202 }
203}
204
205impl TryFrom<&ContractEvent> for NewBlockEvent {
206 type Error = Error;
207
208 fn try_from(event: &ContractEvent) -> Result<Self> {
209 if event.type_tag != TypeTag::Struct(Self::struct_tag()) {
210 anyhow::bail!("Expected NewBlockEvent")
211 }
212 Self::try_from_bytes(&event.event_data)
213 }
214}
215
216impl TryFrom<&ContractEvent> for NewEpochEvent {
217 type Error = Error;
218
219 fn try_from(event: &ContractEvent) -> Result<Self> {
220 if event.type_tag != TypeTag::Struct(Self::struct_tag()) {
221 anyhow::bail!("Expected NewEpochEvent")
222 }
223 Self::try_from_bytes(&event.event_data)
224 }
225}
226
227impl TryFrom<&ContractEvent> for ComplianceKeyRotationEvent {
228 type Error = Error;
229 fn try_from(event: &ContractEvent) -> Result<Self> {
230 if event.type_tag != TypeTag::Struct(Self::struct_tag()) {
231 anyhow::bail!("Expected ComplianceKeyRotationEvent")
232 }
233 Self::try_from_bytes(&event.event_data)
234 }
235}
236
237impl TryFrom<&ContractEvent> for BaseUrlRotationEvent {
238 type Error = Error;
239 fn try_from(event: &ContractEvent) -> Result<Self> {
240 if event.type_tag != TypeTag::Struct(Self::struct_tag()) {
241 anyhow::bail!("Expected BaseUrlRotationEvent")
242 }
243 Self::try_from_bytes(&event.event_data)
244 }
245}
246
247impl TryFrom<&ContractEvent> for CreateAccountEvent {
248 type Error = Error;
249 fn try_from(event: &ContractEvent) -> Result<Self> {
250 if event.type_tag != TypeTag::Struct(Self::struct_tag()) {
251 anyhow::bail!("Expected CreateAccountEvent")
252 }
253 Self::try_from_bytes(&event.event_data)
254 }
255}
256
257impl TryFrom<&ContractEvent> for VASPDomainEvent {
258 type Error = Error;
259 fn try_from(event: &ContractEvent) -> Result<Self> {
260 if event.type_tag != TypeTag::Struct(Self::struct_tag()) {
261 anyhow::bail!("Expected VASPDomainEvent")
262 }
263 Self::try_from_bytes(&event.event_data)
264 }
265}
266
267impl std::fmt::Debug for ContractEvent {
268 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
269 write!(
270 f,
271 "ContractEvent {{ key: {:?}, index: {:?}, type: {:?}, event_data: {:?} }}",
272 self.key,
273 self.sequence_number,
274 self.type_tag,
275 hex::encode(&self.event_data)
276 )
277 }
278}
279
280impl std::fmt::Display for ContractEvent {
281 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
282 if let Ok(payload) = SentPaymentEvent::try_from(self) {
283 write!(
284 f,
285 "ContractEvent {{ key: {}, index: {:?}, type: {:?}, event_data: {:?} }}",
286 self.key, self.sequence_number, self.type_tag, payload,
287 )
288 } else if let Ok(payload) = ReceivedPaymentEvent::try_from(self) {
289 write!(
290 f,
291 "ContractEvent {{ key: {}, index: {:?}, type: {:?}, event_data: {:?} }}",
292 self.key, self.sequence_number, self.type_tag, payload,
293 )
294 } else {
295 write!(f, "{:?}", self)
296 }
297 }
298}
299
300#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
301#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
302pub struct EventWithProof<T> {
303 pub transaction_version: u64, pub event_index: u64,
305 pub event: ContractEvent,
306 pub proof: EventProof<T>,
307}
308
309impl<T: TransactionInfoTrait> std::fmt::Display for EventWithProof<T> {
310 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
311 write!(
312 f,
313 "EventWithProof {{ \n\ttransaction_version: {}, \n\tevent_index: {}, \
314 \n\tevent: {}, \n\tproof: {:?} \n}}",
315 self.transaction_version, self.event_index, self.event, self.proof
316 )
317 }
318}
319
320impl<T: TransactionInfoTrait> EventWithProof<T> {
321 pub fn new(
323 transaction_version: Version,
324 event_index: u64,
325 event: ContractEvent,
326 proof: EventProof<T>,
327 ) -> Self {
328 Self {
329 transaction_version,
330 event_index,
331 event,
332 proof,
333 }
334 }
335
336 pub fn verify(
346 &self,
347 ledger_info: &LedgerInfo,
348 event_key: &EventKey,
349 sequence_number: u64,
350 transaction_version: Version,
351 event_index: u64,
352 ) -> Result<()> {
353 ensure!(
354 self.event.key() == event_key,
355 "Event key ({}) not expected ({}).",
356 self.event.key(),
357 *event_key,
358 );
359 ensure!(
360 self.event.sequence_number == sequence_number,
361 "Sequence number ({}) not expected ({}).",
362 self.event.sequence_number(),
363 sequence_number,
364 );
365 ensure!(
366 self.transaction_version == transaction_version,
367 "Transaction version ({}) not expected ({}).",
368 self.transaction_version,
369 transaction_version,
370 );
371 ensure!(
372 self.event_index == event_index,
373 "Event index ({}) not expected ({}).",
374 self.event_index,
375 event_index,
376 );
377
378 self.proof.verify(
379 ledger_info,
380 self.event.hash(),
381 transaction_version,
382 event_index,
383 )?;
384
385 Ok(())
386 }
387}
388
389#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
426#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
427pub struct EventByVersionWithProof<T> {
428 pub lower_bound_incl: Option<EventWithProof<T>>,
429 pub upper_bound_excl: Option<EventWithProof<T>>,
430}
431
432impl<T: TransactionInfoTrait> EventByVersionWithProof<T> {
433 pub fn new(
434 lower_bound_incl: Option<EventWithProof<T>>,
435 upper_bound_excl: Option<EventWithProof<T>>,
436 ) -> Self {
437 Self {
438 lower_bound_incl,
439 upper_bound_excl,
440 }
441 }
442
443 pub fn verify(
455 &self,
456 ledger_info: &LedgerInfo,
457 event_key: &EventKey,
458 latest_event_count: Option<u64>,
459 event_version: Version,
460 ) -> Result<()> {
461 ensure!(
462 event_version <= ledger_info.version(),
463 "request event_version {} must be <= LedgerInfo version {}",
464 event_version,
465 ledger_info.version(),
466 );
467
468 let latest_event_count = latest_event_count.unwrap_or_else(|| {
471 let upper = self.upper_bound_excl.as_ref();
472 let lower = self.lower_bound_incl.as_ref();
473 upper .or(lower) .map(|proof| proof.event.sequence_number.saturating_add(1))
476 .unwrap_or(0) });
478
479 match (&self.lower_bound_incl, &self.upper_bound_excl) {
480 (None, None) => {
482 ensure!(latest_event_count == 0);
483 }
484 (None, Some(first_event)) => {
491 let txn_version = first_event.transaction_version;
492 let seq_num = first_event.event.sequence_number;
493 ensure!(event_version < txn_version);
494 ensure!(seq_num == 0);
495 ensure!(latest_event_count > 0);
496
497 first_event
498 .verify(
499 ledger_info,
500 event_key,
501 seq_num,
502 first_event.transaction_version,
503 first_event.event_index,
504 )
505 .context("failed to verify first event")?;
506 }
507 (Some(lower_bound_incl), Some(upper_bound_excl)) => {
515 ensure!(lower_bound_incl.transaction_version <= event_version);
516 ensure!(event_version < upper_bound_excl.transaction_version);
517
518 let start_seq_num = lower_bound_incl.event.sequence_number;
519 let end_seq_num = upper_bound_excl.event.sequence_number;
520 ensure!(start_seq_num.saturating_add(1) == end_seq_num);
521 ensure!(latest_event_count > end_seq_num);
522
523 lower_bound_incl
524 .verify(
525 ledger_info,
526 event_key,
527 start_seq_num,
528 lower_bound_incl.transaction_version,
529 lower_bound_incl.event_index,
530 )
531 .context("failed to verify lower bound event")?;
532 upper_bound_excl
533 .verify(
534 ledger_info,
535 event_key,
536 end_seq_num,
537 upper_bound_excl.transaction_version,
538 upper_bound_excl.event_index,
539 )
540 .context("failed to verify upper bound event")?;
541 }
542 (Some(latest_event), None) => {
550 let txn_version = latest_event.transaction_version;
551 let seq_num = latest_event.event.sequence_number;
552 ensure!(txn_version <= event_version);
553 ensure!(seq_num.saturating_add(1) == latest_event_count);
554 latest_event
555 .verify(
556 ledger_info,
557 event_key,
558 seq_num,
559 txn_version,
560 latest_event.event_index,
561 )
562 .context("failed to verify latest event")?;
563 }
564 }
565
566 Ok(())
567 }
568}
569
570pub mod default_protocol {
571 use crate::transaction::TransactionInfo;
572
573 pub type EventWithProof = super::EventWithProof<TransactionInfo>;
574 pub type EventByVersionWithProof = super::EventByVersionWithProof<TransactionInfo>;
575}