exonum_explorer/api/
websocket.rs1use chrono::{DateTime, Utc};
18use exonum::{
19 blockchain::{Block, Schema, TxLocation},
20 crypto::Hash,
21 merkledb::{access::Access, ListProof},
22 runtime::{ExecutionStatus, InstanceId, MethodId},
23};
24use serde_derive::{Deserialize, Serialize};
25
26use std::fmt;
27
28use super::TransactionHex;
29use crate::median_precommits_time;
30
31#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
33#[serde(tag = "type", content = "payload", rename_all = "snake_case")]
34pub enum IncomingMessage {
35 SetSubscriptions(Vec<SubscriptionType>),
37 Transaction(TransactionHex),
39}
40
41#[derive(Debug, PartialEq, Eq, Hash, Clone, PartialOrd, Ord)]
43#[derive(Serialize, Deserialize)]
44#[serde(tag = "type", rename_all = "snake_case")]
45pub enum SubscriptionType {
46 None,
48 Blocks,
50 Transactions {
52 filter: Option<TransactionFilter>,
54 },
55}
56
57#[derive(Debug, PartialEq, Eq, Hash, Clone, PartialOrd, Ord)]
60#[derive(Serialize, Deserialize)]
61pub struct TransactionFilter {
62 pub instance_id: InstanceId,
64 pub method_id: Option<MethodId>,
67}
68
69impl TransactionFilter {
70 pub fn new(instance_id: InstanceId, method_id: Option<MethodId>) -> Self {
72 Self {
73 instance_id,
74 method_id,
75 }
76 }
77}
78
79#[serde(tag = "result", rename_all = "snake_case")]
81#[derive(Debug, PartialEq, Serialize, Deserialize)]
82pub enum Response<T> {
83 Success {
85 response: T,
87 },
88 Error {
90 description: String,
92 },
93}
94
95impl<T> Response<T> {
96 pub fn success(value: T) -> Self {
98 Response::Success { response: value }
99 }
100
101 pub fn error(description: impl fmt::Display) -> Self {
103 Response::Error {
104 description: description.to_string(),
105 }
106 }
107
108 pub fn into_result(self) -> Result<T, String> {
110 match self {
111 Response::Success { response } => Ok(response),
112 Response::Error { description } => Err(description),
113 }
114 }
115}
116
117impl<T> From<Result<T, String>> for Response<T> {
118 fn from(res: Result<T, String>) -> Self {
119 match res {
120 Ok(value) => Self::success(value),
121 Err(description) => Response::Error { description },
122 }
123 }
124}
125
126#[derive(Debug, Serialize, Deserialize)]
128pub struct CommittedTransactionSummary {
129 pub tx_hash: Hash,
131 pub instance_id: InstanceId,
133 pub method_id: MethodId,
135 pub status: ExecutionStatus,
137 pub location: TxLocation,
139 pub location_proof: ListProof<Hash>,
141 pub time: DateTime<Utc>,
143}
144
145impl CommittedTransactionSummary {
146 pub fn new(schema: &Schema<impl Access>, tx_hash: &Hash) -> Option<Self> {
148 let tx = schema.transactions().get(tx_hash)?;
149 let tx = tx.payload();
150 let instance_id = tx.call_info.instance_id;
151 let method_id = tx.call_info.method_id;
152 let location = schema.transactions_locations().get(tx_hash)?;
153 let tx_result = schema.transaction_result(location)?;
154 let location_proof = schema
155 .block_transactions(location.block_height())
156 .get_proof(location.position_in_block().into());
157 let time = median_precommits_time(
158 &schema
159 .block_and_precommits(location.block_height())
160 .unwrap()
161 .precommits,
162 );
163 Some(Self {
164 tx_hash: *tx_hash,
165 instance_id,
166 method_id,
167 status: ExecutionStatus(tx_result),
168 location,
169 location_proof,
170 time,
171 })
172 }
173}
174
175#[derive(Debug, Serialize, Deserialize)]
177#[serde(tag = "type", rename_all = "snake_case")]
178pub enum Notification {
179 Block(Block),
181 Transaction(CommittedTransactionSummary),
183}