fuel_core/schema/
message.rs1use super::{
2 ReadViewProvider,
3 block::Header,
4 scalars::{
5 Address,
6 Bytes32,
7 HexString,
8 Nonce,
9 TransactionId,
10 U64,
11 },
12};
13use crate::{
14 fuel_core_graphql_api::query_costs,
15 graphql_api::IntoApiResult,
16 schema::scalars::{
17 BlockId,
18 U32,
19 },
20};
21use anyhow::anyhow;
22use async_graphql::{
23 Context,
24 Enum,
25 Object,
26 connection::{
27 Connection,
28 EmptyFields,
29 },
30};
31use fuel_core_services::stream::IntoBoxStream;
32use fuel_core_types::entities;
33use futures::StreamExt;
34
35pub struct Message(pub(crate) entities::relayer::message::Message);
36
37#[Object]
38impl Message {
39 async fn amount(&self) -> U64 {
40 self.0.amount().into()
41 }
42
43 async fn sender(&self) -> Address {
44 (*self.0.sender()).into()
45 }
46
47 async fn recipient(&self) -> Address {
48 (*self.0.recipient()).into()
49 }
50
51 async fn nonce(&self) -> Nonce {
52 (*self.0.nonce()).into()
53 }
54
55 async fn data(&self) -> HexString {
56 self.0.data().clone().into()
57 }
58
59 async fn da_height(&self) -> U64 {
60 self.0.da_height().as_u64().into()
61 }
62}
63
64#[derive(Default)]
65pub struct MessageQuery {}
66
67#[Object]
68impl MessageQuery {
69 #[graphql(complexity = "query_costs().storage_read + child_complexity")]
70 async fn message(
71 &self,
72 ctx: &Context<'_>,
73 #[graphql(desc = "The Nonce of the message")] nonce: Nonce,
74 ) -> async_graphql::Result<Option<Message>> {
75 let query = ctx.read_view()?;
76 let nonce = nonce.0;
77 query.message(&nonce).into_api_result()
78 }
79
80 #[graphql(complexity = "{\
81 query_costs().storage_iterator\
82 + first.unwrap_or_default() as usize * (child_complexity + query_costs().storage_read) \
83 + last.unwrap_or_default() as usize * (child_complexity + query_costs().storage_read) \
84 }")]
85 async fn messages(
86 &self,
87 ctx: &Context<'_>,
88 #[graphql(desc = "address of the owner")] owner: Option<Address>,
89 first: Option<i32>,
90 after: Option<String>,
91 last: Option<i32>,
92 before: Option<String>,
93 ) -> async_graphql::Result<Connection<HexString, Message, EmptyFields, EmptyFields>>
94 {
95 let query = ctx.read_view()?;
96 let owner = owner.map(|owner| owner.0);
97 let owner_ref = owner.as_ref();
98 crate::schema::query_pagination(
99 after,
100 before,
101 first,
102 last,
103 |start: &Option<HexString>, direction| {
104 let start = if let Some(start) = start.clone() {
105 Some(start.try_into().map_err(|err| anyhow!("{}", err))?)
106 } else {
107 None
108 };
109
110 let messages = if let Some(owner) = owner_ref {
111 query
112 .owned_messages(owner, start, direction)
113 .into_boxed_ref()
114 } else {
115 query.all_messages(start, direction).into_boxed_ref()
116 };
117
118 let messages = messages.map(|result| {
119 result.map(|message| ((*message.nonce()).into(), message.into()))
120 });
121
122 Ok(messages)
123 },
124 )
125 .await
126 }
127
128 #[graphql(complexity = "256 * query_costs().storage_read + child_complexity")]
130 async fn message_proof(
131 &self,
132 ctx: &Context<'_>,
133 transaction_id: TransactionId,
134 nonce: Nonce,
135 commit_block_id: Option<BlockId>,
136 commit_block_height: Option<U32>,
137 ) -> async_graphql::Result<MessageProof> {
138 let query = ctx.read_view()?;
139 let height = match (commit_block_id, commit_block_height) {
140 (Some(commit_block_id), None) => {
141 query.block_height(&commit_block_id.0.into())?
142 }
143 (None, Some(commit_block_height)) => commit_block_height.0.into(),
144 _ => Err(anyhow::anyhow!(
145 "Either `commit_block_id` or `commit_block_height` must be provided exclusively"
146 ))?,
147 };
148
149 let proof = crate::query::message_proof(
150 query.as_ref(),
151 transaction_id.into(),
152 nonce.into(),
153 height,
154 )?;
155
156 Ok(MessageProof(proof))
157 }
158
159 #[graphql(complexity = "query_costs().storage_read + child_complexity")]
160 async fn message_status(
161 &self,
162 ctx: &Context<'_>,
163 nonce: Nonce,
164 ) -> async_graphql::Result<MessageStatus> {
165 let query = ctx.read_view()?;
166 let status = crate::query::message_status(query.as_ref(), nonce.into())?;
167 Ok(status.into())
168 }
169}
170pub struct MerkleProof(pub(crate) entities::relayer::message::MerkleProof);
171
172#[Object]
173impl MerkleProof {
174 async fn proof_set(&self) -> Vec<Bytes32> {
175 self.0
176 .proof_set
177 .iter()
178 .cloned()
179 .map(|array| Bytes32::from(fuel_core_types::fuel_types::Bytes32::from(array)))
180 .collect()
181 }
182
183 async fn proof_index(&self) -> U64 {
184 self.0.proof_index.into()
185 }
186}
187
188pub struct MessageProof(pub(crate) entities::relayer::message::MessageProof);
189
190#[Object]
191impl MessageProof {
192 async fn message_proof(&self) -> MerkleProof {
193 self.0.message_proof.clone().into()
194 }
195
196 async fn block_proof(&self) -> MerkleProof {
197 self.0.block_proof.clone().into()
198 }
199
200 async fn message_block_header(&self) -> Header {
201 self.0.message_block_header.clone().into()
202 }
203
204 async fn commit_block_header(&self) -> Header {
205 self.0.commit_block_header.clone().into()
206 }
207
208 async fn sender(&self) -> Address {
209 self.0.sender.into()
210 }
211
212 async fn recipient(&self) -> Address {
213 self.0.recipient.into()
214 }
215
216 async fn nonce(&self) -> Nonce {
217 self.0.nonce.into()
218 }
219
220 async fn amount(&self) -> U64 {
221 self.0.amount.into()
222 }
223
224 async fn data(&self) -> HexString {
225 self.0.data.clone().into()
226 }
227}
228
229impl From<entities::relayer::message::Message> for Message {
230 fn from(message: entities::relayer::message::Message) -> Self {
231 Message(message)
232 }
233}
234
235impl From<entities::relayer::message::MerkleProof> for MerkleProof {
236 fn from(proof: entities::relayer::message::MerkleProof) -> Self {
237 MerkleProof(proof)
238 }
239}
240
241pub struct MessageStatus(pub(crate) entities::relayer::message::MessageStatus);
242
243#[derive(Enum, Copy, Clone, Eq, PartialEq)]
244enum MessageState {
245 Unspent,
246 Spent,
247 NotFound,
248}
249
250#[Object]
251impl MessageStatus {
252 async fn state(&self) -> MessageState {
253 match self.0.state {
254 entities::relayer::message::MessageState::Unspent => MessageState::Unspent,
255 entities::relayer::message::MessageState::Spent => MessageState::Spent,
256 entities::relayer::message::MessageState::NotFound => MessageState::NotFound,
257 }
258 }
259}
260
261impl From<entities::relayer::message::MessageStatus> for MessageStatus {
262 fn from(status: entities::relayer::message::MessageStatus) -> Self {
263 MessageStatus(status)
264 }
265}