sui_indexer/models/
events.rs1use std::str::FromStr;
5use std::sync::Arc;
6
7use diesel::prelude::*;
8use move_core_types::identifier::Identifier;
9
10use sui_json_rpc_types::{BcsEvent, SuiEvent, type_and_fields_from_move_event_data};
11use sui_package_resolver::{PackageStore, Resolver};
12use sui_types::base_types::{ObjectID, SuiAddress};
13use sui_types::digests::TransactionDigest;
14use sui_types::event::EventID;
15use sui_types::object::bounded_visitor::BoundedVisitor;
16use sui_types::parse_sui_struct_tag;
17
18use crate::errors::IndexerError;
19use crate::schema::events;
20use crate::types::IndexedEvent;
21
22#[derive(Queryable, QueryableByName, Selectable, Insertable, Debug, Clone)]
23#[diesel(table_name = events)]
24pub struct StoredEvent {
25 pub tx_sequence_number: i64,
26 pub event_sequence_number: i64,
27 pub transaction_digest: Vec<u8>,
28 pub senders: Vec<Option<Vec<u8>>>,
29 pub package: Vec<u8>,
30 pub module: String,
31 pub event_type: String,
32 pub timestamp_ms: i64,
33 pub bcs: Vec<u8>,
34 pub sender: Option<Vec<u8>>,
35}
36
37pub type SendersType = Vec<Option<Vec<u8>>>;
38
39impl From<IndexedEvent> for StoredEvent {
40 fn from(event: IndexedEvent) -> Self {
41 Self {
42 tx_sequence_number: event.tx_sequence_number as i64,
43 event_sequence_number: event.event_sequence_number as i64,
44 transaction_digest: event.transaction_digest.into_inner().to_vec(),
45 senders: vec![Some(event.sender.to_vec())],
46 package: event.package.to_vec(),
47 module: event.module.clone(),
48 event_type: event.event_type.clone(),
49 bcs: event.bcs.clone(),
50 timestamp_ms: event.timestamp_ms as i64,
51 sender: Some(event.sender.to_vec()),
52 }
53 }
54}
55
56impl StoredEvent {
57 pub async fn try_into_sui_event(
58 self,
59 package_resolver: Arc<Resolver<impl PackageStore>>,
60 ) -> Result<SuiEvent, IndexerError> {
61 let package_id = ObjectID::from_bytes(self.package.clone()).map_err(|_e| {
62 IndexerError::PersistentStorageDataCorruptionError(format!(
63 "Failed to parse event package ID: {:?}",
64 self.package
65 ))
66 })?;
67 let sender = {
69 self.senders.first().ok_or_else(|| {
70 IndexerError::PersistentStorageDataCorruptionError(
71 "Event senders should contain at least one address".to_string(),
72 )
73 })?
74 };
75 let sender = match sender {
76 Some(s) => SuiAddress::from_bytes(s).map_err(|_e| {
77 IndexerError::PersistentStorageDataCorruptionError(format!(
78 "Failed to parse event sender address: {:?}",
79 sender
80 ))
81 })?,
82 None => {
83 return Err(IndexerError::PersistentStorageDataCorruptionError(
84 "Event senders element should not be null".to_string(),
85 ));
86 }
87 };
88
89 let type_ = parse_sui_struct_tag(&self.event_type)?;
90 let move_type_layout = package_resolver
91 .type_layout(type_.clone().into())
92 .await
93 .map_err(|e| {
94 IndexerError::ResolveMoveStructError(format!(
95 "Failed to convert to sui event with Error: {e}",
96 ))
97 })?;
98 let move_object = BoundedVisitor::deserialize_value(&self.bcs, &move_type_layout)
99 .map_err(|e| IndexerError::SerdeError(e.to_string()))?;
100 let (_, parsed_json) = type_and_fields_from_move_event_data(move_object)
101 .map_err(|e| IndexerError::SerdeError(e.to_string()))?;
102 let tx_digest =
103 TransactionDigest::try_from(self.transaction_digest.as_slice()).map_err(|e| {
104 IndexerError::SerdeError(format!(
105 "Failed to parse transaction digest: {:?}, error: {}",
106 self.transaction_digest, e
107 ))
108 })?;
109 Ok(SuiEvent {
110 id: EventID {
111 tx_digest,
112 event_seq: self.event_sequence_number as u64,
113 },
114 package_id,
115 transaction_module: Identifier::from_str(&self.module)?,
116 sender,
117 type_,
118 bcs: BcsEvent::new(self.bcs),
119 parsed_json,
120 timestamp_ms: Some(self.timestamp_ms as u64),
121 })
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use super::*;
128 use move_core_types::{account_address::AccountAddress, language_storage::StructTag};
129 use sui_types::event::Event;
130
131 #[test]
132 fn test_canonical_string_of_event_type() {
133 let tx_digest = TransactionDigest::default();
134 let event = Event {
135 package_id: ObjectID::random(),
136 transaction_module: Identifier::new("test").unwrap(),
137 sender: AccountAddress::random().into(),
138 type_: StructTag {
139 address: AccountAddress::TWO,
140 module: Identifier::new("test").unwrap(),
141 name: Identifier::new("test").unwrap(),
142 type_params: vec![],
143 },
144 contents: vec![],
145 };
146
147 let indexed_event = IndexedEvent::from_event(1, 1, 1, tx_digest, &event, 100);
148
149 let stored_event = StoredEvent::from(indexed_event);
150
151 assert_eq!(
152 stored_event.event_type,
153 "0x0000000000000000000000000000000000000000000000000000000000000002::test::test"
154 );
155 }
156}