1use std::io::Cursor;
2
3use bitcoin::hashes::sha256;
4use fedimint_core::core::OperationId;
5use fedimint_core::encoding::{Decodable, Encodable};
6use fedimint_core::module::registry::ModuleDecoderRegistry;
7use fedimint_core::secp256k1::{Keypair, PublicKey};
8use fedimint_core::{OutPoint, TransactionId, impl_db_lookup, impl_db_record};
9use fedimint_ln_common::{LightningGateway, LightningGatewayRegistration};
10use lightning_invoice::Bolt11Invoice;
11use serde::Serialize;
12use strum_macros::EnumIter;
13
14use crate::pay::lightningpay::LightningPayStates;
15use crate::pay::{
16 LightningPayCommon, LightningPayFunded, LightningPayRefund, LightningPayStateMachine,
17 PayInvoicePayload,
18};
19use crate::receive::{
20 LightningReceiveConfirmedInvoice, LightningReceiveStateMachine, LightningReceiveStates,
21 LightningReceiveSubmittedOffer, LightningReceiveSubmittedOfferV0,
22};
23use crate::{LightningClientStateMachines, OutgoingLightningPayment, ReceivingKey};
24
25#[repr(u8)]
26#[derive(Clone, EnumIter, Debug)]
27pub enum DbKeyPrefix {
28 ActiveGateway = 0x28,
30 PaymentResult = 0x29,
31 MetaOverridesDeprecated = 0x30,
32 LightningGateway = 0x45,
33 ExternalReservedStart = 0xb0,
36 CoreInternalReservedStart = 0xd0,
39 CoreInternalReservedEnd = 0xff,
40}
41
42impl std::fmt::Display for DbKeyPrefix {
43 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
44 write!(f, "{self:?}")
45 }
46}
47
48#[derive(Debug, Encodable, Decodable, Serialize)]
49pub struct ActiveGatewayKey;
50
51#[derive(Debug, Encodable, Decodable)]
52pub struct ActiveGatewayKeyPrefix;
53
54impl_db_record!(
55 key = ActiveGatewayKey,
56 value = LightningGatewayRegistration,
57 db_prefix = DbKeyPrefix::ActiveGateway,
58);
59impl_db_lookup!(
60 key = ActiveGatewayKey,
61 query_prefix = ActiveGatewayKeyPrefix
62);
63
64#[derive(Debug, Encodable, Decodable, Serialize)]
65pub struct PaymentResultKey {
66 pub payment_hash: sha256::Hash,
67}
68
69#[derive(Debug, Encodable, Decodable, Serialize)]
70pub struct PaymentResultPrefix;
71
72#[derive(Debug, Encodable, Decodable, Serialize)]
73pub struct PaymentResult {
74 pub index: u16,
75 pub completed_payment: Option<OutgoingLightningPayment>,
76}
77
78impl_db_record!(
79 key = PaymentResultKey,
80 value = PaymentResult,
81 db_prefix = DbKeyPrefix::PaymentResult,
82);
83
84impl_db_lookup!(key = PaymentResultKey, query_prefix = PaymentResultPrefix);
85
86#[derive(Debug, Encodable, Decodable, Serialize)]
87pub struct LightningGatewayKey(pub PublicKey);
88
89#[derive(Debug, Encodable, Decodable)]
90pub struct LightningGatewayKeyPrefix;
91
92impl_db_record!(
93 key = LightningGatewayKey,
94 value = LightningGatewayRegistration,
95 db_prefix = DbKeyPrefix::LightningGateway,
96);
97impl_db_lookup!(
98 key = LightningGatewayKey,
99 query_prefix = LightningGatewayKeyPrefix
100);
101
102pub(crate) fn get_v1_migrated_state(
105 operation_id: OperationId,
106 cursor: &mut Cursor<&[u8]>,
107) -> anyhow::Result<Option<(Vec<u8>, OperationId)>> {
108 #[derive(Debug, Clone, Decodable)]
109 pub struct LightningReceiveConfirmedInvoiceV0 {
110 invoice: Bolt11Invoice,
111 receiving_key: Keypair,
112 }
113
114 let decoders = ModuleDecoderRegistry::default();
115 let ln_sm_variant = u16::consensus_decode_partial(cursor, &decoders)?;
116
117 if ln_sm_variant != 2 {
119 return Ok(None);
120 }
121
122 let _ln_sm_len = u16::consensus_decode_partial(cursor, &decoders)?;
123 let _operation_id = OperationId::consensus_decode_partial(cursor, &decoders)?;
124 let receive_sm_variant = u16::consensus_decode_partial(cursor, &decoders)?;
125
126 let new = match receive_sm_variant {
127 0 => {
129 let _receive_sm_len = u16::consensus_decode_partial(cursor, &decoders)?;
130
131 let v0 = LightningReceiveSubmittedOfferV0::consensus_decode_partial(cursor, &decoders)?;
132
133 let new_offer = LightningReceiveSubmittedOffer {
134 offer_txid: v0.offer_txid,
135 invoice: v0.invoice,
136 receiving_key: ReceivingKey::Personal(v0.payment_keypair),
137 };
138 let new_recv = LightningReceiveStateMachine {
139 operation_id,
140 state: LightningReceiveStates::SubmittedOffer(new_offer),
141 };
142 LightningClientStateMachines::Receive(new_recv)
143 }
144 2 => {
146 let _receive_sm_len = u16::consensus_decode_partial(cursor, &decoders)?;
147 let confirmed_old =
148 LightningReceiveConfirmedInvoiceV0::consensus_decode_partial(cursor, &decoders)?;
149 let confirmed_new = LightningReceiveConfirmedInvoice {
150 invoice: confirmed_old.invoice,
151 receiving_key: ReceivingKey::Personal(confirmed_old.receiving_key),
152 };
153 LightningClientStateMachines::Receive(LightningReceiveStateMachine {
154 operation_id,
155 state: LightningReceiveStates::ConfirmedInvoice(confirmed_new),
156 })
157 }
158 _ => return Ok(None),
159 };
160
161 let bytes = new.consensus_encode_to_vec();
162 Ok(Some((bytes, operation_id)))
163}
164
165pub(crate) fn get_v2_migrated_state(
167 operation_id: OperationId,
168 cursor: &mut Cursor<&[u8]>,
169) -> anyhow::Result<Option<(Vec<u8>, OperationId)>> {
170 let decoders = ModuleDecoderRegistry::default();
171 let ln_sm_variant = u16::consensus_decode_partial(cursor, &decoders)?;
172
173 if ln_sm_variant != 2 {
175 return Ok(None);
176 }
177
178 let _ln_sm_len = u16::consensus_decode_partial(cursor, &decoders)?;
179 let _operation_id = OperationId::consensus_decode_partial(cursor, &decoders)?;
180 let receive_sm_variant = u16::consensus_decode_partial(cursor, &decoders)?;
181 if receive_sm_variant != 5 {
182 return Ok(None);
183 }
184
185 let _receive_sm_len = u16::consensus_decode_partial(cursor, &decoders)?;
186 let old = LightningReceiveSubmittedOffer::consensus_decode_partial(cursor, &decoders)?;
187
188 let new_recv = LightningClientStateMachines::Receive(LightningReceiveStateMachine {
189 operation_id,
190 state: LightningReceiveStates::SubmittedOffer(old),
191 });
192
193 let bytes = new_recv.consensus_encode_to_vec();
194 Ok(Some((bytes, operation_id)))
195}
196
197pub(crate) fn get_v3_migrated_state(
200 operation_id: OperationId,
201 cursor: &mut Cursor<&[u8]>,
202) -> anyhow::Result<Option<(Vec<u8>, OperationId)>> {
203 let decoders = ModuleDecoderRegistry::default();
204 let ln_sm_variant = u16::consensus_decode_partial(cursor, &decoders)?;
205
206 if ln_sm_variant != 1 {
208 return Ok(None);
209 }
210
211 let _ln_sm_len = u16::consensus_decode_partial(cursor, &decoders)?;
212 let common = LightningPayCommon::consensus_decode_partial(cursor, &decoders)?;
213 let pay_sm_variant = u16::consensus_decode_partial(cursor, &decoders)?;
214
215 let _pay_sm_len = u16::consensus_decode_partial(cursor, &decoders)?;
216
217 match pay_sm_variant {
219 2 => {
221 #[derive(Debug, Clone, Eq, PartialEq, Hash, Decodable, Encodable)]
222 pub struct LightningPayFundedV0 {
223 pub payload: PayInvoicePayload,
224 pub gateway: LightningGateway,
225 pub timelock: u32,
226 }
227
228 let v0 = LightningPayFundedV0::consensus_decode_partial(cursor, &decoders)?;
229 let v1 = LightningPayFunded {
230 payload: v0.payload,
231 gateway: v0.gateway,
232 timelock: v0.timelock,
233 funding_time: fedimint_core::time::now(),
234 };
235
236 let new_pay = LightningPayStateMachine {
237 common,
238 state: LightningPayStates::Funded(v1),
239 };
240 let new_sm = LightningClientStateMachines::LightningPay(new_pay);
241 let bytes = new_sm.consensus_encode_to_vec();
242 Ok(Some((bytes, operation_id)))
243 }
244 5 => {
246 #[derive(Debug, Clone, Eq, PartialEq, Hash, Decodable, Encodable)]
247 pub struct LightningPayRefundV0 {
248 txid: TransactionId,
249 out_points: Vec<OutPoint>,
250 }
251
252 let v0 = LightningPayRefundV0::consensus_decode_partial(cursor, &decoders)?;
253 let v1 = LightningPayRefund {
254 txid: v0.txid,
255 out_points: v0.out_points,
256 error_reason: "unknown error (database migration)".to_string(),
257 };
258 let new_pay = LightningPayStateMachine {
259 common,
260 state: LightningPayStates::Refund(v1),
261 };
262 let new_sm = LightningClientStateMachines::LightningPay(new_pay);
263 let bytes = new_sm.consensus_encode_to_vec();
264 Ok(Some((bytes, operation_id)))
265 }
266 _ => Ok(None),
267 }
268}
269
270#[cfg(test)]
271mod tests;