bee_api_types/
responses.rs

1// Copyright 2020-2022 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use bee_block::{
5    output::{dto::OutputDto, RentStructure, RentStructureBuilder},
6    payload::dto::MilestonePayloadDto,
7    protocol::ProtocolParameters,
8    BlockDto,
9};
10use serde::{Deserialize, Serialize};
11
12use crate::{
13    body::BodyInner,
14    dtos::{LedgerInclusionStateDto, PeerDto, ReceiptDto},
15    error::Error,
16};
17
18/// Response of GET /api/core/v2/info.
19/// Returns general information about the node.
20#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
21pub struct InfoResponse {
22    pub name: String,
23    pub version: String,
24    pub status: StatusResponse,
25    #[serde(rename = "supportedProtocolVersions")]
26    pub supported_protocol_versions: Vec<u8>,
27    pub protocol: ProtocolResponse,
28    #[serde(rename = "pendingProtocolParameters")]
29    pub pending_protocol_parameters: Vec<PendingProtocolParameter>,
30    #[serde(rename = "baseToken")]
31    pub base_token: BaseTokenResponse,
32    pub metrics: MetricsResponse,
33    pub features: Vec<String>,
34}
35
36impl BodyInner for InfoResponse {}
37
38/// Returned in [`InfoResponse`].
39/// Status information about the node.
40#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
41pub struct StatusResponse {
42    #[serde(rename = "isHealthy")]
43    pub is_healthy: bool,
44    #[serde(rename = "latestMilestone")]
45    pub latest_milestone: LatestMilestoneResponse,
46    #[serde(rename = "confirmedMilestone")]
47    pub confirmed_milestone: ConfirmedMilestoneResponse,
48    #[serde(rename = "pruningIndex")]
49    pub pruning_index: u32,
50}
51
52/// Returned in [`StatusResponse`].
53/// Information about the latest milestone.
54#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
55pub struct LatestMilestoneResponse {
56    pub index: u32,
57    #[serde(skip_serializing_if = "Option::is_none")]
58    pub timestamp: Option<u32>,
59    #[serde(rename = "milestoneId", skip_serializing_if = "Option::is_none")]
60    pub milestone_id: Option<String>,
61}
62
63/// Returned in [`StatusResponse`].
64/// Information about the confirmed milestone.
65#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
66pub struct ConfirmedMilestoneResponse {
67    pub index: u32,
68    #[serde(skip_serializing_if = "Option::is_none")]
69    pub timestamp: Option<u32>,
70    #[serde(rename = "milestoneId", skip_serializing_if = "Option::is_none")]
71    pub milestone_id: Option<String>,
72}
73
74/// Returned in [`InfoResponse`].
75/// Protocol information about the node.
76#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
77pub struct ProtocolResponse {
78    pub version: u8,
79    #[serde(rename = "networkName")]
80    pub network_name: String,
81    #[serde(rename = "bech32Hrp")]
82    pub bech32_hrp: String,
83    #[serde(rename = "minPowScore")]
84    pub min_pow_score: u32,
85    #[serde(rename = "belowMaxDepth")]
86    pub below_max_depth: u8,
87    #[serde(rename = "rentStructure")]
88    pub rent_structure: RentStructureResponse,
89    #[serde(rename = "tokenSupply")]
90    pub token_supply: String,
91}
92
93impl TryFrom<ProtocolResponse> for ProtocolParameters {
94    type Error = Error;
95
96    fn try_from(response: ProtocolResponse) -> Result<Self, Self::Error> {
97        Ok(ProtocolParameters::new(
98            response.version,
99            response.network_name,
100            response.bech32_hrp,
101            response.min_pow_score,
102            response.below_max_depth,
103            response.rent_structure.into(),
104            response
105                .token_supply
106                .parse()
107                .map_err(|_| Error::InvalidField("token_supply"))?,
108        )?)
109    }
110}
111
112/// Returned in [`InfoResponse`].
113/// Pending protocol parameters.
114#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
115pub struct PendingProtocolParameter {
116    #[serde(rename = "type")]
117    pub kind: u8,
118    #[serde(rename = "targetMilestoneIndex")]
119    pub target_milestone_index: u32,
120    #[serde(rename = "protocolVersion")]
121    pub protocol_version: u8,
122    pub params: String,
123}
124
125/// Returned in [`InfoResponse`].
126/// Information about the base token.
127#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
128pub struct BaseTokenResponse {
129    pub name: String,
130    #[serde(rename = "tickerSymbol")]
131    pub ticker_symbol: String,
132    pub unit: String,
133    #[serde(skip_serializing_if = "Option::is_none")]
134    pub subunit: Option<String>,
135    pub decimals: u8,
136    #[serde(rename = "useMetricPrefix")]
137    pub use_metric_prefix: bool,
138}
139
140/// Returned in [`InfoResponse`].
141/// Rent information about the node.
142#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
143pub struct RentStructureResponse {
144    #[serde(rename = "vByteCost")]
145    pub v_byte_cost: u32,
146    #[serde(rename = "vByteFactorKey")]
147    pub v_byte_factor_key: u8,
148    #[serde(rename = "vByteFactorData")]
149    pub v_byte_factor_data: u8,
150}
151
152impl From<RentStructureResponse> for RentStructure {
153    fn from(response: RentStructureResponse) -> Self {
154        RentStructureBuilder::new()
155            .byte_cost(response.v_byte_cost)
156            .key_factor(response.v_byte_factor_key)
157            .data_factor(response.v_byte_factor_data)
158            .finish()
159    }
160}
161
162/// Returned in [`InfoResponse`].
163/// Metric information about the node.
164#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
165pub struct MetricsResponse {
166    #[serde(rename = "blocksPerSecond")]
167    pub blocks_per_second: f64,
168    #[serde(rename = "referencedBlocksPerSecond")]
169    pub referenced_blocks_per_second: f64,
170    #[serde(rename = "referencedRate")]
171    pub referenced_rate: f64,
172}
173
174/// Response of GET /api/core/v2/tips.
175/// Returns non-lazy tips.
176#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
177pub struct TipsResponse {
178    pub tips: Vec<String>,
179}
180
181/// Response of POST /api/core/v2/blocks.
182/// Returns the block identifier of the submitted block.
183#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
184pub struct SubmitBlockResponse {
185    #[serde(rename = "blockId")]
186    pub block_id: String,
187}
188
189/// Response of GET /api/core/v2/blocks/{block_id}.
190/// Returns a specific block.
191#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
192#[serde(untagged)]
193pub enum BlockResponse {
194    Json(BlockDto),
195    Raw(Vec<u8>),
196}
197
198/// Response of GET /api/core/v2/blocks/{block_id}/metadata.
199/// Returns the metadata of a block.
200#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
201pub struct BlockMetadataResponse {
202    #[serde(rename = "blockId")]
203    pub block_id: String,
204    pub parents: Vec<String>,
205    #[serde(rename = "isSolid")]
206    pub is_solid: bool,
207    #[serde(rename = "referencedByMilestoneIndex", skip_serializing_if = "Option::is_none")]
208    pub referenced_by_milestone_index: Option<u32>,
209    #[serde(rename = "milestoneIndex", skip_serializing_if = "Option::is_none")]
210    pub milestone_index: Option<u32>,
211    #[serde(rename = "ledgerInclusionState", skip_serializing_if = "Option::is_none")]
212    pub ledger_inclusion_state: Option<LedgerInclusionStateDto>,
213    #[serde(rename = "conflictReason", skip_serializing_if = "Option::is_none")]
214    pub conflict_reason: Option<u8>,
215    #[serde(rename = "whiteFlagIndex", skip_serializing_if = "Option::is_none")]
216    pub white_flag_index: Option<u32>,
217    #[serde(rename = "shouldPromote", skip_serializing_if = "Option::is_none")]
218    pub should_promote: Option<bool>,
219    #[serde(rename = "shouldReattach", skip_serializing_if = "Option::is_none")]
220    pub should_reattach: Option<bool>,
221}
222
223/// Response of GET /api/core/v2/outputs/{output_id}.
224/// Returns an output and its metadata.
225#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
226pub struct OutputResponse {
227    pub metadata: OutputMetadataResponse,
228    pub output: OutputDto,
229}
230
231/// Response of GET /api/core/v2/outputs/{output_id}/metadata.
232/// Returns an output metadata.
233#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
234pub struct OutputMetadataResponse {
235    #[serde(rename = "blockId")]
236    pub block_id: String,
237    #[serde(rename = "transactionId")]
238    pub transaction_id: String,
239    #[serde(rename = "outputIndex")]
240    pub output_index: u16,
241    #[serde(rename = "isSpent")]
242    pub is_spent: bool,
243    #[serde(rename = "milestoneIndexSpent", skip_serializing_if = "Option::is_none")]
244    pub milestone_index_spent: Option<u32>,
245    #[serde(rename = "milestoneTimestampSpent", skip_serializing_if = "Option::is_none")]
246    pub milestone_timestamp_spent: Option<u32>,
247    #[serde(rename = "transactionIdSpent", skip_serializing_if = "Option::is_none")]
248    pub transaction_id_spent: Option<String>,
249    #[serde(rename = "milestoneIndexBooked")]
250    pub milestone_index_booked: u32,
251    #[serde(rename = "milestoneTimestampBooked")]
252    pub milestone_timestamp_booked: u32,
253    #[serde(rename = "ledgerIndex", default)]
254    pub ledger_index: u32,
255}
256
257/// Response of:
258/// * GET /api/core/v2/receipts/{milestone_index}, returns all stored receipts for the given milestone index.
259/// * GET /api/core/v2/receipts, returns all stored receipts, independent of a milestone index.
260#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
261pub struct ReceiptsResponse {
262    pub receipts: Vec<ReceiptDto>,
263}
264
265/// Response of GET /api/core/v2/treasury.
266/// Returns all information about the treasury.
267#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
268pub struct TreasuryResponse {
269    #[serde(rename = "milestoneId")]
270    pub milestone_id: String,
271    pub amount: String,
272}
273
274/// Response of GET /api/core/v2/milestone/{milestone_index}.
275/// Returns information about a milestone.
276#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
277#[serde(untagged)]
278pub enum MilestoneResponse {
279    Json(MilestonePayloadDto),
280    Raw(Vec<u8>),
281}
282
283/// Response of GET /api/core/v2/milestone/{milestone_index}/utxo-changes.
284/// Returns all UTXO changes that happened at a specific milestone.
285#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
286pub struct UtxoChangesResponse {
287    pub index: u32,
288    #[serde(rename = "createdOutputs")]
289    pub created_outputs: Vec<String>,
290    #[serde(rename = "consumedOutputs")]
291    pub consumed_outputs: Vec<String>,
292}
293
294/// Response of GET /api/core/v2/peers.
295/// Returns information about all peers of the node.
296#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
297pub struct PeersResponse(pub Vec<PeerDto>);
298
299/// Response of POST /api/core/v2/peers.
300/// Returns information about the added peer.
301#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
302pub struct AddPeerResponse(pub PeerDto);
303
304/// Response of GET /api/core/v2/peer/{peer_id}.
305/// Returns information about a specific peer of the node.
306#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
307pub struct PeerResponse(pub PeerDto);
308
309/// Response of GET /api/plugins/debug/whiteflag.
310/// Returns the computed merkle tree hash for the given white flag traversal.
311#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
312pub struct WhiteFlagResponse {
313    #[serde(rename = "merkleTreeHash")]
314    pub merkle_tree_hash: String,
315}
316
317/// Response of GET /api/routes.
318/// Returns the available API route groups of the node.
319#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
320pub struct RoutesResponse {
321    pub routes: Vec<String>,
322}
323
324#[cfg(feature = "axum")]
325mod axum_response {
326    use axum::{
327        body::BoxBody,
328        http::StatusCode,
329        response::{IntoResponse, Response},
330        Json,
331    };
332
333    use super::*;
334
335    /// Macro to implement `IntoResponse` for simple cases which can just be wrapped in JSON.
336    macro_rules! impl_into_response {
337        ($($t:ty),*) => ($(
338            impl IntoResponse for $t {
339                fn into_response(self) -> Response<BoxBody> {
340                    Json(self).into_response()
341                }
342            }
343        )*)
344    }
345
346    impl_into_response!(
347        InfoResponse,
348        TipsResponse,
349        BlockMetadataResponse,
350        OutputResponse,
351        OutputMetadataResponse,
352        ReceiptsResponse,
353        TreasuryResponse,
354        UtxoChangesResponse,
355        AddPeerResponse,
356        PeersResponse,
357        PeerResponse,
358        WhiteFlagResponse
359    );
360
361    impl IntoResponse for SubmitBlockResponse {
362        fn into_response(self) -> Response<BoxBody> {
363            (StatusCode::CREATED, Json(self)).into_response()
364        }
365    }
366
367    impl IntoResponse for BlockResponse {
368        fn into_response(self) -> Response<BoxBody> {
369            match self {
370                BlockResponse::Json(dto) => Json(dto).into_response(),
371                BlockResponse::Raw(bytes) => bytes.into_response(),
372            }
373        }
374    }
375
376    impl IntoResponse for MilestoneResponse {
377        fn into_response(self) -> Response<BoxBody> {
378            match self {
379                MilestoneResponse::Json(dto) => Json(dto).into_response(),
380                MilestoneResponse::Raw(bytes) => bytes.into_response(),
381            }
382        }
383    }
384}