Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion payjoin-cli/src/app/v2/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -985,7 +985,7 @@ impl App {
loop {
interval.tick().await;
let check_result = proposal
.check_for_broadcast(|txid| {
.check_for_transaction(|txid| {
self.wallet()
.get_raw_transaction(&txid)
.map_err(|e| ImplementationError::from(e.into_boxed_dyn_error()))
Expand Down
20 changes: 11 additions & 9 deletions payjoin-ffi/src/receive/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1437,7 +1437,7 @@ impl HasReplyableError {
}

#[uniffi::export(with_foreign)]
pub trait TransactionExists: Send + Sync {
pub trait TransactionFinder: Send + Sync {
fn callback(&self, txid: String) -> Result<Option<Vec<u8>>, ForeignError>;
}

Expand Down Expand Up @@ -1505,16 +1505,18 @@ fn try_deserialize_tx(

#[uniffi::export]
impl Monitor {
pub fn check_for_broadcast(
pub fn check_for_transaction(
&self,
transaction_exists: Arc<dyn TransactionExists>,
find_transaction: Arc<dyn TransactionFinder>,
) -> MonitorTransition {
MonitorTransition(Arc::new(RwLock::new(Some(self.0.clone().check_for_broadcast(|txid| {
transaction_exists
.callback(txid.to_string())
.and_then(|buf| buf.map(try_deserialize_tx).transpose())
.map_err(|e| ImplementationError::new(e).into())
})))))
MonitorTransition(Arc::new(RwLock::new(Some(self.0.clone().check_for_transaction(
|txid| {
find_transaction
.callback(txid.to_string())
.and_then(|buf| buf.map(try_deserialize_tx).transpose())
.map_err(|e| ImplementationError::new(e).into())
},
)))))
}
}

Expand Down
30 changes: 14 additions & 16 deletions payjoin/src/core/receive/v2/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1469,24 +1469,22 @@ pub struct Monitor {
/// The caller should decide the condition that must be satisfied for the Payjoin to be considered
/// successful.
///
/// Call [`Receiver<Monitor>::check_for_broadcast`] to confirm the status of the transaction in the
/// Call [`Receiver<Monitor>::check_for_transaction`] to confirm the status of the transaction in the
/// network and conclude the Payjoin session.
impl Receiver<Monitor> {
/// Checks the network for the Payjoin proposal or the fallback transaction using the passed
/// `transaction_exists` closure. Concludes the Payjoin session with a Success if the
/// transaction satisfies the condition.
///
/// For example, the condition can be if the transaction has been broadcast to the
/// network, or if it has some number of confirmations on the blockchain.
/// `find_transaction` closure, and concludes the Payjoin session once one is found. The
/// closure defines the condition that counts as found — for example presence in the mempool,
/// or some number of confirmations on the blockchain.
///
/// If the input address type in the fallback transaction is non-SegWit, then this
/// function will directly conclude the Payjoin session with a Success without running the
/// provided `transaction_exists` closure. `transaction_exists` uses the transaction ID to
/// provided `find_transaction` closure. `find_transaction` uses the transaction ID to
/// search for the transaction in the network. Since a non-SegWit input signature is going to
/// change the TXID of the Payjoin proposal, it cannot be monitored.
pub fn check_for_broadcast(
pub fn check_for_transaction(
&self,
transaction_exists: impl Fn(Txid) -> Result<Option<bitcoin::Transaction>, ImplementationError>,
find_transaction: impl Fn(Txid) -> Result<Option<bitcoin::Transaction>, ImplementationError>,
) -> MaybeFatalOrSuccessTransition<SessionEvent, Self, Error> {
let fallback_tx = self.state.fallback_tx();

Expand All @@ -1504,7 +1502,7 @@ impl Receiver<Monitor> {
// If the sender is spending SegWit-only inputs, then the transaction ID of the Payjoin proposal
// is not going to change when the sender signs it. So we can use the TXID to check the
// network for the Payjoin proposal.
match transaction_exists(payjoin_txid) {
match find_transaction(payjoin_txid) {
Ok(Some(tx)) => {
let tx_id = tx.compute_txid();
if tx_id != payjoin_txid {
Expand All @@ -1531,7 +1529,7 @@ impl Receiver<Monitor> {

// If the Payjoin proposal was not found, check the fallback transaction, as it is
// the second of two transactions whose IDs the receiver is aware of.
match transaction_exists(fallback_tx.compute_txid()) {
match find_transaction(fallback_tx.compute_txid()) {
Ok(Some(_)) =>
return MaybeFatalOrSuccessTransition::success(SessionEvent::Closed(
SessionOutcome::FallbackBroadcasted,
Expand Down Expand Up @@ -1699,7 +1697,7 @@ pub mod test {
// Nothing was spent, should be in the same state
let persister = InMemoryPersister::default();
let res = monitor
.check_for_broadcast(|_| Ok(None))
.check_for_transaction(|_| Ok(None))
.save(&persister)
.expect("InMemoryPersister shouldn't fail");
assert!(matches!(res, OptionalTransitionOutcome::Stasis(_)));
Expand All @@ -1709,7 +1707,7 @@ pub mod test {
// Payjoin was broadcasted, should progress to success
let persister = InMemoryPersister::default();
let res = monitor
.check_for_broadcast(|_| Ok(Some(payjoin_tx.clone())))
.check_for_transaction(|_| Ok(Some(payjoin_tx.clone())))
.save(&persister)
.expect("InMemoryPersister shouldn't fail");

Expand All @@ -1727,7 +1725,7 @@ pub mod test {
// Fallback was broadcasted, should progress to success
let persister = InMemoryPersister::default();
let res = monitor
.check_for_broadcast(|txid| {
.check_for_transaction(|txid| {
// Emulate if one of the fallback outpoints was double spent
if txid == original_tx.compute_txid() {
Ok(Some(original_tx.clone()))
Expand Down Expand Up @@ -1764,8 +1762,8 @@ pub mod test {

let persister = InMemoryPersister::default();
let res = monitor
.check_for_broadcast(|_| {
panic!("check_for_broadcast should return before this closure is called")
.check_for_transaction(|_| {
panic!("check_for_transaction should return before this closure is called")
})
.save(&persister)
.expect("InMemoryPersister shouldn't fail");
Expand Down
12 changes: 6 additions & 6 deletions payjoin/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -557,8 +557,8 @@ mod integration {
// The sender is using a non-SegWit address, so their signature is going to change the TXID. So we test whether the
// function exists early and does not call the closure.
monitoring_payment
.check_for_broadcast(|_| {
panic!("when the sender is using a non-SegWit address type, the check_for_broadcast function should skip the check and return success")
.check_for_transaction(|_| {
panic!("when the sender is using a non-SegWit address type, the check_for_transaction function should skip the check and return success")
})
.save(&recv_persister)
.expect("receiver should successfully monitor for the payment");
Expand Down Expand Up @@ -612,7 +612,7 @@ mod integration {

// Receiver should be able to validate that the sender has broadcasted the Payjoin proposal.
monitoring_payment
.check_for_broadcast(|txid| {
.check_for_transaction(|txid| {
let get_tx_result = receiver.get_raw_transaction(txid);
match get_tx_result {
Ok(tx) =>
Expand Down Expand Up @@ -694,7 +694,7 @@ mod integration {

// Receiver should be able to validate that the sender has broadcasted the Payjoin proposal.
monitoring_payment
.check_for_broadcast(|txid| {
.check_for_transaction(|txid| {
let get_tx_result = receiver.get_raw_transaction(txid);
match get_tx_result {
Ok(tx) =>
Expand Down Expand Up @@ -770,10 +770,10 @@ mod integration {
);

// Receiver should be able to validate that the sender has broadcasted the fallback transaction.
// The check_for_broadcast closure should be called twice: first for the Payjoin proposal, which will not be found,
// The check_for_transaction closure should be called twice: first for the Payjoin proposal, which will not be found,
// and then for the fallback transaction, which will be found..
monitoring_payment
.check_for_broadcast(|txid| {
.check_for_transaction(|txid| {
let get_tx_result = receiver.get_raw_transaction(txid);
match get_tx_result {
Ok(tx) =>
Expand Down
Loading