fedimint_server/consensus/
db.rs1use std::collections::BTreeMap;
2use std::fmt::Debug;
3
4use fedimint_core::core::ModuleInstanceId;
5use fedimint_core::db::{DatabaseTransaction, DatabaseVersion, IDatabaseTransactionOpsCoreTyped};
6use fedimint_core::encoding::{Decodable, Encodable};
7use fedimint_core::session_outcome::{AcceptedItem, ConsensusItem, SignedSessionOutcome};
8use fedimint_core::util::BoxStream;
9use fedimint_core::{
10 OutPoint, TransactionId, apply, async_trait_maybe_send, impl_db_lookup, impl_db_record,
11};
12use fedimint_server_core::migration::{
13 DynModuleHistoryItem, DynServerDbMigrationFn, IServerDbMigrationContext,
14};
15use futures::StreamExt;
16use serde::Serialize;
17
18use crate::consensus::peer_availability::PeerAvailabilityState;
19use crate::db::DbKeyPrefix;
20
21#[derive(Clone, Debug, Encodable, Decodable)]
22pub struct AcceptedItemKey(pub u64);
23
24#[derive(Clone, Debug, Encodable, Decodable)]
25pub struct AcceptedItemPrefix;
26
27impl_db_record!(
28 key = AcceptedItemKey,
29 value = AcceptedItem,
30 db_prefix = DbKeyPrefix::AcceptedItem,
31 notify_on_modify = true,
32);
33impl_db_lookup!(key = AcceptedItemKey, query_prefix = AcceptedItemPrefix);
34
35#[derive(Debug, Encodable, Decodable, Serialize)]
36pub struct AcceptedTransactionKey(pub TransactionId);
37
38#[derive(Debug, Encodable, Decodable)]
39pub struct AcceptedTransactionKeyPrefix;
40
41impl_db_record!(
42 key = AcceptedTransactionKey,
43 value = Vec<ModuleInstanceId>,
44 db_prefix = DbKeyPrefix::AcceptedTransaction,
45 notify_on_modify = true,
46);
47impl_db_lookup!(
48 key = AcceptedTransactionKey,
49 query_prefix = AcceptedTransactionKeyPrefix
50);
51
52#[derive(Debug, Encodable, Decodable)]
53pub struct SignedSessionOutcomeKey(pub u64);
54
55#[derive(Debug, Encodable, Decodable)]
56pub struct SignedSessionOutcomePrefix;
57
58impl_db_record!(
59 key = SignedSessionOutcomeKey,
60 value = SignedSessionOutcome,
61 db_prefix = DbKeyPrefix::SignedSessionOutcome,
62 notify_on_modify = true,
63);
64impl_db_lookup!(
65 key = SignedSessionOutcomeKey,
66 query_prefix = SignedSessionOutcomePrefix
67);
68
69#[derive(Debug, Encodable, Decodable)]
70pub struct PeerAvailabilityKey;
71
72impl_db_record!(
73 key = PeerAvailabilityKey,
74 value = PeerAvailabilityState,
75 db_prefix = DbKeyPrefix::PeerAvailability,
76 notify_on_modify = false,
77);
78
79#[derive(Debug, Encodable, Decodable)]
80pub struct AlephUnitsKey(pub u64);
81
82#[derive(Debug, Encodable, Decodable)]
83pub struct AlephUnitsPrefix;
84
85impl_db_record!(
86 key = AlephUnitsKey,
87 value = Vec<u8>,
88 db_prefix = DbKeyPrefix::AlephUnits,
89 notify_on_modify = false,
90);
91impl_db_lookup!(key = AlephUnitsKey, query_prefix = AlephUnitsPrefix);
92
93pub fn get_global_database_migrations() -> BTreeMap<DatabaseVersion, DynServerDbMigrationFn> {
94 BTreeMap::new()
95}
96
97pub struct ServerDbMigrationContext;
100
101#[apply(async_trait_maybe_send!)]
102impl IServerDbMigrationContext for ServerDbMigrationContext {
103 async fn get_module_history_stream<'s, 'tx>(
104 &'s self,
105 module_instance_id: ModuleInstanceId,
106 dbtx: &'s mut DatabaseTransaction<'tx>,
107 ) -> BoxStream<'s, DynModuleHistoryItem>
108 where
109 'tx: 's,
110 {
111 dbtx.ensure_global().expect("Dbtx must be global");
112
113 let active_session_items = dbtx
117 .find_by_prefix(&AcceptedItemPrefix)
118 .await
119 .map(|(_, item)| item)
120 .collect::<Vec<_>>()
121 .await;
122
123 let stream =
124 dbtx.find_by_prefix(&SignedSessionOutcomePrefix)
125 .await
126 .flat_map(|(_, signed_session_outcome): (_, SignedSessionOutcome)| {
128 futures::stream::iter(signed_session_outcome.session_outcome.items)
129 })
130 .chain(futures::stream::iter(active_session_items))
133 .flat_map(move |item| {
134 let history_items =
135 match item.item {
136 ConsensusItem::Transaction(tx) => {
137 let txid = tx.tx_hash();
138 let input_items = tx.inputs.into_iter().filter_map(|input| {
139 (input.module_instance_id() == module_instance_id)
140 .then_some(DynModuleHistoryItem::Input(input))
141 });
142
143 let output_items = tx.outputs.into_iter().zip(0..).filter_map(
144 |(output, out_idx)| {
145 (output.module_instance_id() == module_instance_id)
146 .then_some(DynModuleHistoryItem::Output(
147 output,
148 OutPoint { txid, out_idx },
149 ))
150 },
151 );
152
153 input_items.chain(output_items).collect::<Vec<_>>()
154 }
155 ConsensusItem::Module(mci) => {
156 if mci.module_instance_id() == module_instance_id {
157 vec![DynModuleHistoryItem::ConsensusItem(mci)]
158 } else {
159 vec![]
160 }
161 }
162 ConsensusItem::Default { .. } => {
163 unreachable!("We never save unknown CIs on the server side")
164 }
165 };
166 futures::stream::iter(history_items)
167 });
168
169 Box::pin(stream)
170 }
171}