next_local_commitment_tx_fee_info_cached: Mutex<Option<CommitmentTxInfoCached>>,
#[cfg(any(test, feature = "fuzztarget"))]
next_remote_commitment_tx_fee_info_cached: Mutex<Option<CommitmentTxInfoCached>>,
+
+ /// lnd has a long-standing bug where, upon reconnection, if the channel is not yet confirmed
+ /// they will not send a channel_reestablish until the channel locks in. Then, they will send a
+ /// funding_locked *before* sending the channel_reestablish (which is clearly a violation of
+ /// the BOLT specs). We copy c-lightning's workaround here and simply store the funding_locked
+ /// message until we receive a channel_reestablish.
+ ///
+ /// See-also <https://github.com/lightningnetwork/lnd/issues/4006>
+ pub workaround_lnd_bug_4006: Option<msgs::FundingLocked>,
}
#[cfg(any(test, feature = "fuzztarget"))]
next_local_commitment_tx_fee_info_cached: Mutex::new(None),
#[cfg(any(test, feature = "fuzztarget"))]
next_remote_commitment_tx_fee_info_cached: Mutex::new(None),
+
+ workaround_lnd_bug_4006: None,
})
}
next_local_commitment_tx_fee_info_cached: Mutex::new(None),
#[cfg(any(test, feature = "fuzztarget"))]
next_remote_commitment_tx_fee_info_cached: Mutex::new(None),
+
+ workaround_lnd_bug_4006: None,
};
Ok(chan)
if msg.channel_reserve_satoshis > self.channel_value_satoshis {
return Err(ChannelError::Close(format!("Bogus channel_reserve_satoshis ({}). Must not be greater than ({})", msg.channel_reserve_satoshis, self.channel_value_satoshis)));
}
- if msg.dust_limit_satoshis > msg.channel_reserve_satoshis {
- return Err(ChannelError::Close(format!("Bogus channel_reserve ({}) and dust_limit ({})", msg.channel_reserve_satoshis, msg.dust_limit_satoshis)));
- }
if msg.channel_reserve_satoshis < self.holder_dust_limit_satoshis {
return Err(ChannelError::Close(format!("Peer never wants payout outputs? channel_reserve_satoshis was ({}). dust_limit is ({})", msg.channel_reserve_satoshis, self.holder_dust_limit_satoshis)));
}
pub fn funding_locked(&mut self, msg: &msgs::FundingLocked) -> Result<(), ChannelError> {
if self.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 {
- return Err(ChannelError::Close("Peer sent funding_locked when we needed a channel_reestablish".to_owned()));
+ self.workaround_lnd_bug_4006 = Some(msg.clone());
+ return Err(ChannelError::Ignore("Peer sent funding_locked when we needed a channel_reestablish. The peer is likely lnd, see https://github.com/lightningnetwork/lnd/issues/4006".to_owned()));
}
let non_shutdown_state = self.channel_state & (!MULTI_STATE_FLAGS);
const SERIALIZATION_VERSION: u8 = 1;
const MIN_SERIALIZATION_VERSION: u8 = 1;
-impl Writeable for InboundHTLCRemovalReason {
- fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
- match self {
- &InboundHTLCRemovalReason::FailRelay(ref error_packet) => {
- 0u8.write(writer)?;
- error_packet.write(writer)?;
- },
- &InboundHTLCRemovalReason::FailMalformed((ref onion_hash, ref err_code)) => {
- 1u8.write(writer)?;
- onion_hash.write(writer)?;
- err_code.write(writer)?;
- },
- &InboundHTLCRemovalReason::Fulfill(ref payment_preimage) => {
- 2u8.write(writer)?;
- payment_preimage.write(writer)?;
- },
- }
- Ok(())
- }
-}
-
-impl Readable for InboundHTLCRemovalReason {
- fn read<R: ::std::io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
- Ok(match <u8 as Readable>::read(reader)? {
- 0 => InboundHTLCRemovalReason::FailRelay(Readable::read(reader)?),
- 1 => InboundHTLCRemovalReason::FailMalformed((Readable::read(reader)?, Readable::read(reader)?)),
- 2 => InboundHTLCRemovalReason::Fulfill(Readable::read(reader)?),
- _ => return Err(DecodeError::InvalidValue),
- })
- }
-}
+impl_writeable_tlv_based_enum!(InboundHTLCRemovalReason,;
+ (0, FailRelay),
+ (1, FailMalformed),
+ (2, Fulfill),
+);
impl Writeable for ChannelUpdateStatus {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
&OutboundHTLCState::Committed => {
1u8.write(writer)?;
},
- &OutboundHTLCState::RemoteRemoved(ref fail_reason) => {
- 2u8.write(writer)?;
- fail_reason.write(writer)?;
+ &OutboundHTLCState::RemoteRemoved(_) => {
+ // Treat this as a Committed because we haven't received the CS - they'll
+ // resend the claim/fail on reconnect as we all (hopefully) the missing CS.
+ 1u8.write(writer)?;
},
&OutboundHTLCState::AwaitingRemoteRevokeToRemove(ref fail_reason) => {
3u8.write(writer)?;
next_local_commitment_tx_fee_info_cached: Mutex::new(None),
#[cfg(any(test, feature = "fuzztarget"))]
next_remote_commitment_tx_fee_info_cached: Mutex::new(None),
+
+ workaround_lnd_bug_4006: None,
})
}
}