fedimint_dummy_client/
db.rs

1use std::io::Cursor;
2
3use fedimint_core::core::{ModuleInstanceId, OperationId};
4use fedimint_core::db::{DatabaseTransaction, IDatabaseTransactionOpsCoreTyped};
5use fedimint_core::encoding::{Decodable, Encodable};
6use fedimint_core::module::registry::ModuleDecoderRegistry;
7use fedimint_core::{impl_db_record, Amount, TransactionId};
8use strum_macros::EnumIter;
9use tracing::warn;
10
11use crate::states::DummyStateMachine;
12
13#[repr(u8)]
14#[derive(Clone, Debug, EnumIter)]
15pub enum DbKeyPrefix {
16    ClientFunds = 0x04,
17    // Used to verify that 0x50 key can be written to, which used to conflict with
18    // `DatabaseVersionKeyV0`
19    ClientName = 0x50,
20}
21
22impl std::fmt::Display for DbKeyPrefix {
23    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
24        write!(f, "{self:?}")
25    }
26}
27
28#[derive(Debug, Clone, Encodable, Decodable, Eq, PartialEq, Hash)]
29pub struct DummyClientFundsKeyV0;
30
31impl_db_record!(
32    key = DummyClientFundsKeyV0,
33    value = (),
34    db_prefix = DbKeyPrefix::ClientFunds,
35);
36
37#[derive(Debug, Clone, Encodable, Decodable, Eq, PartialEq, Hash)]
38pub struct DummyClientFundsKeyV1;
39
40impl_db_record!(
41    key = DummyClientFundsKeyV1,
42    value = Amount,
43    db_prefix = DbKeyPrefix::ClientFunds,
44);
45
46#[derive(Debug, Clone, Encodable, Decodable, Eq, PartialEq, Hash)]
47pub struct DummyClientNameKey;
48
49impl_db_record!(
50    key = DummyClientNameKey,
51    value = String,
52    db_prefix = DbKeyPrefix::ClientName,
53);
54
55/// Migrates the database from version 0 to version 1 by
56/// removing `DummyClientFundsKeyV0` and inserting `DummyClientFundsKeyV1`.
57/// The new key/value pair has an `Amount` as the value.
58pub async fn migrate_to_v1(
59    dbtx: &mut DatabaseTransaction<'_>,
60) -> anyhow::Result<Option<(Vec<(Vec<u8>, OperationId)>, Vec<(Vec<u8>, OperationId)>)>> {
61    if dbtx.remove_entry(&DummyClientFundsKeyV0).await.is_some() {
62        // Since this is a dummy migration, we can insert any value for the client
63        // funds. Real modules should handle the funds properly.
64
65        dbtx.insert_new_entry(&DummyClientFundsKeyV1, &Amount::from_sats(1000))
66            .await;
67    } else {
68        warn!("Dummy client did not have client funds, skipping database migration");
69    }
70
71    Ok(None)
72}
73
74/// Maps all `Unreachable` states in the state machine to `OutputDone`
75pub(crate) fn get_v1_migrated_state(
76    operation_id: OperationId,
77    cursor: &mut Cursor<&[u8]>,
78) -> anyhow::Result<Option<(Vec<u8>, OperationId)>> {
79    let decoders = ModuleDecoderRegistry::default();
80    let dummy_sm_variant = u16::consensus_decode(cursor, &decoders)?;
81
82    // We are only migrating the type of one of the variants, so we do nothing on
83    // other discriminants.
84    if dummy_sm_variant != 5 {
85        return Ok(None);
86    }
87
88    // Migrate `Unreachable` states to `OutputDone`
89    let unreachable = Unreachable::consensus_decode(cursor, &decoders)?;
90    let new_state = DummyStateMachine::OutputDone(
91        unreachable.amount,
92        unreachable.txid,
93        unreachable.operation_id,
94    );
95    let bytes = new_state.consensus_encode_to_vec();
96    Ok(Some((bytes, operation_id)))
97}
98
99#[derive(Debug)]
100struct Unreachable {
101    _module_instance_id: ModuleInstanceId,
102    operation_id: OperationId,
103    txid: TransactionId,
104    amount: Amount,
105}
106
107impl Decodable for Unreachable {
108    fn consensus_decode<R: std::io::Read>(
109        reader: &mut R,
110        modules: &ModuleDecoderRegistry,
111    ) -> Result<Self, fedimint_core::encoding::DecodeError> {
112        let module_instance_id = ModuleInstanceId::consensus_decode(reader, modules)?;
113        let operation_id = OperationId::consensus_decode(reader, modules)?;
114        let txid = TransactionId::consensus_decode(reader, modules)?;
115        let amount = Amount::consensus_decode(reader, modules)?;
116
117        Ok(Unreachable {
118            _module_instance_id: module_instance_id,
119            operation_id,
120            txid,
121            amount,
122        })
123    }
124}