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}
33
34impl std::fmt::Display for DbKeyPrefix {
35    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
36        write!(f, "{self:?}")
37    }
38}
39
40#[derive(Clone, Debug, Encodable, Decodable, Serialize)]
41pub struct BlockHashKey(pub BlockHash);
42
43#[derive(Clone, Debug, Encodable, Decodable)]
44pub struct BlockHashKeyPrefix;
45
46impl_db_record!(
47    key = BlockHashKey,
48    value = (),
49    db_prefix = DbKeyPrefix::BlockHash,
50);
51impl_db_lookup!(key = BlockHashKey, query_prefix = BlockHashKeyPrefix);
52
53#[derive(Clone, Debug, Eq, PartialEq, Encodable, Decodable, Serialize)]
54pub struct UTXOKey(pub bitcoin::OutPoint);
55
56#[derive(Clone, Debug, Encodable, Decodable)]
57pub struct UTXOPrefixKey;
58
59impl_db_record!(
60    key = UTXOKey,
61    value = SpendableUTXO,
62    db_prefix = DbKeyPrefix::Utxo,
63);
64impl_db_lookup!(key = UTXOKey, query_prefix = UTXOPrefixKey);
65
66#[derive(Clone, Debug, Encodable, Decodable, Serialize)]
67pub struct UnsignedTransactionKey(pub Txid);
68
69#[derive(Clone, Debug, Encodable, Decodable)]
70pub struct UnsignedTransactionPrefixKey;
71
72impl_db_record!(
73    key = UnsignedTransactionKey,
74    value = UnsignedTransaction,
75    db_prefix = DbKeyPrefix::UnsignedTransaction,
76);
77impl_db_lookup!(
78    key = UnsignedTransactionKey,
79    query_prefix = UnsignedTransactionPrefixKey
80);
81
82#[derive(Clone, Debug, Encodable, Decodable, Serialize)]
83pub struct PendingTransactionKey(pub Txid);
84
85#[derive(Clone, Debug, Encodable, Decodable)]
86pub struct PendingTransactionPrefixKey;
87
88impl_db_record!(
89    key = PendingTransactionKey,
90    value = PendingTransaction,
91    db_prefix = DbKeyPrefix::PendingTransaction,
92);
93impl_db_lookup!(
94    key = PendingTransactionKey,
95    query_prefix = PendingTransactionPrefixKey
96);
97
98#[derive(Clone, Debug, Encodable, Decodable, Serialize)]
99pub struct PegOutTxSignatureCI(pub Txid);
100
101#[derive(Clone, Debug, Encodable, Decodable)]
102pub struct PegOutTxSignatureCIPrefix;
103
104impl_db_record!(
105    key = PegOutTxSignatureCI,
106    value = Vec<Signature>,
107    db_prefix = DbKeyPrefix::PegOutTxSigCi,
108);
109impl_db_lookup!(
110    key = PegOutTxSignatureCI,
111    query_prefix = PegOutTxSignatureCIPrefix
112);
113
114#[derive(Clone, Debug, Encodable, Decodable, Serialize)]
115pub struct PegOutBitcoinTransaction(pub fedimint_core::OutPoint);
116
117#[derive(Clone, Debug, Encodable, Decodable)]
118pub struct PegOutBitcoinTransactionPrefix;
119
120impl_db_record!(
121    key = PegOutBitcoinTransaction,
122    value = WalletOutputOutcome,
123    db_prefix = DbKeyPrefix::PegOutBitcoinOutPoint,
124);
125
126impl_db_lookup!(
127    key = PegOutBitcoinTransaction,
128    query_prefix = PegOutBitcoinTransactionPrefix
129);
130
131#[derive(Clone, Debug, Encodable, Decodable, Serialize)]
132pub struct BlockCountVoteKey(pub PeerId);
133
134#[derive(Clone, Debug, Encodable, Decodable)]
135pub struct BlockCountVotePrefix;
136
137impl_db_record!(
138    key = BlockCountVoteKey,
139    value = u32,
140    db_prefix = DbKeyPrefix::BlockCountVote
141);
142
143impl_db_lookup!(key = BlockCountVoteKey, query_prefix = BlockCountVotePrefix);
144
145#[derive(Clone, Debug, Encodable, Decodable, Serialize)]
146pub struct FeeRateVoteKey(pub PeerId);
147
148#[derive(Clone, Debug, Encodable, Decodable)]
149pub struct FeeRateVotePrefix;
150
151impl_db_record!(
152    key = FeeRateVoteKey,
153    value = fedimint_core::Feerate,
154    db_prefix = DbKeyPrefix::FeeRateVote
155);
156
157impl_db_lookup!(key = FeeRateVoteKey, query_prefix = FeeRateVotePrefix);
158
159#[derive(Clone, Debug, Encodable, Decodable, Serialize)]
160pub struct ConsensusVersionVoteKey(pub PeerId);
161
162#[derive(Clone, Debug, Encodable, Decodable)]
163pub struct ConsensusVersionVotePrefix;
164
165impl_db_record!(
166    key = ConsensusVersionVoteKey,
167    value = ModuleConsensusVersion,
168    db_prefix = DbKeyPrefix::ConsensusVersionVote
169);
170
171impl_db_lookup!(
172    key = ConsensusVersionVoteKey,
173    query_prefix = ConsensusVersionVotePrefix
174);
175
176#[derive(Clone, Debug, Encodable, Decodable)]
177pub struct PegOutNonceKey;
178
179impl_db_record!(
180    key = PegOutNonceKey,
181    value = u64,
182    db_prefix = DbKeyPrefix::PegOutNonce
183);
184
185#[derive(Clone, Debug, Eq, PartialEq, Encodable, Decodable, Serialize)]
186pub struct ClaimedPegInOutpointKey(pub OutPoint);
187
188#[derive(Clone, Debug, Encodable, Decodable)]
189pub struct ClaimedPegInOutpointPrefixKey;
190
191impl_db_record!(
192    key = ClaimedPegInOutpointKey,
193    value = (),
194    db_prefix = DbKeyPrefix::ClaimedPegInOutpoint,
195);
196impl_db_lookup!(
197    key = ClaimedPegInOutpointKey,
198    query_prefix = ClaimedPegInOutpointPrefixKey
199);
200
201/// Migrate to v1, backfilling all previously pegged-in outpoints
202pub async fn migrate_to_v1(
203    mut ctx: ServerModuleDbMigrationFnContext<'_, Wallet>,
204) -> Result<(), anyhow::Error> {
205    let outpoints = ctx
206        .get_typed_module_history_stream()
207        .await
208        .filter_map(|item| async {
209            match item {
210                ModuleHistoryItem::Input(input) => {
211                    let outpoint = input
212                        .maybe_v0_ref()
213                        .expect("can only support V0 wallet inputs")
214                        .0
215                        .outpoint();
216
217                    Some(outpoint)
218                }
219                ModuleHistoryItem::Output(_) | ModuleHistoryItem::ConsensusItem(_) => None,
220            }
221        })
222        .collect::<Vec<_>>()
223        .await;
224
225    let mut dbtx = ctx.dbtx();
226    for outpoint in outpoints {
227        dbtx.insert_new_entry(&ClaimedPegInOutpointKey(outpoint), &())
228            .await;
229    }
230
231    Ok(())
232}
233
234#[derive(Clone, Debug, Encodable, Decodable, Serialize)]
235pub struct UnspentTxOutKey(pub bitcoin::OutPoint);
236
237#[derive(Clone, Debug, Encodable, Decodable)]
238pub struct UnspentTxOutPrefix;
239
240impl_db_record!(
241    key = UnspentTxOutKey,
242    value = TxOut,
243    db_prefix = DbKeyPrefix::UnspentTxOut,
244);
245impl_db_lookup!(key = UnspentTxOutKey, query_prefix = UnspentTxOutPrefix);
246
247#[derive(Clone, Debug, Encodable, Decodable, Serialize)]
248pub struct ConsensusVersionVotingActivationKey;
249
250#[derive(Clone, Debug, Encodable, Decodable)]
251pub struct ConsensusVersionVotingActivationPrefix;
252
253impl_db_record!(
254    key = ConsensusVersionVotingActivationKey,
255    value = (),
256    db_prefix = DbKeyPrefix::ConsensusVersionVotingActivation,
257);
258impl_db_lookup!(
259    key = ConsensusVersionVotingActivationKey,
260    query_prefix = ConsensusVersionVotingActivationPrefix
261);