Skip to main content

bee_rest_api/types/
dtos.rs

1// Copyright 2020-2021 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::types::error::Error;
5
6use bee_ledger::types::Receipt;
7use bee_message::{
8    address::{Address, Ed25519Address, ED25519_ADDRESS_LENGTH},
9    input::{Input, TreasuryInput, UtxoInput},
10    milestone::MilestoneIndex,
11    output::{Output, SignatureLockedDustAllowanceOutput, SignatureLockedSingleOutput, TreasuryOutput},
12    parents::Parents,
13    payload::{
14        indexation::IndexationPayload,
15        milestone::{
16            MilestoneId, MilestonePayload, MilestonePayloadEssence, MILESTONE_MERKLE_PROOF_LENGTH,
17            MILESTONE_PUBLIC_KEY_LENGTH,
18        },
19        receipt::{MigratedFundsEntry, ReceiptPayload, TailTransactionHash, TAIL_TRANSACTION_HASH_LEN},
20        transaction::{Essence, RegularEssence, TransactionId, TransactionPayload},
21        treasury::TreasuryTransactionPayload,
22        Payload,
23    },
24    signature::{Ed25519Signature, SignatureUnlock},
25    unlock::{ReferenceUnlock, UnlockBlock, UnlockBlocks},
26    Message, MessageBuilder, MessageId,
27};
28#[cfg(feature = "peer")]
29use bee_protocol::types::peer::Peer;
30
31use serde::{Deserialize, Serialize, Serializer};
32use serde_json::Value;
33
34/// The message object that nodes gossip around in the network.
35#[derive(Clone, Debug, Serialize, Deserialize)]
36pub struct MessageDto {
37    #[serde(rename = "networkId")]
38    pub network_id: String,
39    #[serde(rename = "parentMessageIds")]
40    pub parents: Vec<String>,
41    pub payload: Option<PayloadDto>,
42    pub nonce: String,
43}
44
45impl From<&Message> for MessageDto {
46    fn from(value: &Message) -> Self {
47        MessageDto {
48            network_id: value.network_id().to_string(),
49            parents: value.parents().iter().map(|p| p.to_string()).collect(),
50            payload: value.payload().as_ref().map(Into::into),
51            nonce: value.nonce().to_string(),
52        }
53    }
54}
55
56impl TryFrom<&MessageDto> for Message {
57    type Error = Error;
58
59    fn try_from(value: &MessageDto) -> Result<Self, Self::Error> {
60        let mut builder = MessageBuilder::new()
61            .with_network_id(
62                value
63                    .network_id
64                    .parse::<u64>()
65                    .map_err(|_| Error::InvalidSyntaxField("networkId"))?,
66            )
67            .with_parents(Parents::new(
68                value
69                    .parents
70                    .iter()
71                    .map(|m| {
72                        m.parse::<MessageId>()
73                            .map_err(|_| Error::InvalidSyntaxField("parentMessageIds"))
74                    })
75                    .collect::<Result<Vec<MessageId>, Error>>()?,
76            )?)
77            .with_nonce_provider(
78                value
79                    .nonce
80                    .parse::<u64>()
81                    .map_err(|_| Error::InvalidSyntaxField("nonce"))?,
82                0f64,
83            );
84        if let Some(p) = value.payload.as_ref() {
85            builder = builder.with_payload(p.try_into()?);
86        }
87
88        Ok(builder.finish()?)
89    }
90}
91
92/// Describes all the different payload types.
93#[derive(Clone, Debug, Serialize, Deserialize)]
94#[serde(untagged)]
95pub enum PayloadDto {
96    Transaction(Box<TransactionPayloadDto>),
97    Milestone(Box<MilestonePayloadDto>),
98    Indexation(Box<IndexationPayloadDto>),
99    Receipt(Box<ReceiptPayloadDto>),
100    TreasuryTransaction(Box<TreasuryTransactionPayloadDto>),
101}
102
103impl From<&Payload> for PayloadDto {
104    fn from(value: &Payload) -> Self {
105        match value {
106            Payload::Transaction(t) => PayloadDto::Transaction(Box::new(TransactionPayloadDto::from(t.as_ref()))),
107            Payload::Milestone(m) => PayloadDto::Milestone(Box::new(MilestonePayloadDto::from(m.as_ref()))),
108            Payload::Indexation(i) => PayloadDto::Indexation(Box::new(IndexationPayloadDto::from(i.as_ref()))),
109            Payload::Receipt(r) => PayloadDto::Receipt(Box::new(ReceiptPayloadDto::from(r.as_ref()))),
110            Payload::TreasuryTransaction(t) => {
111                PayloadDto::TreasuryTransaction(Box::new(TreasuryTransactionPayloadDto::from(t.as_ref())))
112            }
113        }
114    }
115}
116
117impl TryFrom<&PayloadDto> for Payload {
118    type Error = Error;
119    fn try_from(value: &PayloadDto) -> Result<Self, Self::Error> {
120        Ok(match value {
121            PayloadDto::Transaction(t) => Payload::Transaction(Box::new(TransactionPayload::try_from(t.as_ref())?)),
122            PayloadDto::Milestone(m) => Payload::Milestone(Box::new(MilestonePayload::try_from(m.as_ref())?)),
123            PayloadDto::Indexation(i) => Payload::Indexation(Box::new(IndexationPayload::try_from(i.as_ref())?)),
124            PayloadDto::Receipt(r) => Payload::Receipt(Box::new(ReceiptPayload::try_from(r.as_ref())?)),
125            PayloadDto::TreasuryTransaction(t) => {
126                Payload::TreasuryTransaction(Box::new(TreasuryTransactionPayload::try_from(t.as_ref())?))
127            }
128        })
129    }
130}
131
132/// The payload type to define a value transaction.
133#[derive(Clone, Debug, Serialize, Deserialize)]
134pub struct TransactionPayloadDto {
135    #[serde(rename = "type")]
136    pub kind: u32,
137    pub essence: EssenceDto,
138    #[serde(rename = "unlockBlocks")]
139    pub unlock_blocks: Vec<UnlockBlockDto>,
140}
141
142impl From<&TransactionPayload> for TransactionPayloadDto {
143    fn from(value: &TransactionPayload) -> Self {
144        TransactionPayloadDto {
145            kind: TransactionPayload::KIND,
146            essence: value.essence().into(),
147            unlock_blocks: value.unlock_blocks().iter().map(|u| u.into()).collect::<Vec<_>>(),
148        }
149    }
150}
151
152impl TryFrom<&TransactionPayloadDto> for TransactionPayload {
153    type Error = Error;
154
155    fn try_from(value: &TransactionPayloadDto) -> Result<Self, Self::Error> {
156        let mut unlock_blocks = Vec::new();
157        for b in &value.unlock_blocks {
158            unlock_blocks.push(b.try_into()?);
159        }
160        let builder = TransactionPayload::builder()
161            .with_essence((&value.essence).try_into()?)
162            .with_unlock_blocks(UnlockBlocks::new(unlock_blocks)?);
163
164        Ok(builder.finish()?)
165    }
166}
167
168/// Describes all the different essence types.
169#[derive(Clone, Debug, Serialize, Deserialize)]
170#[serde(untagged)]
171pub enum EssenceDto {
172    Regular(RegularEssenceDto),
173}
174
175impl From<&Essence> for EssenceDto {
176    fn from(value: &Essence) -> Self {
177        match value {
178            Essence::Regular(r) => EssenceDto::Regular(r.into()),
179        }
180    }
181}
182
183impl TryFrom<&EssenceDto> for Essence {
184    type Error = Error;
185
186    fn try_from(value: &EssenceDto) -> Result<Self, Self::Error> {
187        match value {
188            EssenceDto::Regular(r) => Ok(Essence::Regular(r.try_into()?)),
189        }
190    }
191}
192
193/// Describes the essence data making up a transaction by defining its inputs and outputs and an optional payload.
194#[derive(Clone, Debug, Serialize, Deserialize)]
195pub struct RegularEssenceDto {
196    #[serde(rename = "type")]
197    pub kind: u8,
198    pub inputs: Vec<InputDto>,
199    pub outputs: Vec<OutputDto>,
200    pub payload: Option<PayloadDto>,
201}
202
203impl From<&RegularEssence> for RegularEssenceDto {
204    fn from(value: &RegularEssence) -> Self {
205        RegularEssenceDto {
206            kind: RegularEssence::KIND,
207            inputs: value.inputs().iter().map(|i| i.into()).collect::<Vec<_>>(),
208            outputs: value.outputs().iter().map(|o| o.into()).collect::<Vec<_>>(),
209            payload: match value.payload() {
210                Some(Payload::Indexation(i)) => Some(PayloadDto::Indexation(Box::new(i.as_ref().into()))),
211                Some(_) => unimplemented!(),
212                None => None,
213            },
214        }
215    }
216}
217
218impl TryFrom<&RegularEssenceDto> for RegularEssence {
219    type Error = Error;
220
221    fn try_from(value: &RegularEssenceDto) -> Result<Self, Self::Error> {
222        let mut builder = RegularEssence::builder();
223
224        for i in &value.inputs {
225            builder = builder.add_input(i.try_into()?);
226        }
227
228        for o in &value.outputs {
229            builder = builder.add_output(o.try_into()?);
230        }
231
232        if let Some(p) = &value.payload {
233            if let PayloadDto::Indexation(i) = p {
234                builder = builder.with_payload(Payload::Indexation(Box::new((i.as_ref()).try_into()?)));
235            } else {
236                return Err(Error::InvalidSemanticField("payload"));
237            }
238        }
239
240        Ok(builder.finish()?)
241    }
242}
243
244/// Describes all the different input types.
245#[derive(Clone, Debug, Serialize, Deserialize)]
246#[serde(untagged)]
247pub enum InputDto {
248    Utxo(UtxoInputDto),
249    Treasury(TreasuryInputDto),
250}
251
252impl From<&Input> for InputDto {
253    fn from(value: &Input) -> Self {
254        match value {
255            Input::Utxo(u) => InputDto::Utxo(UtxoInputDto {
256                kind: UtxoInput::KIND,
257                transaction_id: u.output_id().transaction_id().to_string(),
258                transaction_output_index: u.output_id().index(),
259            }),
260            Input::Treasury(t) => InputDto::Treasury(TreasuryInputDto {
261                kind: TreasuryInput::KIND,
262                milestone_id: t.milestone_id().to_string(),
263            }),
264        }
265    }
266}
267
268impl TryFrom<&InputDto> for Input {
269    type Error = Error;
270
271    fn try_from(value: &InputDto) -> Result<Self, Self::Error> {
272        match value {
273            InputDto::Utxo(i) => Ok(Input::Utxo(UtxoInput::new(
274                i.transaction_id
275                    .parse::<TransactionId>()
276                    .map_err(|_| Error::InvalidSyntaxField("transactionId"))?,
277                i.transaction_output_index,
278            )?)),
279            InputDto::Treasury(t) => Ok(Input::Treasury(
280                t.milestone_id
281                    .parse::<MilestoneId>()
282                    .map_err(|_| Error::InvalidSyntaxField("milestoneId"))?
283                    .into(),
284            )),
285        }
286    }
287}
288
289/// Describes an input which references an unspent transaction output to consume.
290#[derive(Clone, Debug, Serialize, Deserialize)]
291pub struct UtxoInputDto {
292    #[serde(rename = "type")]
293    pub kind: u8,
294    #[serde(rename = "transactionId")]
295    pub transaction_id: String,
296    #[serde(rename = "transactionOutputIndex")]
297    pub transaction_output_index: u16,
298}
299
300/// Describes an input which references an unspent treasury output to consume.
301#[derive(Clone, Debug, Serialize, Deserialize)]
302pub struct TreasuryInputDto {
303    #[serde(rename = "type")]
304    pub kind: u8,
305    #[serde(rename = "milestoneId")]
306    pub milestone_id: String,
307}
308
309/// Describes all the different output types.
310#[derive(Clone, Debug)]
311pub enum OutputDto {
312    SignatureLockedSingle(SignatureLockedSingleOutputDto),
313    SignatureLockedDustAllowance(SignatureLockedDustAllowanceOutputDto),
314    Treasury(TreasuryOutputDto),
315}
316
317impl From<&Output> for OutputDto {
318    fn from(value: &Output) -> Self {
319        match value {
320            Output::SignatureLockedSingle(s) => OutputDto::SignatureLockedSingle(SignatureLockedSingleOutputDto {
321                kind: SignatureLockedSingleOutput::KIND,
322                address: s.address().into(),
323                amount: s.amount(),
324            }),
325            Output::SignatureLockedDustAllowance(s) => {
326                OutputDto::SignatureLockedDustAllowance(SignatureLockedDustAllowanceOutputDto {
327                    kind: SignatureLockedDustAllowanceOutput::KIND,
328                    address: s.address().into(),
329                    amount: s.amount(),
330                })
331            }
332            Output::Treasury(t) => OutputDto::Treasury(TreasuryOutputDto {
333                kind: TreasuryOutput::KIND,
334                amount: t.amount(),
335            }),
336        }
337    }
338}
339
340impl TryFrom<&OutputDto> for Output {
341    type Error = Error;
342
343    fn try_from(value: &OutputDto) -> Result<Self, Self::Error> {
344        match value {
345            OutputDto::SignatureLockedSingle(s) => Ok(Output::SignatureLockedSingle(SignatureLockedSingleOutput::new(
346                (&s.address).try_into()?,
347                s.amount,
348            )?)),
349            OutputDto::SignatureLockedDustAllowance(s) => Ok(Output::SignatureLockedDustAllowance(
350                SignatureLockedDustAllowanceOutput::new((&s.address).try_into()?, s.amount)?,
351            )),
352            OutputDto::Treasury(t) => Ok(Output::Treasury(TreasuryOutput::new(t.amount)?)),
353        }
354    }
355}
356
357impl<'de> serde::Deserialize<'de> for OutputDto {
358    fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
359        let value = Value::deserialize(d)?;
360        Ok(
361            match value
362                .get("type")
363                .and_then(Value::as_u64)
364                .ok_or_else(|| serde::de::Error::custom("invalid output type"))? as u8
365            {
366                SignatureLockedSingleOutput::KIND => OutputDto::SignatureLockedSingle(
367                    SignatureLockedSingleOutputDto::deserialize(value)
368                        .map_err(|e| serde::de::Error::custom(format!("can not deserialize output: {}", e)))?,
369                ),
370                SignatureLockedDustAllowanceOutput::KIND => OutputDto::SignatureLockedDustAllowance(
371                    SignatureLockedDustAllowanceOutputDto::deserialize(value)
372                        .map_err(|e| serde::de::Error::custom(format!("can not deserialize output: {}", e)))?,
373                ),
374                TreasuryOutput::KIND => OutputDto::Treasury(
375                    TreasuryOutputDto::deserialize(value)
376                        .map_err(|e| serde::de::Error::custom(format!("can not deserialize output: {}", e)))?,
377                ),
378                _ => unimplemented!(),
379            },
380        )
381    }
382}
383
384impl Serialize for OutputDto {
385    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
386    where
387        S: Serializer,
388    {
389        #[derive(Serialize)]
390        #[serde(untagged)]
391        enum OutputDto_<'a> {
392            T1(&'a SignatureLockedSingleOutputDto),
393            T2(&'a SignatureLockedDustAllowanceOutputDto),
394            T3(&'a TreasuryOutputDto),
395        }
396        #[derive(Serialize)]
397        struct TypedOutput<'a> {
398            #[serde(flatten)]
399            output: OutputDto_<'a>,
400        }
401        let output = match self {
402            OutputDto::SignatureLockedSingle(s) => TypedOutput {
403                output: OutputDto_::T1(s),
404            },
405            OutputDto::SignatureLockedDustAllowance(s) => TypedOutput {
406                output: OutputDto_::T2(s),
407            },
408            OutputDto::Treasury(t) => TypedOutput {
409                output: OutputDto_::T3(t),
410            },
411        };
412        output.serialize(serializer)
413    }
414}
415
416/// Describes a deposit to a single address which is unlocked via a signature.
417#[derive(Clone, Debug, Serialize, Deserialize)]
418pub struct SignatureLockedSingleOutputDto {
419    #[serde(rename = "type")]
420    pub kind: u8,
421    pub address: AddressDto,
422    pub amount: u64,
423}
424
425/// Output type for deposits that enables an address to receive dust outputs. It can be consumed as an input like a
426/// regular SigLockedSingleOutput.
427#[derive(Clone, Debug, Serialize, Deserialize)]
428pub struct SignatureLockedDustAllowanceOutputDto {
429    #[serde(rename = "type")]
430    pub kind: u8,
431    pub address: AddressDto,
432    pub amount: u64,
433}
434
435/// Describes all the different address types.
436#[derive(Clone, Debug, Serialize, Deserialize)]
437#[serde(untagged)]
438pub enum AddressDto {
439    Ed25519(Ed25519AddressDto),
440}
441
442impl From<&Address> for AddressDto {
443    fn from(value: &Address) -> Self {
444        match value {
445            Address::Ed25519(ed) => AddressDto::Ed25519(ed.into()),
446        }
447    }
448}
449
450impl TryFrom<&AddressDto> for Address {
451    type Error = Error;
452
453    fn try_from(value: &AddressDto) -> Result<Self, Self::Error> {
454        match value {
455            AddressDto::Ed25519(a) => Ok(Address::Ed25519(a.try_into()?)),
456        }
457    }
458}
459
460/// Describes an Ed25519 address.
461#[derive(Clone, Debug, Serialize, Deserialize)]
462pub struct Ed25519AddressDto {
463    #[serde(rename = "type")]
464    pub kind: u8,
465    pub address: String,
466}
467
468impl From<&Ed25519Address> for Ed25519AddressDto {
469    fn from(value: &Ed25519Address) -> Self {
470        Self {
471            kind: Ed25519Address::KIND,
472            address: value.to_string(),
473        }
474    }
475}
476
477impl TryFrom<&Ed25519AddressDto> for Ed25519Address {
478    type Error = Error;
479
480    fn try_from(value: &Ed25519AddressDto) -> Result<Self, Self::Error> {
481        value
482            .address
483            .parse::<Ed25519Address>()
484            .map_err(|_| Error::InvalidSyntaxField("address"))
485    }
486}
487
488/// Describes a treasury output.
489#[derive(Clone, Debug, Serialize, Deserialize)]
490pub struct TreasuryOutputDto {
491    #[serde(rename = "type")]
492    pub kind: u8,
493    pub amount: u64,
494}
495
496/// Describes all the different unlock types.
497#[derive(Clone, Debug, Serialize, Deserialize)]
498#[serde(untagged)]
499pub enum UnlockBlockDto {
500    Signature(SignatureUnlockDto),
501    Reference(ReferenceUnlockDto),
502}
503
504impl From<&UnlockBlock> for UnlockBlockDto {
505    fn from(value: &UnlockBlock) -> Self {
506        match value {
507            UnlockBlock::Signature(SignatureUnlock::Ed25519(ed)) => UnlockBlockDto::Signature(SignatureUnlockDto {
508                kind: SignatureUnlock::KIND,
509                signature: SignatureDto::Ed25519(Ed25519SignatureDto {
510                    kind: Ed25519Signature::KIND,
511                    public_key: hex::encode(ed.public_key()),
512                    signature: hex::encode(ed.signature()),
513                }),
514            }),
515            UnlockBlock::Reference(r) => UnlockBlockDto::Reference(ReferenceUnlockDto {
516                kind: ReferenceUnlock::KIND,
517                index: r.index(),
518            }),
519        }
520    }
521}
522
523impl TryFrom<&UnlockBlockDto> for UnlockBlock {
524    type Error = Error;
525
526    fn try_from(value: &UnlockBlockDto) -> Result<Self, Self::Error> {
527        match value {
528            UnlockBlockDto::Signature(s) => match &s.signature {
529                SignatureDto::Ed25519(ed) => {
530                    let mut public_key = [0u8; ED25519_ADDRESS_LENGTH];
531                    hex::decode_to_slice(&ed.public_key, &mut public_key)
532                        .map_err(|_| Error::InvalidSyntaxField("publicKey"))?;
533                    // TODO const
534                    let mut signature = [0u8; 64];
535                    hex::decode_to_slice(&ed.signature, &mut signature)
536                        .map_err(|_| Error::InvalidSyntaxField("signature"))?;
537                    Ok(UnlockBlock::Signature(SignatureUnlock::Ed25519(Ed25519Signature::new(
538                        public_key, signature,
539                    ))))
540                }
541            },
542            UnlockBlockDto::Reference(r) => Ok(UnlockBlock::Reference(ReferenceUnlock::new(r.index)?)),
543        }
544    }
545}
546
547/// Defines an unlock block containing signature(s) unlocking input(s).
548#[derive(Clone, Debug, Serialize, Deserialize)]
549pub struct SignatureUnlockDto {
550    #[serde(rename = "type")]
551    pub kind: u8,
552    pub signature: SignatureDto,
553}
554
555/// Describes all the different signature types.
556#[derive(Clone, Debug, Serialize, Deserialize)]
557#[serde(untagged)]
558pub enum SignatureDto {
559    Ed25519(Ed25519SignatureDto),
560}
561
562/// Defines an Ed25519 signature.
563#[derive(Clone, Debug, Serialize, Deserialize)]
564pub struct Ed25519SignatureDto {
565    #[serde(rename = "type")]
566    pub kind: u8,
567    #[serde(rename = "publicKey")]
568    pub public_key: String,
569    pub signature: String,
570}
571
572/// References a previous unlock block in order to substitute the duplication of the same unlock block data for inputs
573/// which unlock through the same data.
574#[derive(Clone, Debug, Serialize, Deserialize)]
575pub struct ReferenceUnlockDto {
576    #[serde(rename = "type")]
577    pub kind: u8,
578    #[serde(rename = "reference")]
579    pub index: u16,
580}
581
582/// The payload type to define a milestone.
583#[derive(Clone, Debug, Serialize, Deserialize)]
584pub struct MilestonePayloadDto {
585    #[serde(rename = "type")]
586    pub kind: u32,
587    pub index: u32,
588    pub timestamp: u64,
589    #[serde(rename = "parentMessageIds")]
590    pub parents: Vec<String>,
591    #[serde(rename = "inclusionMerkleProof")]
592    pub inclusion_merkle_proof: String,
593    #[serde(rename = "nextPoWScore")]
594    pub next_pow_score: u32,
595    #[serde(rename = "nextPoWScoreMilestoneIndex")]
596    pub next_pow_score_milestone_index: u32,
597    #[serde(rename = "publicKeys")]
598    pub public_keys: Vec<String>,
599    pub receipt: Option<PayloadDto>,
600    pub signatures: Vec<String>,
601}
602
603impl From<&MilestonePayload> for MilestonePayloadDto {
604    fn from(value: &MilestonePayload) -> Self {
605        MilestonePayloadDto {
606            kind: MilestonePayload::KIND,
607            index: *value.essence().index(),
608            timestamp: value.essence().timestamp(),
609            parents: value.essence().parents().iter().map(|p| p.to_string()).collect(),
610            inclusion_merkle_proof: hex::encode(value.essence().merkle_proof()),
611            next_pow_score: value.essence().next_pow_score(),
612            next_pow_score_milestone_index: value.essence().next_pow_score_milestone_index(),
613            public_keys: value.essence().public_keys().iter().map(hex::encode).collect(),
614            receipt: value.essence().receipt().map(Into::into),
615            signatures: value.signatures().iter().map(hex::encode).collect(),
616        }
617    }
618}
619
620impl TryFrom<&MilestonePayloadDto> for MilestonePayload {
621    type Error = Error;
622
623    fn try_from(value: &MilestonePayloadDto) -> Result<Self, Self::Error> {
624        let essence = {
625            let index = value.index;
626            let timestamp = value.timestamp;
627            let mut parent_ids = Vec::new();
628            for msg_id in &value.parents {
629                parent_ids.push(
630                    msg_id
631                        .parse::<MessageId>()
632                        .map_err(|_| Error::InvalidSyntaxField("parentMessageIds"))?,
633                );
634            }
635            let merkle_proof = {
636                let mut buf = [0u8; MILESTONE_MERKLE_PROOF_LENGTH];
637                hex::decode_to_slice(&value.inclusion_merkle_proof, &mut buf)
638                    .map_err(|_| Error::InvalidSyntaxField("inclusionMerkleProof"))?;
639                buf
640            };
641            let next_pow_score = value.next_pow_score;
642            let next_pow_score_milestone_index = value.next_pow_score_milestone_index;
643            let mut public_keys = Vec::new();
644            for v in &value.public_keys {
645                let key = {
646                    let mut buf = [0u8; MILESTONE_PUBLIC_KEY_LENGTH];
647                    hex::decode_to_slice(v, &mut buf).map_err(|_| Error::InvalidSyntaxField("publicKeys"))?;
648                    buf
649                };
650                public_keys.push(key);
651            }
652            let receipt = if let Some(receipt) = value.receipt.as_ref() {
653                Some(receipt.try_into()?)
654            } else {
655                None
656            };
657            MilestonePayloadEssence::new(
658                MilestoneIndex(index),
659                timestamp,
660                Parents::new(parent_ids)?,
661                merkle_proof,
662                next_pow_score,
663                next_pow_score_milestone_index,
664                public_keys,
665                receipt,
666            )?
667        };
668        let mut signatures = Vec::new();
669        for v in &value.signatures {
670            signatures.push(
671                hex::decode(v)
672                    .map_err(|_| Error::InvalidSyntaxField("signatures"))?
673                    .try_into()
674                    .map_err(|_| Error::InvalidSyntaxField("signatures"))?,
675            )
676        }
677
678        Ok(MilestonePayload::new(essence, signatures)?)
679    }
680}
681
682/// The payload type to define a indexation payload.
683#[derive(Clone, Debug, Serialize, Deserialize)]
684pub struct IndexationPayloadDto {
685    #[serde(rename = "type")]
686    pub kind: u32,
687    pub index: String,
688    pub data: String,
689}
690
691impl From<&IndexationPayload> for IndexationPayloadDto {
692    fn from(value: &IndexationPayload) -> Self {
693        IndexationPayloadDto {
694            kind: IndexationPayload::KIND,
695            index: hex::encode(value.index()),
696            data: hex::encode(value.data()),
697        }
698    }
699}
700
701impl TryFrom<&IndexationPayloadDto> for IndexationPayload {
702    type Error = Error;
703
704    fn try_from(value: &IndexationPayloadDto) -> Result<Self, Self::Error> {
705        Ok(IndexationPayload::new(
706            &hex::decode(value.index.clone()).map_err(|_| Error::InvalidSyntaxField("index"))?,
707            &hex::decode(value.data.clone()).map_err(|_| Error::InvalidSyntaxField("data"))?,
708        )?)
709    }
710}
711
712/// The payload type to define a receipt.
713#[derive(Clone, Debug, Serialize, Deserialize)]
714pub struct ReceiptPayloadDto {
715    #[serde(rename = "type")]
716    pub kind: u32,
717    #[serde(rename = "migratedAt")]
718    pub migrated_at: u32,
719    pub funds: Vec<MigratedFundsEntryDto>,
720    pub transaction: PayloadDto,
721    #[serde(rename = "final")]
722    pub last: bool,
723}
724
725impl From<&ReceiptPayload> for ReceiptPayloadDto {
726    fn from(value: &ReceiptPayload) -> Self {
727        ReceiptPayloadDto {
728            kind: ReceiptPayload::KIND,
729            migrated_at: *value.migrated_at(),
730            last: value.last(),
731            funds: value.funds().iter().map(|m| m.into()).collect::<_>(),
732            transaction: value.transaction().into(),
733        }
734    }
735}
736
737impl TryFrom<&ReceiptPayloadDto> for ReceiptPayload {
738    type Error = Error;
739
740    fn try_from(value: &ReceiptPayloadDto) -> Result<Self, Self::Error> {
741        Ok(ReceiptPayload::new(
742            MilestoneIndex(value.migrated_at),
743            value.last,
744            value.funds.iter().map(|m| m.try_into()).collect::<Result<_, _>>()?,
745            (&value.transaction).try_into()?,
746        )?)
747    }
748}
749
750#[derive(Clone, Debug, Serialize, Deserialize)]
751pub struct MigratedFundsEntryDto {
752    #[serde(rename = "tailTransactionHash")]
753    pub tail_transaction_hash: String,
754    pub address: AddressDto,
755    pub deposit: u64,
756}
757
758impl From<&MigratedFundsEntry> for MigratedFundsEntryDto {
759    fn from(value: &MigratedFundsEntry) -> Self {
760        MigratedFundsEntryDto {
761            tail_transaction_hash: hex::encode(value.tail_transaction_hash().as_ref()),
762            address: value.output().address().into(),
763            deposit: value.output().amount(),
764        }
765    }
766}
767
768impl TryFrom<&MigratedFundsEntryDto> for MigratedFundsEntry {
769    type Error = Error;
770
771    fn try_from(value: &MigratedFundsEntryDto) -> Result<Self, Self::Error> {
772        let mut tail_transaction_hash = [0u8; TAIL_TRANSACTION_HASH_LEN];
773        hex::decode_to_slice(&value.tail_transaction_hash, &mut tail_transaction_hash)
774            .map_err(|_| Error::InvalidSyntaxField("tailTransactionHash"))?;
775        Ok(MigratedFundsEntry::new(
776            TailTransactionHash::new(tail_transaction_hash)?,
777            SignatureLockedSingleOutput::new((&value.address).try_into()?, value.deposit)?,
778        )?)
779    }
780}
781
782/// The payload type to define a treasury transaction.
783#[derive(Clone, Debug, Serialize, Deserialize)]
784pub struct TreasuryTransactionPayloadDto {
785    #[serde(rename = "type")]
786    pub kind: u32,
787    pub input: InputDto,
788    pub output: OutputDto,
789}
790
791impl From<&TreasuryTransactionPayload> for TreasuryTransactionPayloadDto {
792    fn from(value: &TreasuryTransactionPayload) -> Self {
793        TreasuryTransactionPayloadDto {
794            kind: TreasuryTransactionPayload::KIND,
795            input: value.input().into(),
796            output: value.output().into(),
797        }
798    }
799}
800
801impl TryFrom<&TreasuryTransactionPayloadDto> for TreasuryTransactionPayload {
802    type Error = Error;
803
804    fn try_from(value: &TreasuryTransactionPayloadDto) -> Result<Self, Self::Error> {
805        Ok(TreasuryTransactionPayload::new(
806            Input::try_from(&value.input)?,
807            Output::try_from(&value.output)?,
808        )?)
809    }
810}
811
812/// Describes a peer.
813#[derive(Clone, Debug, Serialize, Deserialize)]
814pub struct PeerDto {
815    pub id: String,
816    #[serde(rename = "multiAddresses")]
817    pub multi_addresses: Vec<String>,
818    #[serde(skip_serializing_if = "Option::is_none")]
819    pub alias: Option<String>,
820    pub relation: RelationDto,
821    pub connected: bool,
822    #[serde(skip_serializing_if = "Option::is_none")]
823    pub gossip: Option<GossipDto>,
824}
825
826#[cfg(feature = "peer")]
827impl From<&Peer> for PeerDto {
828    fn from(peer: &Peer) -> Self {
829        PeerDto {
830            id: peer.id().to_string(),
831            alias: Some(peer.alias().to_string()),
832            multi_addresses: vec![peer.address().to_string()],
833            relation: {
834                if peer.relation().is_known() {
835                    RelationDto::Known
836                } else if peer.relation().is_unknown() {
837                    RelationDto::Unknown
838                } else {
839                    RelationDto::Autopeered
840                }
841            },
842            connected: peer.is_connected(),
843            gossip: Some(GossipDto {
844                heartbeat: HeartbeatDto {
845                    solid_milestone_index: *peer.solid_milestone_index(),
846                    pruned_milestone_index: *peer.pruned_index(),
847                    latest_milestone_index: *peer.latest_milestone_index(),
848                    connected_neighbors: peer.connected_peers(),
849                    synced_neighbors: peer.synced_peers(),
850                },
851                metrics: MetricsDto {
852                    new_messages: peer.metrics().new_messages(),
853                    received_messages: peer.metrics().messages_received(),
854                    known_messages: peer.metrics().known_messages(),
855                    received_message_requests: peer.metrics().message_requests_received(),
856                    received_milestone_requests: peer.metrics().milestone_requests_received(),
857                    received_heartbeats: peer.metrics().heartbeats_received(),
858                    sent_messages: peer.metrics().messages_sent(),
859                    sent_message_requests: peer.metrics().message_requests_sent(),
860                    sent_milestone_requests: peer.metrics().milestone_requests_sent(),
861                    sent_heartbeats: peer.metrics().heartbeats_sent(),
862                    dropped_packets: 0,
863                },
864            }),
865        }
866    }
867}
868
869/// Returns all information about the gossip stream with the peer.
870#[derive(Clone, Debug, Serialize, Deserialize, Default)]
871pub struct GossipDto {
872    pub heartbeat: HeartbeatDto,
873    pub metrics: MetricsDto,
874}
875
876/// Describes the relation with the peer.
877#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
878pub enum RelationDto {
879    #[serde(rename = "known")]
880    Known,
881    #[serde(rename = "unknown")]
882    Unknown,
883    #[serde(rename = "autopeered")]
884    Autopeered,
885}
886
887/// Describes the heartbeat of a node.
888#[derive(Clone, Debug, Default, Serialize, Deserialize)]
889pub struct HeartbeatDto {
890    #[serde(rename = "solidMilestoneIndex")]
891    pub solid_milestone_index: u32,
892    #[serde(rename = "prunedMilestoneIndex")]
893    pub pruned_milestone_index: u32,
894    #[serde(rename = "latestMilestoneIndex")]
895    pub latest_milestone_index: u32,
896    #[serde(rename = "connectedNeighbors")]
897    pub connected_neighbors: u8,
898    #[serde(rename = "syncedNeighbors")]
899    pub synced_neighbors: u8,
900}
901
902/// Describes metrics of a gossip stream.
903#[derive(Clone, Debug, Default, Serialize, Deserialize)]
904pub struct MetricsDto {
905    #[serde(rename = "newMessages")]
906    pub new_messages: u64,
907    #[serde(rename = "receivedMessages")]
908    pub received_messages: u64,
909    #[serde(rename = "knownMessages")]
910    pub known_messages: u64,
911    #[serde(rename = "receivedMessageRequests")]
912    pub received_message_requests: u64,
913    #[serde(rename = "receivedMilestoneRequests")]
914    pub received_milestone_requests: u64,
915    #[serde(rename = "receivedHeartbeats")]
916    pub received_heartbeats: u64,
917    #[serde(rename = "sentMessages")]
918    pub sent_messages: u64,
919    #[serde(rename = "sentMessageRequests")]
920    pub sent_message_requests: u64,
921    #[serde(rename = "sentMilestoneRequests")]
922    pub sent_milestone_requests: u64,
923    #[serde(rename = "sentHeartbeats")]
924    pub sent_heartbeats: u64,
925    #[serde(rename = "droppedPackets")]
926    pub dropped_packets: u64,
927}
928
929/// Describes a receipt.
930#[derive(Clone, Debug, Serialize, Deserialize)]
931pub struct ReceiptDto {
932    pub receipt: ReceiptPayloadDto,
933    #[serde(rename = "milestoneIndex")]
934    pub milestone_index: u32,
935}
936
937impl From<Receipt> for ReceiptDto {
938    fn from(value: Receipt) -> Self {
939        ReceiptDto {
940            receipt: value.inner().into(),
941            milestone_index: **value.included_in(),
942        }
943    }
944}
945
946/// Describes the ledger inclusion state of a transaction.
947#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
948pub enum LedgerInclusionStateDto {
949    #[serde(rename = "conflicting")]
950    Conflicting,
951    #[serde(rename = "included")]
952    Included,
953    #[serde(rename = "noTransaction")]
954    NoTransaction,
955}