Skip to main content

fuel_core/schema/
chain.rs

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    // Storage micro-ops
958
959    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    // Non-opcode prices
976
977    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}