Skip to content

Commit

Permalink
Bubble up many integration.rs errors
Browse files Browse the repository at this point in the history
Avoid unwrap() by returning a Result<_, BoxError>
  • Loading branch information
DanGould committed Oct 19, 2024
1 parent b86b639 commit e07f10f
Showing 1 changed file with 23 additions and 35 deletions.
58 changes: 23 additions & 35 deletions payjoin/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ mod integration {
// **********************
// Inside the Receiver:
// this data would transit from one party to another over the network in production
let response = handle_v1_pj_request(req, headers, &receiver, None, None, None);
let response = handle_v1_pj_request(req, headers, &receiver, None, None, None)?;
// this response would be returned as http response to the sender

// **********************
Expand Down Expand Up @@ -157,18 +157,15 @@ mod integration {
.unwrap();
let psbt = build_original_psbt(&sender, &uri)?;
debug!("Original psbt: {:#?}", psbt);
let (req, ctx) = RequestBuilder::from_psbt_and_uri(psbt, uri)?
let (req, _ctx) = RequestBuilder::from_psbt_and_uri(psbt, uri)?
.build_with_additional_fee(Amount::from_sat(10000), None, FeeRate::ZERO, false)?
.extract_v1()?;
let headers = HeaderMock::new(&req.body, req.content_type);

// **********************
// Inside the Receiver:
// This should error because the receiver is attempting to introduce mixed input script types
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
handle_v1_pj_request(req, headers, &receiver, None, None, None)
}));
assert!(result.is_err());
assert!(handle_v1_pj_request(req, headers, &receiver, None, None, None).is_err());
Ok(())
}
}
Expand Down Expand Up @@ -611,7 +608,7 @@ mod integration {
// **********************
// Inside the Receiver:
// this data would transit from one party to another over the network in production
let response = handle_v1_pj_request(req, headers, &receiver, None, None, None);
let response = handle_v1_pj_request(req, headers, &receiver, None, None, None)?;
// this response would be returned as http response to the sender

// **********************
Expand Down Expand Up @@ -1051,7 +1048,7 @@ mod integration {
Some(outputs),
Some(&drain_script),
Some(inputs),
);
)?;
// this response would be returned as http response to the sender

// **********************
Expand Down Expand Up @@ -1137,7 +1134,7 @@ mod integration {
Some(outputs),
Some(&drain_script),
Some(inputs),
);
)?;
// this response would be returned as http response to the sender

// **********************
Expand Down Expand Up @@ -1247,20 +1244,19 @@ mod integration {
custom_outputs: Option<Vec<TxOut>>,
drain_script: Option<&bitcoin::Script>,
custom_inputs: Option<Vec<(PsbtInput, TxIn)>>,
) -> String {
) -> Result<String, BoxError> {
// Receiver receive payjoin proposal, IRL it will be an HTTP request (over ssl or onion)
let proposal = payjoin::receive::UncheckedProposal::from_request(
req.body.as_slice(),
req.url.query().unwrap_or(""),
headers,
)
.unwrap();
)?;
let proposal =
handle_proposal(proposal, receiver, custom_outputs, drain_script, custom_inputs);
handle_proposal(proposal, receiver, custom_outputs, drain_script, custom_inputs)?;
assert!(!proposal.is_output_substitution_disabled());
let psbt = proposal.psbt();
tracing::debug!("Receiver's Payjoin proposal PSBT: {:#?}", &psbt);
psbt.to_string()
Ok(psbt.to_string())
}

fn handle_proposal(
Expand All @@ -1269,7 +1265,7 @@ mod integration {
custom_outputs: Option<Vec<TxOut>>,
drain_script: Option<&bitcoin::Script>,
custom_inputs: Option<Vec<(PsbtInput, TxIn)>>,
) -> payjoin::receive::PayjoinProposal {
) -> Result<payjoin::receive::PayjoinProposal, BoxError> {
// in a payment processor where the sender could go offline, this is where you schedule to broadcast the original_tx
let _to_broadcast_in_failure_case = proposal.extract_tx_to_schedule_broadcast();

Expand All @@ -1282,54 +1278,47 @@ mod integration {
.first()
.unwrap()
.allowed)
})
.expect("Payjoin proposal should be broadcastable");
})?;

// Receive Check 2: receiver can't sign for proposal inputs
let proposal = proposal
.check_inputs_not_owned(|input| {
let address =
bitcoin::Address::from_script(&input, bitcoin::Network::Regtest).unwrap();
Ok(receiver.get_address_info(&address).unwrap().is_mine.unwrap())
})
.expect("Receiver should not own any of the inputs");
})?;

// Receive Check 3: have we seen this input before? More of a check for non-interactive i.e. payment processor receivers.
let payjoin = proposal
.check_no_inputs_seen_before(|_| Ok(false))
.unwrap()
.check_no_inputs_seen_before(|_| Ok(false))?
.identify_receiver_outputs(|output_script| {
let address =
bitcoin::Address::from_script(&output_script, bitcoin::Network::Regtest)
.unwrap();
Ok(receiver.get_address_info(&address).unwrap().is_mine.unwrap())
})
.expect("Receiver should have at least one output");
})?;

let payjoin = match custom_outputs {
Some(txos) => payjoin
.replace_receiver_outputs(txos, &drain_script.unwrap())
.expect("Could not substitute outputs"),
.replace_receiver_outputs(txos, &drain_script.unwrap())?,
None => payjoin
.substitute_receiver_script(
&receiver.get_new_address(None, None).unwrap().assume_checked().script_pubkey(),
)
.expect("Could not substitute outputs"),
&receiver.get_new_address(None, None)?.assume_checked().script_pubkey(),
)?,
}
.commit_outputs();

let inputs = match custom_inputs {
Some(inputs) => inputs,
None => {
let available_inputs = receiver.list_unspent(None, None, None, None, None).unwrap();
let available_inputs = receiver.list_unspent(None, None, None, None, None)?;
let candidate_inputs: HashMap<Amount, OutPoint> = available_inputs
.iter()
.map(|i| (i.amount, OutPoint { txid: i.txid, vout: i.vout }))
.collect();

let selected_outpoint = payjoin
.try_preserving_privacy(candidate_inputs)
.expect("Failed to make privacy preserving selection");
.try_preserving_privacy(candidate_inputs).map_err(|e| format!("Failed to make privacy preserving selection: {:?}", e))?;
let selected_utxo = available_inputs
.iter()
.find(|i| i.txid == selected_outpoint.txid && i.vout == selected_outpoint.vout)
Expand All @@ -1338,7 +1327,7 @@ mod integration {
vec![input_pair]
}
};
let payjoin = payjoin.contribute_inputs(inputs).unwrap().commit_inputs();
let payjoin = payjoin.contribute_inputs(inputs).map_err(|e| format!("Failed to contribute inputs: {:?}", e))?.commit_inputs();

let payjoin_proposal = payjoin
.finalize_proposal(
Expand All @@ -1358,9 +1347,8 @@ mod integration {
},
Some(FeeRate::BROADCAST_MIN),
FeeRate::from_sat_per_vb_unchecked(2),
)
.unwrap();
payjoin_proposal
)?;
Ok(payjoin_proposal)
}

fn extract_pj_tx(
Expand Down

0 comments on commit e07f10f

Please sign in to comment.