Skip to content

Commit bbf1d93

Browse files
committed
Make PackageTemplate::merge_package fallible
This moves panics to a higher level, allows failures to be handled gracefully in some cases, and supports more explicit testing without using `#[should_panic]`.
1 parent 69e1c70 commit bbf1d93

File tree

2 files changed

+21
-22
lines changed

2 files changed

+21
-22
lines changed

lightning/src/chain/onchaintx.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -772,8 +772,12 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
772772
for j in 0..i {
773773
if requests[i].can_merge_with(&requests[j], cur_height) {
774774
let merge = requests.remove(i);
775-
requests[j].merge_package(merge);
776-
break;
775+
if let Err(rejected) = requests[j].merge_package(merge) {
776+
debug_assert!(false, "Merging package should not be rejected after verifying can_merge_with.");
777+
requests.insert(i, rejected);
778+
} else {
779+
break;
780+
}
777781
}
778782
}
779783
}
@@ -1102,7 +1106,7 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
11021106
OnchainEvent::ContentiousOutpoint { package } => {
11031107
if let Some(pending_claim) = self.claimable_outpoints.get(package.outpoints()[0]) {
11041108
if let Some(request) = self.pending_claim_requests.get_mut(&pending_claim.0) {
1105-
request.merge_package(package);
1109+
assert!(request.merge_package(package).is_ok());
11061110
// Using a HashMap guarantee us than if we have multiple outpoints getting
11071111
// resurrected only one bump claim tx is going to be broadcast
11081112
bump_candidates.insert(pending_claim.clone(), request.clone());

lightning/src/chain/package.rs

+14-19
Original file line numberDiff line numberDiff line change
@@ -831,18 +831,18 @@ impl PackageTemplate {
831831
}
832832
}
833833
}
834-
pub(crate) fn merge_package(&mut self, mut merge_from: PackageTemplate) {
834+
pub(crate) fn merge_package(&mut self, mut merge_from: PackageTemplate) -> Result<(), PackageTemplate> {
835835
if self.malleability == PackageMalleability::Untractable || merge_from.malleability == PackageMalleability::Untractable {
836-
panic!("Merging template on untractable packages");
836+
return Err(merge_from);
837837
}
838838
if !self.aggregable || !merge_from.aggregable {
839-
panic!("Merging non aggregatable packages");
839+
return Err(merge_from);
840840
}
841841
if let Some((_, lead_input)) = self.inputs.first() {
842842
for (_, v) in merge_from.inputs.iter() {
843-
if !lead_input.is_compatible(v) { panic!("Merging outputs from differing types !"); }
843+
if !lead_input.is_compatible(v) { return Err(merge_from); }
844844
}
845-
} else { panic!("Merging template on an empty package"); }
845+
} else { return Err(merge_from); }
846846
for (k, v) in merge_from.inputs.drain(..) {
847847
self.inputs.push((k, v));
848848
}
@@ -854,6 +854,7 @@ impl PackageTemplate {
854854
self.feerate_previous = merge_from.feerate_previous;
855855
}
856856
self.height_timer = cmp::min(self.height_timer, merge_from.height_timer);
857+
Ok(())
857858
}
858859
/// Gets the amount of all outptus being spent by this package, only valid for malleable
859860
/// packages.
@@ -1323,7 +1324,6 @@ mod tests {
13231324
}
13241325

13251326
#[test]
1326-
#[should_panic]
13271327
fn test_package_untractable_merge_to() {
13281328
let txid = Txid::from_str("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap();
13291329
let secp_ctx = Secp256k1::new();
@@ -1332,11 +1332,10 @@ mod tests {
13321332

13331333
let mut untractable_package = PackageTemplate::build_package(txid, 0, revk_outp.clone(), 1000);
13341334
let malleable_package = PackageTemplate::build_package(txid, 1, htlc_outp.clone(), 1000);
1335-
untractable_package.merge_package(malleable_package);
1335+
assert!(untractable_package.merge_package(malleable_package).is_err());
13361336
}
13371337

13381338
#[test]
1339-
#[should_panic]
13401339
fn test_package_untractable_merge_from() {
13411340
let txid = Txid::from_str("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap();
13421341
let secp_ctx = Secp256k1::new();
@@ -1345,11 +1344,10 @@ mod tests {
13451344

13461345
let mut malleable_package = PackageTemplate::build_package(txid, 0, htlc_outp.clone(), 1000);
13471346
let untractable_package = PackageTemplate::build_package(txid, 1, revk_outp.clone(), 1000);
1348-
malleable_package.merge_package(untractable_package);
1347+
assert!(malleable_package.merge_package(untractable_package).is_err());
13491348
}
13501349

13511350
#[test]
1352-
#[should_panic]
13531351
fn test_package_noaggregation_to() {
13541352
let txid = Txid::from_str("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap();
13551353
let secp_ctx = Secp256k1::new();
@@ -1358,11 +1356,10 @@ mod tests {
13581356

13591357
let mut noaggregation_package = PackageTemplate::build_package(txid, 0, revk_outp_counterparty_balance.clone(), 1000);
13601358
let aggregation_package = PackageTemplate::build_package(txid, 1, revk_outp.clone(), 1000);
1361-
noaggregation_package.merge_package(aggregation_package);
1359+
assert!(noaggregation_package.merge_package(aggregation_package).is_err());
13621360
}
13631361

13641362
#[test]
1365-
#[should_panic]
13661363
fn test_package_noaggregation_from() {
13671364
let txid = Txid::from_str("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap();
13681365
let secp_ctx = Secp256k1::new();
@@ -1371,11 +1368,10 @@ mod tests {
13711368

13721369
let mut aggregation_package = PackageTemplate::build_package(txid, 0, revk_outp.clone(), 1000);
13731370
let noaggregation_package = PackageTemplate::build_package(txid, 1, revk_outp_counterparty_balance.clone(), 1000);
1374-
aggregation_package.merge_package(noaggregation_package);
1371+
assert!(aggregation_package.merge_package(noaggregation_package).is_err());
13751372
}
13761373

13771374
#[test]
1378-
#[should_panic]
13791375
fn test_package_empty() {
13801376
let txid = Txid::from_str("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap();
13811377
let secp_ctx = Secp256k1::new();
@@ -1384,11 +1380,10 @@ mod tests {
13841380
let mut empty_package = PackageTemplate::build_package(txid, 0, revk_outp.clone(), 1000);
13851381
empty_package.inputs = vec![];
13861382
let package = PackageTemplate::build_package(txid, 1, revk_outp.clone(), 1000);
1387-
empty_package.merge_package(package);
1383+
assert!(empty_package.merge_package(package).is_err());
13881384
}
13891385

13901386
#[test]
1391-
#[should_panic]
13921387
fn test_package_differing_categories() {
13931388
let txid = Txid::from_str("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap();
13941389
let secp_ctx = Secp256k1::new();
@@ -1397,7 +1392,7 @@ mod tests {
13971392

13981393
let mut revoked_package = PackageTemplate::build_package(txid, 0, revk_outp, 1000);
13991394
let counterparty_package = PackageTemplate::build_package(txid, 1, counterparty_outp, 1000);
1400-
revoked_package.merge_package(counterparty_package);
1395+
assert!(revoked_package.merge_package(counterparty_package).is_err());
14011396
}
14021397

14031398
#[test]
@@ -1412,8 +1407,8 @@ mod tests {
14121407
let package_two = PackageTemplate::build_package(txid, 1, revk_outp_two, 1000);
14131408
let package_three = PackageTemplate::build_package(txid, 2, revk_outp_three, 1000);
14141409

1415-
package_one.merge_package(package_two);
1416-
package_one.merge_package(package_three);
1410+
assert!(package_one.merge_package(package_two).is_ok());
1411+
assert!(package_one.merge_package(package_three).is_ok());
14171412
assert_eq!(package_one.outpoints().len(), 3);
14181413

14191414
if let Some(split_package) = package_one.split_package(&BitcoinOutPoint { txid, vout: 1 }) {

0 commit comments

Comments
 (0)