fedimint_dummy_client/
input_sm.rs1use fedimint_client_module::DynGlobalClientContext;
2use fedimint_client_module::sm::{ClientSMDatabaseTransaction, State, StateTransition};
3use fedimint_core::core::OperationId;
4use fedimint_core::db::IDatabaseTransactionOpsCoreTyped;
5use fedimint_core::encoding::{Decodable, Encodable};
6use fedimint_core::module::AmountUnit;
7use fedimint_core::{Amount, OutPoint};
8
9use crate::DummyClientContext;
10use crate::db::DummyClientFundsKey;
11
12#[derive(Debug, Clone, Eq, PartialEq, Hash, Decodable, Encodable)]
17pub struct DummyInputStateMachine {
18 pub common: DummyInputSMCommon,
19 pub state: DummyInputSMState,
20}
21
22#[derive(Debug, Clone, Eq, PartialEq, Hash, Decodable, Encodable)]
23pub struct DummyInputSMCommon {
24 pub operation_id: OperationId,
25 pub out_point: OutPoint,
26 pub amount: Amount,
27 pub unit: AmountUnit,
28}
29
30#[derive(Debug, Clone, Eq, PartialEq, Hash, Decodable, Encodable)]
31pub enum DummyInputSMState {
32 Created,
33 Accepted,
34 Refunded,
35}
36
37impl DummyInputStateMachine {
38 fn update(&self, state: DummyInputSMState) -> Self {
39 Self {
40 common: self.common.clone(),
41 state,
42 }
43 }
44}
45
46impl State for DummyInputStateMachine {
47 type ModuleContext = DummyClientContext;
48
49 fn transitions(
50 &self,
51 context: &Self::ModuleContext,
52 global_context: &DynGlobalClientContext,
53 ) -> Vec<StateTransition<Self>> {
54 match self.state {
55 DummyInputSMState::Created => {
56 let global = global_context.clone();
57 let txid = self.common.out_point.txid;
58 let balance_update_sender = context.balance_update_sender.clone();
59
60 vec![StateTransition::new(
61 async move { global.await_tx_accepted(txid).await },
62 move |dbtx, result, old_state| {
63 Box::pin(Self::transition_created(
64 dbtx,
65 result,
66 old_state,
67 balance_update_sender.clone(),
68 ))
69 },
70 )]
71 }
72 DummyInputSMState::Accepted | DummyInputSMState::Refunded => vec![],
73 }
74 }
75
76 fn operation_id(&self) -> OperationId {
77 self.common.operation_id
78 }
79}
80
81impl DummyInputStateMachine {
82 async fn transition_created(
83 dbtx: &mut ClientSMDatabaseTransaction<'_, '_>,
84 result: Result<(), String>,
85 old_state: Self,
86 balance_update_sender: tokio::sync::watch::Sender<()>,
87 ) -> Self {
88 if result.is_ok() {
89 old_state.update(DummyInputSMState::Accepted)
90 } else {
91 let current = dbtx
92 .module_tx()
93 .get_value(&DummyClientFundsKey(old_state.common.unit))
94 .await
95 .unwrap_or(Amount::ZERO);
96
97 dbtx.module_tx()
98 .insert_entry(
99 &DummyClientFundsKey(old_state.common.unit),
100 &(current + old_state.common.amount),
101 )
102 .await;
103
104 dbtx.module_tx().on_commit(move || {
105 balance_update_sender.send_replace(());
106 });
107
108 old_state.update(DummyInputSMState::Refunded)
109 }
110 }
111}