Guard concurrent sends with exclusive DB lock and URI/RK checks#1376
Guard concurrent sends with exclusive DB lock and URI/RK checks#1376Mshehu5 wants to merge 1 commit intopayjoin:masterfrom
Conversation
Pull Request Test Coverage Report for Build 23953519233Details
💛 - Coveralls |
zealsham
left a comment
There was a problem hiding this comment.
tAck!
Can you rebase as this branch is almost a month old.
payjoin-cli/src/db/v2.rs
Outdated
| // Create a new session in send_sessions and get its ID | ||
| let session_id: i64 = conn.query_row( | ||
| "INSERT INTO send_sessions (session_id, receiver_pubkey) VALUES (NULL, ?1) RETURNING session_id", | ||
| params![receiver_pubkey.to_compressed_bytes()], | ||
| "INSERT INTO send_sessions (pj_uri, receiver_pubkey) VALUES (?1, ?2) RETURNING session_id", | ||
| params![pj_uri, &receiver_pubkey_bytes.as_slice()], |
There was a problem hiding this comment.
I don't think .as_slice() does anything here as the receiver_pubkey_bytes is already [u8]
39a1c67 to
cc8e38d
Compare
There was a problem hiding this comment.
ACK! , it still needs another pair of eyes before we can get it in
tested and got this
✦ ❯ ./../../target/debug/payjoin-cli send "bitcoin:bcrt1qdlfxfpmyn08g6wytw0qqq623mn7463ezplreaq?amount=0.00001&pjos=0&pj=HTTPS://PAYJO.IN/FZRC3CRDXV826%23EX1VEHUG6G-OH1QYPFLM8XL59R0XV4VGPLS7FRDSSM4TUXL07TXCWC4S0GLVLNK2SE4NQ-RK1QV6EYM8CPS9DL5CZKYGC2WWNLNL8D00PCPZ3M83K70ATLGC2GAD6Q " --fee-rate=1 & ./../../target/debug/payjoin-cli send "bitcoin:bcrt1qdlfxfpmyn08g6wytw0qqq623mn7463ezplreaq?amount=0.00001&pjos=0&pj=HTTPS://PAYJO.IN/FZRC3CRDXV826%23EX1VEHUG6G-OH1QYPFLM8XL59R0XV4VGPLS7FRDSSM4TUXL07TXCWC4S0GLVLNK2SE4NQ-RK1QV6EYM8CPS9DL5CZKYGC2WWNLNL8D00PCPZ3M83K70ATLGC2GAD6Q " --fee-rate=1
[1] 62106
Error: Database operation failed: database is locked
Caused by:
0: database is locked
1: Error code 5: The database file is locked
rust-payjoin/payjoin-cli/sender on guard_send [?] took 5s
✦ ❯ Bootstrapping private network transport over Oblivious HTTP
Posted original proposal...
Proposal received. Processing...
Payjoin sent. TXID: af8dee914cbb9608723e49a88be8a5e70e0f62a442db9d6b79c53740bd56172a
[1] + 62106 done ./../../target/debug/payjoin-cli send --fee-rate=1
with only one of the transaction going through which is intended as per implementation
nothingmuch
left a comment
There was a problem hiding this comment.
i think completed sessions should still not allow reuse
Specific carveouts for canceled or failed sessions can be added, but we should still do that carefully, for example if two non-double-spending fallback transactions are given, that can result in the sender overpaying. this PR currently makes doing that unintentionally more difficult, but not impossible, IMO it should be impossible
| pub(crate) fn create(path: impl AsRef<Path>) -> Result<Self> { | ||
| let manager = SqliteConnectionManager::file(path.as_ref()); | ||
| let manager = SqliteConnectionManager::file(path.as_ref()) | ||
| .with_init(|conn| conn.execute_batch("PRAGMA locking_mode = EXCLUSIVE;")); |
There was a problem hiding this comment.
isn't it more appropriate to put this in init_schema? or was this done deliberately to upgrade existing databases? if so some explanatory comment should be given
There was a problem hiding this comment.
thanks for the clarification, i thought it was a schema level pragma
payjoin-cli/src/db/v2.rs
Outdated
| EXISTS(SELECT 1 FROM send_sessions WHERE completed_at IS NULL AND pj_uri = ?1), \ | ||
| EXISTS(SELECT 1 FROM send_sessions WHERE completed_at IS NULL AND receiver_pubkey = ?2)", |
There was a problem hiding this comment.
what's the rationale for completed_at IS NULL? if a completed session with a duplicate session exists shouldn't this also ensure that it was canceled in order to allow reusing the URI?
There was a problem hiding this comment.
true, this has been removed
payjoin-cli/Cargo.toml
Outdated
| anyhow = "1.0.99" | ||
| async-trait = "0.1.89" | ||
| bitcoind-async-client = { git = "https://github.com/benalleng/bitcoind-async-client.git", rev = "a6292420de5cfd666d6185c534bea3f22736452b" } | ||
| bitcoind-async-client = { git = "https://github.com/benalleng/bitcoind-async-client.git", rev = "96a4bde287c397981faba74896dd3ceff6bd58e4" } |
There was a problem hiding this comment.
is this change intended?
There was a problem hiding this comment.
also for this bitcoind-async-client had an issues so we had to use a fork of ben allen at the time so i had to make the change to pass CI this has been fixed in #1441
payjoin-cli/src/db/v2.rs
Outdated
| ); | ||
| } | ||
|
|
||
| /// After a session is marked completed, a new session with the same URI should be allowed. |
There was a problem hiding this comment.
i disagree, that may result in address reuse, which is very bad, as well as key reuse of the HPKE receiver key, which is arguably not as bad but still undesirable
There was a problem hiding this comment.
changes have been so even after a completed session, a new session with the same URI will still be rejected
nothingmuch
left a comment
There was a problem hiding this comment.
utACK except for minor nits
i'm confused about the weird formatting of that removed line, i would have expected CI to complain about that
|
|
||
| pub fn from_id(db: Arc<Database>, id: SessionId) -> Self { Self { db, session_id: id } } | ||
| } | ||
|
|
There was a problem hiding this comment.
i think this needs rustfmt
There was a problem hiding this comment.
seems according to rustfmt rules this is the right way to write it
also tried adding the line but rust fmt removed it
| } | ||
|
|
||
| #[derive(Clone)] | ||
| #[derive(Clone, Debug)] |
There was a problem hiding this comment.
is the debug still necessary?
There was a problem hiding this comment.
still needed for test, when removed test error
| for session_id in send_session_ids { | ||
| let sender_persiter = SenderPersister::from_id(self.db.clone(), session_id.clone()); | ||
| match replay_sender_event_log(&sender_persiter) { | ||
| let sender_persister = SenderPersister::from_id(self.db.clone(), session_id.clone()); |
There was a problem hiding this comment.
in this case it doesn't matter but as i'm lookinmg at this change for the 3rd time and remembering it's just a typo fix that's unrelated, it'd be helpful if in the future this kind of change was in a separate commit
Two concurrent send commands targeting the same URI could select different coins. Set PRAGMA locking_mode = EXCLUSIVE so only one process holds write access at a time. Check uniqueness of URI and recceiver pubkey with duplicate checks
This PR Closes #1032
As discussed in the issue two concurrent send commands targeting the same URI could select different coins. PRAGMA locking_mode = EXCLUSIVE has been set as stated to make only one process holds write access at a time.
And also check to make sure URI and recceiver pubkey which are in use for another session is not reused
Co-authored by claude sonnet 4.6
Pull Request Checklist
Please confirm the following before requesting review:
AI
in the body of this PR.