diff --git a/rusk/src/lib/http/chain/graphql.rs b/rusk/src/lib/http/chain/graphql.rs index c75862d3b..f1eba5b8e 100644 --- a/rusk/src/lib/http/chain/graphql.rs +++ b/rusk/src/lib/http/chain/graphql.rs @@ -14,10 +14,13 @@ use tx::*; use async_graphql::{Context, FieldError, FieldResult, Object}; use execution_core::{transfer::TRANSFER_CONTRACT, ContractId}; -#[cfg(feature = "archive")] -use node::archive::{Archive, MoonlightGroup}; use node::database::rocksdb::Backend; use node::database::{Ledger, DB}; +#[cfg(feature = "archive")] +use { + deserialized_archive_data::DeserializedMoonlightGroups, + node::archive::{Archive, MoonlightGroup}, +}; use std::sync::Arc; use tokio::sync::RwLock; @@ -141,7 +144,7 @@ impl Query { &self, ctx: &Context<'_>, address: String, - ) -> OptResult { + ) -> OptResult { full_moonlight_history(ctx, address).await } diff --git a/rusk/src/lib/http/chain/graphql/data.rs b/rusk/src/lib/http/chain/graphql/data.rs index 734161f67..5fa4c173c 100644 --- a/rusk/src/lib/http/chain/graphql/data.rs +++ b/rusk/src/lib/http/chain/graphql/data.rs @@ -337,3 +337,230 @@ pub struct CallData { fn_name: String, data: String, } + +/// Interim solution for sending out deserialized event data +#[cfg(feature = "archive")] +pub(super) mod deserialized_archive_data { + use super::*; + use execution_core::stake::STAKE_CONTRACT; + use execution_core::transfer::withdraw::WithdrawReceiver; + use execution_core::transfer::{ + ConvertEvent, DepositEvent, MoonlightTransactionEvent, WithdrawEvent, + CONVERT_TOPIC, DEPOSIT_TOPIC, MINT_TOPIC, MOONLIGHT_TOPIC, + TRANSFER_CONTRACT, WITHDRAW_TOPIC, + }; + use node_data::events::contract::{ + ContractEvent, TxHash, WrappedContractId, + }; + use serde::ser::SerializeStruct; + use serde::{Deserialize, Serialize}; + + #[serde_with::serde_as] + #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] + pub struct DeserializedMoonlightGroup { + pub events: serde_json::Value, + #[serde_as(as = "serde_with::hex::Hex")] + pub origin: TxHash, + pub block_height: u64, + } + pub struct DeserializedMoonlightGroups(pub Vec); + + #[Object] + impl DeserializedMoonlightGroups { + pub async fn json(&self) -> serde_json::Value { + serde_json::to_value(&self.0).unwrap_or_default() + } + } + + #[derive(Debug, Clone, PartialEq)] + pub struct DeserializedMoonlightTransactionEvent( + pub MoonlightTransactionEvent, + ); + + impl Serialize for DeserializedMoonlightTransactionEvent { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let moonlight_event = &self.0; + + let mut state = + serializer.serialize_struct("MoonlightTransactionEvent", 6)?; + state.serialize_field( + "sender", + &bs58::encode(moonlight_event.sender.to_bytes()).into_string(), + )?; + state.serialize_field( + "receiver", + &moonlight_event + .receiver + .map(|r| bs58::encode(r.to_bytes()).into_string()), + )?; + state.serialize_field("value", &moonlight_event.value)?; + state + .serialize_field("memo", &hex::encode(&moonlight_event.memo))?; + state.serialize_field("gas_spent", &moonlight_event.gas_spent)?; + state.serialize_field( + "refund_info", + &moonlight_event.refund_info.map(|(pk, amt)| { + (bs58::encode(pk.to_bytes()).into_string(), amt) + }), + )?; + + state.end() + } + } + + #[derive(Debug, Clone, PartialEq)] + pub struct DeserializedWithdrawEvent(pub WithdrawEvent); + + impl Serialize for DeserializedWithdrawEvent { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let withdraw_event = &self.0; + let mut state = serializer.serialize_struct("WithdrawEvent", 3)?; + state.serialize_field( + "sender", + &WrappedContractId(withdraw_event.sender), + )?; + state.serialize_field( + "receiver", + &match withdraw_event.receiver { + WithdrawReceiver::Moonlight(pk) => { + bs58::encode(pk.to_bytes()).into_string() + } + WithdrawReceiver::Phoenix(pk) => { + bs58::encode(pk.to_bytes()).into_string() + } + }, + )?; + state.serialize_field("value", &withdraw_event.value)?; + + state.end() + } + } + + #[derive(Debug, Clone, PartialEq)] + pub struct DeserializedConvertEvent(pub ConvertEvent); + + impl Serialize for DeserializedConvertEvent { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let convert_event = &self.0; + let mut state = serializer.serialize_struct("ConvertEvent", 3)?; + state.serialize_field( + "sender", + &convert_event + .sender + .map(|pk| bs58::encode(pk.to_bytes()).into_string()), + )?; + state.serialize_field( + "receiver", + &match convert_event.receiver { + WithdrawReceiver::Moonlight(pk) => { + bs58::encode(pk.to_bytes()).into_string() + } + WithdrawReceiver::Phoenix(pk) => { + bs58::encode(pk.to_bytes()).into_string() + } + }, + )?; + state.serialize_field("value", &convert_event.value)?; + state.end() + } + } + + #[derive(Debug, Clone, PartialEq)] + pub struct DeserializedDepositEvent(pub DepositEvent); + + impl Serialize for DeserializedDepositEvent { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let deposit_event = &self.0; + let mut state = serializer.serialize_struct("DepositEvent", 3)?; + state.serialize_field( + "sender", + &deposit_event + .sender + .map(|pk| bs58::encode(pk.to_bytes()).into_string()), + )?; + state.serialize_field( + "receiver", + &WrappedContractId(deposit_event.receiver), + )?; + state.serialize_field("value", &deposit_event.value)?; + + state.end() + } + } + + #[derive(Debug, Clone, PartialEq, Serialize)] + pub struct DeserializedContractEvent { + pub target: WrappedContractId, + pub topic: String, + pub data: serde_json::Value, + } + + impl From for DeserializedContractEvent { + fn from(event: ContractEvent) -> Self { + let deserialized_data = if event.target.0 == TRANSFER_CONTRACT { + match event.topic.as_str() { + MOONLIGHT_TOPIC => rkyv::from_bytes::< + MoonlightTransactionEvent, + >(&event.data) + .map(|e| { + serde_json::to_value( + DeserializedMoonlightTransactionEvent(e), + ) + }) + .unwrap_or_else(|_| serde_json::to_value(event.data)), + WITHDRAW_TOPIC | MINT_TOPIC => rkyv::from_bytes::< + WithdrawEvent, + >( + &event.data + ) + .map(|e| serde_json::to_value(DeserializedWithdrawEvent(e))) + .unwrap_or_else(|_| serde_json::to_value(event.data)), + CONVERT_TOPIC => { + rkyv::from_bytes::(&event.data) + .map(|e| { + serde_json::to_value(DeserializedConvertEvent( + e, + )) + }) + .unwrap_or_else(|_| { + serde_json::to_value(event.data) + }) + } + DEPOSIT_TOPIC => { + rkyv::from_bytes::(&event.data) + .map(|e| { + serde_json::to_value(DeserializedDepositEvent( + e, + )) + }) + .unwrap_or_else(|_| { + serde_json::to_value(event.data) + }) + } + _ => serde_json::to_value(hex::encode(event.data)), + } + } else { + serde_json::to_value(hex::encode(event.data)) + } + .unwrap_or_else(|e| serde_json::Value::String(e.to_string())); + + Self { + target: event.target, + topic: event.topic, + data: deserialized_data, + } + } + } +} diff --git a/rusk/src/lib/http/chain/graphql/tx.rs b/rusk/src/lib/http/chain/graphql/tx.rs index 0ce5ed17d..e240b95e5 100644 --- a/rusk/src/lib/http/chain/graphql/tx.rs +++ b/rusk/src/lib/http/chain/graphql/tx.rs @@ -8,9 +8,16 @@ use node::database::rocksdb::MD_HASH_KEY; use node::database::{Mempool, Metadata}; #[cfg(feature = "archive")] use { + data::deserialized_archive_data::*, dusk_bytes::Serializable, execution_core::signatures::bls::PublicKey as AccountPublicKey, + execution_core::transfer::{ + ConvertEvent, DepositEvent, MoonlightTransactionEvent, WithdrawEvent, + CONVERT_TOPIC, MINT_TOPIC, MOONLIGHT_TOPIC, TRANSFER_CONTRACT, + WITHDRAW_TOPIC, + }, node::archive::MoonlightGroup, + node_data::events::contract::ContractEvent, }; use super::*; @@ -88,9 +95,7 @@ pub async fn mempool_by_hash<'a>( pub(super) async fn full_moonlight_history( ctx: &Context<'_>, address: String, -) -> OptResult { - use dusk_bytes::ParseHexStr; - +) -> OptResult { let (_, archive) = ctx.data::()?; let v = bs58::decode(address).into_vec()?; @@ -101,12 +106,34 @@ pub(super) async fn full_moonlight_history( let pk = AccountPublicKey::from_bytes(&pk_bytes) .map_err(|_| anyhow::anyhow!("Failed to serialize given public key"))?; - let moonlight_events = archive.full_moonlight_history(pk)?; + let moonlight_groups = archive.full_moonlight_history(pk)?; - if let Some(moonlight_events) = moonlight_events { - Ok(Some(MoonlightTransactions(moonlight_events))) - } else { + // Deserialize the MoonlightGroup as an interim solution until the consumer + // api wrapper can do it + let mut deser_moonlight_groups = Vec::new(); + + if let Some(moonlight_groups) = moonlight_groups { + for moonlight_group in moonlight_groups { + let deser_events = moonlight_group + .events() + .iter() + .map(|event| event.clone().into()) + .collect::>(); + + let deserialized_moonlight_group = DeserializedMoonlightGroup { + events: serde_json::to_value(deser_events)?, + origin: *moonlight_group.origin(), + block_height: moonlight_group.block_height(), + }; + + deser_moonlight_groups.push(deserialized_moonlight_group); + } + } + + if deser_moonlight_groups.is_empty() { Ok(None) + } else { + Ok(Some(DeserializedMoonlightGroups(deser_moonlight_groups))) } }