fuel_core_client/client/schema/
block.rs

1use super::{
2    Bytes32,
3    HexString,
4};
5use crate::client::schema::{
6    BlockId,
7    ConnectionArgsFields,
8    PageInfo,
9    Signature,
10    Tai64Timestamp,
11    TransactionId,
12    U16,
13    U32,
14    U64,
15    schema,
16};
17use fuel_core_types::{
18    fuel_crypto,
19    fuel_types::BlockHeight,
20};
21
22#[derive(cynic::QueryVariables, Debug)]
23pub struct BlockByIdArgs {
24    pub id: Option<BlockId>,
25}
26
27#[derive(cynic::QueryFragment, Clone, Debug)]
28#[cynic(
29    schema_path = "./assets/schema.sdl",
30    graphql_type = "Query",
31    variables = "BlockByIdArgs"
32)]
33pub struct BlockByIdQuery {
34    #[arguments(id: $id)]
35    pub block: Option<Block>,
36}
37
38#[derive(cynic::QueryVariables, Debug)]
39pub struct BlockByHeightArgs {
40    pub height: Option<U32>,
41}
42
43#[derive(cynic::QueryFragment, Clone, Debug)]
44#[cynic(
45    schema_path = "./assets/schema.sdl",
46    graphql_type = "Query",
47    variables = "BlockByHeightArgs"
48)]
49pub struct BlockByHeightQuery {
50    #[arguments(height: $height)]
51    pub block: Option<Block>,
52}
53
54#[derive(cynic::QueryFragment, Clone, Debug)]
55#[cynic(
56    schema_path = "./assets/schema.sdl",
57    graphql_type = "Query",
58    variables = "ConnectionArgs"
59)]
60pub struct BlocksQuery {
61    #[arguments(after: $after, before: $before, first: $first, last: $last)]
62    pub blocks: BlockConnection,
63}
64
65#[derive(cynic::QueryFragment, Clone, Debug)]
66#[cynic(schema_path = "./assets/schema.sdl")]
67pub struct BlockConnection {
68    pub edges: Vec<BlockEdge>,
69    pub page_info: PageInfo,
70}
71
72#[derive(cynic::QueryFragment, Clone, Debug)]
73#[cynic(schema_path = "./assets/schema.sdl")]
74pub struct BlockEdge {
75    pub cursor: String,
76    pub node: Block,
77}
78
79#[derive(cynic::Enum, Clone, Debug)]
80#[cynic(schema_path = "./assets/schema.sdl")]
81pub enum BlockVersion {
82    V1,
83    #[cynic(fallback)]
84    Unknown,
85}
86
87/// Block with transaction ids
88#[derive(cynic::QueryFragment, Clone, Debug)]
89#[cynic(schema_path = "./assets/schema.sdl")]
90pub struct Block {
91    pub version: BlockVersion,
92    pub id: BlockId,
93    pub header: Header,
94    pub consensus: Consensus,
95    pub transaction_ids: Vec<TransactionId>,
96}
97
98#[derive(cynic::QueryFragment, Clone, Debug)]
99#[cynic(schema_path = "./assets/schema.sdl", graphql_type = "Block")]
100pub struct BlockIdFragment {
101    pub id: BlockId,
102}
103
104#[derive(cynic::QueryFragment, Clone, Debug)]
105#[cynic(schema_path = "./assets/schema.sdl", graphql_type = "Block")]
106pub struct BlockHeightFragment {
107    pub height: U32,
108}
109
110#[derive(cynic::QueryVariables, Debug)]
111pub struct ProduceBlockArgs {
112    pub start_timestamp: Option<Tai64Timestamp>,
113    pub blocks_to_produce: U32,
114}
115
116#[derive(cynic::QueryFragment, Clone, Debug)]
117#[cynic(
118    schema_path = "./assets/schema.sdl",
119    variables = "ProduceBlockArgs",
120    graphql_type = "Mutation"
121)]
122pub struct BlockMutation {
123    #[arguments(blocksToProduce: $blocks_to_produce, startTimestamp: $start_timestamp)]
124    pub produce_blocks: U32,
125}
126
127#[derive(cynic::Enum, Clone, Debug)]
128#[cynic(schema_path = "./assets/schema.sdl")]
129pub enum HeaderVersion {
130    V1,
131    V2,
132    #[cynic(fallback)]
133    Unknown,
134}
135
136#[derive(cynic::QueryFragment, Clone, Debug)]
137#[cynic(schema_path = "./assets/schema.sdl")]
138pub struct Header {
139    pub version: HeaderVersion,
140    pub id: BlockId,
141    pub da_height: U64,
142    pub consensus_parameters_version: U32,
143    pub state_transition_bytecode_version: U32,
144    pub transactions_count: U16,
145    pub message_receipt_count: U32,
146    pub transactions_root: Bytes32,
147    pub message_outbox_root: Bytes32,
148    pub event_inbox_root: Bytes32,
149    pub height: U32,
150    pub prev_root: Bytes32,
151    pub time: Tai64Timestamp,
152    pub application_hash: Bytes32,
153    #[cfg(feature = "fault-proving")]
154    pub tx_id_commitment: Option<Bytes32>,
155}
156
157#[derive(cynic::InlineFragments, Clone, Debug)]
158#[cynic(schema_path = "./assets/schema.sdl")]
159pub enum Consensus {
160    Genesis(Genesis),
161    PoAConsensus(PoAConsensus),
162    #[cynic(fallback)]
163    Unknown,
164}
165
166#[derive(cynic::QueryFragment, Clone, Debug)]
167#[cynic(schema_path = "./assets/schema.sdl")]
168pub struct Genesis {
169    pub chain_config_hash: Bytes32,
170    pub coins_root: Bytes32,
171    pub contracts_root: Bytes32,
172    pub messages_root: Bytes32,
173    pub transactions_root: Bytes32,
174}
175
176#[derive(cynic::QueryFragment, Clone, Debug)]
177#[cynic(schema_path = "./assets/schema.sdl")]
178pub struct PoAConsensus {
179    pub signature: Signature,
180}
181
182impl Block {
183    /// Returns the block producer public key, if any.
184    pub fn block_producer(&self) -> Option<fuel_crypto::PublicKey> {
185        let message = self.header.id.clone().into_message();
186        match &self.consensus {
187            Consensus::Genesis(_) => Some(Default::default()),
188            Consensus::PoAConsensus(poa) => {
189                let signature = poa.signature.clone().into_signature();
190                let producer_pub_key = signature.recover(&message);
191                producer_pub_key.ok()
192            }
193            Consensus::Unknown => None,
194        }
195    }
196}
197
198#[derive(cynic::QueryFragment, Clone, Debug)]
199#[cynic(schema_path = "./assets/schema.sdl", graphql_type = "Subscription")]
200pub struct NewBlocksSubscription {
201    #[cynic(rename = "alpha__new_blocks")]
202    pub new_blocks: HexString,
203}
204
205impl From<BlockHeightFragment> for BlockHeight {
206    fn from(fragment: BlockHeightFragment) -> Self {
207        BlockHeight::new(fragment.height.into())
208    }
209}
210
211#[cfg(test)]
212mod tests {
213    use super::*;
214
215    #[test]
216    fn block_by_id_query_gql_output() {
217        use cynic::QueryBuilder;
218        let operation = BlockByIdQuery::build(BlockByIdArgs {
219            id: Some(BlockId::default()),
220        });
221
222        let snapshot_name = if cfg!(feature = "fault-proving") {
223            "block_by_id_query_gql_output_with_tx_id_commitment"
224        } else {
225            "block_by_id_query_gql_output"
226        };
227
228        insta::assert_snapshot!(snapshot_name, operation.query)
229    }
230
231    #[test]
232    fn block_by_height_query_gql_output() {
233        use cynic::QueryBuilder;
234        let operation = BlockByHeightQuery::build(BlockByHeightArgs {
235            height: Some(U32(0)),
236        });
237
238        let snapshot_name = if cfg!(feature = "fault-proving") {
239            "block_by_height_query_gql_output_with_tx_id_commitment"
240        } else {
241            "block_by_height_query_gql_output"
242        };
243
244        insta::assert_snapshot!(snapshot_name, operation.query)
245    }
246
247    #[test]
248    fn block_mutation_query_gql_output() {
249        use cynic::MutationBuilder;
250        let operation = BlockMutation::build(ProduceBlockArgs {
251            blocks_to_produce: U32(0),
252            start_timestamp: None,
253        });
254        insta::assert_snapshot!(operation.query)
255    }
256
257    #[test]
258    fn blocks_connection_query_gql_output() {
259        use cynic::QueryBuilder;
260        let args = crate::client::schema::ConnectionArgs {
261            after: None,
262            before: None,
263            first: None,
264            last: None,
265        };
266        let operation = BlocksQuery::build(args);
267
268        let snapshot_name = if cfg!(feature = "fault-proving") {
269            "blocks_connection_query_gql_output_with_tx_id_commitment"
270        } else {
271            "blocks_connection_query_gql_output"
272        };
273
274        insta::assert_snapshot!(snapshot_name, operation.query)
275    }
276}