1use diesel::{Insertable, Queryable, Selectable};
6use iota_json_rpc_types::{EndOfEpochInfo, EpochInfo};
7use iota_types::iota_system_state::iota_system_state_summary::{
8 IotaSystemStateSummary, IotaSystemStateSummaryV1,
9};
10
11use crate::{
12 errors::IndexerError,
13 schema::{epochs, feature_flags, protocol_configs},
14 types::{IndexedEpochInfo, IotaSystemStateSummaryView},
15};
16
17#[derive(Queryable, Insertable, Debug, Clone, Default)]
18#[diesel(table_name = epochs)]
19#[diesel(check_for_backend(diesel::pg::Pg))]
20pub struct StoredEpochInfo {
21 pub epoch: i64,
22 pub first_checkpoint_id: i64,
23 pub epoch_start_timestamp: i64,
24 pub reference_gas_price: i64,
25 pub protocol_version: i64,
26 pub total_stake: i64,
27 pub storage_fund_balance: i64,
28 pub system_state: Vec<u8>,
29 pub epoch_total_transactions: Option<i64>,
30 pub last_checkpoint_id: Option<i64>,
31 pub epoch_end_timestamp: Option<i64>,
32 pub storage_charge: Option<i64>,
33 pub storage_rebate: Option<i64>,
34 pub total_gas_fees: Option<i64>,
35 pub total_stake_rewards_distributed: Option<i64>,
36 pub epoch_commitments: Option<Vec<u8>>,
37 pub burnt_tokens_amount: Option<i64>,
38 pub minted_tokens_amount: Option<i64>,
39}
40
41#[derive(Queryable, Insertable, Debug, Clone, Default)]
42#[diesel(table_name = protocol_configs)]
43pub struct StoredProtocolConfig {
44 pub protocol_version: i64,
45 pub config_name: String,
46 pub config_value: Option<String>,
47}
48
49#[derive(Queryable, Insertable, Debug, Clone, Default)]
50#[diesel(table_name = feature_flags)]
51pub struct StoredFeatureFlag {
52 pub protocol_version: i64,
53 pub flag_name: String,
54 pub flag_value: bool,
55}
56
57#[derive(Queryable, Selectable, Clone)]
58#[diesel(table_name = epochs)]
59#[diesel(check_for_backend(diesel::pg::Pg))]
60pub struct QueryableEpochInfo {
61 pub epoch: i64,
62 pub first_checkpoint_id: i64,
63 pub epoch_start_timestamp: i64,
64 pub reference_gas_price: i64,
65 pub protocol_version: i64,
66 pub total_stake: i64,
67 pub storage_fund_balance: i64,
68 pub epoch_total_transactions: Option<i64>,
69 pub last_checkpoint_id: Option<i64>,
70 pub epoch_end_timestamp: Option<i64>,
71 pub storage_charge: Option<i64>,
72 pub storage_rebate: Option<i64>,
73 pub total_gas_fees: Option<i64>,
74 pub total_stake_rewards_distributed: Option<i64>,
75 pub epoch_commitments: Option<Vec<u8>>,
76 pub burnt_tokens_amount: Option<i64>,
77 pub minted_tokens_amount: Option<i64>,
78}
79
80#[derive(Queryable)]
81pub struct QueryableEpochSystemState {
82 pub epoch: i64,
83 pub system_state: Vec<u8>,
84}
85
86impl StoredEpochInfo {
87 pub fn from_epoch_beginning_info(e: &IndexedEpochInfo) -> Self {
88 Self {
89 epoch: e.epoch as i64,
90 first_checkpoint_id: e.first_checkpoint_id as i64,
91 epoch_start_timestamp: e.epoch_start_timestamp as i64,
92 reference_gas_price: e.reference_gas_price as i64,
93 protocol_version: e.protocol_version as i64,
94 total_stake: e.total_stake as i64,
95 storage_fund_balance: e.storage_fund_balance as i64,
96 system_state: e.system_state.clone(),
97 ..Default::default()
98 }
99 }
100
101 pub fn from_epoch_end_info(e: &IndexedEpochInfo) -> Self {
102 Self {
103 epoch: e.epoch as i64,
104 system_state: e.system_state.clone(),
105 epoch_total_transactions: e.epoch_total_transactions.map(|v| v as i64),
106 last_checkpoint_id: e.last_checkpoint_id.map(|v| v as i64),
107 epoch_end_timestamp: e.epoch_end_timestamp.map(|v| v as i64),
108 storage_charge: e.storage_charge.map(|v| v as i64),
109 storage_rebate: e.storage_rebate.map(|v| v as i64),
110 total_gas_fees: e.total_gas_fees.map(|v| v as i64),
111 total_stake_rewards_distributed: e.total_stake_rewards_distributed.map(|v| v as i64),
112 epoch_commitments: e
113 .epoch_commitments
114 .as_ref()
115 .map(|v| bcs::to_bytes(&v).unwrap()),
116
117 first_checkpoint_id: 0,
122 epoch_start_timestamp: 0,
123 reference_gas_price: 0,
124 protocol_version: 0,
125 total_stake: 0,
126 storage_fund_balance: 0,
127 burnt_tokens_amount: e.burnt_tokens_amount.map(|v| v as i64),
128 minted_tokens_amount: e.minted_tokens_amount.map(|v| v as i64),
129 }
130 }
131}
132
133impl From<&StoredEpochInfo> for Option<EndOfEpochInfo> {
134 fn from(info: &StoredEpochInfo) -> Option<EndOfEpochInfo> {
135 Some(EndOfEpochInfo {
136 reference_gas_price: (info.reference_gas_price as u64),
137 protocol_version: (info.protocol_version as u64),
138 last_checkpoint_id: info.last_checkpoint_id.map(|v| v as u64)?,
139 total_stake: info.total_stake as u64,
140 storage_fund_balance: info.storage_fund_balance as u64,
141 epoch_end_timestamp: info.epoch_end_timestamp.map(|v| v as u64)?,
142 storage_charge: info.storage_charge.map(|v| v as u64)?,
143 storage_rebate: info.storage_rebate.map(|v| v as u64)?,
144 total_gas_fees: info.total_gas_fees.map(|v| v as u64)?,
145 total_stake_rewards_distributed: info
146 .total_stake_rewards_distributed
147 .map(|v| v as u64)?,
148 burnt_tokens_amount: info.burnt_tokens_amount.map(|v| v as u64)?,
149 minted_tokens_amount: info.minted_tokens_amount.map(|v| v as u64)?,
150 })
151 }
152}
153
154impl TryFrom<&StoredEpochInfo> for IotaSystemStateSummary {
155 type Error = IndexerError;
156
157 fn try_from(value: &StoredEpochInfo) -> Result<Self, Self::Error> {
158 IotaSystemStateSummaryV1::try_from(value)
159 .map(Into::into)
160 .or_else(|_| {
161 bcs::from_bytes(&value.system_state).map_err(|_| {
162 IndexerError::PersistentStorageDataCorruption(
163 "failed to deserialize `system_state`".into(),
164 )
165 })
166 })
167 }
168}
169
170impl TryFrom<&StoredEpochInfo> for IotaSystemStateSummaryV1 {
171 type Error = IndexerError;
172
173 fn try_from(value: &StoredEpochInfo) -> Result<Self, Self::Error> {
174 bcs::from_bytes(&value.system_state).map_err(|_| {
175 IndexerError::PersistentStorageDataCorruption(
176 "failed to deserialize `system_state`".into(),
177 )
178 })
179 }
180}
181
182impl TryFrom<StoredEpochInfo> for EpochInfo {
183 type Error = IndexerError;
184
185 fn try_from(value: StoredEpochInfo) -> Result<Self, Self::Error> {
186 let epoch = value.epoch as u64;
187 let end_of_epoch_info = (&value).into();
188 let system_state = IotaSystemStateSummary::try_from(&value).map_err(|_| {
189 IndexerError::PersistentStorageDataCorruption(format!(
190 "failed to deserialize `system_state` for epoch {epoch}",
191 ))
192 })?;
193 Ok(EpochInfo {
194 epoch: value.epoch as u64,
195 validators: system_state.active_validators().to_vec(),
196 epoch_total_transactions: value.epoch_total_transactions.unwrap_or(0) as u64,
197 first_checkpoint_id: value.first_checkpoint_id as u64,
198 epoch_start_timestamp: value.epoch_start_timestamp as u64,
199 end_of_epoch_info,
200 reference_gas_price: Some(value.reference_gas_price as u64),
201 committee_members: system_state.to_committee_members(),
202 })
203 }
204}