fedimint_dummy_server/
db.rs

1use fedimint_core::db::{IDatabaseTransactionOpsCore as _, IDatabaseTransactionOpsCoreTyped};
2use fedimint_core::encoding::{Decodable, Encodable};
3use fedimint_core::module::AmountUnit;
4use fedimint_core::module::registry::ModuleRegistry;
5use fedimint_core::secp256k1::PublicKey;
6use fedimint_core::{Amount, OutPoint, impl_db_lookup, impl_db_record};
7use fedimint_dummy_common::DummyOutputOutcomeV0;
8use fedimint_server_core::migration::ServerModuleDbMigrationFnContext;
9use futures::StreamExt;
10use serde::Serialize;
11use strum_macros::EnumIter;
12
13use crate::{Dummy, DummyOutputOutcome};
14
15/// Namespaces DB keys for this module
16#[repr(u8)]
17#[derive(Clone, EnumIter, Debug)]
18pub enum DbKeyPrefix {
19    Funds = 0x01,
20    Outcome = 0x02,
21}
22
23// TODO: Boilerplate-code
24impl std::fmt::Display for DbKeyPrefix {
25    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
26        write!(f, "{self:?}")
27    }
28}
29
30/// Example old version 0 of DB entries
31// TODO: can we simplify this by just using macros?
32#[derive(Debug, Clone, Encodable, Decodable, Eq, PartialEq, Hash, Serialize)]
33pub struct DummyFundsKeyV0(pub PublicKey);
34
35#[derive(Debug, Encodable, Decodable)]
36pub struct DummyFundsKeyPrefixV0;
37
38impl_db_record!(
39    key = DummyFundsKeyV0,
40    value = (),
41    db_prefix = DbKeyPrefix::Funds,
42);
43impl_db_lookup!(key = DummyFundsKeyV0, query_prefix = DummyFundsKeyPrefixV0);
44
45/// Lookup funds for a user by key or prefix
46#[derive(Debug, Clone, Encodable, Decodable, Eq, PartialEq, Hash, Serialize)]
47pub struct DummyFundsKeyV1(pub PublicKey);
48
49#[derive(Debug, Encodable, Decodable)]
50pub struct DummyFundsPrefixV1;
51
52impl_db_record!(
53    key = DummyFundsKeyV1,
54    value = Amount,
55    db_prefix = DbKeyPrefix::Funds,
56);
57impl_db_lookup!(key = DummyFundsKeyV1, query_prefix = DummyFundsPrefixV1);
58
59/// Example DB migration from version 0 to version 1
60pub async fn migrate_to_v1(
61    mut ctx: ServerModuleDbMigrationFnContext<'_, Dummy>,
62) -> Result<(), anyhow::Error> {
63    let mut dbtx = ctx.dbtx();
64    // Select old entries
65    let v0_entries = dbtx
66        .find_by_prefix(&DummyFundsKeyPrefixV0)
67        .await
68        .collect::<Vec<(DummyFundsKeyV0, ())>>()
69        .await;
70
71    // Remove old entries
72    dbtx.remove_by_prefix(&DummyFundsKeyPrefixV0).await;
73
74    // Migrate to new entries
75    for (v0_key, _v0_val) in v0_entries {
76        let v1_key = DummyFundsKeyV1(v0_key.0);
77        dbtx.insert_new_entry(&v1_key, &Amount::ZERO).await;
78    }
79    Ok(())
80}
81
82pub async fn migrate_to_v2(
83    mut ctx: ServerModuleDbMigrationFnContext<'_, Dummy>,
84) -> Result<(), anyhow::Error> {
85    const OUTCOME_RAW_KEY_PREFIX: [u8; 1] = [DbKeyPrefix::Outcome as u8];
86
87    let mut dbtx = ctx.dbtx();
88
89    // Select old entries
90    let raw_entries = dbtx
91        .raw_find_by_prefix(&OUTCOME_RAW_KEY_PREFIX)
92        .await?
93        .collect::<Vec<(Vec<u8>, Vec<u8>)>>()
94        .await;
95
96    // Remove old entries
97    dbtx.raw_remove_by_prefix(&OUTCOME_RAW_KEY_PREFIX).await?;
98
99    // Migrate to new entries
100    for (key, val) in raw_entries {
101        let old = DummyOutputOutcomeV0::consensus_decode_whole(&val, &ModuleRegistry::default())?;
102        dbtx.raw_insert_bytes(
103            &key,
104            &DummyOutputOutcome(old.0, AmountUnit::BITCOIN, old.1).consensus_encode_to_vec(),
105        )
106        .await?;
107    }
108    Ok(())
109}
110
111/// Lookup tx outputs by key or prefix
112#[derive(Debug, Clone, Encodable, Decodable, Eq, PartialEq, Hash, Serialize)]
113pub struct DummyOutcomeKey(pub OutPoint);
114
115#[derive(Debug, Encodable, Decodable)]
116pub struct DummyOutcomePrefix;
117
118impl_db_record!(
119    key = DummyOutcomeKey,
120    value = DummyOutputOutcome,
121    db_prefix = DbKeyPrefix::Outcome,
122);
123impl_db_lookup!(key = DummyOutcomeKey, query_prefix = DummyOutcomePrefix);