fedimint_wallet_server/
db.rs

1use bitcoin::secp256k1::ecdsa::Signature;
2use bitcoin::{BlockHash, OutPoint, TxOut, Txid};
3use fedimint_core::db::IDatabaseTransactionOpsCoreTyped;
4use fedimint_core::encoding::{Decodable, Encodable};
5use fedimint_core::module::ModuleConsensusVersion;
6use fedimint_core::{PeerId, impl_db_lookup, impl_db_record};
7use fedimint_server_core::migration::{
8    ModuleHistoryItem, ServerModuleDbMigrationFnContext, ServerModuleDbMigrationFnContextExt as _,
9};
10use futures::StreamExt;
11use serde::Serialize;
12use strum_macros::EnumIter;
13
14use crate::{PendingTransaction, SpendableUTXO, UnsignedTransaction, Wallet, WalletOutputOutcome};
15
16#[repr(u8)]
17#[derive(Clone, EnumIter, Debug)]
18pub enum DbKeyPrefix {
19    BlockHash = 0x30,
20    Utxo = 0x31,
21    BlockCountVote = 0x32,
22    FeeRateVote = 0x33,
23    UnsignedTransaction = 0x34,
24    PendingTransaction = 0x35,
25    PegOutTxSigCi = 0x36,
26    PegOutBitcoinOutPoint = 0x37,
27    PegOutNonce = 0x38,
28    ClaimedPegInOutpoint = 0x39,
29    ConsensusVersionVote = 0x40,
30    UnspentTxOut = 0x41,
31    ConsensusVersionVotingActivation = 0x42,
32    // Note: this key was added in 0.8, and it is not guaranteed
33    // to be present for all past processed blocks, unless Federation
34    // was started with fedimint 0.8 or later
35    BlockHashByHeight = 0x43,
36}
37
38impl std::fmt::Display for DbKeyPrefix {
39    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
40        write!(f, "{self:?}")
41    }
42}
43
44#[derive(Clone, Debug, Encodable, Decodable, Serialize)]
45pub struct BlockHashKey(pub BlockHash);
46
47#[derive(Clone, Debug, Encodable, Decodable)]
48pub struct BlockHashKeyPrefix;
49
50impl_db_record!(
51    key = BlockHashKey,
52    value = (),
53    db_prefix = DbKeyPrefix::BlockHash,
54);
55impl_db_lookup!(key = BlockHashKey, query_prefix = BlockHashKeyPrefix);
56
57/// Note: only added in 0.8 and not backfilled. See
58/// [`DbKeyPrefix::BlockHashByHeight`]
59#[derive(Clone, Debug, Encodable, Decodable, Serialize)]
60pub struct BlockHashByHeightKey(pub u32);
61
62#[derive(Clone, Debug, Encodable, Decodable, Serialize)]
63pub struct BlockHashByHeightValue(pub BlockHash);
64
65#[derive(Clone, Debug, Encodable, Decodable)]
66pub struct BlockHashByHeightKeyPrefix;
67
68impl_db_record!(
69    key = BlockHashByHeightKey,
70    value = BlockHashByHeightValue,
71    db_prefix = DbKeyPrefix::BlockHashByHeight,
72);
73impl_db_lookup!(
74    key = BlockHashByHeightKey,
75    query_prefix = BlockHashByHeightKeyPrefix
76);
77
78#[derive(Clone, Debug, Eq, PartialEq, Encodable, Decodable, Serialize)]
79pub struct UTXOKey(pub bitcoin::OutPoint);
80
81#[derive(Clone, Debug, Encodable, Decodable)]
82pub struct UTXOPrefixKey;
83
84impl_db_record!(
85    key = UTXOKey,
86    value = SpendableUTXO,
87    db_prefix = DbKeyPrefix::Utxo,
88);
89impl_db_lookup!(key = UTXOKey, query_prefix = UTXOPrefixKey);
90
91#[derive(Clone, Debug, Encodable, Decodable, Serialize)]
92pub struct UnsignedTransactionKey(pub Txid);
93
94#[derive(Clone, Debug, Encodable, Decodable)]
95pub struct UnsignedTransactionPrefixKey;
96
97impl_db_record!(
98    key = UnsignedTransactionKey,
99    value = UnsignedTransaction,
100    db_prefix = DbKeyPrefix::UnsignedTransaction,
101);
102impl_db_lookup!(
103    key = UnsignedTransactionKey,
104    query_prefix = UnsignedTransactionPrefixKey
105);
106
107#[derive(Clone, Debug, Encodable, Decodable, Serialize)]
108pub struct PendingTransactionKey(pub Txid);
109
110#[derive(Clone, Debug, Encodable, Decodable)]
111pub struct PendingTransactionPrefixKey;
112
113impl_db_record!(
114    key = PendingTransactionKey,
115    value = PendingTransaction,
116    db_prefix = DbKeyPrefix::PendingTransaction,
117);
118impl_db_lookup!(
119    key = PendingTransactionKey,
120    query_prefix = PendingTransactionPrefixKey
121);
122
123#[derive(Clone, Debug, Encodable, Decodable, Serialize)]
124pub struct PegOutTxSignatureCI(pub Txid);
125
126#[derive(Clone, Debug, Encodable, Decodable)]
127pub struct PegOutTxSignatureCIPrefix;
128
129impl_db_record!(
130    key = PegOutTxSignatureCI,
131    value = Vec<Signature>,
132    db_prefix = DbKeyPrefix::PegOutTxSigCi,
133);
134impl_db_lookup!(
135    key = PegOutTxSignatureCI,
136    query_prefix = PegOutTxSignatureCIPrefix
137);
138
139#[derive(Clone, Debug, Encodable, Decodable, Serialize)]
140pub struct PegOutBitcoinTransaction(pub fedimint_core::OutPoint);
141
142#[derive(Clone, Debug, Encodable, Decodable)]
143pub struct PegOutBitcoinTransactionPrefix;
144
145impl_db_record!(
146    key = PegOutBitcoinTransaction,
147    value = WalletOutputOutcome,
148    db_prefix = DbKeyPrefix::PegOutBitcoinOutPoint,
149);
150
151impl_db_lookup!(
152    key = PegOutBitcoinTransaction,
153    query_prefix = PegOutBitcoinTransactionPrefix
154);
155
156#[derive(Clone, Debug, Encodable, Decodable, Serialize)]
157pub struct BlockCountVoteKey(pub PeerId);
158
159#[derive(Clone, Debug, Encodable, Decodable)]
160pub struct BlockCountVotePrefix;
161
162impl_db_record!(
163    key = BlockCountVoteKey,
164    value = u32,
165    db_prefix = DbKeyPrefix::BlockCountVote
166);
167
168impl_db_lookup!(key = BlockCountVoteKey, query_prefix = BlockCountVotePrefix);
169
170#[derive(Clone, Debug, Encodable, Decodable, Serialize)]
171pub struct FeeRateVoteKey(pub PeerId);
172
173#[derive(Clone, Debug, Encodable, Decodable)]
174pub struct FeeRateVotePrefix;
175
176impl_db_record!(
177    key = FeeRateVoteKey,
178    value = fedimint_core::Feerate,
179    db_prefix = DbKeyPrefix::FeeRateVote
180);
181
182impl_db_lookup!(key = FeeRateVoteKey, query_prefix = FeeRateVotePrefix);
183
184#[derive(Clone, Debug, Encodable, Decodable, Serialize)]
185pub struct ConsensusVersionVoteKey(pub PeerId);
186
187#[derive(Clone, Debug, Encodable, Decodable)]
188pub struct ConsensusVersionVotePrefix;
189
190impl_db_record!(
191    key = ConsensusVersionVoteKey,
192    value = ModuleConsensusVersion,
193    db_prefix = DbKeyPrefix::ConsensusVersionVote
194);
195
196impl_db_lookup!(
197    key = ConsensusVersionVoteKey,
198    query_prefix = ConsensusVersionVotePrefix
199);
200
201#[derive(Clone, Debug, Encodable, Decodable)]
202pub struct PegOutNonceKey;
203
204impl_db_record!(
205    key = PegOutNonceKey,
206    value = u64,
207    db_prefix = DbKeyPrefix::PegOutNonce
208);
209
210#[derive(Clone, Debug, Eq, PartialEq, Encodable, Decodable, Serialize)]
211pub struct ClaimedPegInOutpointKey(pub OutPoint);
212
213#[derive(Clone, Debug, Encodable, Decodable)]
214pub struct ClaimedPegInOutpointPrefixKey;
215
216impl_db_record!(
217    key = ClaimedPegInOutpointKey,
218    value = (),
219    db_prefix = DbKeyPrefix::ClaimedPegInOutpoint,
220);
221impl_db_lookup!(
222    key = ClaimedPegInOutpointKey,
223    query_prefix = ClaimedPegInOutpointPrefixKey
224);
225
226/// Migrate to v1, backfilling all previously pegged-in outpoints
227pub async fn migrate_to_v1(
228    mut ctx: ServerModuleDbMigrationFnContext<'_, Wallet>,
229) -> Result<(), anyhow::Error> {
230    let outpoints = ctx
231        .get_typed_module_history_stream()
232        .await
233        .filter_map(|item| async {
234            match item {
235                ModuleHistoryItem::Input(input) => {
236                    let outpoint = input
237                        .maybe_v0_ref()
238                        .expect("can only support V0 wallet inputs")
239                        .0
240                        .outpoint();
241
242                    Some(outpoint)
243                }
244                ModuleHistoryItem::Output(_) | ModuleHistoryItem::ConsensusItem(_) => None,
245            }
246        })
247        .collect::<Vec<_>>()
248        .await;
249
250    let mut dbtx = ctx.dbtx();
251    for outpoint in outpoints {
252        dbtx.insert_new_entry(&ClaimedPegInOutpointKey(outpoint), &())
253            .await;
254    }
255
256    Ok(())
257}
258
259#[derive(Clone, Debug, Encodable, Decodable, Serialize)]
260pub struct UnspentTxOutKey(pub bitcoin::OutPoint);
261
262#[derive(Clone, Debug, Encodable, Decodable)]
263pub struct UnspentTxOutPrefix;
264
265impl_db_record!(
266    key = UnspentTxOutKey,
267    value = TxOut,
268    db_prefix = DbKeyPrefix::UnspentTxOut,
269);
270impl_db_lookup!(key = UnspentTxOutKey, query_prefix = UnspentTxOutPrefix);
271
272#[derive(Clone, Debug, Encodable, Decodable, Serialize)]
273pub struct ConsensusVersionVotingActivationKey;
274
275#[derive(Clone, Debug, Encodable, Decodable)]
276pub struct ConsensusVersionVotingActivationPrefix;
277
278impl_db_record!(
279    key = ConsensusVersionVotingActivationKey,
280    value = (),
281    db_prefix = DbKeyPrefix::ConsensusVersionVotingActivation,
282);
283impl_db_lookup!(
284    key = ConsensusVersionVotingActivationKey,
285    query_prefix = ConsensusVersionVotingActivationPrefix
286);