Skip to main content

fedimint_client/client/
global_ctx.rs

1use std::sync::Arc;
2
3use fedimint_api_client::api::{DynGlobalApi, DynModuleApi};
4use fedimint_client_module::error::TransactionSubmitError;
5use fedimint_client_module::module::OutPointRange;
6use fedimint_client_module::sm::{ClientSMDatabaseTransaction, DynState, IState};
7use fedimint_client_module::transaction::{TransactionBuilder, TxSubmissionStatesSM};
8use fedimint_client_module::{
9    AddStateMachinesResult, IGlobalClientContext, InstancelessDynClientInputBundle,
10    InstancelessDynClientOutputBundle,
11};
12use fedimint_core::config::ClientConfig;
13use fedimint_core::core::{IntoDynInstance, ModuleInstanceId, ModuleKind, OperationId};
14use fedimint_core::module::registry::ModuleDecoderRegistry;
15use fedimint_core::util::BoxStream;
16use fedimint_core::{apply, async_trait_maybe_send, maybe_add_send_sync};
17use fedimint_eventlog::{EventKind, EventPersistence};
18
19use super::Client;
20
21/// Global state given to a specific client module and state. It is aware inside
22/// which module instance and operation it is used and to avoid module being
23/// aware of their instance id etc.
24#[derive(Clone, Debug)]
25pub(crate) struct ModuleGlobalClientContext {
26    pub(crate) client: Arc<Client>,
27    pub(crate) module_instance_id: ModuleInstanceId,
28    pub(crate) operation: OperationId,
29}
30
31#[apply(async_trait_maybe_send!)]
32impl IGlobalClientContext for ModuleGlobalClientContext {
33    fn module_api(&self) -> DynModuleApi {
34        self.api().with_module(self.module_instance_id)
35    }
36
37    fn api(&self) -> &DynGlobalApi {
38        &self.client.api
39    }
40
41    fn decoders(&self) -> &ModuleDecoderRegistry {
42        self.client.decoders()
43    }
44
45    async fn client_config(&self) -> ClientConfig {
46        self.client.config().await
47    }
48
49    async fn claim_inputs_dyn(
50        &self,
51        dbtx: &mut ClientSMDatabaseTransaction<'_, '_>,
52        inputs: InstancelessDynClientInputBundle,
53    ) -> Result<OutPointRange, TransactionSubmitError> {
54        let tx_builder =
55            TransactionBuilder::new().with_inputs(inputs.into_dyn(self.module_instance_id));
56
57        self.client
58            .finalize_and_submit_transaction_inner(
59                &mut dbtx.global_tx().to_ref_nc(),
60                self.operation,
61                tx_builder,
62            )
63            .await
64    }
65
66    async fn fund_output_dyn(
67        &self,
68        dbtx: &mut ClientSMDatabaseTransaction<'_, '_>,
69        outputs: InstancelessDynClientOutputBundle,
70    ) -> Result<OutPointRange, TransactionSubmitError> {
71        let tx_builder =
72            TransactionBuilder::new().with_outputs(outputs.into_dyn(self.module_instance_id));
73
74        self.client
75            .finalize_and_submit_transaction_inner(
76                &mut dbtx.global_tx().to_ref_nc(),
77                self.operation,
78                tx_builder,
79            )
80            .await
81    }
82
83    async fn add_state_machine_dyn(
84        &self,
85        dbtx: &mut ClientSMDatabaseTransaction<'_, '_>,
86        sm: Box<maybe_add_send_sync!(dyn IState)>,
87    ) -> AddStateMachinesResult {
88        let state = DynState::from_parts(self.module_instance_id, sm);
89
90        self.client
91            .executor
92            .add_state_machines_dbtx(&mut dbtx.global_tx().to_ref_nc(), vec![state])
93            .await
94    }
95
96    async fn transaction_update_stream(&self) -> BoxStream<TxSubmissionStatesSM> {
97        self.client.transaction_update_stream(self.operation).await
98    }
99
100    async fn log_event_json(
101        &self,
102        dbtx: &mut ClientSMDatabaseTransaction<'_, '_>,
103        kind: EventKind,
104        module: Option<(ModuleKind, ModuleInstanceId)>,
105        payload: serde_json::Value,
106        persist: EventPersistence,
107    ) {
108        self.client
109            .log_event_raw_dbtx(
110                dbtx.global_tx(),
111                kind,
112                module,
113                serde_json::to_vec(&payload).expect("Serialization can't fail"),
114                persist,
115            )
116            .await;
117    }
118
119    async fn log_event_json_no_dbtx(
120        &self,
121        kind: EventKind,
122        module_kind: Option<ModuleKind>,
123        payload: serde_json::Value,
124        persist: EventPersistence,
125    ) {
126        let mut dbtx = self.client.db().begin_transaction().await;
127        self.client
128            .log_event_raw_dbtx(
129                &mut dbtx,
130                kind,
131                module_kind.map(|m| (m, self.module_instance_id)),
132                serde_json::to_vec(&payload).expect("Serialization can't fail"),
133                persist,
134            )
135            .await;
136        dbtx.commit_tx().await;
137    }
138
139    async fn core_api_version(&self) -> fedimint_core::module::ApiVersion {
140        self.client.core_api_version().await
141    }
142}