1use std::collections::BTreeMap;
2
3use borsh::{BorshDeserialize, BorshSerialize};
4use serde::{Deserialize, Serialize};
5use serde_with::serde_as;
6use strum::IntoDiscriminant;
7use utoipa::ToSchema;
8
9use crate::{
10 utils::TimestampMs, BlockHash, BlockHeight, ConsensusProposalHash, ContractName,
11 DataProposalHash, Identity, LaneBytesSize, LaneId, ProgramId, StateCommitment, TimeoutWindow,
12 Transaction, TransactionKind, TxHash, ValidatorPublicKey, Verifier,
13};
14
15#[derive(Clone, Serialize, Deserialize, Debug, ToSchema)]
16pub struct NodeInfo {
17 pub id: String,
18 pub pubkey: Option<ValidatorPublicKey>,
19 pub da_address: String,
20}
21
22#[derive(Clone, Serialize, Deserialize, Debug, ToSchema)]
23pub struct NetworkStats {
24 pub total_transactions: i64, pub txs_last_day: i64, pub total_contracts: i64, pub contracts_last_day: i64, pub graph_tx_volume: Vec<(i64, i64)>, pub graph_block_time: Vec<(i64, f64)>, pub peak_txs: (i64, i64), }
32
33#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
34#[derive(Clone, Serialize, Deserialize, Debug, ToSchema)]
35pub struct ProofStat {
36 pub verifier: String,
37 pub proof_count: i64,
38}
39
40#[derive(Clone, Debug, Default, Serialize, Deserialize, ToSchema)]
41pub struct APIRegisterContract {
42 pub verifier: Verifier,
43 pub program_id: ProgramId,
44 pub state_commitment: StateCommitment,
45 pub contract_name: ContractName,
46 pub timeout_window: Option<(u64, u64)>,
47 pub constructor_metadata: Option<Vec<u8>>,
48}
49
50#[derive(Debug, Default, Serialize, Deserialize, ToSchema, Clone, PartialEq, Eq)]
52pub struct APIStaking {
53 pub stakes: BTreeMap<Identity, u128>,
54 pub delegations: BTreeMap<ValidatorPublicKey, Vec<Identity>>,
55 pub rewarded: BTreeMap<ValidatorPublicKey, Vec<BlockHeight>>,
58
59 pub bonded: Vec<ValidatorPublicKey>,
61 pub total_bond: u128,
62
63 pub fees: APIFees,
65}
66
67#[derive(Debug, Serialize, Deserialize, ToSchema, Clone, PartialEq, Eq)]
68pub struct APIFeesBalance {
69 pub balance: i128,
70 pub cumul_sizes: BTreeMap<LaneId, LaneBytesSize>,
71}
72
73#[derive(Debug, Default, Serialize, Deserialize, ToSchema, Clone, PartialEq, Eq)]
74pub struct APIFees {
75 pub balances: BTreeMap<ValidatorPublicKey, APIFeesBalance>,
77}
78
79#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
80pub struct APIBlock {
81 pub hash: ConsensusProposalHash,
83 pub parent_hash: ConsensusProposalHash,
84 pub height: u64, pub timestamp: i64, pub total_txs: u64, }
88
89#[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
90#[cfg_attr(
91 feature = "sqlx",
92 sqlx(type_name = "transaction_type", rename_all = "snake_case")
93)]
94#[derive(Debug, Serialize, Deserialize, ToSchema, Clone, PartialEq, Eq)]
95pub enum TransactionTypeDb {
96 BlobTransaction,
97 ProofTransaction,
98 RegisterContractTransaction,
99 Stake,
100}
101
102#[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
103#[derive(
104 Debug, Serialize, Deserialize, BorshSerialize, BorshDeserialize, ToSchema, Clone, PartialEq, Eq,
105)]
106#[cfg_attr(
107 feature = "sqlx",
108 sqlx(type_name = "transaction_status", rename_all = "snake_case")
109)]
110pub enum TransactionStatusDb {
111 WaitingDissemination,
112 DataProposalCreated,
113 Success,
114 Failure,
115 Sequenced,
116 TimedOut,
117}
118
119impl std::str::FromStr for TransactionStatusDb {
120 type Err = String;
121
122 fn from_str(s: &str) -> Result<Self, Self::Err> {
123 match s {
124 "waiting_dissemination" => Ok(TransactionStatusDb::WaitingDissemination),
125 "data_proposal_created" => Ok(TransactionStatusDb::DataProposalCreated),
126 "success" => Ok(TransactionStatusDb::Success),
127 "failure" => Ok(TransactionStatusDb::Failure),
128 "sequenced" => Ok(TransactionStatusDb::Sequenced),
129 "timed_out" => Ok(TransactionStatusDb::TimedOut),
130 _ => Err(format!("Invalid transaction status: {}", s)),
131 }
132 }
133}
134
135impl std::fmt::Display for TransactionStatusDb {
136 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137 let str = match self {
138 TransactionStatusDb::WaitingDissemination => "waiting_dissemination",
139 TransactionStatusDb::DataProposalCreated => "data_proposal_created",
140 TransactionStatusDb::Success => "success",
141 TransactionStatusDb::Failure => "failure",
142 TransactionStatusDb::Sequenced => "sequenced",
143 TransactionStatusDb::TimedOut => "timed_out",
144 };
145 write!(f, "{}", str)
146 }
147}
148
149impl TransactionTypeDb {
150 pub fn from(transaction: &Transaction) -> Self {
151 transaction.transaction_data.discriminant().into()
152 }
153}
154
155impl From<TransactionKind> for TransactionTypeDb {
156 fn from(value: TransactionKind) -> Self {
157 match value {
158 TransactionKind::Blob => TransactionTypeDb::BlobTransaction,
159 TransactionKind::Proof => TransactionTypeDb::ProofTransaction,
160 TransactionKind::VerifiedProof => TransactionTypeDb::ProofTransaction,
161 }
162 }
163}
164
165#[derive(Debug, Serialize, Deserialize, ToSchema, Clone, PartialEq, Eq)]
166pub struct APITransaction {
167 pub tx_hash: TxHash, pub parent_dp_hash: DataProposalHash, pub block_hash: Option<ConsensusProposalHash>, pub block_height: Option<BlockHeight>, pub index: Option<u32>, pub version: u32, pub transaction_type: TransactionTypeDb, pub transaction_status: TransactionStatusDb, pub timestamp: Option<TimestampMs>, pub lane_id: Option<LaneId>, pub identity: Option<String>,
179}
180
181#[derive(Debug, Serialize, Deserialize, ToSchema, Clone, PartialEq, Eq)]
182pub struct APITransactionEvents {
183 pub block_hash: BlockHash,
184 pub block_height: BlockHeight,
185 pub events: Vec<serde_json::Value>,
186}
187
188#[derive(Serialize, Deserialize, ToSchema, Debug, Clone, PartialEq)]
189pub struct TransactionWithBlobs {
190 pub tx_hash: TxHash,
192 pub parent_dp_hash: DataProposalHash,
193 pub block_hash: ConsensusProposalHash,
194 pub block_height: BlockHeight,
195 pub index: u32,
196 pub version: u32,
197 pub transaction_type: TransactionTypeDb,
198 pub transaction_status: TransactionStatusDb,
199 pub timestamp: Option<TimestampMs>,
200 pub lane_id: Option<LaneId>,
201 pub identity: String,
202 pub blobs: Vec<BlobWithStatus>,
204}
205
206#[derive(Debug, Serialize, Deserialize, ToSchema, Clone, PartialEq, Eq)]
207pub struct APIProofDetails {
208 pub tx_hash: TxHash, pub parent_dp_hash: DataProposalHash, pub block_hash: Option<ConsensusProposalHash>, pub block_height: Option<BlockHeight>, pub index: Option<u32>, pub version: u32, pub transaction_type: TransactionTypeDb, pub transaction_status: TransactionStatusDb, pub timestamp: Option<TimestampMs>, pub lane_id: Option<LaneId>, pub proof_outputs: Vec<(TxHash, u32, u32, serde_json::Value)>,
220}
221
222#[serde_as]
223#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ToSchema)]
224pub struct BlobWithStatus {
225 pub contract_name: String, #[serde_as(as = "serde_with::hex::Hex")]
227 pub data: Vec<u8>, pub proof_outputs: Vec<serde_json::Value>, }
230
231#[serde_as]
232#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ToSchema)]
233pub struct APIContract {
234 pub tx_hash: TxHash, pub verifier: String, #[serde_as(as = "serde_with::hex::Hex")]
238 pub program_id: Vec<u8>, #[serde_as(as = "serde_with::hex::Hex")]
240 pub state_commitment: Vec<u8>, pub contract_name: String, pub total_tx: u64, pub unsettled_tx: u64, pub earliest_unsettled: Option<BlockHeight>, }
246
247#[derive(Debug, Serialize, ToSchema)]
248pub struct APINodeContract {
249 pub contract_name: ContractName, pub state_block_height: BlockHeight, pub state_commitment: StateCommitment, pub program_id: ProgramId, pub verifier: Verifier, pub timeout_window: Option<(u64, u64)>, }
256
257impl<'de> Deserialize<'de> for APINodeContract {
258 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
259 where
260 D: serde::Deserializer<'de>,
261 {
262 #[derive(Deserialize)]
263 #[serde(untagged)]
264 enum Helper {
265 Old(crate::Contract),
266 New {
267 contract_name: ContractName,
268 state_block_height: BlockHeight,
269 state_commitment: StateCommitment,
270 program_id: ProgramId,
271 verifier: Verifier,
272 timeout_window: Option<(u64, u64)>,
273 },
274 }
275
276 match Helper::deserialize(deserializer)? {
277 Helper::Old(c) => Ok(APINodeContract {
278 contract_name: c.name,
279 state_block_height: BlockHeight(0),
280 state_commitment: c.state,
281 program_id: c.program_id,
282 verifier: c.verifier,
283 timeout_window: match c.timeout_window {
284 TimeoutWindow::Timeout {
285 hard_timeout,
286 soft_timeout,
287 } => Some((hard_timeout.0, soft_timeout.0)),
288 TimeoutWindow::NoTimeout => None,
289 },
290 }),
291 Helper::New {
292 contract_name,
293 state_block_height,
294 state_commitment,
295 program_id,
296 verifier,
297 timeout_window,
298 } => Ok(APINodeContract {
299 contract_name,
300 state_block_height,
301 state_commitment,
302 program_id,
303 verifier,
304 timeout_window,
305 }),
306 }
307 }
308}
309
310#[test]
311fn test_deserialize_api_node_contract() {
312 let old_json = serde_json::to_value(&crate::Contract {
314 name: ContractName("my_contract".to_string()),
315 program_id: ProgramId(vec![4, 5, 6]),
316 state: StateCommitment(vec![1, 2, 3]),
317 verifier: Verifier("verifier1".to_string()),
318 timeout_window: TimeoutWindow::timeout(BlockHeight(32), BlockHeight(32)),
319 })
320 .unwrap();
321 let old_contract: APINodeContract = serde_json::from_value(old_json).unwrap();
322 assert_eq!(old_contract.contract_name.0, "my_contract");
323 assert_eq!(old_contract.state_block_height.0, 0); assert_eq!(old_contract.state_commitment.0, vec![1, 2, 3]);
325 assert_eq!(old_contract.program_id.0, vec![4, 5, 6]);
326 assert_eq!(old_contract.verifier.0, "verifier1");
327 assert_eq!(old_contract.timeout_window, Some((32, 32)));
328 let new_json = serde_json::to_value(&APINodeContract {
330 contract_name: ContractName("new_contract".to_string()),
331 state_block_height: BlockHeight(42),
332 state_commitment: StateCommitment(vec![7, 8, 9]),
333 program_id: ProgramId(vec![10, 11, 12]),
334 verifier: Verifier("verifier2".to_string()),
335 timeout_window: Some((123, 123)),
336 })
337 .unwrap();
338 let new_contract: APINodeContract = serde_json::from_value(new_json).unwrap();
339 assert_eq!(new_contract.contract_name.0, "new_contract");
340 assert_eq!(new_contract.state_block_height.0, 42);
341 assert_eq!(new_contract.state_commitment.0, vec![7, 8, 9]);
342 assert_eq!(new_contract.program_id.0, vec![10, 11, 12]);
343 assert_eq!(new_contract.verifier.0, "verifier2");
344 assert_eq!(new_contract.timeout_window, Some((123, 123)));
345}
346
347#[derive(Debug, Serialize, Deserialize, ToSchema)]
348pub struct APIContractState {
349 pub contract_name: String, pub block_hash: ConsensusProposalHash, pub state_commitment: Vec<u8>, }
354
355#[serde_as]
356#[derive(Debug, Serialize, Deserialize, ToSchema)]
357pub struct APIBlob {
358 pub tx_hash: TxHash, pub blob_index: u32, pub identity: String, pub contract_name: String, #[serde_as(as = "serde_with::hex::Hex")]
363 pub data: Vec<u8>, pub proof_outputs: Vec<serde_json::Value>, pub verified: bool, }
367
368#[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
369#[cfg_attr(
370 feature = "sqlx",
371 sqlx(type_name = "contract_change_type", rename_all = "snake_case")
372)]
373#[derive(
374 Debug, Serialize, Deserialize, ToSchema, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize,
375)]
376#[serde(rename_all = "snake_case")]
377pub enum ContractChangeType {
378 Registered,
379 ProgramIdUpdated,
380 StateUpdated,
381 TimeoutUpdated,
382 Deleted,
383}
384
385#[serde_as]
386#[derive(Debug, Serialize, Deserialize, ToSchema, Clone)]
387pub struct APIContractHistory {
388 pub contract_name: String, pub block_height: u64, pub tx_index: i32, pub change_type: Vec<ContractChangeType>, pub verifier: String, #[serde_as(as = "serde_with::hex::Hex")]
394 pub program_id: Vec<u8>, #[serde_as(as = "serde_with::hex::Hex")]
396 pub state_commitment: Vec<u8>, pub soft_timeout: Option<i64>, pub hard_timeout: Option<i64>, pub tx_hash: TxHash, pub parent_dp_hash: DataProposalHash, }