Skip to content

Commit a2e01d5

Browse files
benthecarmandunxen
authored andcommitted
Handle if funding output is in a coinbase transaction
1 parent e9d9711 commit a2e01d5

File tree

2 files changed

+34
-11
lines changed

2 files changed

+34
-11
lines changed

lightning/src/ln/channel.rs

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,9 @@ pub(crate) const DISCONNECT_PEER_AWAITING_RESPONSE_TICKS: usize = 2;
594594
/// exceeding this age limit will be force-closed and purged from memory.
595595
pub(crate) const UNFUNDED_CHANNEL_AGE_LIMIT_TICKS: usize = 60;
596596

597+
/// Number of blocks needed for an output from a coinbase transaction to be spendable.
598+
pub(crate) const COINBASE_MATURITY: u32 = 100;
599+
597600
struct PendingChannelMonitorUpdate {
598601
update: ChannelMonitorUpdate,
599602
}
@@ -4734,12 +4737,14 @@ impl<SP: Deref> Channel<SP> where
47344737
return Err(ClosureReason::ProcessingError { err: err_reason.to_owned() });
47354738
} else {
47364739
if self.context.is_outbound() {
4737-
for input in tx.input.iter() {
4738-
if input.witness.is_empty() {
4739-
// We generated a malleable funding transaction, implying we've
4740-
// just exposed ourselves to funds loss to our counterparty.
4741-
#[cfg(not(fuzzing))]
4742-
panic!("Client called ChannelManager::funding_transaction_generated with bogus transaction!");
4740+
if !tx.is_coin_base() {
4741+
for input in tx.input.iter() {
4742+
if input.witness.is_empty() {
4743+
// We generated a malleable funding transaction, implying we've
4744+
// just exposed ourselves to funds loss to our counterparty.
4745+
#[cfg(not(fuzzing))]
4746+
panic!("Client called ChannelManager::funding_transaction_generated with bogus transaction!");
4747+
}
47434748
}
47444749
}
47454750
}
@@ -4750,6 +4755,13 @@ impl<SP: Deref> Channel<SP> where
47504755
Err(_) => panic!("Block was bogus - either height was > 16 million, had > 16 million transactions, or had > 65k outputs"),
47514756
}
47524757
}
4758+
// If this is a coinbase transaction and not a 0-conf channel
4759+
// we should update our min_depth to 100 to handle coinbase maturity
4760+
if tx.is_coin_base() &&
4761+
self.context.minimum_depth.unwrap_or(0) > 0 &&
4762+
self.context.minimum_depth.unwrap_or(0) < COINBASE_MATURITY {
4763+
self.context.minimum_depth = Some(COINBASE_MATURITY);
4764+
}
47534765
}
47544766
// If we allow 1-conf funding, we may need to check for channel_ready here and
47554767
// send it immediately instead of waiting for a best_block_updated call (which
@@ -5821,6 +5833,15 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
58215833

58225834
self.context.channel_state = ChannelState::FundingCreated as u32;
58235835
self.context.channel_id = funding_txo.to_channel_id();
5836+
5837+
// If the funding transaction is a coinbase transaction, we need to set the minimum depth to 100.
5838+
// We can skip this if it is a zero-conf channel.
5839+
if funding_transaction.is_coin_base() &&
5840+
self.context.minimum_depth.unwrap_or(0) > 0 &&
5841+
self.context.minimum_depth.unwrap_or(0) < COINBASE_MATURITY {
5842+
self.context.minimum_depth = Some(COINBASE_MATURITY);
5843+
}
5844+
58245845
self.context.funding_transaction = Some(funding_transaction);
58255846

58265847
let channel = Channel {

lightning/src/ln/channelmanager.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3561,11 +3561,13 @@ where
35613561
pub fn funding_transaction_generated(&self, temporary_channel_id: &ChannelId, counterparty_node_id: &PublicKey, funding_transaction: Transaction) -> Result<(), APIError> {
35623562
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
35633563

3564-
for inp in funding_transaction.input.iter() {
3565-
if inp.witness.is_empty() {
3566-
return Err(APIError::APIMisuseError {
3567-
err: "Funding transaction must be fully signed and spend Segwit outputs".to_owned()
3568-
});
3564+
if !funding_transaction.is_coin_base() {
3565+
for inp in funding_transaction.input.iter() {
3566+
if inp.witness.is_empty() {
3567+
return Err(APIError::APIMisuseError {
3568+
err: "Funding transaction must be fully signed and spend Segwit outputs".to_owned()
3569+
});
3570+
}
35693571
}
35703572
}
35713573
{

0 commit comments

Comments
 (0)