Skip to content

Commit d8db75b

Browse files
committed
feat: add SQLite database for payjoin session persistence
- Create db.rs with Database, SenderPersister and ReceiverPersister - Implement SessionPersister trait for both sender and receiver - Add session ID management and query methods - Add input deduplication tracking to prevent probing attacks - Add timestamp formatting utilities
1 parent f80d92a commit d8db75b

2 files changed

Lines changed: 462 additions & 0 deletions

File tree

src/error.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,10 @@ pub enum BDKCliError {
141141
#[error("Payjoin create request error: {0}")]
142142
PayjoinCreateRequest(#[from] payjoin::send::v2::CreateRequestError),
143143

144+
#[cfg(feature = "payjoin")]
145+
#[error("Payjoin database error: {0}")]
146+
PayjoinDb(#[from] PayjoinDbError),
147+
144148
#[cfg(feature = "bip322")]
145149
#[error("BIP-322 error: {0}")]
146150
Bip322Error(#[from] bdk_bip322::error::Error),
@@ -172,3 +176,64 @@ impl From<bdk_wallet::rusqlite::Error> for BDKCliError {
172176
BDKCliError::RusqliteError(Box::new(err))
173177
}
174178
}
179+
180+
/// Error type for payjoin database operations
181+
#[cfg(feature = "payjoin")]
182+
#[derive(Debug)]
183+
pub enum PayjoinDbError {
184+
/// SQLite database error
185+
Rusqlite(bdk_wallet::rusqlite::Error),
186+
/// JSON serialization error
187+
Serialize(serde_json::Error),
188+
/// JSON deserialization error
189+
Deserialize(serde_json::Error),
190+
}
191+
192+
#[cfg(feature = "payjoin")]
193+
impl std::fmt::Display for PayjoinDbError {
194+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
195+
match self {
196+
PayjoinDbError::Rusqlite(e) => write!(f, "Database operation failed: {e}"),
197+
PayjoinDbError::Serialize(e) => write!(f, "Serialization failed: {e}"),
198+
PayjoinDbError::Deserialize(e) => write!(f, "Deserialization failed: {e}"),
199+
}
200+
}
201+
}
202+
203+
#[cfg(feature = "payjoin")]
204+
impl std::error::Error for PayjoinDbError {
205+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
206+
match self {
207+
PayjoinDbError::Rusqlite(e) => Some(e),
208+
PayjoinDbError::Serialize(e) => Some(e),
209+
PayjoinDbError::Deserialize(e) => Some(e),
210+
}
211+
}
212+
}
213+
214+
#[cfg(feature = "payjoin")]
215+
impl From<bdk_wallet::rusqlite::Error> for PayjoinDbError {
216+
fn from(error: bdk_wallet::rusqlite::Error) -> Self {
217+
PayjoinDbError::Rusqlite(error)
218+
}
219+
}
220+
221+
#[cfg(feature = "payjoin")]
222+
impl From<PayjoinDbError> for payjoin::ImplementationError {
223+
fn from(error: PayjoinDbError) -> Self {
224+
payjoin::ImplementationError::new(error)
225+
}
226+
}
227+
228+
#[cfg(feature = "payjoin")]
229+
impl<ApiErr, StorageErr, ErrorState>
230+
From<payjoin::persist::PersistedError<ApiErr, StorageErr, ErrorState>> for BDKCliError
231+
where
232+
ApiErr: std::error::Error,
233+
StorageErr: std::error::Error,
234+
ErrorState: std::fmt::Debug,
235+
{
236+
fn from(e: payjoin::persist::PersistedError<ApiErr, StorageErr, ErrorState>) -> Self {
237+
BDKCliError::Generic(e.to_string())
238+
}
239+
}

0 commit comments

Comments
 (0)