1use diesel::prelude::*;
6use iota_json_rpc_types::Checkpoint as RpcCheckpoint;
7use iota_types::{base_types::TransactionDigest, digests::CheckpointDigest, gas::GasCostSummary};
8
9use crate::{
10 errors::IndexerError,
11 schema::{chain_identifier, checkpoints, pruner_cp_watermark},
12 types::IndexedCheckpoint,
13};
14
15#[derive(Queryable, Insertable, Selectable, Debug, Clone, Default)]
16#[diesel(table_name = chain_identifier)]
17pub struct StoredChainIdentifier {
18 pub checkpoint_digest: Vec<u8>,
19}
20
21#[derive(Queryable, Insertable, Selectable, Debug, Clone, Default)]
22#[diesel(table_name = checkpoints)]
23pub struct StoredCheckpoint {
24 pub sequence_number: i64,
25 pub checkpoint_digest: Vec<u8>,
26 pub epoch: i64,
27 pub network_total_transactions: i64,
28 pub previous_checkpoint_digest: Option<Vec<u8>>,
29 pub end_of_epoch: bool,
30 pub tx_digests: Vec<Option<Vec<u8>>>,
31 pub timestamp_ms: i64,
32 pub total_gas_cost: i64,
33 pub computation_cost: i64,
34 pub storage_cost: i64,
35 pub storage_rebate: i64,
36 pub non_refundable_storage_fee: i64,
37 pub checkpoint_commitments: Vec<u8>,
38 pub validator_signature: Vec<u8>,
39 pub end_of_epoch_data: Option<Vec<u8>>,
40 pub min_tx_sequence_number: Option<i64>,
41 pub max_tx_sequence_number: Option<i64>,
42 pub computation_cost_burned: Option<i64>,
43}
44
45impl StoredCheckpoint {
46 pub fn computation_cost_burned(&self) -> u64 {
48 self.computation_cost_burned
49 .unwrap_or(self.computation_cost) as u64
50 }
51}
52
53impl From<&IndexedCheckpoint> for StoredCheckpoint {
54 fn from(c: &IndexedCheckpoint) -> Self {
55 Self {
56 sequence_number: c.sequence_number as i64,
57 checkpoint_digest: c.checkpoint_digest.into_inner().to_vec(),
58 epoch: c.epoch as i64,
59 tx_digests: c
60 .tx_digests
61 .iter()
62 .map(|tx| Some(tx.into_inner().to_vec()))
63 .collect(),
64 network_total_transactions: c.network_total_transactions as i64,
65 previous_checkpoint_digest: c
66 .previous_checkpoint_digest
67 .as_ref()
68 .map(|d| (*d).into_inner().to_vec()),
69 timestamp_ms: c.timestamp_ms as i64,
70 total_gas_cost: c.total_gas_cost,
71 computation_cost: c.computation_cost as i64,
72 computation_cost_burned: Some(c.computation_cost_burned as i64),
73 storage_cost: c.storage_cost as i64,
74 storage_rebate: c.storage_rebate as i64,
75 non_refundable_storage_fee: c.non_refundable_storage_fee as i64,
76 checkpoint_commitments: bcs::to_bytes(&c.checkpoint_commitments).unwrap(),
77 validator_signature: bcs::to_bytes(&c.validator_signature).unwrap(),
78 end_of_epoch_data: c
79 .end_of_epoch_data
80 .as_ref()
81 .map(|d| bcs::to_bytes(d).unwrap()),
82 end_of_epoch: c.end_of_epoch_data.is_some(),
83 min_tx_sequence_number: Some(c.min_tx_sequence_number as i64),
84 max_tx_sequence_number: Some(c.max_tx_sequence_number as i64),
85 }
86 }
87}
88
89impl TryFrom<StoredCheckpoint> for RpcCheckpoint {
90 type Error = IndexerError;
91 fn try_from(checkpoint: StoredCheckpoint) -> Result<RpcCheckpoint, IndexerError> {
92 let computation_cost_burned = checkpoint.computation_cost_burned();
93 let parsed_digest = CheckpointDigest::try_from(checkpoint.checkpoint_digest.clone())
94 .map_err(|e| {
95 IndexerError::PersistentStorageDataCorruption(format!(
96 "Failed to decode checkpoint digest: {:?} with err: {:?}",
97 checkpoint.checkpoint_digest, e
98 ))
99 })?;
100
101 let parsed_previous_digest: Option<CheckpointDigest> = checkpoint
102 .previous_checkpoint_digest
103 .map(|digest| {
104 CheckpointDigest::try_from(digest.clone()).map_err(|e| {
105 IndexerError::PersistentStorageDataCorruption(format!(
106 "Failed to decode previous checkpoint digest: {:?} with err: {:?}",
107 digest, e
108 ))
109 })
110 })
111 .transpose()?;
112
113 let transactions: Vec<TransactionDigest> = {
114 {
115 checkpoint
116 .tx_digests
117 .into_iter()
118 .map(|tx_digest| match tx_digest {
119 None => Err(IndexerError::PersistentStorageDataCorruption(
120 "tx_digests should not contain null elements".to_string(),
121 )),
122 Some(tx_digest) => TransactionDigest::try_from(tx_digest.as_slice())
123 .map_err(|e| {
124 IndexerError::PersistentStorageDataCorruption(format!(
125 "Failed to decode transaction digest: {:?} with err: {:?}",
126 tx_digest, e
127 ))
128 }),
129 })
130 .collect::<Result<Vec<TransactionDigest>, IndexerError>>()?
131 }
132 };
133 let validator_signature =
134 bcs::from_bytes(&checkpoint.validator_signature).map_err(|e| {
135 IndexerError::PersistentStorageDataCorruption(format!(
136 "Failed to decode validator signature: {:?} with err: {:?}",
137 checkpoint.validator_signature, e
138 ))
139 })?;
140
141 let checkpoint_commitments =
142 bcs::from_bytes(&checkpoint.checkpoint_commitments).map_err(|e| {
143 IndexerError::PersistentStorageDataCorruption(format!(
144 "Failed to decode checkpoint commitments: {:?} with err: {:?}",
145 checkpoint.checkpoint_commitments, e
146 ))
147 })?;
148
149 let end_of_epoch_data = checkpoint
150 .end_of_epoch_data
151 .as_ref()
152 .map(|data| {
153 bcs::from_bytes(data).map_err(|e| {
154 IndexerError::PersistentStorageDataCorruption(format!(
155 "Failed to decode end of epoch data: {:?} with err: {:?}",
156 data, e
157 ))
158 })
159 })
160 .transpose()?;
161
162 Ok(RpcCheckpoint {
163 epoch: checkpoint.epoch as u64,
164 sequence_number: checkpoint.sequence_number as u64,
165 digest: parsed_digest,
166 previous_digest: parsed_previous_digest,
167 end_of_epoch_data,
168 epoch_rolling_gas_cost_summary: GasCostSummary {
169 computation_cost: checkpoint.computation_cost as u64,
170 computation_cost_burned,
171 storage_cost: checkpoint.storage_cost as u64,
172 storage_rebate: checkpoint.storage_rebate as u64,
173 non_refundable_storage_fee: checkpoint.non_refundable_storage_fee as u64,
174 },
175 network_total_transactions: checkpoint.network_total_transactions as u64,
176 timestamp_ms: checkpoint.timestamp_ms as u64,
177 transactions,
178 validator_signature,
179 checkpoint_commitments,
180 })
181 }
182}
183
184#[derive(Queryable, Insertable, Selectable, Debug, Clone, Default)]
185#[diesel(table_name = pruner_cp_watermark)]
186pub struct StoredCpTx {
187 pub checkpoint_sequence_number: i64,
188 pub min_tx_sequence_number: i64,
189 pub max_tx_sequence_number: i64,
190}
191
192impl From<&IndexedCheckpoint> for StoredCpTx {
193 fn from(c: &IndexedCheckpoint) -> Self {
194 Self {
195 checkpoint_sequence_number: c.sequence_number as i64,
196 min_tx_sequence_number: c.min_tx_sequence_number as i64,
197 max_tx_sequence_number: c.max_tx_sequence_number as i64,
198 }
199 }
200}