fuel-core 0.18.3

Fuel client library is aggregation of all fuels service. It contains the all business logic of the fuel protocol.
Documentation
use std::ops::Deref;

use super::{
    block::Header,
    scalars::{
        Address,
        Bytes32,
        HexString,
        MessageId,
        Nonce,
        TransactionId,
        U64,
    },
};
use crate::{
    fuel_core_graphql_api::service::Database,
    query::MessageQueryData,
    schema::scalars::{
        BlockId,
        U32,
    },
};
use anyhow::anyhow;
use async_graphql::{
    connection::{
        Connection,
        EmptyFields,
    },
    Context,
    Object,
};
use fuel_core_types::entities;

pub struct Message(pub(crate) entities::message::Message);

#[Object]
impl Message {
    async fn amount(&self) -> U64 {
        self.0.amount.into()
    }

    async fn sender(&self) -> Address {
        self.0.sender.into()
    }

    async fn recipient(&self) -> Address {
        self.0.recipient.into()
    }

    async fn nonce(&self) -> Nonce {
        self.0.nonce.into()
    }

    async fn data(&self) -> HexString {
        self.0.data.clone().into()
    }

    async fn da_height(&self) -> U64 {
        self.0.da_height.as_u64().into()
    }
}

#[derive(Default)]
pub struct MessageQuery {}

#[Object]
impl MessageQuery {
    async fn messages(
        &self,
        ctx: &Context<'_>,
        #[graphql(desc = "address of the owner")] owner: Option<Address>,
        first: Option<i32>,
        after: Option<String>,
        last: Option<i32>,
        before: Option<String>,
    ) -> async_graphql::Result<Connection<HexString, Message, EmptyFields, EmptyFields>>
    {
        let query: &Database = ctx.data_unchecked();
        crate::schema::query_pagination(
            after,
            before,
            first,
            last,
            |start: &Option<HexString>, direction| {
                let start = if let Some(start) = start.clone() {
                    Some(start.try_into().map_err(|err| anyhow!("{}", err))?)
                } else {
                    None
                };

                let messages = if let Some(owner) = owner {
                    // Rocksdb doesn't support reverse iteration over a prefix
                    if matches!(last, Some(last) if last > 0) {
                        return Err(anyhow!(
                            "reverse pagination isn't supported for this resource"
                        )
                        .into())
                    }

                    query.owned_messages(&owner.0, start, direction)
                } else {
                    query.all_messages(start, direction)
                };

                let messages = messages.map(|result| {
                    result
                        .map(|message| (message.nonce.into(), message.into()))
                        .map_err(Into::into)
                });

                Ok(messages)
            },
        )
        .await
    }

    async fn message_proof(
        &self,
        ctx: &Context<'_>,
        transaction_id: TransactionId,
        message_id: MessageId,
        commit_block_id: Option<BlockId>,
        commit_block_height: Option<U32>,
    ) -> async_graphql::Result<Option<MessageProof>> {
        let data: &Database = ctx.data_unchecked();
        let block_id = match (commit_block_id, commit_block_height) {
            (Some(commit_block_id), None) => commit_block_id.0.into(),
            (None, Some(commit_block_height)) => {
                let block_height = commit_block_height.0.into();
                data.block_id(&block_height)?
            }
            _ => Err(anyhow::anyhow!(
                "Either `commit_block_id` or `commit_block_height` must be provided exclusively"
            ))?,
        };

        Ok(crate::query::message_proof(
            data.deref(),
            transaction_id.into(),
            message_id.into(),
            block_id,
        )?
        .map(MessageProof))
    }
}
pub struct MerkleProof(pub(crate) entities::message::MerkleProof);

#[Object]
impl MerkleProof {
    async fn proof_set(&self) -> Vec<Bytes32> {
        self.0
            .proof_set
            .iter()
            .cloned()
            .map(|array| Bytes32::from(fuel_core_types::fuel_types::Bytes32::from(array)))
            .collect()
    }

    async fn proof_index(&self) -> U64 {
        self.0.proof_index.into()
    }
}

pub struct MessageProof(pub(crate) entities::message::MessageProof);

#[Object]
impl MessageProof {
    async fn message_proof(&self) -> MerkleProof {
        self.0.message_proof.clone().into()
    }

    async fn block_proof(&self) -> MerkleProof {
        self.0.block_proof.clone().into()
    }

    async fn message_block_header(&self) -> Header {
        self.0.message_block_header.clone().into()
    }

    async fn commit_block_header(&self) -> Header {
        self.0.commit_block_header.clone().into()
    }

    async fn sender(&self) -> Address {
        self.0.sender.into()
    }

    async fn recipient(&self) -> Address {
        self.0.recipient.into()
    }

    async fn nonce(&self) -> Nonce {
        self.0.nonce.into()
    }

    async fn amount(&self) -> U64 {
        self.0.amount.into()
    }

    async fn data(&self) -> HexString {
        self.0.data.clone().into()
    }
}

impl From<entities::message::Message> for Message {
    fn from(message: entities::message::Message) -> Self {
        Message(message)
    }
}

impl From<entities::message::MerkleProof> for MerkleProof {
    fn from(proof: entities::message::MerkleProof) -> Self {
        MerkleProof(proof)
    }
}