Skip to content

Commit 02091df

Browse files
authored
Update select_first_candidate to return InternalSelectionError::Empty (payjoin#542)
Fix payjoin#535 Update `select_first_candidate` to return `InternalSelectionError::Empty` when there are no candidates available for selection
2 parents 3311a09 + 96fe0c0 commit 02091df

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
@@ -410,9 +410,6 @@ impl WantsInputs {
410410
candidate_inputs: impl IntoIterator<Item = InputPair>,
411411
) -> Result<InputPair, SelectionError> {
412412
let mut candidate_inputs = candidate_inputs.into_iter().peekable();
413-
if candidate_inputs.peek().is_none() {
414-
return Err(InternalSelectionError::Empty.into());
415-
}
416413

417414
self.avoid_uih(&mut candidate_inputs)
418415
.or_else(|_| self.select_first_candidate(&mut candidate_inputs))
@@ -472,7 +469,7 @@ impl WantsInputs {
472469
&self,
473470
candidate_inputs: impl IntoIterator<Item = InputPair>,
474471
) -> Result<InputPair, SelectionError> {
475-
candidate_inputs.into_iter().next().ok_or(InternalSelectionError::NotFound.into())
472+
candidate_inputs.into_iter().next().ok_or(InternalSelectionError::Empty.into())
476473
}
477474

478475
/// Add the provided list of inputs to the transaction.
@@ -848,6 +845,43 @@ pub(crate) mod test {
848845
}
849846
}
850847

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

0 commit comments

Comments
 (0)