Skip to content

Commit 96fe0c0

Browse files
pseudoramdomspacebear21
authored andcommitted
Fix select_first_candidate error variant
Fixes payjoin#535. If there are no candidates, it should return `InternalSelectionError::Empty` instead of `NotFound`. The check in try_preserving_privacy was redundant so it is removed.
1 parent 68bdf3e commit 96fe0c0

File tree

1 file changed

+38
-4
lines changed

1 file changed

+38
-4
lines changed

payjoin/src/receive/v1/mod.rs

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -415,9 +415,6 @@ impl WantsInputs {
415415
candidate_inputs: impl IntoIterator<Item = InputPair>,
416416
) -> Result<InputPair, SelectionError> {
417417
let mut candidate_inputs = candidate_inputs.into_iter().peekable();
418-
if candidate_inputs.peek().is_none() {
419-
return Err(InternalSelectionError::Empty.into());
420-
}
421418

422419
self.avoid_uih(&mut candidate_inputs)
423420
.or_else(|_| self.select_first_candidate(&mut candidate_inputs))
@@ -477,7 +474,7 @@ impl WantsInputs {
477474
&self,
478475
candidate_inputs: impl IntoIterator<Item = InputPair>,
479476
) -> Result<InputPair, SelectionError> {
480-
candidate_inputs.into_iter().next().ok_or(InternalSelectionError::NotFound.into())
477+
candidate_inputs.into_iter().next().ok_or(InternalSelectionError::Empty.into())
481478
}
482479

483480
/// Add the provided list of inputs to the transaction.
@@ -842,6 +839,43 @@ pub(crate) mod test {
842839
}
843840
}
844841

842+
#[test]
843+
fn empty_candidates_inputs() {
844+
let proposal = proposal_from_test_vector().unwrap();
845+
let wants_inputs = proposal
846+
.assume_interactive_receiver()
847+
.check_inputs_not_owned(|_| Ok(false))
848+
.expect("No inputs should be owned")
849+
.check_no_inputs_seen_before(|_| Ok(false))
850+
.expect("No inputs should be seen before")
851+
.identify_receiver_outputs(|script| {
852+
let network = Network::Bitcoin;
853+
let target_address = Address::from_str("3CZZi7aWFugaCdUCS15dgrUUViupmB8bVM")
854+
.map_err(|e| e.to_string())?
855+
.require_network(network)
856+
.map_err(|e| e.to_string())?;
857+
858+
let script_address =
859+
Address::from_script(script, network).map_err(|e| e.to_string())?;
860+
Ok(script_address == target_address)
861+
})
862+
.expect("Receiver output should be identified")
863+
.commit_outputs();
864+
let empty_candidate_inputs: Vec<InputPair> = vec![];
865+
let result = wants_inputs.try_preserving_privacy(empty_candidate_inputs);
866+
match result {
867+
Err(err) => {
868+
let debug_str = format!("{:?}", err);
869+
assert!(
870+
debug_str.contains("Empty"),
871+
"Error should indicate 'Empty' but was: {}",
872+
debug_str
873+
);
874+
}
875+
Ok(_) => panic!("try_preserving_privacy should fail with empty candidate inputs"),
876+
}
877+
}
878+
845879
#[test]
846880
fn sender_specifies_excessive_fee_rate() {
847881
let mut proposal = proposal_from_test_vector().unwrap();

0 commit comments

Comments
 (0)