1use 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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[derive(Clone, Debug, Serialize, Deserialize)]
490pub struct TreasuryOutputDto {
491 #[serde(rename = "type")]
492 pub kind: u8,
493 pub amount: u64,
494}
495
496#[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 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#[derive(Clone, Debug, Serialize, Deserialize)]
549pub struct SignatureUnlockDto {
550 #[serde(rename = "type")]
551 pub kind: u8,
552 pub signature: SignatureDto,
553}
554
555#[derive(Clone, Debug, Serialize, Deserialize)]
557#[serde(untagged)]
558pub enum SignatureDto {
559 Ed25519(Ed25519SignatureDto),
560}
561
562#[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#[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#[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#[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#[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#[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#[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#[derive(Clone, Debug, Serialize, Deserialize, Default)]
871pub struct GossipDto {
872 pub heartbeat: HeartbeatDto,
873 pub metrics: MetricsDto,
874}
875
876#[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#[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#[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#[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#[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}