Handle if funding output is in a coinbase transaction

This commit is contained in:
benthecarman 2022-12-19 02:02:22 -06:00 committed by Duncan Dean
parent e9d9711de4
commit a2e01d5648
No known key found for this signature in database
2 changed files with 34 additions and 11 deletions

View file

@ -594,6 +594,9 @@ pub(crate) const DISCONNECT_PEER_AWAITING_RESPONSE_TICKS: usize = 2;
/// exceeding this age limit will be force-closed and purged from memory.
pub(crate) const UNFUNDED_CHANNEL_AGE_LIMIT_TICKS: usize = 60;
/// Number of blocks needed for an output from a coinbase transaction to be spendable.
pub(crate) const COINBASE_MATURITY: u32 = 100;
struct PendingChannelMonitorUpdate {
update: ChannelMonitorUpdate,
}
@ -4734,12 +4737,14 @@ impl<SP: Deref> Channel<SP> where
return Err(ClosureReason::ProcessingError { err: err_reason.to_owned() });
} else {
if self.context.is_outbound() {
for input in tx.input.iter() {
if input.witness.is_empty() {
// We generated a malleable funding transaction, implying we've
// just exposed ourselves to funds loss to our counterparty.
#[cfg(not(fuzzing))]
panic!("Client called ChannelManager::funding_transaction_generated with bogus transaction!");
if !tx.is_coin_base() {
for input in tx.input.iter() {
if input.witness.is_empty() {
// We generated a malleable funding transaction, implying we've
// just exposed ourselves to funds loss to our counterparty.
#[cfg(not(fuzzing))]
panic!("Client called ChannelManager::funding_transaction_generated with bogus transaction!");
}
}
}
}
@ -4750,6 +4755,13 @@ impl<SP: Deref> Channel<SP> where
Err(_) => panic!("Block was bogus - either height was > 16 million, had > 16 million transactions, or had > 65k outputs"),
}
}
// If this is a coinbase transaction and not a 0-conf channel
// we should update our min_depth to 100 to handle coinbase maturity
if tx.is_coin_base() &&
self.context.minimum_depth.unwrap_or(0) > 0 &&
self.context.minimum_depth.unwrap_or(0) < COINBASE_MATURITY {
self.context.minimum_depth = Some(COINBASE_MATURITY);
}
}
// If we allow 1-conf funding, we may need to check for channel_ready here and
// 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 {
self.context.channel_state = ChannelState::FundingCreated as u32;
self.context.channel_id = funding_txo.to_channel_id();
// If the funding transaction is a coinbase transaction, we need to set the minimum depth to 100.
// We can skip this if it is a zero-conf channel.
if funding_transaction.is_coin_base() &&
self.context.minimum_depth.unwrap_or(0) > 0 &&
self.context.minimum_depth.unwrap_or(0) < COINBASE_MATURITY {
self.context.minimum_depth = Some(COINBASE_MATURITY);
}
self.context.funding_transaction = Some(funding_transaction);
let channel = Channel {

View file

@ -3561,11 +3561,13 @@ where
pub fn funding_transaction_generated(&self, temporary_channel_id: &ChannelId, counterparty_node_id: &PublicKey, funding_transaction: Transaction) -> Result<(), APIError> {
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
for inp in funding_transaction.input.iter() {
if inp.witness.is_empty() {
return Err(APIError::APIMisuseError {
err: "Funding transaction must be fully signed and spend Segwit outputs".to_owned()
});
if !funding_transaction.is_coin_base() {
for inp in funding_transaction.input.iter() {
if inp.witness.is_empty() {
return Err(APIError::APIMisuseError {
err: "Funding transaction must be fully signed and spend Segwit outputs".to_owned()
});
}
}
}
{