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