• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

payjoin / rust-payjoin / 18538611557

15 Oct 2025 06:20PM UTC coverage: 83.718% (-0.02%) from 83.737%
18538611557

Pull #1158

github

web-flow
Merge 486699407 into 7ac750c14
Pull Request #1158: Add completed_event_id FK to prevent session replay

88 of 108 new or added lines in 4 files covered. (81.48%)

125 existing lines in 4 files now uncovered.

9034 of 10791 relevant lines covered (83.72%)

916.7 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.06
/payjoin-cli/src/db/mod.rs
1
use std::path::Path;
2

3
use payjoin::bitcoin::consensus::encode::serialize;
4
use payjoin::bitcoin::OutPoint;
5
use r2d2::Pool;
6
use r2d2_sqlite::SqliteConnectionManager;
7
use rusqlite::{params, Connection};
8

9
pub(crate) mod error;
10
use error::*;
11

12
#[inline]
13
pub(crate) fn now() -> i64 {
46✔
14
    std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs() as i64
46✔
15
}
46✔
16

17
pub(crate) const DB_PATH: &str = "payjoin.sqlite";
18

19
pub(crate) struct Database(Pool<SqliteConnectionManager>);
20

21
impl Database {
22
    pub(crate) fn create(path: impl AsRef<Path>) -> Result<Self> {
26✔
23
        let manager = SqliteConnectionManager::file(path.as_ref());
26✔
24
        let pool = Pool::new(manager)?;
26✔
25

26
        // Initialize database schema
27
        let conn = pool.get()?;
26✔
28
        Self::init_schema(&conn)?;
26✔
29

30
        Ok(Self(pool))
26✔
31
    }
26✔
32

33
    fn init_schema(conn: &Connection) -> Result<()> {
26✔
34
        // Enable foreign keys
35
        conn.execute("PRAGMA foreign_keys = ON", [])?;
26✔
36

37
        conn.execute(
26✔
38
            "CREATE TABLE IF NOT EXISTS send_sessions (
26✔
39
                session_id INTEGER PRIMARY KEY AUTOINCREMENT,
26✔
40
                receiver_pubkey BLOB NOT NULL,
26✔
41
                completed_at INTEGER,
26✔
42
                completed_event_id INTEGER,
26✔
43
                FOREIGN KEY(completed_event_id) REFERENCES send_session_events(id)
26✔
44
            )",
26✔
45
            [],
26✔
UNCOV
46
        )?;
×
47

48
        conn.execute(
26✔
49
            "CREATE TABLE IF NOT EXISTS receive_sessions (
26✔
50
                session_id INTEGER PRIMARY KEY AUTOINCREMENT,
26✔
51
                completed_at INTEGER,
26✔
52
                completed_event_id INTEGER,
26✔
53
                FOREIGN KEY(completed_event_id) REFERENCES receive_session_events(id)
26✔
54
            )",
26✔
55
            [],
26✔
UNCOV
56
        )?;
×
57

58
        conn.execute(
26✔
59
            "CREATE TABLE IF NOT EXISTS send_session_events (
26✔
60
                id INTEGER PRIMARY KEY AUTOINCREMENT,
26✔
61
                session_id INTEGER NOT NULL,
26✔
62
                event_data TEXT NOT NULL,
26✔
63
                created_at INTEGER NOT NULL,
26✔
64
                FOREIGN KEY(session_id) REFERENCES send_sessions(session_id)
26✔
65
            )",
26✔
66
            [],
26✔
UNCOV
67
        )?;
×
68

69
        conn.execute(
26✔
70
            "CREATE TABLE IF NOT EXISTS receive_session_events (
26✔
71
                id INTEGER PRIMARY KEY AUTOINCREMENT,
26✔
72
                session_id INTEGER NOT NULL,
26✔
73
                event_data TEXT NOT NULL,
26✔
74
                created_at INTEGER NOT NULL,
26✔
75
                FOREIGN KEY(session_id) REFERENCES receive_sessions(session_id)
26✔
76
            )",
26✔
77
            [],
26✔
UNCOV
78
        )?;
×
79

80
        conn.execute(
26✔
81
            "CREATE TABLE IF NOT EXISTS inputs_seen (
26✔
82
                outpoint BLOB PRIMARY KEY,
26✔
83
                created_at INTEGER NOT NULL
26✔
84
            )",
26✔
85
            [],
26✔
UNCOV
86
        )?;
×
87

88
        Ok(())
26✔
89
    }
26✔
90

91
    pub(crate) fn get_connection(&self) -> Result<r2d2::PooledConnection<SqliteConnectionManager>> {
78✔
92
        Ok(self.0.get()?)
78✔
93
    }
78✔
94
    /// Inserts the input and returns true if the input was seen before, false otherwise.
95
    pub(crate) fn insert_input_seen_before(&self, input: OutPoint) -> Result<bool> {
8✔
96
        let conn = self.get_connection()?;
8✔
97
        let key = serialize(&input);
8✔
98

99
        let was_seen_before = conn.execute(
8✔
100
            "INSERT OR IGNORE INTO inputs_seen (outpoint, created_at) VALUES (?1, ?2)",
8✔
101
            params![key, now()],
8✔
102
        )? == 0;
8✔
103

104
        Ok(was_seen_before)
8✔
105
    }
8✔
106
}
107

108
#[cfg(feature = "v2")]
109
pub(crate) mod v2;
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc