1use crate::{
2 fuel_core_graphql_api::{
3 api_service::ChainInfoProvider,
4 query_costs,
5 },
6 graphql_api::Config,
7 schema::{
8 ReadViewProvider,
9 block::Block,
10 scalars::{
11 Address,
12 AssetId,
13 U16,
14 U32,
15 U64,
16 },
17 },
18};
19use async_graphql::{
20 Context,
21 Enum,
22 Lookahead,
23 Object,
24 Union,
25};
26use fuel_core_types::{
27 fuel_tx,
28 fuel_tx::{
29 GasCostsValues,
30 consensus_parameters::gas::GasCostsValuesV6,
31 },
32};
33use std::{
34 ops::Deref,
35 sync::Arc,
36};
37
38pub struct ChainInfo;
39pub struct ConsensusParameters(pub Arc<fuel_tx::ConsensusParameters>);
40pub struct TxParameters(fuel_tx::TxParameters);
41pub struct PredicateParameters(fuel_tx::PredicateParameters);
42pub struct ScriptParameters(fuel_tx::ScriptParameters);
43pub struct ContractParameters(fuel_tx::ContractParameters);
44pub struct FeeParameters(fuel_tx::FeeParameters);
45
46pub struct GasCosts(fuel_tx::GasCosts);
47
48#[derive(Clone, Copy, Debug, Enum, Eq, PartialEq)]
49pub enum GasCostsVersion {
50 V1,
51}
52
53#[derive(Clone, Copy, Debug, Enum, Eq, PartialEq)]
54pub enum FeeParametersVersion {
55 V1,
56}
57
58#[derive(Clone, Copy, Debug, Enum, Eq, PartialEq)]
59pub enum ContractParametersVersion {
60 V1,
61}
62
63#[derive(Clone, Copy, Debug, Enum, Eq, PartialEq)]
64pub enum ScriptParametersVersion {
65 V1,
66 V2,
67}
68
69#[derive(Clone, Copy, Debug, Enum, Eq, PartialEq)]
70pub enum PredicateParametersVersion {
71 V1,
72}
73
74#[derive(Clone, Copy, Debug, Enum, Eq, PartialEq)]
75pub enum TxParametersVersion {
76 V1,
77}
78
79#[derive(Clone, Copy, Debug, Enum, Eq, PartialEq)]
80pub enum ConsensusParametersVersion {
81 V1,
82}
83
84#[derive(Union)]
85pub enum DependentCost {
86 LightOperation(LightOperation),
87 HeavyOperation(HeavyOperation),
88}
89
90pub struct LightOperation {
91 base: u64,
92 units_per_gas: u64,
93}
94
95pub struct HeavyOperation {
96 base: u64,
97 gas_per_unit: u64,
98}
99
100fn requires_v2_consensus_parameters(look_ahead: &Lookahead<'_>) -> bool {
101 let script_params_require_v2 = look_ahead
102 .field("scriptParams")
103 .field("maxStorageSlotLength")
104 .exists();
105 let gas_costs_require_v2 = [
106 "storageReadCold",
107 "storageReadHot",
108 "storageWrite",
109 "storageClear",
110 ]
111 .into_iter()
112 .any(|field| look_ahead.field("gasCosts").field(field).exists());
113
114 script_params_require_v2 || gas_costs_require_v2
115}
116
117#[allow(unused)]
118fn script_params_as_v1(
119 script_params: fuel_tx::ScriptParameters,
120) -> fuel_tx::ScriptParameters {
121 match script_params {
122 fuel_tx::ScriptParameters::V1(params) => params.into(),
123 fuel_tx::ScriptParameters::V2(params) => {
124 fuel_tx::consensus_parameters::ScriptParametersV1 {
125 max_script_length: params.max_script_length,
126 max_script_data_length: params.max_script_data_length,
127 }
128 .into()
129 }
130 }
131}
132
133#[allow(unused)]
134fn gas_costs_as_v6(gas_costs: fuel_tx::GasCosts) -> fuel_tx::GasCosts {
135 use fuel_tx::consensus_parameters::DependentCost;
136
137 match gas_costs.deref() {
138 GasCostsValues::V1(_)
139 | GasCostsValues::V2(_)
140 | GasCostsValues::V3(_)
141 | GasCostsValues::V4(_)
142 | GasCostsValues::V5(_)
143 | GasCostsValues::V6(_) => gas_costs,
144 GasCostsValues::V7(values) => fuel_tx::GasCosts::new(
145 GasCostsValuesV6 {
146 add: values.add,
147 addi: values.addi,
148 and: values.and,
149 andi: values.andi,
150 bal: values.bal,
151 bhei: values.bhei,
152 bhsh: values.bhsh,
153 burn: values.burn,
154 cb: values.cb,
155 cfsi: values.cfsi,
156 div: values.div,
157 divi: values.divi,
158 eck1: values.eck1,
159 ecr1: values.ecr1,
160 eq: values.eq,
161 exp: values.exp,
162 expi: values.expi,
163 flag: values.flag,
164 gm: values.gm,
165 gt: values.gt,
166 gtf: values.gtf,
167 ji: values.ji,
168 jmp: values.jmp,
169 jne: values.jne,
170 jnei: values.jnei,
171 jnzi: values.jnzi,
172 jmpf: values.jmpf,
173 jmpb: values.jmpb,
174 jnzf: values.jnzf,
175 jnzb: values.jnzb,
176 jnef: values.jnef,
177 jneb: values.jneb,
178 lb: values.lb,
179 log: values.log,
180 lt: values.lt,
181 lw: values.lw,
182 mint: values.mint,
183 mlog: values.mlog,
184 mod_op: values.mod_op,
185 modi: values.modi,
186 move_op: values.move_op,
187 movi: values.movi,
188 mroo: values.mroo,
189 mul: values.mul,
190 muli: values.muli,
191 mldv: values.mldv,
192 niop: values.niop,
193 noop: values.noop,
194 not: values.not,
195 or: values.or,
196 ori: values.ori,
197 poph: values.poph,
198 popl: values.popl,
199 pshh: values.pshh,
200 pshl: values.pshl,
201 ret: values.ret,
202 rvrt: values.rvrt,
203 sb: values.sb,
204 sll: values.sll,
205 slli: values.slli,
206 srl: values.srl,
207 srli: values.srli,
208 srw: 0,
209 sub: values.sub,
210 subi: values.subi,
211 sw: values.sw,
212 sww: 0,
213 time: values.time,
214 tr: values.tr,
215 tro: values.tro,
216 wdcm: values.wdcm,
217 wqcm: values.wqcm,
218 wdop: values.wdop,
219 wqop: values.wqop,
220 wdml: values.wdml,
221 wqml: values.wqml,
222 wddv: values.wddv,
223 wqdv: values.wqdv,
224 wdmd: values.wdmd,
225 wqmd: values.wqmd,
226 wdam: values.wdam,
227 wqam: values.wqam,
228 wdmm: values.wdmm,
229 wqmm: values.wqmm,
230 xor: values.xor,
231 xori: values.xori,
232 ecop: values.ecop,
233 aloc: values.aloc,
234 bsiz: values.bsiz,
235 bldd: values.bldd,
236 cfe: values.cfe,
237 cfei: values.cfei,
238 call: values.call,
239 ccp: values.ccp,
240 croo: values.croo,
241 csiz: values.csiz,
242 ed19: values.ed19,
243 k256: values.k256,
244 ldc: values.ldc,
245 logd: values.logd,
246 mcl: values.mcl,
247 mcli: values.mcli,
248 mcp: values.mcp,
249 mcpi: values.mcpi,
250 meq: values.meq,
251 retd: values.retd,
252 s256: values.s256,
253 scwq: DependentCost::free(),
254 smo: values.smo,
255 srwq: DependentCost::free(),
256 swwq: DependentCost::free(),
257 epar: values.epar,
258 contract_root: values.contract_root,
259 state_root: values.state_root,
260 vm_initialization: values.vm_initialization,
261 new_storage_per_byte: values.new_storage_per_byte,
262 }
263 .into(),
264 ),
265 }
266}
267
268pub(crate) fn consensus_params_for_selection(
269 params: Arc<fuel_tx::ConsensusParameters>,
270 look_ahead: &Lookahead<'_>,
271) -> Arc<fuel_tx::ConsensusParameters> {
272 if requires_v2_consensus_parameters(look_ahead) {
273 return params;
274 }
275
276 match params.as_ref() {
277 fuel_tx::ConsensusParameters::V1(_) => params,
278 fuel_tx::ConsensusParameters::V2(params) => Arc::new(
279 fuel_tx::consensus_parameters::ConsensusParametersV2 {
280 tx_params: params.tx_params,
281 predicate_params: params.predicate_params,
282 script_params: script_params_as_v1(params.script_params),
283 contract_params: params.contract_params,
284 fee_params: params.fee_params,
285 chain_id: params.chain_id,
286 gas_costs: gas_costs_as_v6(params.gas_costs.clone()),
287 base_asset_id: params.base_asset_id,
288 block_gas_limit: params.block_gas_limit,
289 block_transaction_size_limit: params.block_transaction_size_limit,
290 privileged_address: params.privileged_address,
291 }
292 .into(),
293 ),
294 }
295}
296
297impl From<fuel_tx::DependentCost> for DependentCost {
298 fn from(value: fuel_tx::DependentCost) -> Self {
299 match value {
300 fuel_tx::DependentCost::LightOperation {
301 base,
302 units_per_gas,
303 } => DependentCost::LightOperation(LightOperation {
304 base,
305 units_per_gas,
306 }),
307 fuel_tx::DependentCost::HeavyOperation { base, gas_per_unit } => {
308 DependentCost::HeavyOperation(HeavyOperation { base, gas_per_unit })
309 }
310 }
311 }
312}
313
314#[Object]
315impl ConsensusParameters {
316 async fn version(&self) -> ConsensusParametersVersion {
317 match self.0.as_ref() {
318 fuel_tx::ConsensusParameters::V1(_) | fuel_tx::ConsensusParameters::V2(_) => {
319 ConsensusParametersVersion::V1
320 }
321 }
322 }
323
324 async fn tx_params(&self) -> TxParameters {
325 TxParameters(self.0.tx_params().to_owned())
326 }
327
328 async fn predicate_params(&self) -> PredicateParameters {
329 PredicateParameters(self.0.predicate_params().to_owned())
330 }
331
332 async fn script_params(&self) -> ScriptParameters {
333 ScriptParameters(self.0.script_params().to_owned())
334 }
335
336 async fn contract_params(&self) -> ContractParameters {
337 ContractParameters(self.0.contract_params().to_owned())
338 }
339
340 async fn fee_params(&self) -> FeeParameters {
341 FeeParameters(self.0.fee_params().to_owned())
342 }
343
344 async fn base_asset_id(&self) -> AssetId {
345 AssetId(*self.0.base_asset_id())
346 }
347
348 async fn block_gas_limit(&self) -> U64 {
349 self.0.block_gas_limit().into()
350 }
351
352 async fn block_transaction_size_limit(&self) -> U64 {
353 self.0.block_transaction_size_limit().into()
354 }
355
356 async fn chain_id(&self) -> U64 {
357 (*self.0.chain_id()).into()
358 }
359
360 async fn gas_costs(&self) -> async_graphql::Result<GasCosts> {
361 Ok(GasCosts(self.0.gas_costs().clone()))
362 }
363
364 async fn privileged_address(&self) -> async_graphql::Result<Address> {
365 Ok(Address(*self.0.privileged_address()))
366 }
367}
368
369#[Object]
370impl TxParameters {
371 async fn version(&self) -> TxParametersVersion {
372 match self.0 {
373 fuel_tx::TxParameters::V1(_) => TxParametersVersion::V1,
374 }
375 }
376
377 async fn max_inputs(&self) -> U16 {
378 self.0.max_inputs().into()
379 }
380
381 async fn max_outputs(&self) -> U16 {
382 self.0.max_outputs().into()
383 }
384
385 async fn max_witnesses(&self) -> U32 {
386 self.0.max_witnesses().into()
387 }
388
389 async fn max_gas_per_tx(&self) -> U64 {
390 self.0.max_gas_per_tx().into()
391 }
392
393 async fn max_size(&self) -> U64 {
394 self.0.max_size().into()
395 }
396
397 async fn max_bytecode_subsections(&self) -> U16 {
398 self.0.max_bytecode_subsections().into()
399 }
400}
401
402#[Object]
403impl PredicateParameters {
404 async fn version(&self) -> PredicateParametersVersion {
405 match self.0 {
406 fuel_tx::PredicateParameters::V1(_) => PredicateParametersVersion::V1,
407 }
408 }
409
410 async fn max_predicate_length(&self) -> U64 {
411 self.0.max_predicate_length().into()
412 }
413
414 async fn max_predicate_data_length(&self) -> U64 {
415 self.0.max_predicate_data_length().into()
416 }
417
418 async fn max_gas_per_predicate(&self) -> U64 {
419 self.0.max_gas_per_predicate().into()
420 }
421
422 async fn max_message_data_length(&self) -> U64 {
423 self.0.max_message_data_length().into()
424 }
425}
426
427#[Object]
428impl ScriptParameters {
429 async fn version(&self) -> ScriptParametersVersion {
430 match self.0 {
431 fuel_tx::ScriptParameters::V1(_) => ScriptParametersVersion::V1,
432 fuel_tx::ScriptParameters::V2(_) => ScriptParametersVersion::V2,
433 }
434 }
435
436 async fn max_script_length(&self) -> U64 {
437 self.0.max_script_length().into()
438 }
439
440 async fn max_script_data_length(&self) -> U64 {
441 self.0.max_script_data_length().into()
442 }
443
444 async fn max_storage_slot_length(&self) -> U64 {
445 self.0.max_storage_slot_length().into()
446 }
447}
448
449#[Object]
450impl ContractParameters {
451 async fn version(&self) -> ContractParametersVersion {
452 match self.0 {
453 fuel_tx::ContractParameters::V1(_) => ContractParametersVersion::V1,
454 }
455 }
456
457 async fn contract_max_size(&self) -> U64 {
458 self.0.contract_max_size().into()
459 }
460
461 async fn max_storage_slots(&self) -> U64 {
462 self.0.max_storage_slots().into()
463 }
464}
465
466#[Object]
467impl FeeParameters {
468 async fn version(&self) -> FeeParametersVersion {
469 match self.0 {
470 fuel_tx::FeeParameters::V1(_) => FeeParametersVersion::V1,
471 }
472 }
473
474 async fn gas_price_factor(&self) -> U64 {
475 self.0.gas_price_factor().into()
476 }
477
478 async fn gas_per_byte(&self) -> U64 {
479 self.0.gas_per_byte().into()
480 }
481}
482
483#[Object]
484impl GasCosts {
485 async fn version(&self) -> GasCostsVersion {
486 match self.0.deref() {
487 GasCostsValues::V1(_)
488 | GasCostsValues::V2(_)
489 | GasCostsValues::V3(_)
490 | GasCostsValues::V4(_)
491 | GasCostsValues::V5(_)
492 | GasCostsValues::V6(_)
493 | GasCostsValues::V7(_) => GasCostsVersion::V1,
494 }
495 }
496
497 async fn add(&self) -> U64 {
498 self.0.add().into()
499 }
500
501 async fn addi(&self) -> U64 {
502 self.0.addi().into()
503 }
504
505 async fn aloc(&self) -> U64 {
506 self.0.aloc().base().into()
507 }
508
509 async fn and(&self) -> U64 {
510 self.0.and().into()
511 }
512
513 async fn andi(&self) -> U64 {
514 self.0.andi().into()
515 }
516
517 async fn bal(&self) -> U64 {
518 self.0.bal().into()
519 }
520
521 async fn bhei(&self) -> U64 {
522 self.0.bhei().into()
523 }
524
525 async fn bhsh(&self) -> U64 {
526 self.0.bhsh().into()
527 }
528
529 async fn burn(&self) -> U64 {
530 self.0.burn().into()
531 }
532
533 async fn cb(&self) -> U64 {
534 self.0.cb().into()
535 }
536
537 async fn cfei(&self) -> U64 {
538 self.0.cfei().base().into()
539 }
540
541 async fn cfsi(&self) -> U64 {
542 self.0.cfsi().into()
543 }
544
545 async fn div(&self) -> U64 {
546 self.0.div().into()
547 }
548
549 async fn divi(&self) -> U64 {
550 self.0.divi().into()
551 }
552
553 async fn ecr1(&self) -> U64 {
554 self.0.ecr1().into()
555 }
556
557 async fn eck1(&self) -> U64 {
558 self.0.eck1().into()
559 }
560
561 async fn ed19(&self) -> U64 {
562 self.0.ed19().base().into()
563 }
564
565 async fn eq(&self) -> U64 {
566 self.0.eq_().into()
567 }
568
569 async fn exp(&self) -> U64 {
570 self.0.exp().into()
571 }
572
573 async fn expi(&self) -> U64 {
574 self.0.expi().into()
575 }
576
577 async fn flag(&self) -> U64 {
578 self.0.flag().into()
579 }
580
581 async fn gm(&self) -> U64 {
582 self.0.gm().into()
583 }
584
585 async fn gt(&self) -> U64 {
586 self.0.gt().into()
587 }
588
589 async fn gtf(&self) -> U64 {
590 self.0.gtf().into()
591 }
592
593 async fn ji(&self) -> U64 {
594 self.0.ji().into()
595 }
596
597 async fn jmp(&self) -> U64 {
598 self.0.jmp().into()
599 }
600
601 async fn jne(&self) -> U64 {
602 self.0.jne().into()
603 }
604
605 async fn jnei(&self) -> U64 {
606 self.0.jnei().into()
607 }
608
609 async fn jnzi(&self) -> U64 {
610 self.0.jnzi().into()
611 }
612
613 async fn jmpf(&self) -> U64 {
614 self.0.jmpf().into()
615 }
616
617 async fn jmpb(&self) -> U64 {
618 self.0.jmpb().into()
619 }
620
621 async fn jnzf(&self) -> U64 {
622 self.0.jnzf().into()
623 }
624
625 async fn jnzb(&self) -> U64 {
626 self.0.jnzb().into()
627 }
628
629 async fn jnef(&self) -> U64 {
630 self.0.jnef().into()
631 }
632
633 async fn jneb(&self) -> U64 {
634 self.0.jneb().into()
635 }
636
637 async fn lb(&self) -> U64 {
638 self.0.lb().into()
639 }
640
641 async fn log(&self) -> U64 {
642 self.0.log().into()
643 }
644
645 async fn lt(&self) -> U64 {
646 self.0.lt().into()
647 }
648
649 async fn lw(&self) -> U64 {
650 self.0.lw().into()
651 }
652
653 async fn mint(&self) -> U64 {
654 self.0.mint().into()
655 }
656
657 async fn mlog(&self) -> U64 {
658 self.0.mlog().into()
659 }
660
661 async fn mod_op(&self) -> U64 {
662 self.0.mod_op().into()
663 }
664
665 async fn modi(&self) -> U64 {
666 self.0.modi().into()
667 }
668
669 async fn move_op(&self) -> U64 {
670 self.0.move_op().into()
671 }
672
673 async fn movi(&self) -> U64 {
674 self.0.movi().into()
675 }
676
677 async fn mroo(&self) -> U64 {
678 self.0.mroo().into()
679 }
680
681 async fn mul(&self) -> U64 {
682 self.0.mul().into()
683 }
684
685 async fn muli(&self) -> U64 {
686 self.0.muli().into()
687 }
688
689 async fn mldv(&self) -> U64 {
690 self.0.mldv().into()
691 }
692
693 async fn niop(&self) -> Option<U64> {
694 self.0.niop().ok().map(Into::into)
695 }
696
697 async fn noop(&self) -> U64 {
698 self.0.noop().into()
699 }
700
701 async fn not(&self) -> U64 {
702 self.0.not().into()
703 }
704
705 async fn or(&self) -> U64 {
706 self.0.or().into()
707 }
708
709 async fn ori(&self) -> U64 {
710 self.0.ori().into()
711 }
712
713 async fn poph(&self) -> U64 {
714 self.0.poph().into()
715 }
716
717 async fn popl(&self) -> U64 {
718 self.0.popl().into()
719 }
720
721 async fn pshh(&self) -> U64 {
722 self.0.pshh().into()
723 }
724
725 async fn pshl(&self) -> U64 {
726 self.0.pshl().into()
727 }
728
729 async fn ret(&self) -> U64 {
730 self.0.ret().into()
731 }
732
733 async fn rvrt(&self) -> U64 {
734 self.0.rvrt().into()
735 }
736
737 async fn sb(&self) -> U64 {
738 self.0.sb().into()
739 }
740
741 async fn sll(&self) -> U64 {
742 self.0.sll().into()
743 }
744
745 async fn slli(&self) -> U64 {
746 self.0.slli().into()
747 }
748
749 async fn srl(&self) -> U64 {
750 self.0.srl().into()
751 }
752
753 async fn srli(&self) -> U64 {
754 self.0.srli().into()
755 }
756
757 async fn srw(&self) -> Option<U64> {
758 self.0.srw().ok().map(Into::into)
759 }
760
761 async fn sub(&self) -> U64 {
762 self.0.sub().into()
763 }
764
765 async fn subi(&self) -> U64 {
766 self.0.subi().into()
767 }
768
769 async fn sw(&self) -> U64 {
770 self.0.sw().into()
771 }
772
773 async fn sww(&self) -> Option<U64> {
774 self.0.sww().ok().map(Into::into)
775 }
776
777 async fn time(&self) -> U64 {
778 self.0.time().into()
779 }
780
781 async fn tr(&self) -> U64 {
782 self.0.tr().into()
783 }
784
785 async fn tro(&self) -> U64 {
786 self.0.tro().into()
787 }
788
789 async fn wdcm(&self) -> U64 {
790 self.0.wdcm().into()
791 }
792
793 async fn wqcm(&self) -> U64 {
794 self.0.wqcm().into()
795 }
796
797 async fn wdop(&self) -> U64 {
798 self.0.wdop().into()
799 }
800
801 async fn wqop(&self) -> U64 {
802 self.0.wqop().into()
803 }
804
805 async fn wdml(&self) -> U64 {
806 self.0.wdml().into()
807 }
808
809 async fn wqml(&self) -> U64 {
810 self.0.wqml().into()
811 }
812
813 async fn wddv(&self) -> U64 {
814 self.0.wddv().into()
815 }
816
817 async fn wqdv(&self) -> U64 {
818 self.0.wqdv().into()
819 }
820
821 async fn wdmd(&self) -> U64 {
822 self.0.wdmd().into()
823 }
824
825 async fn wqmd(&self) -> U64 {
826 self.0.wqmd().into()
827 }
828
829 async fn wdam(&self) -> U64 {
830 self.0.wdam().into()
831 }
832
833 async fn wqam(&self) -> U64 {
834 self.0.wqam().into()
835 }
836
837 async fn wdmm(&self) -> U64 {
838 self.0.wdmm().into()
839 }
840
841 async fn wqmm(&self) -> U64 {
842 self.0.wqmm().into()
843 }
844
845 async fn xor(&self) -> U64 {
846 self.0.xor().into()
847 }
848
849 async fn xori(&self) -> U64 {
850 self.0.xori().into()
851 }
852
853 async fn ecop(&self) -> Option<U64> {
854 self.0.ecop().ok().map(Into::into)
855 }
856
857 async fn aloc_dependent_cost(&self) -> DependentCost {
858 self.0.aloc().into()
859 }
860
861 async fn bldd(&self) -> Option<DependentCost> {
862 self.0.bldd().ok().map(Into::into)
863 }
864
865 async fn bsiz(&self) -> Option<DependentCost> {
866 self.0.bsiz().ok().map(Into::into)
867 }
868
869 async fn cfe(&self) -> DependentCost {
870 self.0.cfe().into()
871 }
872
873 async fn cfei_dependent_cost(&self) -> DependentCost {
874 self.0.cfei().into()
875 }
876
877 async fn call(&self) -> DependentCost {
878 self.0.call().into()
879 }
880
881 async fn ccp(&self) -> DependentCost {
882 self.0.ccp().into()
883 }
884
885 async fn croo(&self) -> DependentCost {
886 self.0.croo().into()
887 }
888
889 async fn csiz(&self) -> DependentCost {
890 self.0.csiz().into()
891 }
892
893 async fn ed19_dependent_cost(&self) -> DependentCost {
894 self.0.ed19().into()
895 }
896
897 async fn k256(&self) -> DependentCost {
898 self.0.k256().into()
899 }
900
901 async fn ldc(&self) -> DependentCost {
902 self.0.ldc().into()
903 }
904
905 async fn logd(&self) -> DependentCost {
906 self.0.logd().into()
907 }
908
909 async fn mcl(&self) -> DependentCost {
910 self.0.mcl().into()
911 }
912
913 async fn mcli(&self) -> DependentCost {
914 self.0.mcli().into()
915 }
916
917 async fn mcp(&self) -> DependentCost {
918 self.0.mcp().into()
919 }
920
921 async fn mcpi(&self) -> DependentCost {
922 self.0.mcpi().into()
923 }
924
925 async fn meq(&self) -> DependentCost {
926 self.0.meq().into()
927 }
928
929 async fn retd(&self) -> DependentCost {
930 self.0.retd().into()
931 }
932
933 async fn s256(&self) -> DependentCost {
934 self.0.s256().into()
935 }
936
937 async fn scwq(&self) -> Option<DependentCost> {
938 self.0.scwq().ok().map(Into::into)
939 }
940
941 async fn smo(&self) -> DependentCost {
942 self.0.smo().into()
943 }
944
945 async fn srwq(&self) -> Option<DependentCost> {
946 self.0.srwq().ok().map(Into::into)
947 }
948
949 async fn swwq(&self) -> Option<DependentCost> {
950 self.0.swwq().ok().map(Into::into)
951 }
952
953 async fn epar(&self) -> Option<DependentCost> {
954 self.0.epar().ok().map(Into::into)
955 }
956
957 async fn storage_read_cold(&self) -> Option<DependentCost> {
960 self.0.storage_read_cold().ok().map(Into::into)
961 }
962
963 async fn storage_read_hot(&self) -> Option<DependentCost> {
964 self.0.storage_read_hot().ok().map(Into::into)
965 }
966
967 async fn storage_write(&self) -> Option<DependentCost> {
968 self.0.storage_write().ok().map(Into::into)
969 }
970
971 async fn storage_clear(&self) -> Option<DependentCost> {
972 self.0.storage_clear().ok().map(Into::into)
973 }
974
975 async fn contract_root(&self) -> DependentCost {
978 self.0.contract_root().into()
979 }
980
981 async fn state_root(&self) -> DependentCost {
982 self.0.state_root().into()
983 }
984
985 async fn vm_initialization(&self) -> DependentCost {
986 self.0.vm_initialization().into()
987 }
988
989 async fn new_storage_per_byte(&self) -> U64 {
990 self.0.new_storage_per_byte().into()
991 }
992}
993
994#[Object]
995impl LightOperation {
996 async fn base(&self) -> U64 {
997 self.base.into()
998 }
999
1000 async fn units_per_gas(&self) -> U64 {
1001 self.units_per_gas.into()
1002 }
1003}
1004
1005#[Object]
1006impl HeavyOperation {
1007 async fn base(&self) -> U64 {
1008 self.base.into()
1009 }
1010
1011 async fn gas_per_unit(&self) -> U64 {
1012 self.gas_per_unit.into()
1013 }
1014}
1015
1016#[Object]
1017impl ChainInfo {
1018 #[graphql(complexity = "query_costs().storage_read")]
1019 async fn name(&self, ctx: &Context<'_>) -> async_graphql::Result<String> {
1020 let config: &Config = ctx.data_unchecked();
1021 Ok(config.chain_name.clone())
1022 }
1023
1024 #[graphql(complexity = "query_costs().storage_read + child_complexity")]
1025 async fn latest_block(&self, ctx: &Context<'_>) -> async_graphql::Result<Block> {
1026 let query = ctx.read_view()?;
1027
1028 let latest_block = query.latest_block()?.into();
1029 Ok(latest_block)
1030 }
1031
1032 #[graphql(complexity = "query_costs().storage_read")]
1033 async fn da_height(&self, ctx: &Context<'_>) -> U64 {
1034 let Ok(query) = ctx.read_view() else {
1035 return 0.into();
1036 };
1037
1038 query.da_height().unwrap_or_default().0.into()
1039 }
1040
1041 #[graphql(complexity = "query_costs().storage_read + child_complexity")]
1042 async fn consensus_parameters(
1043 &self,
1044 ctx: &Context<'_>,
1045 ) -> async_graphql::Result<ConsensusParameters> {
1046 let params = ctx
1047 .data_unchecked::<ChainInfoProvider>()
1048 .current_consensus_params();
1049
1050 Ok(ConsensusParameters(consensus_params_for_selection(
1051 params,
1052 &ctx.look_ahead(),
1053 )))
1054 }
1055
1056 #[graphql(complexity = "query_costs().storage_read + child_complexity")]
1057 async fn gas_costs(&self, ctx: &Context<'_>) -> async_graphql::Result<GasCosts> {
1058 let params = ctx
1059 .data_unchecked::<ChainInfoProvider>()
1060 .current_consensus_params();
1061
1062 Ok(GasCosts(params.gas_costs().clone()))
1063 }
1064}
1065
1066#[derive(Default)]
1067pub struct ChainQuery;
1068
1069#[Object]
1070impl ChainQuery {
1071 async fn chain(&self) -> ChainInfo {
1072 ChainInfo
1073 }
1074}
1075
1076#[cfg(test)]
1077mod tests {
1078 use super::*;
1079 use crate::{
1080 graphql_api::{
1081 Config,
1082 ServiceConfig,
1083 ports::MockChainStateProvider,
1084 },
1085 schema::build_schema,
1086 };
1087 use async_graphql::Request;
1088 use fuel_tx::consensus_parameters::ConsensusParametersV2;
1089 use std::{
1090 net::{
1091 IpAddr,
1092 Ipv4Addr,
1093 SocketAddr,
1094 },
1095 time::Duration,
1096 };
1097
1098 #[test]
1099 fn gas_costs_downgrade_to_v6_fills_legacy_only_fields() {
1100 use fuel_tx::consensus_parameters::DependentCost;
1101
1102 let downgraded =
1103 gas_costs_as_v6(fuel_tx::ConsensusParameters::standard().gas_costs().clone());
1104
1105 let GasCostsValues::V6(values) = downgraded.deref() else {
1106 panic!("expected downgraded gas costs to be V6");
1107 };
1108
1109 assert_eq!(values.srw, 0);
1110 assert_eq!(values.sww, 0);
1111 assert_eq!(values.scwq, DependentCost::free());
1112 assert_eq!(values.srwq, DependentCost::free());
1113 assert_eq!(values.swwq, DependentCost::free());
1114 }
1115
1116 #[tokio::test]
1117 async fn v047_shape_query_keeps_block_transaction_size_limit() {
1118 const BLOCK_TRANSACTION_SIZE_LIMIT: u64 = 1_234_567;
1119
1120 let mut params = ConsensusParametersV2::standard();
1121 params.block_transaction_size_limit = BLOCK_TRANSACTION_SIZE_LIMIT;
1122
1123 let mut mocked_provider = MockChainStateProvider::default();
1124 mocked_provider
1125 .expect_current_consensus_params()
1126 .return_const(Arc::new(params.into()));
1127
1128 let config = Config {
1129 config: ServiceConfig {
1130 addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 0),
1131 number_of_threads: 1,
1132 database_batch_size: 1,
1133 block_subscriptions_queue: 1,
1134 max_queries_depth: 16,
1135 max_queries_complexity: 10_000,
1136 max_queries_recursive_depth: 32,
1137 max_queries_resolver_recursive_depth: 32,
1138 max_queries_directives: 16,
1139 max_concurrent_queries: 16,
1140 request_body_bytes_limit: 1024 * 1024,
1141 required_fuel_block_height_tolerance: 0,
1142 required_fuel_block_height_timeout: Duration::from_secs(1),
1143 query_log_threshold_time: Duration::from_secs(1),
1144 api_request_timeout: Duration::from_secs(1),
1145 assemble_tx_dry_run_limit: 1,
1146 assemble_tx_estimate_predicates_limit: 1,
1147 costs: Default::default(),
1148 },
1149 utxo_validation: false,
1150 debug: false,
1151 allow_syscall: false,
1152 historical_execution: false,
1153 expensive_subscriptions: false,
1154 max_tx: 1,
1155 max_gas: 1,
1156 max_size: 1,
1157 max_txpool_dependency_chain_length: 1,
1158 chain_name: "test".into(),
1159 };
1160
1161 let schema = build_schema()
1162 .data(config)
1163 .data(Box::new(mocked_provider)
1164 as crate::graphql_api::api_service::ChainInfoProvider)
1165 .finish();
1166
1167 let response = schema
1168 .execute(Request::new(
1169 "{ chain { consensusParameters { blockTransactionSizeLimit } } }",
1170 ))
1171 .await;
1172
1173 assert!(
1174 response.errors.is_empty(),
1175 "unexpected GraphQL errors: {:?}",
1176 response.errors
1177 );
1178 assert_eq!(
1179 response.data.into_json().unwrap(),
1180 serde_json::json!({
1181 "chain": {
1182 "consensusParameters": {
1183 "blockTransactionSizeLimit": BLOCK_TRANSACTION_SIZE_LIMIT.to_string()
1184 }
1185 }
1186 })
1187 );
1188 }
1189}