Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adjust moonlight endpoints to contain ledger tx data #3261

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions node/src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ pub trait Ledger {
fn block_exists(&self, hash: &[u8]) -> Result<bool>;

fn ledger_tx(&self, tx_id: &[u8]) -> Result<Option<SpentTransaction>>;
fn ledger_txs(
&self,
tx_ids: Vec<&[u8; 32]>,
) -> Result<Vec<SpentTransaction>>;

fn ledger_tx_exists(&self, tx_id: &[u8]) -> Result<bool>;

Expand Down
37 changes: 37 additions & 0 deletions node/src/database/rocksdb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,43 @@ impl<'db, DB: DBAccess> Ledger for DBTransaction<'db, DB> {
Ok(tx)
}

/// Returns a list of transactions from the ledger
///
/// This function expects a list of transaction IDs that are in the ledger.
///
/// It will return an error if any of the transaction IDs are not found in
/// the ledger.
fn ledger_txs(
&self,
tx_ids: Vec<&[u8; 32]>,
) -> Result<Vec<SpentTransaction>> {
let cf = self.ledger_txs_cf;

let ids = tx_ids.into_iter().map(|id| (cf, id)).collect::<Vec<_>>();

let multi_get_results = self.inner.multi_get_cf(ids);

let mut spent_transactions =
Vec::with_capacity(multi_get_results.len());
for result in multi_get_results.into_iter() {
let opt_blob = result.map_err(|e| {
std::io::Error::new(std::io::ErrorKind::Other, e)
})?;

let Some(blob) = opt_blob else {
return Err(anyhow::anyhow!(
"At least one Transaction ID was not found"
));
};

let stx = SpentTransaction::read(&mut &blob[..])?;

spent_transactions.push(stx);
}

Ok(spent_transactions)
}

/// Returns true if the transaction exists in the
/// ledger
///
Expand Down
61 changes: 59 additions & 2 deletions rusk/src/lib/http/chain/graphql/archive/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,65 @@ use async_graphql::Object;
use dusk_bytes::Serializable;
use dusk_core::signatures::bls::PublicKey as AccountPublicKey;
use node::archive::MoonlightGroup;
use serde::Serialize;
use tracing::error;

pub struct MoonlightTransfers(pub Vec<MoonlightGroup>);
use crate::http::chain::graphql::data::SpentTransaction;

/// Struct containing all information about a Moonlight transfer.
///
/// # Private Fields
///
/// - `moonlight_group`: A `MoonlightGroup` of events that belong to the same
/// Moonlight transaction.
/// - `spent_transaction`: The `SpentTransaction` of the Moonlight transaction.
pub struct MoonlightTransfers {
moonlight_group: Vec<MoonlightGroup>,
spent_transaction: Vec<SpentTransaction>,
}

impl MoonlightTransfers {
/// Create a new `MoonlightTransfers` instance.
///
/// # Arguments
///
/// - `moonlight_group`: A group of events that belong to the same Moonlight
/// transaction.
/// - `spent_transaction`: The payload of the Moonlight transaction.
///
/// # Note
///
/// Both fields are expected to correspond to each other i.e., the first
/// element of `moonlight_group` corresponds to the first element of
/// `spent_transaction`.
///
/// That means that the n-th element of `moonlight_group` belongs to the
/// same transaction as the n-th element of `spent_transaction`.
pub(crate) fn new(
moonlight_group: Vec<MoonlightGroup>,
spent_transaction: Vec<SpentTransaction>,
) -> Self {
Self {
moonlight_group,
spent_transaction,
}
}
}

impl Serialize for MoonlightTransfers {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let zipped = &self
.moonlight_group
.iter()
.zip(&self.spent_transaction)
.collect::<Vec<(&MoonlightGroup, &SpentTransaction)>>();

zipped.serialize(serializer)
}
}

pub struct ContractEvents(pub(super) serde_json::Value);

Expand All @@ -34,7 +91,7 @@ impl TryInto<NewAccountPublicKey> for String {
#[Object]
impl MoonlightTransfers {
pub async fn json(&self) -> serde_json::Value {
serde_json::to_value(&self.0).unwrap_or_default()
serde_json::to_value(self).unwrap_or_default()
}
}

Expand Down
26 changes: 23 additions & 3 deletions rusk/src/lib/http/chain/graphql/archive/moonlight.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use async_graphql::{Context, FieldError};

use super::data::deserialized_archive_data::*;
use super::data::{MoonlightTransfers, NewAccountPublicKey};
use crate::http::chain::graphql::{DBContext, OptResult};
use crate::http::chain::graphql::{tx, DBContext, OptResult};

pub async fn full_moonlight_history(
ctx: &Context<'_>,
Expand Down Expand Up @@ -95,7 +95,7 @@ pub async fn fetch_moonlight_history(
if let Some(moonlight_events) = archive.fetch_moonlight_history(
sender, receiver, from_block, to_block, max_count, page_count,
)? {
Ok(Some(MoonlightTransfers(moonlight_events)))
aggregate_moonlight_transfers(ctx, moonlight_events).await
} else {
Ok(None)
}
Expand All @@ -110,8 +110,28 @@ pub async fn moonlight_tx_by_memo(
let moonlight_events = archive.moonlight_txs_by_memo(memo)?;

if let Some(moonlight_events) = moonlight_events {
Ok(Some(MoonlightTransfers(moonlight_events)))
aggregate_moonlight_transfers(ctx, moonlight_events).await
} else {
Ok(None)
}
}

async fn aggregate_moonlight_transfers(
ctx: &Context<'_>,
moonlight_groups: Vec<MoonlightGroup>,
) -> OptResult<MoonlightTransfers> {
let spent_moonlight_tx = {
let moonlight_origins_by_ref: Vec<&[u8; 32]> = moonlight_groups
.iter()
.map(|event| event.origin())
.collect::<Vec<_>>();

// multi get SpentTransaction
tx::txs_by_hashes(ctx, moonlight_origins_by_ref).await?
};

Ok(Some(MoonlightTransfers::new(
moonlight_groups,
spent_moonlight_tx,
)))
}
5 changes: 5 additions & 0 deletions rusk/src/lib/http/chain/graphql/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ impl Block {
}

pub struct Header<'a>(&'a node_data::ledger::Header);
#[derive(Serialize)]
pub struct SpentTransaction(pub node_data::ledger::SpentTransaction);
pub struct Transaction<'a>(TransactionData<'a>);

Expand Down Expand Up @@ -188,6 +189,10 @@ impl Header<'_> {

#[Object]
impl SpentTransaction {
pub async fn json(&self) -> serde_json::Value {
serde_json::to_value(&self.0).unwrap_or_default()
}

pub async fn tx(&self) -> Transaction {
let inner = &self.0.inner;
inner.into()
Expand Down
12 changes: 12 additions & 0 deletions rusk/src/lib/http/chain/graphql/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,18 @@ pub async fn tx_by_hash(
Ok(tx.map(SpentTransaction))
}

pub async fn txs_by_hashes(
ctx: &Context<'_>,
hashes: Vec<&[u8; 32]>,
) -> FieldResult<Vec<SpentTransaction>> {
let (db, _) = ctx.data::<DBContext>()?;
db.read().await.view(|t| {
let txs = t.ledger_txs(hashes)?;

Ok(txs.into_iter().map(SpentTransaction).collect::<Vec<_>>())
})
}

pub async fn last_transactions(
ctx: &Context<'_>,
count: usize,
Expand Down
Loading