fedimint_client_module/
db.rs

1use std::io::Cursor;
2
3use fedimint_core::core::OperationId;
4use fedimint_core::db::{DatabaseTransaction, DatabaseValue as _};
5use fedimint_core::encoding::Decodable;
6use fedimint_core::module::registry::ModuleDecoderRegistry;
7use fedimint_core::util::BoxFuture;
8
9/// `ClientMigrationFn` is a function that modules can implement to "migrate"
10/// the database to the next database version.
11pub type ClientModuleMigrationFn = for<'r, 'tx> fn(
12    &'r mut DatabaseTransaction<'tx>,
13    Vec<(Vec<u8>, OperationId)>, // active states
14    Vec<(Vec<u8>, OperationId)>, // inactive states
15) -> BoxFuture<
16    'r,
17    anyhow::Result<Option<(Vec<(Vec<u8>, OperationId)>, Vec<(Vec<u8>, OperationId)>)>>,
18>;
19
20/// Helper function definition for migrating a single state.
21type MigrateStateFn =
22    fn(OperationId, &mut Cursor<&[u8]>) -> anyhow::Result<Option<(Vec<u8>, OperationId)>>;
23
24/// Migrates a particular state by looping over all active and inactive states.
25/// If the `migrate` closure returns `None`, this state was not migrated and
26/// should be added to the new state machine vectors.
27pub fn migrate_state(
28    active_states: Vec<(Vec<u8>, OperationId)>,
29    inactive_states: Vec<(Vec<u8>, OperationId)>,
30    migrate: MigrateStateFn,
31) -> anyhow::Result<Option<(Vec<(Vec<u8>, OperationId)>, Vec<(Vec<u8>, OperationId)>)>> {
32    let mut new_active_states = Vec::with_capacity(active_states.len());
33    for (active_state, operation_id) in active_states {
34        let bytes = active_state.as_slice();
35
36        let decoders = ModuleDecoderRegistry::default();
37        let mut cursor = std::io::Cursor::new(bytes);
38        let module_instance_id = fedimint_core::core::ModuleInstanceId::consensus_decode_partial(
39            &mut cursor,
40            &decoders,
41        )?;
42
43        let state = match migrate(operation_id, &mut cursor)? {
44            Some((mut state, operation_id)) => {
45                let mut final_state = module_instance_id.to_bytes();
46                final_state.append(&mut state);
47                (final_state, operation_id)
48            }
49            None => (active_state, operation_id),
50        };
51
52        new_active_states.push(state);
53    }
54
55    let mut new_inactive_states = Vec::with_capacity(inactive_states.len());
56    for (inactive_state, operation_id) in inactive_states {
57        let bytes = inactive_state.as_slice();
58
59        let decoders = ModuleDecoderRegistry::default();
60        let mut cursor = std::io::Cursor::new(bytes);
61        let module_instance_id = fedimint_core::core::ModuleInstanceId::consensus_decode_partial(
62            &mut cursor,
63            &decoders,
64        )?;
65
66        let state = match migrate(operation_id, &mut cursor)? {
67            Some((mut state, operation_id)) => {
68                let mut final_state = module_instance_id.to_bytes();
69                final_state.append(&mut state);
70                (final_state, operation_id)
71            }
72            None => (inactive_state, operation_id),
73        };
74
75        new_inactive_states.push(state);
76    }
77
78    Ok(Some((new_active_states, new_inactive_states)))
79}